Version in base suite: 0.3.10-2 Base version: libxmlb_0.3.10-2 Target version: libxmlb_0.3.22-1~deb12u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/libx/libxmlb/libxmlb_0.3.10-2.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/libx/libxmlb/libxmlb_0.3.22-1~deb12u1.dsc /srv/release.debian.org/tmp/GXPluD2F8H/libxmlb-0.3.22/data/test.xml.zst |binary libxmlb-0.3.22/.clang-format | 6 libxmlb-0.3.22/.clang-tidy | 42 libxmlb-0.3.22/.github/dependabot.yml | 6 libxmlb-0.3.22/.github/workflows/main.yml | 23 libxmlb-0.3.22/.github/workflows/scorecard.yml | 73 libxmlb-0.3.22/.pre-commit-config.yaml | 2 libxmlb-0.3.22/NEWS | 122 + libxmlb-0.3.22/README.md | 11 libxmlb-0.3.22/RELEASE | 11 libxmlb-0.3.22/SECURITY.md | 13 libxmlb-0.3.22/contrib/ci/Dockerfile-debian | 3 libxmlb-0.3.22/contrib/ci/Dockerfile-fedora | 3 libxmlb-0.3.22/contrib/ci/Dockerfile-fedora-w64 | 3 libxmlb-0.3.22/contrib/ci/check-license.py | 6 libxmlb-0.3.22/contrib/ci/check-null-false-returns.py | 4 libxmlb-0.3.22/contrib/libxmlb.spec.in | 5 libxmlb-0.3.22/contrib/reformat-code.py | 4 libxmlb-0.3.22/data/meson.build | 9 libxmlb-0.3.22/data/test.desktop | 5 libxmlb-0.3.22/data/test.quirk | 2 libxmlb-0.3.22/data/test.xml | 1 libxmlb-0.3.22/debian/changelog | 85 + libxmlb-0.3.22/debian/control | 6 libxmlb-0.3.22/debian/libxmlb2.symbols | 3 libxmlb-0.3.22/debian/rules | 2 libxmlb-0.3.22/debian/tests/installed-tests | 1 libxmlb-0.3.22/docs/fuzzing.md | 1 libxmlb-0.3.22/meson.build | 38 libxmlb-0.3.22/meson_options.txt | 14 libxmlb-0.3.22/src/gen-def-from-map.py | 101 + libxmlb-0.3.22/src/generate-version-script.py | 6 libxmlb-0.3.22/src/libxmlb.map | 6 libxmlb-0.3.22/src/meson.build | 54 libxmlb-0.3.22/src/xb-builder-fixup-private.h | 13 libxmlb-0.3.22/src/xb-builder-fixup.c | 4 libxmlb-0.3.22/src/xb-builder-fixup.h | 12 libxmlb-0.3.22/src/xb-builder-node-private.h | 35 libxmlb-0.3.22/src/xb-builder-node.c | 56 libxmlb-0.3.22/src/xb-builder-node.h | 73 libxmlb-0.3.22/src/xb-builder-source-ctx-private.h | 13 libxmlb-0.3.22/src/xb-builder-source-ctx.c | 4 libxmlb-0.3.22/src/xb-builder-source-ctx.h | 15 libxmlb-0.3.22/src/xb-builder-source-private.h | 22 libxmlb-0.3.22/src/xb-builder-source.c | 62 libxmlb-0.3.22/src/xb-builder-source.h | 23 libxmlb-0.3.22/src/xb-builder.c | 157 - libxmlb-0.3.22/src/xb-builder.h | 23 libxmlb-0.3.22/src/xb-common-private.h | 8 libxmlb-0.3.22/src/xb-common.c | 39 libxmlb-0.3.22/src/xb-compile.h | 18 libxmlb-0.3.22/src/xb-lzma-decompressor.c | 51 libxmlb-0.3.22/src/xb-lzma-decompressor.h | 8 libxmlb-0.3.22/src/xb-machine-private.h | 8 libxmlb-0.3.22/src/xb-machine.c | 805 ++++++---- libxmlb-0.3.22/src/xb-machine.h | 58 libxmlb-0.3.22/src/xb-node-private.h | 10 libxmlb-0.3.22/src/xb-node-query.c | 16 libxmlb-0.3.22/src/xb-node-query.h | 29 libxmlb-0.3.22/src/xb-node-silo.h | 8 libxmlb-0.3.22/src/xb-node.c | 41 libxmlb-0.3.22/src/xb-node.h | 49 libxmlb-0.3.22/src/xb-opcode-private.h | 89 - libxmlb-0.3.22/src/xb-opcode.c | 119 - libxmlb-0.3.22/src/xb-opcode.h | 31 libxmlb-0.3.22/src/xb-query-context.c | 7 libxmlb-0.3.22/src/xb-query-context.h | 27 libxmlb-0.3.22/src/xb-query-private.h | 8 libxmlb-0.3.22/src/xb-query.c | 4 libxmlb-0.3.22/src/xb-query.h | 23 libxmlb-0.3.22/src/xb-self-test.c | 244 ++- libxmlb-0.3.22/src/xb-silo-export-private.h | 7 libxmlb-0.3.22/src/xb-silo-export.c | 104 - libxmlb-0.3.22/src/xb-silo-export.h | 8 libxmlb-0.3.22/src/xb-silo-node.c | 111 - libxmlb-0.3.22/src/xb-silo-node.h | 124 + libxmlb-0.3.22/src/xb-silo-private.h | 57 libxmlb-0.3.22/src/xb-silo-query-private.h | 16 libxmlb-0.3.22/src/xb-silo-query.c | 85 - libxmlb-0.3.22/src/xb-silo-query.h | 20 libxmlb-0.3.22/src/xb-silo.c | 274 ++- libxmlb-0.3.22/src/xb-silo.h | 41 libxmlb-0.3.22/src/xb-stack-private.h | 23 libxmlb-0.3.22/src/xb-stack.c | 14 libxmlb-0.3.22/src/xb-stack.h | 10 libxmlb-0.3.22/src/xb-string-private.h | 10 libxmlb-0.3.22/src/xb-string.c | 4 libxmlb-0.3.22/src/xb-string.h | 11 libxmlb-0.3.22/src/xb-tool.c | 4 libxmlb-0.3.22/src/xb-value-bindings-private.h | 12 libxmlb-0.3.22/src/xb-value-bindings.c | 128 + libxmlb-0.3.22/src/xb-value-bindings.h | 48 libxmlb-0.3.22/src/xb-version.c | 25 libxmlb-0.3.22/src/xb-version.h.in | 17 libxmlb-0.3.22/src/xb-zstd-decompressor.c | 113 + libxmlb-0.3.22/src/xb-zstd-decompressor.h | 19 libxmlb-0.3.22/src/xmlb.h | 4 97 files changed, 2845 insertions(+), 1327 deletions(-) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp_y7pux20/libxmlb_0.3.10-2.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp_y7pux20/libxmlb_0.3.22-1~deb12u1.dsc: no acceptable signature found diff -Nru libxmlb-0.3.10/.clang-format libxmlb-0.3.22/.clang-format --- libxmlb-0.3.10/.clang-format 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/.clang-format 2025-03-12 09:35:38.000000000 +0000 @@ -39,9 +39,9 @@ Language: 'Cpp' IncludeCategories: - Regex: '^"config.h"$' - Priority: '1' + Priority: '0' - Regex: '^<' - Priority: '2' + Priority: '1' - Regex: '.*' - Priority: '4' + Priority: '2' ... diff -Nru libxmlb-0.3.10/.clang-tidy libxmlb-0.3.22/.clang-tidy --- libxmlb-0.3.10/.clang-tidy 1970-01-01 00:00:00.000000000 +0000 +++ libxmlb-0.3.22/.clang-tidy 2025-03-12 09:35:38.000000000 +0000 @@ -0,0 +1,42 @@ +--- +Checks: "-*,\ +bugprone-*,\ +-bugprone-assignment-in-if-condition,\ +-bugprone-easily-swappable-parameters,\ +-bugprone-implicit-widening-of-multiplication-result,\ +-bugprone-macro-parentheses,\ +-bugprone-misplaced-widening-cast,\ +-bugprone-narrowing-conversions,\ +-bugprone-reserved-identifier,\ +-bugprone-too-small-loop-variable,\ +-bugprone-unchecked-optional-access,\ +misc-*,\ +-misc-confusable-identifiers,\ +-misc-const-correctness,\ +-misc-non-private-member-variables-in-classes,\ +-misc-no-recursion,\ +-misc-static-assert,\ +-misc-unused-parameters,\ +modernize-*,\ +-modernize-macro-to-enum,\ +-modernize-use-trailing-return-type,\ +-modernize-use-transparent-functors,\ +performance-*,\ +-performance-inefficient-vector-operation,\ +-performance-no-int-to-ptr,\ +readability-*,\ +-readability-avoid-const-params-in-decls,\ +-readability-braces-around-statements,\ +-readability-function-cognitive-complexity,\ +-readability-identifier-length,\ +-readability-identifier-naming,\ +-readability-implicit-bool-conversion,\ +-readability-isolate-declaration,\ +-readability-magic-numbers,\ +-readability-non-const-parameter,\ +-readability-qualified-auto,\ +-readability-redundant-declaration,\ +-readability-suspicious-call-argument,\ +-readability-uppercase-literal-suffix,\ +" +... diff -Nru libxmlb-0.3.10/.github/dependabot.yml libxmlb-0.3.22/.github/dependabot.yml --- libxmlb-0.3.10/.github/dependabot.yml 1970-01-01 00:00:00.000000000 +0000 +++ libxmlb-0.3.22/.github/dependabot.yml 2025-03-12 09:35:38.000000000 +0000 @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff -Nru libxmlb-0.3.10/.github/workflows/main.yml libxmlb-0.3.22/.github/workflows/main.yml --- libxmlb-0.3.10/.github/workflows/main.yml 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/.github/workflows/main.yml 2025-03-12 09:35:38.000000000 +0000 @@ -6,6 +6,9 @@ pull_request: branches: [ main ] +permissions: + contents: read + jobs: build-linux: runs-on: ubuntu-latest @@ -13,26 +16,10 @@ matrix: distro: - fedora + - fedora-w64 - debian fail-fast: false steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - run: docker build -t libxmlb-${{ matrix.distro }} -f contrib/ci/Dockerfile-${{ matrix.distro }} . - run: docker run -t -v `pwd`:/build libxmlb-${{ matrix.distro }} ./contrib/ci/build-${{ matrix.distro }}.sh - - build-freebsd: - runs-on: macos-10.15 - - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Build - id: test - uses: vmactions/freebsd-vm@v0.1.5 - with: - usesh: true - mem: 8192 - prepare: | - pkg install -y git python3 glib meson pkgconf gobject-introspection gtk-doc lzma - sync: rsync - run: ./contrib/ci/build-debian.sh diff -Nru libxmlb-0.3.10/.github/workflows/scorecard.yml libxmlb-0.3.22/.github/workflows/scorecard.yml --- libxmlb-0.3.10/.github/workflows/scorecard.yml 1970-01-01 00:00:00.000000000 +0000 +++ libxmlb-0.3.22/.github/workflows/scorecard.yml 2025-03-12 09:35:38.000000000 +0000 @@ -0,0 +1,73 @@ +# This workflow uses actions that are not certified by GitHub. They are provided +# by a third-party and are governed by separate terms of service, privacy +# policy, and support documentation. + +name: Scorecard supply-chain security +on: + # For Branch-Protection check. Only the default branch is supported. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection + branch_protection_rule: + # To guarantee Maintained check is occasionally updated. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained + schedule: + - cron: '25 11 * * 1' + push: + branches: [ "main" ] + +# Declare default permissions as read only. +permissions: read-all + +jobs: + analysis: + name: Scorecard analysis + runs-on: ubuntu-latest + permissions: + # Needed to upload the results to code-scanning dashboard. + security-events: write + # Needed to publish results and get a badge (see publish_results below). + id-token: write + # Uncomment the permissions below if installing in a private repository. + # contents: read + # actions: read + + steps: + - name: "Checkout code" + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + persist-credentials: false + + - name: "Run analysis" + uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1 + with: + results_file: results.sarif + results_format: sarif + # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: + # - you want to enable the Branch-Protection check on a *public* repository, or + # - you are installing Scorecard on a *private* repository + # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action?tab=readme-ov-file#authentication-with-fine-grained-pat-optional. + # repo_token: ${{ secrets.SCORECARD_TOKEN }} + + # Public repositories: + # - Publish results to OpenSSF REST API for easy access by consumers + # - Allows the repository to include the Scorecard badge. + # - See https://github.com/ossf/scorecard-action#publishing-results. + # For private repositories: + # - `publish_results` will always be set to `false`, regardless + # of the value entered here. + publish_results: true + + # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF + # format to the repository Actions tab. + - name: "Upload artifact" + uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + # Upload the results to GitHub's code scanning dashboard (optional). + # Commenting out will disable upload of results to your repo's Code Scanning dashboard + - name: "Upload to code-scanning" + uses: github/codeql-action/upload-sarif@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11 + with: + sarif_file: results.sarif diff -Nru libxmlb-0.3.10/.pre-commit-config.yaml libxmlb-0.3.22/.pre-commit-config.yaml --- libxmlb-0.3.10/.pre-commit-config.yaml 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/.pre-commit-config.yaml 2025-03-12 09:35:38.000000000 +0000 @@ -21,7 +21,7 @@ - id: mixed-line-ending args: [--fix=lf] - repo: https://github.com/ambv/black - rev: 21.12b0 + rev: 22.3.0 hooks: - id: black - repo: local diff -Nru libxmlb-0.3.10/NEWS libxmlb-0.3.22/NEWS --- libxmlb-0.3.10/NEWS 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/NEWS 2025-03-12 09:35:38.000000000 +0000 @@ -1,3 +1,125 @@ +Version 0.3.22 +~~~~~~~~~~~~~~ +Released: 2025-03-12 + +New Features: + - Add support for COLLAPSE_EMPTY when exporting an XbBuilderNode (Richard Hughes) + - Store the expected file size in the header to detect truncation (Richard Hughes) + +Bugfixes: + - Check the strtab has a trailing NUL byte (Richard Hughes) + - Fix an issue when exporting a silo using COLLAPSE_EMPTY (Richard Hughes) + - Fix calling text() on an empty element (Richard Hughes) + +Version 0.3.21 +~~~~~~~~~~~~~~ +Released: 2024-10-15 + +Bugfixes: + - Check for corrupt XbSiloNode values in a smarter way (Richard Hughes) + +Version 0.3.20 +~~~~~~~~~~~~~~ +Released: 2024-10-14 + +Bugfixes: + - Do not always strip literal text (Richard Hughes) + - Do not assume .txt files are application/xml (Richard Hughes) + - Fix a crash when loading a corrupt XMLb store (Richard Hughes) + - Fix writing files on Windows (Richard Hughes) + +Version 0.3.19 +~~~~~~~~~~~~~~ +Released: 2024-04-22 + +New Features: + - Add xb_version_string() to get the runtime ABI version (Richard Hughes) + +Bugfixes: + - Add the runtime version as the default XMLb invalidation GUID (Richard Hughes) + +Version 0.3.18 +~~~~~~~~~~~~~~ +Released: 2024-04-09 + +Bugfixes: + - Fix decompressing large zstd files, harder (Richard Hughes) + - Include the pkgconfig variables in the subproject declared dependency (Richard Hughes) + +Version 0.3.17 +~~~~~~~~~~~~~~ +Released: 2024-04-05 + +Bugfixes: + - Create SECURITY.md for the OpenSSF scorecard (Richard Hughes) + - Fix decompressing large zstd files (Richard Hughes) + - Use zst as the file extension for zstd (Richard Hughes) + +Version 0.3.16 +~~~~~~~~~~~~~~ +Released: 2024-04-03 + +New Features: + - Add the lzma and zstd support to the pkgconfig file (Richard Hughes) + +Bugfixes: + - Make the LZMA support optional (Richard Hughes) + +Version 0.3.15 +~~~~~~~~~~~~~~ +Released: 2024-01-02 + +New Features: + - Sprinkle __attribute__((nonnull)) to give a little more compile-time safety (Richard Hughes) + +Bugfixes: + - Accept text/xml as an alternative to application/xml (peigongdsd) + - Do not inline shared code (Chun-wei Fan) + - Fix compiling with Visual Studio (Chun-wei Fan) + - Fix the exported api test on Windows (Chun-wei Fan) + - Generate and use .def file for clang-cl builds (Chun-wei Fan) + - Release source file handles early (Milan Crha) + +Version 0.3.14 +~~~~~~~~~~~~~~ +Released: 2023-10-24 + +Bugfixes: + - Fix comparing indexed text with integer values (Richard Hughes) + +Version 0.3.13 +~~~~~~~~~~~~~~ +Released: 2023-10-17 + +Bugfixes: + - Correctly tokenize when using a bound text value (Richard Hughes) + - Ensure tokens are all NULL when using xb_opcode_init() (Richard Hughes) + +Version 0.3.12 +~~~~~~~~~~~~~~ +Released: 2023-10-10 + +New Features: + - Use indexes when binding value (Richard Hughes) + +Bugfixes: + - Avoid building errors and debug strings when possible to make XbQuery faster (Christian Hergert) + - Fix content type detection on macOS (Richard Hughes) + - Inline a number of machine internals to make queries faster (Christian Hergert) + - Make zstd support optional (sulincix, aliriza) + - Setup various release build options (Christian Hergert) + +Version 0.3.11 +~~~~~~~~~~~~~~ +Released: 2023-02-20 + +New Features: + - Add limited support for XPath 1.0 'in' (Richard Hughes) + - Add support for zstd (Richard Hughes) + +Bugfixes: + - Do not assert() when decompressing invalid LZMA (Richard Hughes) + Version 0.3.10 ~~~~~~~~~~~~~~ Released: 2022-09-11 diff -Nru libxmlb-0.3.10/README.md libxmlb-0.3.22/README.md --- libxmlb-0.3.10/README.md 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/README.md 2025-03-12 09:35:38.000000000 +0000 @@ -1,6 +1,9 @@ libxmlb ======= +[![Coverity Scan Build Status](https://scan.coverity.com/projects/17055/badge.svg)](https://scan.coverity.com/projects/17055) +[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/hughsie/libxmlb/badge)](https://securityscorecards.dev/viewer/?uri=github.com/hughsie/libxmlb) + Introduction ------------ @@ -117,3 +120,11 @@ This will by default install the library into `/usr/local`. On some Linux distributions you may need to configure the linker path in `/etc/ld.so.conf` to be able to locate it. The call to `ldconfig` is needed to refresh the linker cache. + +`meson build` has options that can be used to disable certain features, e.g. + +``` +# meson build -Dintrospection=false -Dgtkdoc=false -Dcli=false +``` + +will remove support for GObject introspection, Gtk documentation, and will only build the library without the command line tool. As a result, fewer libraries are needed for building and running the project. diff -Nru libxmlb-0.3.10/RELEASE libxmlb-0.3.22/RELEASE --- libxmlb-0.3.10/RELEASE 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/RELEASE 2025-03-12 09:35:38.000000000 +0000 @@ -2,11 +2,11 @@ 1. Write NEWS entries for libxmlb in the same format as usual. -git shortlog 0.3.9.. | grep -i -v trivial | grep -v Merge > NEWS.new +git shortlog 0.3.21.. | grep -i -v trivial | grep -v Merge > NEWS.new -Version 0.3.10 +Version 0.3.22 ~~~~~~~~~~~~~~ -Released: 2022-xx-xx +Released: 2025-xx-xx New Features: Bugfixes: @@ -15,7 +15,7 @@ Commit changes to git: # MAKE SURE THESE ARE CORRECT -export release_ver="0.3.10" +export release_ver="0.3.22" git commit -a -m "Release libxmlb ${release_ver}" --no-verify git tag -s -f -m "Release libxmlb ${release_ver}" "${release_ver}" @@ -23,7 +23,8 @@ git push --tags git push gpg -b -a meson-dist/libxmlb-${release_ver}.tar.xz -scp meson-dist/libxmlb-${release_ver}.tar.* hughsient@people.freedesktop.org:~/public_html/releases + +Upload release artifacts via https://github.com/hughsie/libxmlb/tags Do post release version bump in meson.build diff -Nru libxmlb-0.3.10/SECURITY.md libxmlb-0.3.22/SECURITY.md --- libxmlb-0.3.10/SECURITY.md 1970-01-01 00:00:00.000000000 +0000 +++ libxmlb-0.3.22/SECURITY.md 2025-03-12 09:35:38.000000000 +0000 @@ -0,0 +1,13 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +| ------- | ------------------ | +| 0.3.x | :white_check_mark: | +| 0.2.x | :x: | +| 0.1.x | :x: | + +## Reporting a Vulnerability + +We have enabled private reporting in GitHub, so please [follow these steps](https://github.com/hughsie/libxmlb/security) to report vulnerabilities. diff -Nru libxmlb-0.3.10/contrib/ci/Dockerfile-debian libxmlb-0.3.22/contrib/ci/Dockerfile-debian --- libxmlb-0.3.10/contrib/ci/Dockerfile-debian 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/contrib/ci/Dockerfile-debian 2025-03-12 09:35:38.000000000 +0000 @@ -15,10 +15,11 @@ python3-wheel \ shared-mime-info \ liblzma-dev \ + libzstd-dev \ uuid-dev \ pkg-config # Meson is too old in unstable, and that won't change until Buster is released -RUN pip3 install meson +RUN pip3 install meson --break-system-packages WORKDIR /build diff -Nru libxmlb-0.3.10/contrib/ci/Dockerfile-fedora libxmlb-0.3.22/contrib/ci/Dockerfile-fedora --- libxmlb-0.3.10/contrib/ci/Dockerfile-fedora 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/contrib/ci/Dockerfile-fedora 2025-03-12 09:35:38.000000000 +0000 @@ -1,10 +1,11 @@ -FROM fedora:31 +FROM fedora:40 RUN dnf -y update RUN dnf -y install \ diffutils \ gcovr \ xz-devel \ + libzstd-devel \ git-core \ glib2-devel \ gobject-introspection-devel \ diff -Nru libxmlb-0.3.10/contrib/ci/Dockerfile-fedora-w64 libxmlb-0.3.22/contrib/ci/Dockerfile-fedora-w64 --- libxmlb-0.3.10/contrib/ci/Dockerfile-fedora-w64 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/contrib/ci/Dockerfile-fedora-w64 2025-03-12 09:35:38.000000000 +0000 @@ -1,4 +1,4 @@ -FROM fedora:31 +FROM fedora:40 RUN dnf -y update RUN dnf -y install \ @@ -7,6 +7,7 @@ git-core \ meson \ mingw64-xz-libs \ + mingw64-zstd \ mingw64-gcc \ mingw64-glib2 \ mingw64-pkg-config \ diff -Nru libxmlb-0.3.10/contrib/ci/check-license.py libxmlb-0.3.22/contrib/ci/check-license.py --- libxmlb-0.3.10/contrib/ci/check-license.py 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/contrib/ci/check-license.py 2025-03-12 09:35:38.000000000 +0000 @@ -1,9 +1,9 @@ #!/usr/bin/python3 # -# Copyright (C) 2021 Richard Hughes -# Copyright (C) 2021 Mario Limonciello +# Copyright 2021 Richard Hughes +# Copyright 2021 Mario Limonciello # -# SPDX-License-Identifier: LGPL-2.1+ +# SPDX-License-Identifier: LGPL-2.1-or-later import glob import os diff -Nru libxmlb-0.3.10/contrib/ci/check-null-false-returns.py libxmlb-0.3.22/contrib/ci/check-null-false-returns.py --- libxmlb-0.3.10/contrib/ci/check-null-false-returns.py 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/contrib/ci/check-null-false-returns.py 2025-03-12 09:35:38.000000000 +0000 @@ -2,9 +2,9 @@ # pylint: disable=invalid-name,missing-docstring,too-many-branches # pylint: disable=too-many-statements,too-many-return-statements,too-few-public-methods # -# Copyright (C) 2021 Richard Hughes +# Copyright 2021 Richard Hughes # -# SPDX-License-Identifier: LGPL-2.1+ +# SPDX-License-Identifier: LGPL-2.1-or-later import glob import sys diff -Nru libxmlb-0.3.10/contrib/libxmlb.spec.in libxmlb-0.3.22/contrib/libxmlb.spec.in --- libxmlb-0.3.10/contrib/libxmlb.spec.in 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/contrib/libxmlb.spec.in 2025-03-12 09:35:38.000000000 +0000 @@ -6,7 +6,7 @@ Name: libxmlb Version: #VERSION# Release: 0.#BUILD#%{?alphatag}%{?dist} -License: LGPLv2+ +License: LGPL-2.1-or-later URL: https://github.com/hughsie/libxmlb Source0: http://people.freedesktop.org/~hughsient/releases/%{name}-%{version}.tar.xz @@ -16,6 +16,7 @@ BuildRequires: meson BuildRequires: gobject-introspection-devel BuildRequires: xz-devel +BuildRequires: libzstd-devel %if 0%{?rhel} == 7 BuildRequires: python36-setuptools %else @@ -90,7 +91,7 @@ %files tests %dir %{_libexecdir}/installed-tests/libxmlb %{_libexecdir}/installed-tests/libxmlb/xb-self-test -%{_libexecdir}/installed-tests/libxmlb/test.xml.gz.gz.gz +%{_libexecdir}/installed-tests/libxmlb/test.* %dir %{_datadir}/installed-tests/libxmlb %{_datadir}/installed-tests/libxmlb/libxmlb.test diff -Nru libxmlb-0.3.10/contrib/reformat-code.py libxmlb-0.3.22/contrib/reformat-code.py --- libxmlb-0.3.10/contrib/reformat-code.py 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/contrib/reformat-code.py 2025-03-12 09:35:38.000000000 +0000 @@ -1,8 +1,8 @@ #!/usr/bin/python3 # -# Copyright (C) 2017 Dell Inc. +# Copyright 2017 Dell Inc. # -# SPDX-License-Identifier: LGPL-2.1+ +# SPDX-License-Identifier: LGPL-2.1-or-later # import os diff -Nru libxmlb-0.3.10/data/meson.build libxmlb-0.3.22/data/meson.build --- libxmlb-0.3.10/data/meson.build 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/data/meson.build 2025-03-12 09:35:38.000000000 +0000 @@ -7,7 +7,14 @@ install_dir: installed_test_datadir, ) - install_data(['test.xml.gz.gz.gz'], + install_data([ + 'test.desktop', + 'test.quirk', + 'test.xml', + 'test.xml.gz.gz.gz', + 'test.xml.xz', + 'test.xml.zst', + ], install_dir: installed_test_bindir, ) endif diff -Nru libxmlb-0.3.10/data/test.desktop libxmlb-0.3.22/data/test.desktop --- libxmlb-0.3.10/data/test.desktop 1970-01-01 00:00:00.000000000 +0000 +++ libxmlb-0.3.22/data/test.desktop 2025-03-12 09:35:38.000000000 +0000 @@ -0,0 +1,5 @@ +[Desktop Entry] +Name=Test +Exec=test +Icon=application-x-executable +Type=Application diff -Nru libxmlb-0.3.10/data/test.quirk libxmlb-0.3.22/data/test.quirk --- libxmlb-0.3.10/data/test.quirk 1970-01-01 00:00:00.000000000 +0000 +++ libxmlb-0.3.22/data/test.quirk 2025-03-12 09:35:38.000000000 +0000 @@ -0,0 +1,2 @@ +[USB\VID_1D50&PID_5119] +Plugin = dfu diff -Nru libxmlb-0.3.10/data/test.xml libxmlb-0.3.22/data/test.xml --- libxmlb-0.3.10/data/test.xml 1970-01-01 00:00:00.000000000 +0000 +++ libxmlb-0.3.22/data/test.xml 2025-03-12 09:35:38.000000000 +0000 @@ -0,0 +1 @@ + Binary files /srv/release.debian.org/tmp/UJBn3SPqOc/libxmlb-0.3.10/data/test.xml.zst and /srv/release.debian.org/tmp/GXPluD2F8H/libxmlb-0.3.22/data/test.xml.zst differ diff -Nru libxmlb-0.3.10/debian/changelog libxmlb-0.3.22/debian/changelog --- libxmlb-0.3.10/debian/changelog 2022-12-22 22:54:36.000000000 +0000 +++ libxmlb-0.3.22/debian/changelog 2026-06-04 23:42:55.000000000 +0000 @@ -1,3 +1,88 @@ +libxmlb (0.3.22-1~deb12u1) bookworm; urgency=medium + + * Backport to oldstable to support fwupd backport. + + -- Mario Limonciello Thu, 04 Jun 2026 18:42:55 -0500 + +libxmlb (0.3.22-1) unstable; urgency=medium + + * New upstream version + + -- Mario Limonciello Wed, 19 Mar 2025 10:11:39 -0500 + +libxmlb (0.3.21-1) unstable; urgency=medium + + * New upstream version + + -- Mario Limonciello Wed, 19 Mar 2025 10:11:37 -0500 + +libxmlb (0.3.20-1) unstable; urgency=medium + + * New upstream version + + -- Mario Limonciello Mon, 14 Oct 2024 09:20:56 -0500 + +libxmlb (0.3.19-1) unstable; urgency=medium + + * New upstream version + + -- Mario Limonciello Wed, 21 Aug 2024 14:09:17 -0500 + +libxmlb (0.3.18-1) unstable; urgency=medium + + * New upstream version (0.3.18) + * Drop patch for zstd decompression issue, upstream. + + -- Mario Limonciello Tue, 09 Apr 2024 15:52:31 -0500 + +libxmlb (0.3.17-2) unstable; urgency=medium + + * Backport a patch from upstream to fix decompressing some zstd metadata. + This fixes accessing some remotes in fwupd. + + -- Mario Limonciello Tue, 09 Apr 2024 14:23:10 -0500 + +libxmlb (0.3.17-1) unstable; urgency=medium + + * New upstream release + + -- Mario Limonciello Fri, 05 Apr 2024 06:31:05 -0500 + +libxmlb (0.3.16-1) unstable; urgency=medium + + * New upstream release + + -- Mario Limonciello Wed, 03 Apr 2024 09:10:32 -0500 + +libxmlb (0.3.15-1) unstable; urgency=medium + + * Team upload + * New upstream release + * Add Build-Depends: dh-sequence-gir + * Add Build-Depends-Package + + -- Jeremy Bícha Thu, 22 Feb 2024 18:56:44 -0500 + +libxmlb (0.3.14-2) unstable; urgency=medium + + * Fix autopkgtest by setting the right data location + + -- Matthias Klumpp Fri, 01 Sep 2023 10:42:10 +0200 + +libxmlb (0.3.14-1) unstable; urgency=medium + + * New upstream bugfix release: 0.3.14 + + -- Matthias Klumpp Thu, 24 Aug 2023 22:44:50 +0200 + +libxmlb (0.3.13-1) unstable; urgency=medium + + * New upstream release: 0.3.13 + * Add dependency on libzstd + * Mark rules as not requiring root + + -- Matthias Klumpp Tue, 22 Aug 2023 22:45:18 +0200 + libxmlb (0.3.10-2) unstable; urgency=medium * No-change upload to trigger a full rebuild diff -Nru libxmlb-0.3.10/debian/control libxmlb-0.3.22/debian/control --- libxmlb-0.3.10/debian/control 2022-12-20 17:15:25.000000000 +0000 +++ libxmlb-0.3.22/debian/control 2024-04-03 14:09:15.000000000 +0000 @@ -6,16 +6,18 @@ Matthias Klumpp , Mario Limonciello Build-Depends: debhelper-compat (= 13), + dh-sequence-gir, gir1.2-glib-2.0, - gobject-introspection, gtk-doc-tools, libgirepository1.0-dev, libglib2.0-dev, libglib2.0-doc, liblzma-dev, + libzstd-dev, meson (>= 0.52.0), shared-mime-info -Standards-Version: 4.6.1 +Standards-Version: 4.6.2 +Rules-Requires-Root: no Homepage: https://github.com/hughsie/libxmlb Vcs-Git: https://salsa.debian.org/efi-team/libxmlb.git Vcs-Browser: https://salsa.debian.org/efi-team/libxmlb diff -Nru libxmlb-0.3.10/debian/libxmlb2.symbols libxmlb-0.3.22/debian/libxmlb2.symbols --- libxmlb-0.3.10/debian/libxmlb2.symbols 2022-12-20 16:40:14.000000000 +0000 +++ libxmlb-0.3.22/debian/libxmlb2.symbols 2024-08-21 19:09:04.000000000 +0000 @@ -1,4 +1,5 @@ libxmlb.so.2 libxmlb2 #MINVER# +* Build-Depends-Package: libxmlb-dev LIBXMLB_0.1.0@LIBXMLB_0.1.0 0.1.0 LIBXMLB_0.1.11@LIBXMLB_0.1.11 0.1.11 LIBXMLB_0.1.12@LIBXMLB_0.1.12 0.1.12 @@ -13,6 +14,7 @@ LIBXMLB_0.1.7@LIBXMLB_0.1.7 0.1.7 LIBXMLB_0.2.0@LIBXMLB_0.2.0 0.2.0 LIBXMLB_0.3.0@LIBXMLB_0.3.0 0.3.2 + LIBXMLB_0.3.19@LIBXMLB_0.3.19 0.3.19 LIBXMLB_0.3.1@LIBXMLB_0.3.1 0.3.2 LIBXMLB_0.3.4@LIBXMLB_0.3.4 0.3.4 xb_builder_add_fixup@LIBXMLB_0.1.3 0.1.3 @@ -206,3 +208,4 @@ xb_value_bindings_init@LIBXMLB_0.3.0 0.3.2 xb_value_bindings_is_bound@LIBXMLB_0.3.0 0.3.2 xb_value_bindings_lookup_opcode@LIBXMLB_0.3.0 0.3.2 + xb_version_string@LIBXMLB_0.3.19 0.3.19 diff -Nru libxmlb-0.3.10/debian/rules libxmlb-0.3.22/debian/rules --- libxmlb-0.3.10/debian/rules 2022-12-20 17:08:25.000000000 +0000 +++ libxmlb-0.3.22/debian/rules 2024-04-03 14:09:00.000000000 +0000 @@ -1,4 +1,4 @@ #!/usr/bin/make -f %: - dh $@ --with gir + dh $@ diff -Nru libxmlb-0.3.10/debian/tests/installed-tests libxmlb-0.3.22/debian/tests/installed-tests --- libxmlb-0.3.10/debian/tests/installed-tests 2022-12-20 16:40:14.000000000 +0000 +++ libxmlb-0.3.22/debian/tests/installed-tests 2024-04-03 14:09:15.000000000 +0000 @@ -2,4 +2,5 @@ set -e +export G_TEST_SRCDIR=/usr/libexec/installed-tests/libxmlb/ gnome-desktop-testing-runner libxmlb diff -Nru libxmlb-0.3.10/docs/fuzzing.md libxmlb-0.3.22/docs/fuzzing.md --- libxmlb-0.3.10/docs/fuzzing.md 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/docs/fuzzing.md 2025-03-12 09:35:38.000000000 +0000 @@ -8,6 +8,7 @@ ------------- afl-fuzz -m 300 -i fuzzing-src -o findings ./src/xb-tool --force dump @@ + afl-fuzz -m 300 -i fuzzing-src -o findings ./src/xb-tool query @@ "component/id" mkdir -p fuzzing-src ./src/xb-tool compile fuzzing-src/appdata.xmlb ../data/fuzzing-src/appdata.xml diff -Nru libxmlb-0.3.10/meson.build libxmlb-0.3.22/meson.build --- libxmlb-0.3.10/meson.build 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/meson.build 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ project('libxmlb', 'c', - version : '0.3.10', - license : 'LGPL-2.1+', - meson_version : '>=0.47.0', + version : '0.3.22', + license : 'LGPL-2.1-or-later', + meson_version : '>=0.60.0', default_options : ['warning_level=2', 'c_std=c99'], ) @@ -27,6 +27,7 @@ # get supported warning flags warning_flags = [ + '-Wno-nonnull-compare', '-Wno-aggregate-return', '-Wunused', '-Warray-bounds', @@ -85,13 +86,25 @@ add_project_arguments('-fstack-protector-strong', language : 'c') endif +if cc.get_id() == 'msvc' + error('MSVC is not supported as it does not support __attribute__((cleanup))') +endif + # enable full RELRO where possible # FIXME: until https://github.com/mesonbuild/meson/issues/1140 is fixed global_link_args = [] +release_args = [] test_link_args = [ '-Wl,-z,relro', '-Wl,-z,now', ] +if not get_option('debug') + release_args += ['-DG_DISABLE_CAST_CHECKS', '-DG_DISABLE_ASSERT'] + test_link_args += [ + '-Wl,-Bsymbolic', + '-fno-plt', + ] +endif foreach link_arg: test_link_args if cc.has_link_argument(link_arg) global_link_args += link_arg @@ -102,12 +115,12 @@ language: 'c' ) +prefix = get_option('prefix') if host_machine.system() == 'windows' bindir = get_option('bindir') installed_test_bindir = get_option('libexecdir') installed_test_datadir = get_option('datadir') else - prefix = get_option('prefix') datadir = join_paths(prefix, get_option('datadir')) bindir = join_paths(prefix, get_option('bindir')) libexecdir = join_paths(prefix, get_option('libexecdir')) @@ -118,7 +131,14 @@ gio = dependency('gio-2.0', version : '>= 2.45.8') giounix = dependency('gio-unix-2.0', version : '>= 2.45.8', required: false) -lzma = dependency('liblzma') +lzma = dependency('liblzma', required: get_option('lzma')) +if lzma.found() + conf.set('HAVE_LZMA', 1) +endif +zstd = dependency('libzstd', required: get_option('zstd')) +if zstd.found() + conf.set('HAVE_ZSTD', 1) +endif if giounix.found() conf.set('HAVE_GIO_UNIX', '1') endif @@ -131,9 +151,13 @@ libxmlb_deps = [ gio, - lzma, ] - +if lzma.found() + libxmlb_deps += lzma +endif +if zstd.found() + libxmlb_deps += zstd +endif # support stemming of search tokens if get_option('stemmer') cc = meson.get_compiler('c') diff -Nru libxmlb-0.3.10/meson_options.txt libxmlb-0.3.22/meson_options.txt --- libxmlb-0.3.10/meson_options.txt 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/meson_options.txt 2025-03-12 09:35:38.000000000 +0000 @@ -1,5 +1,17 @@ -option('gtkdoc', type : 'boolean', value : true, description : 'enable developer documentation') +option('gtkdoc',type : 'boolean', value : true, description : 'enable developer documentation') option('introspection', type : 'boolean', value : true, description : 'generate GObject Introspection data') option('tests', type : 'boolean', value : true, description : 'enable tests') option('stemmer', type : 'boolean', value : false, description : 'enable stemmer support') option('cli', type : 'boolean', value : true, description : 'build and install the xb-tool CLI') +option('lzma', + type: 'feature', + description : 'enable lzma (xz) support', +) +option('zstd', + type: 'feature', + description: 'enable zstd support', + deprecated: { + 'true': 'enabled', + 'false': 'disabled', + }, +) diff -Nru libxmlb-0.3.10/src/gen-def-from-map.py libxmlb-0.3.22/src/gen-def-from-map.py --- libxmlb-0.3.10/src/gen-def-from-map.py 1970-01-01 00:00:00.000000000 +0000 +++ libxmlb-0.3.22/src/gen-def-from-map.py 2025-03-12 09:35:38.000000000 +0000 @@ -0,0 +1,101 @@ +#!/usr/bin/python3 +# pylint: disable=invalid-name,missing-docstring +# +# Copyright 2023 Chun-wei Fan +# +# SPDX-License-Identifier: LGPL-2.1-or-later + +# Script to generate .def file from .map files + +import os +import re +import sys + + +def get_sym_groups(lines, namespace): + sym_groups = [] + search_header = True + collect_symbols = False + search_tail = False + + # namespace + version of library + namespace_with_ver_regex = re.escape(namespace) + r"_[0-9]+\.[0-9]+\.[0-9]+" + # Look for symbols added in version in library from map file, + # which defines a group of symbols + header_regex = re.compile(r"^" + namespace_with_ver_regex) + # Look for where to start collecting symbols for the group + global_regex = re.compile(r"^\s+global:\s+$") + # Look for where to end collecting symbols for the group + local_regex = re.compile(r"^\s+local:\s+\*+;\s+$") + # Look, if any, since which version were the symbols + # group added + ending_notail_regex = re.compile(r"^};\s+$") + ending_tail_regex = re.compile(r"^}\s+" + namespace_with_ver_regex + ";\s+$") + + for l in lines: + # New symbols group found in map file + if search_header and header_regex.match(l): + symbols = [] + header = l.split()[0] + search_header = False + + # Go through map file to gather up info for this symbols group + elif not search_header: + if not collect_symbols and global_regex.match(l): + collect_symbols = True + elif collect_symbols: + tail = None + + # Stop gathering for group if `local: *;` is found + if local_regex.match(l): + search_tail = True + elif search_tail: + # Populate symbols group info and append + # to the groups we gathered previously + if ending_notail_regex.match(l) or ending_tail_regex.match(l): + if ending_tail_regex.match(l): + tail_ = l.split()[1] + tail = tail_[: tail_.index(";")] + sym_group = { + "header": header, + "symbols": symbols, + "tail": tail, + } + sym_groups.append(sym_group) + search_tail = False + collect_symbols = False + search_header = True + + # Gather up symbols for this group + else: + symbol = l[: l.index(";")].strip() + symbols.append(symbol) + + return sym_groups + + +def output_def_file(def_file, sym_groups): + with open(def_file, "w") as out: + out.write("EXPORTS\n") + for group in sym_groups: + out.write("\n") + if group["tail"] is not None: + out.write( + "; APIs added in %s since %s\n" % (group["header"], group["tail"]) + ) + else: + out.write("; APIs added in %s\n" % group["header"]) + for symbol in group["symbols"]: + out.write("%s\n" % symbol) + + +if __name__ == "__main__": + if len(sys.argv) != 4: + raise SystemExit("%s " % sys.argv[0]) + mapfile = sys.argv[1] + namespace = sys.argv[2] + def_file = sys.argv[3] + with open(mapfile, "r") as m: + lines = m.readlines() + groups = get_sym_groups(lines, namespace) + output_def_file(def_file, groups) diff -Nru libxmlb-0.3.10/src/generate-version-script.py libxmlb-0.3.22/src/generate-version-script.py --- libxmlb-0.3.10/src/generate-version-script.py 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/generate-version-script.py 2025-03-12 09:35:38.000000000 +0000 @@ -1,9 +1,9 @@ #!/usr/bin/python3 # pylint: disable=invalid-name,missing-docstring # -# Copyright (C) 2017 Richard Hughes +# Copyright 2017 Richard Hughes # -# SPDX-License-Identifier: LGPL-2.1+ +# SPDX-License-Identifier: LGPL-2.1-or-later import sys import argparse @@ -139,4 +139,4 @@ for override_symbol, override_version in args.override: ld.overrides[override_symbol] = override_version ld.import_gir(argv[1]) - open(argv[2], "w").write(ld.render()) + open(argv[2], "w", newline="\n").write(ld.render()) diff -Nru libxmlb-0.3.10/src/libxmlb.map libxmlb-0.3.22/src/libxmlb.map --- libxmlb-0.3.10/src/libxmlb.map 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/libxmlb.map 2025-03-12 09:35:38.000000000 +0000 @@ -270,3 +270,9 @@ xb_node_child_iter_next; local: *; } LIBXMLB_0.3.1; + +LIBXMLB_0.3.19 { + global: + xb_version_string; + local: *; +} LIBXMLB_0.3.4; diff -Nru libxmlb-0.3.10/src/meson.build libxmlb-0.3.22/src/meson.build --- libxmlb-0.3.10/src/meson.build 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/meson.build 2025-03-12 09:35:38.000000000 +0000 @@ -15,6 +15,7 @@ 'xb-builder-node.h', 'xb-builder-source.h', 'xb-builder-source-ctx.h', + 'xb-compile.h', 'xb-machine.h', 'xb-node.h', 'xb-node-query.h', @@ -39,6 +40,27 @@ mapfile = 'libxmlb.map' vflag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), mapfile) +extra_sources = [] +if zstd.found() + extra_sources += ['xb-zstd-decompressor.c'] +endif +if lzma.found() + extra_sources += ['xb-lzma-decompressor.c'] +endif + +def_file_target = custom_target( + 'libxmlb-defile', + input: mapfile, + output: 'libxmlb.def', + command: [ + python3, + join_paths(meson.current_source_dir(), 'gen-def-from-map.py'), + '@INPUT@', + 'LIBXMLB', + '@OUTPUT@', + ], +) + libxmlb = library( 'xmlb', sources : [ @@ -48,7 +70,6 @@ 'xb-builder-source.c', 'xb-builder-source-ctx.c', 'xb-common.c', - 'xb-lzma-decompressor.c', 'xb-machine.c', 'xb-opcode.c', 'xb-node.c', @@ -62,14 +83,17 @@ 'xb-stack.c', 'xb-string.c', 'xb-value-bindings.c', - ], + 'xb-version.c', + ] + extra_sources, soversion : lt_current, version : lt_version, include_directories : [ configinc, ], dependencies : libxmlb_deps, + c_args : release_args, link_args : cc.get_supported_link_arguments([vflag]), + vs_module_defs: def_file_target, link_depends : mapfile, install : true ) @@ -77,7 +101,11 @@ libxmlb_dep = declare_dependency( link_with : libxmlb, include_directories : include_directories('.'), - dependencies : libxmlb_deps + dependencies : libxmlb_deps, + variables : { + 'lzma': '@0@'.format(lzma.found()), + 'zstd': '@0@'.format(zstd.found()), + }, ) if get_option('cli') @@ -115,6 +143,10 @@ name : 'libxmlb', filebase : 'xmlb', description : 'libxmlb is a library to create or query compressed XML files', + variables : { + 'lzma': '@0@'.format(lzma.found()), + 'zstd': '@0@'.format(zstd.found()), + }, ) if get_option('introspection') @@ -156,10 +188,16 @@ 'xb-string.h', 'xb-value-bindings.c', 'xb-value-bindings.h', + 'xb-version.c', + libxmlb_version_h, ], nsversion : '2.0', namespace : 'Xmlb', - symbol_prefix : 'xb', + symbol_prefix : [ + 'xb', + 'xmlb', + 'libxmlb', + ], identifier_prefix : 'Xb', export_packages : 'xmlb', header : 'xmlb.h', @@ -207,7 +245,7 @@ if get_option('tests') testdatadirs = environment() - testdatadirs.set('G_TEST_SRCDIR', join_paths(meson.source_root(), 'data')) + testdatadirs.set('G_TEST_SRCDIR', join_paths(meson.project_source_root(), 'data')) testdatadirs.set('G_TEST_BUILDDIR', meson.current_build_dir()) e = executable( 'xb-self-test', @@ -219,7 +257,6 @@ 'xb-builder-source.c', 'xb-builder-source-ctx.c', 'xb-common.c', - 'xb-lzma-decompressor.c', 'xb-machine.c', 'xb-node.c', 'xb-node-query.c', @@ -234,7 +271,7 @@ 'xb-stack.c', 'xb-string.c', 'xb-value-bindings.c', - ], + ] + extra_sources, include_directories : [ configinc, ], @@ -242,6 +279,9 @@ gio, libxmlb_dep, ], + c_args: [ + '-DSRCDIR="' + join_paths(meson.project_source_root(), 'data') + '"', + ], install : true, install_dir : installed_test_bindir ) diff -Nru libxmlb-0.3.10/src/xb-builder-fixup-private.h libxmlb-0.3.22/src/xb-builder-fixup-private.h --- libxmlb-0.3.10/src/xb-builder-fixup-private.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-builder-fixup-private.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,22 +1,21 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include - #include "xb-builder-fixup.h" G_BEGIN_DECLS gboolean -xb_builder_fixup_node(XbBuilderFixup *self, XbBuilderNode *bn, GError **error); +xb_builder_fixup_node(XbBuilderFixup *self, XbBuilderNode *bn, GError **error) + G_GNUC_NON_NULL(1, 2); const gchar * -xb_builder_fixup_get_id(XbBuilderFixup *self); +xb_builder_fixup_get_id(XbBuilderFixup *self) G_GNUC_NON_NULL(1); gchar * -xb_builder_fixup_get_guid(XbBuilderFixup *self); +xb_builder_fixup_get_guid(XbBuilderFixup *self) G_GNUC_NON_NULL(1); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-builder-fixup.c libxmlb-0.3.22/src/xb-builder-fixup.c --- libxmlb-0.3.10/src/xb-builder-fixup.c 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-builder-fixup.c 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #define G_LOG_DOMAIN "XbSilo" diff -Nru libxmlb-0.3.10/src/xb-builder-fixup.h libxmlb-0.3.22/src/xb-builder-fixup.h --- libxmlb-0.3.10/src/xb-builder-fixup.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-builder-fixup.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,13 +1,11 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include - #include "xb-builder-node.h" G_BEGIN_DECLS @@ -37,10 +35,10 @@ xb_builder_fixup_new(const gchar *id, XbBuilderFixupFunc func, gpointer user_data, - GDestroyNotify user_data_free); + GDestroyNotify user_data_free) G_GNUC_NON_NULL(1, 2); gint -xb_builder_fixup_get_max_depth(XbBuilderFixup *self); +xb_builder_fixup_get_max_depth(XbBuilderFixup *self) G_GNUC_NON_NULL(1); void -xb_builder_fixup_set_max_depth(XbBuilderFixup *self, gint max_depth); +xb_builder_fixup_set_max_depth(XbBuilderFixup *self, gint max_depth) G_GNUC_NON_NULL(1); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-builder-node-private.h libxmlb-0.3.22/src/xb-builder-node-private.h --- libxmlb-0.3.10/src/xb-builder-node-private.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-builder-node-private.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,14 +1,13 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include - #include "xb-builder-node.h" +#include "xb-compile.h" G_BEGIN_DECLS @@ -21,32 +20,32 @@ } XbBuilderNodeAttr; GPtrArray * -xb_builder_node_get_attrs(XbBuilderNode *self); +xb_builder_node_get_attrs(XbBuilderNode *self) G_GNUC_NON_NULL(1); guint32 -xb_builder_node_size(XbBuilderNode *self); +xb_builder_node_size(XbBuilderNode *self) G_GNUC_NON_NULL(1); guint32 -xb_builder_node_get_offset(XbBuilderNode *self); +xb_builder_node_get_offset(XbBuilderNode *self) G_GNUC_NON_NULL(1); void -xb_builder_node_set_offset(XbBuilderNode *self, guint32 offset); +xb_builder_node_set_offset(XbBuilderNode *self, guint32 offset) G_GNUC_NON_NULL(1); gint -xb_builder_node_get_priority(XbBuilderNode *self); +xb_builder_node_get_priority(XbBuilderNode *self) G_GNUC_NON_NULL(1); void -xb_builder_node_set_priority(XbBuilderNode *self, gint priority); +xb_builder_node_set_priority(XbBuilderNode *self, gint priority) G_GNUC_NON_NULL(1); guint32 -xb_builder_node_get_element_idx(XbBuilderNode *self); +xb_builder_node_get_element_idx(XbBuilderNode *self) G_GNUC_NON_NULL(1); void -xb_builder_node_set_element_idx(XbBuilderNode *self, guint32 element_idx); +xb_builder_node_set_element_idx(XbBuilderNode *self, guint32 element_idx) G_GNUC_NON_NULL(1); guint32 -xb_builder_node_get_text_idx(XbBuilderNode *self); +xb_builder_node_get_text_idx(XbBuilderNode *self) G_GNUC_NON_NULL(1); void -xb_builder_node_set_text_idx(XbBuilderNode *self, guint32 text_idx); +xb_builder_node_set_text_idx(XbBuilderNode *self, guint32 text_idx) G_GNUC_NON_NULL(1); guint32 -xb_builder_node_get_tail_idx(XbBuilderNode *self); +xb_builder_node_get_tail_idx(XbBuilderNode *self) G_GNUC_NON_NULL(1); void -xb_builder_node_set_tail_idx(XbBuilderNode *self, guint32 tail_idx); +xb_builder_node_set_tail_idx(XbBuilderNode *self, guint32 tail_idx) G_GNUC_NON_NULL(1); void -xb_builder_node_add_token_idx(XbBuilderNode *self, guint32 tail_idx); +xb_builder_node_add_token_idx(XbBuilderNode *self, guint32 tail_idx) G_GNUC_NON_NULL(1); GArray * -xb_builder_node_get_token_idxs(XbBuilderNode *self); +xb_builder_node_get_token_idxs(XbBuilderNode *self) G_GNUC_NON_NULL(1); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-builder-node.c libxmlb-0.3.22/src/xb-builder-node.c --- libxmlb-0.3.10/src/xb-builder-node.c 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-builder-node.c 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #define G_LOG_DOMAIN "XbSilo" @@ -279,9 +279,6 @@ tmp = g_string_sized_new((gsize)text_len_safe + 1); split = g_strsplit(text, "\n", -1); for (guint i = 0; split[i] != NULL; i++) { - /* remove leading and trailing whitespace */ - g_strstrip(split[i]); - /* if this is a blank line we end the paragraph mode * and swallow the newline. If we see exactly two * newlines in sequence then do a paragraph break */ @@ -1120,32 +1117,37 @@ g_string_append_printf(helper->xml, " %s=\"%s\"", key, val); } - /* finish the opening tag and add any text if it exists */ - if (priv->text != NULL) { - g_autofree gchar *text = xb_string_xml_escape(priv->text); - g_string_append(helper->xml, ">"); - g_string_append(helper->xml, text); + if (helper->flags & XB_NODE_EXPORT_FLAG_COLLAPSE_EMPTY && priv->text == NULL && + priv->children == NULL) { + g_string_append(helper->xml, " />"); } else { - g_string_append(helper->xml, ">"); - if (helper->flags & XB_NODE_EXPORT_FLAG_FORMAT_MULTILINE) - g_string_append(helper->xml, "\n"); - } + /* finish the opening tag and add any text if it exists */ + if (priv->text != NULL) { + g_autofree gchar *text = xb_string_xml_escape(priv->text); + g_string_append(helper->xml, ">"); + g_string_append(helper->xml, text); + } else { + g_string_append(helper->xml, ">"); + if (helper->flags & XB_NODE_EXPORT_FLAG_FORMAT_MULTILINE) + g_string_append(helper->xml, "\n"); + } - /* recurse deeper */ - for (guint i = 0; priv->children != NULL && i < priv->children->len; i++) { - XbBuilderNode *child = g_ptr_array_index(priv->children, i); - helper->level++; - if (!xb_builder_node_export_helper(child, helper, error)) - return FALSE; - helper->level--; - } + /* recurse deeper */ + for (guint i = 0; priv->children != NULL && i < priv->children->len; i++) { + XbBuilderNode *child = g_ptr_array_index(priv->children, i); + helper->level++; + if (!xb_builder_node_export_helper(child, helper, error)) + return FALSE; + helper->level--; + } - /* add closing tag */ - if ((helper->flags & XB_NODE_EXPORT_FLAG_FORMAT_INDENT) > 0 && priv->text == NULL) { - for (guint i = 0; i < helper->level; i++) - g_string_append(helper->xml, " "); + /* add closing tag */ + if ((helper->flags & XB_NODE_EXPORT_FLAG_FORMAT_INDENT) > 0 && priv->text == NULL) { + for (guint i = 0; i < helper->level; i++) + g_string_append(helper->xml, " "); + } + g_string_append_printf(helper->xml, "", priv->element); } - g_string_append_printf(helper->xml, "", priv->element); /* add any tail if it exists */ if (priv->tail != NULL) { diff -Nru libxmlb-0.3.10/src/xb-builder-node.h libxmlb-0.3.22/src/xb-builder-node.h --- libxmlb-0.3.10/src/xb-builder-node.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-builder-node.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,13 +1,12 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include - +#include "xb-compile.h" #include "xb-node.h" G_BEGIN_DECLS @@ -60,71 +59,77 @@ XbBuilderNode * xb_builder_node_insert(XbBuilderNode *parent, const gchar *element, - ...) G_GNUC_NULL_TERMINATED G_GNUC_WARN_UNUSED_RESULT; + ...) G_GNUC_NULL_TERMINATED G_GNUC_WARN_UNUSED_RESULT G_GNUC_NON_NULL(2); void xb_builder_node_insert_text(XbBuilderNode *parent, const gchar *element, const gchar *text, ...) - G_GNUC_NULL_TERMINATED; + G_GNUC_NULL_TERMINATED G_GNUC_NON_NULL(1, 2); gboolean -xb_builder_node_has_flag(XbBuilderNode *self, XbBuilderNodeFlags flag); +xb_builder_node_has_flag(XbBuilderNode *self, XbBuilderNodeFlags flag) G_GNUC_NON_NULL(1); void -xb_builder_node_add_flag(XbBuilderNode *self, XbBuilderNodeFlags flag); +xb_builder_node_add_flag(XbBuilderNode *self, XbBuilderNodeFlags flag) G_GNUC_NON_NULL(1); const gchar * -xb_builder_node_get_element(XbBuilderNode *self); +xb_builder_node_get_element(XbBuilderNode *self) G_GNUC_NON_NULL(1); void -xb_builder_node_set_element(XbBuilderNode *self, const gchar *element); +xb_builder_node_set_element(XbBuilderNode *self, const gchar *element) G_GNUC_NON_NULL(1); const gchar * -xb_builder_node_get_text(XbBuilderNode *self); +xb_builder_node_get_text(XbBuilderNode *self) G_GNUC_NON_NULL(1); guint64 -xb_builder_node_get_text_as_uint(XbBuilderNode *self); +xb_builder_node_get_text_as_uint(XbBuilderNode *self) G_GNUC_NON_NULL(1); void -xb_builder_node_set_text(XbBuilderNode *self, const gchar *text, gssize text_len); +xb_builder_node_set_text(XbBuilderNode *self, const gchar *text, gssize text_len) + G_GNUC_NON_NULL(1); void -xb_builder_node_tokenize_text(XbBuilderNode *self); +xb_builder_node_tokenize_text(XbBuilderNode *self) G_GNUC_NON_NULL(1); const gchar * -xb_builder_node_get_tail(XbBuilderNode *self); +xb_builder_node_get_tail(XbBuilderNode *self) G_GNUC_NON_NULL(1); void -xb_builder_node_set_tail(XbBuilderNode *self, const gchar *tail, gssize tail_len); +xb_builder_node_set_tail(XbBuilderNode *self, const gchar *tail, gssize tail_len) + G_GNUC_NON_NULL(1); const gchar * -xb_builder_node_get_attr(XbBuilderNode *self, const gchar *name); +xb_builder_node_get_attr(XbBuilderNode *self, const gchar *name) G_GNUC_NON_NULL(1, 2); guint64 -xb_builder_node_get_attr_as_uint(XbBuilderNode *self, const gchar *name); +xb_builder_node_get_attr_as_uint(XbBuilderNode *self, const gchar *name) G_GNUC_NON_NULL(1, 2); void -xb_builder_node_set_attr(XbBuilderNode *self, const gchar *name, const gchar *value); +xb_builder_node_set_attr(XbBuilderNode *self, const gchar *name, const gchar *value) + G_GNUC_NON_NULL(1, 2); void -xb_builder_node_remove_attr(XbBuilderNode *self, const gchar *name); +xb_builder_node_remove_attr(XbBuilderNode *self, const gchar *name) G_GNUC_NON_NULL(1); void -xb_builder_node_add_child(XbBuilderNode *self, XbBuilderNode *child); +xb_builder_node_add_child(XbBuilderNode *self, XbBuilderNode *child) G_GNUC_NON_NULL(2); void -xb_builder_node_remove_child(XbBuilderNode *self, XbBuilderNode *child); +xb_builder_node_remove_child(XbBuilderNode *self, XbBuilderNode *child) G_GNUC_NON_NULL(1); GPtrArray * -xb_builder_node_get_children(XbBuilderNode *self); +xb_builder_node_get_children(XbBuilderNode *self) G_GNUC_NON_NULL(1); XbBuilderNode * -xb_builder_node_get_first_child(XbBuilderNode *self); +xb_builder_node_get_first_child(XbBuilderNode *self) G_GNUC_NON_NULL(1); XbBuilderNode * -xb_builder_node_get_last_child(XbBuilderNode *self); +xb_builder_node_get_last_child(XbBuilderNode *self) G_GNUC_NON_NULL(1); XbBuilderNode * -xb_builder_node_get_child(XbBuilderNode *self, const gchar *element, const gchar *text); +xb_builder_node_get_child(XbBuilderNode *self, const gchar *element, const gchar *text) + G_GNUC_NON_NULL(1); void -xb_builder_node_unlink(XbBuilderNode *self); +xb_builder_node_unlink(XbBuilderNode *self) G_GNUC_NON_NULL(1); XbBuilderNode * -xb_builder_node_get_parent(XbBuilderNode *self); +xb_builder_node_get_parent(XbBuilderNode *self) G_GNUC_NON_NULL(1); guint -xb_builder_node_depth(XbBuilderNode *self); +xb_builder_node_depth(XbBuilderNode *self) G_GNUC_NON_NULL(1); void xb_builder_node_traverse(XbBuilderNode *self, GTraverseType order, GTraverseFlags flags, gint max_depth, XbBuilderNodeTraverseFunc func, - gpointer user_data); + gpointer user_data) G_GNUC_NON_NULL(1, 5); void -xb_builder_node_sort_children(XbBuilderNode *self, XbBuilderNodeSortFunc func, gpointer user_data); +xb_builder_node_sort_children(XbBuilderNode *self, XbBuilderNodeSortFunc func, gpointer user_data) + G_GNUC_NON_NULL(1, 2); gchar * -xb_builder_node_export(XbBuilderNode *self, XbNodeExportFlags flags, GError **error); +xb_builder_node_export(XbBuilderNode *self, XbNodeExportFlags flags, GError **error) + G_GNUC_NON_NULL(1); GPtrArray * -xb_builder_node_get_tokens(XbBuilderNode *self); +xb_builder_node_get_tokens(XbBuilderNode *self) G_GNUC_NON_NULL(1); void -xb_builder_node_add_token(XbBuilderNode *self, const gchar *token); +xb_builder_node_add_token(XbBuilderNode *self, const gchar *token) G_GNUC_NON_NULL(1, 2); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-builder-source-ctx-private.h libxmlb-0.3.22/src/xb-builder-source-ctx-private.h --- libxmlb-0.3.10/src/xb-builder-source-ctx-private.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-builder-source-ctx-private.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,24 +1,23 @@ /* - * Copyright (C) 2019 Richard Hughes + * Copyright 2019 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include - #include "xb-builder-source-ctx.h" G_BEGIN_DECLS XbBuilderSourceCtx * -xb_builder_source_ctx_new(GFile *file, GInputStream *istream); +xb_builder_source_ctx_new(GFile *file, GInputStream *istream) G_GNUC_NON_NULL(2); void -xb_builder_source_ctx_set_filename(XbBuilderSourceCtx *self, const gchar *filename); +xb_builder_source_ctx_set_filename(XbBuilderSourceCtx *self, const gchar *basename) + G_GNUC_NON_NULL(1); gchar * xb_builder_source_ctx_get_content_type(XbBuilderSourceCtx *self, GCancellable *cancellable, - GError **error); + GError **error) G_GNUC_NON_NULL(1); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-builder-source-ctx.c libxmlb-0.3.22/src/xb-builder-source-ctx.c --- libxmlb-0.3.10/src/xb-builder-source-ctx.c 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-builder-source-ctx.c 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #define G_LOG_DOMAIN "XbSilo" diff -Nru libxmlb-0.3.10/src/xb-builder-source-ctx.h libxmlb-0.3.22/src/xb-builder-source-ctx.h --- libxmlb-0.3.10/src/xb-builder-source-ctx.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-builder-source-ctx.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,12 +1,12 @@ /* - * Copyright (C) 2019 Richard Hughes + * Copyright 2019 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include +#include "xb-compile.h" G_BEGIN_DECLS @@ -26,12 +26,11 @@ }; GInputStream * -xb_builder_source_ctx_get_stream(XbBuilderSourceCtx *self); +xb_builder_source_ctx_get_stream(XbBuilderSourceCtx *self) G_GNUC_NON_NULL(1); const gchar * -xb_builder_source_ctx_get_filename(XbBuilderSourceCtx *self); +xb_builder_source_ctx_get_filename(XbBuilderSourceCtx *self) G_GNUC_NON_NULL(1); GBytes * -xb_builder_source_ctx_get_bytes(XbBuilderSourceCtx *self, - GCancellable *cancellable, - GError **error); +xb_builder_source_ctx_get_bytes(XbBuilderSourceCtx *self, GCancellable *cancellable, GError **error) + G_GNUC_NON_NULL(1); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-builder-source-private.h libxmlb-0.3.22/src/xb-builder-source-private.h --- libxmlb-0.3.10/src/xb-builder-source-private.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-builder-source-private.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,31 +1,31 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include - #include "xb-builder-node.h" #include "xb-builder-source.h" G_BEGIN_DECLS XbBuilderNode * -xb_builder_source_get_info(XbBuilderSource *self); +xb_builder_source_get_info(XbBuilderSource *self) G_GNUC_NON_NULL(1); gchar * -xb_builder_source_get_guid(XbBuilderSource *self); +xb_builder_source_get_guid(XbBuilderSource *self) G_GNUC_NON_NULL(1); const gchar * -xb_builder_source_get_prefix(XbBuilderSource *self); +xb_builder_source_get_prefix(XbBuilderSource *self) G_GNUC_NON_NULL(1); GInputStream * -xb_builder_source_get_istream(XbBuilderSource *self, GCancellable *cancellable, GError **error); +xb_builder_source_get_istream(XbBuilderSource *self, GCancellable *cancellable, GError **error) + G_GNUC_NON_NULL(1); GFile * -xb_builder_source_get_file(XbBuilderSource *self); +xb_builder_source_get_file(XbBuilderSource *self) G_GNUC_NON_NULL(1); gboolean -xb_builder_source_fixup(XbBuilderSource *self, XbBuilderNode *bn, GError **error); +xb_builder_source_fixup(XbBuilderSource *self, XbBuilderNode *bn, GError **error) + G_GNUC_NON_NULL(1, 2); XbBuilderSourceFlags -xb_builder_source_get_flags(XbBuilderSource *self); +xb_builder_source_get_flags(XbBuilderSource *self) G_GNUC_NON_NULL(1); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-builder-source.c libxmlb-0.3.22/src/xb-builder-source.c --- libxmlb-0.3.10/src/xb-builder-source.c 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-builder-source.c 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #define G_LOG_DOMAIN "XbSilo" @@ -14,8 +14,12 @@ #include "xb-builder-fixup-private.h" #include "xb-builder-source-ctx-private.h" #include "xb-builder-source-private.h" +#ifdef HAVE_LZMA #include "xb-lzma-decompressor.h" - +#endif +#ifdef HAVE_ZSTD +#include "xb-zstd-decompressor.h" +#endif typedef struct { GInputStream *istream; GFile *file; @@ -306,6 +310,10 @@ * Adds a function that can be used to convert streams loaded with * xb_builder_source_load_xml(). * + * This will decompress multiple layers of content, for instance decompressing a gzip stream into a + * different content type that can then be parsed. Use xb_builder_source_add_simple_adapter() when + * this recursive behaviour is not desired. + * * Since: 0.1.7 **/ void @@ -329,6 +337,10 @@ * Adds a function that can be used to convert streams loaded with * xb_builder_source_load_xml(). * + * This function is similar to xb_builder_source_add_adapter() but is limited to one "layer" of + * content, for instance handling application/xml or a single simple type added using + * xb_builder_source_add_adapter(). + * * Since: 0.1.15 **/ void @@ -427,6 +439,7 @@ { XbBuilderSourcePrivate *priv = GET_PRIVATE(self); g_autofree gchar *basename = NULL; + g_autoptr(GInputStream) istream = NULL; GFile *file; g_return_val_if_fail(XB_IS_BUILDER_SOURCE(self), NULL); @@ -436,8 +449,8 @@ return g_object_ref(priv->istream); /* convert the file to a GFileInputStream */ - priv->istream = G_INPUT_STREAM(g_file_read(priv->file, cancellable, error)); - if (priv->istream == NULL) + istream = G_INPUT_STREAM(g_file_read(priv->file, cancellable, error)); + if (istream == NULL) return NULL; /* run the content type handlers until we get application/xml */ @@ -448,15 +461,20 @@ XbBuilderSourceAdapter *item; g_autofree gchar *content_type = NULL; g_autoptr(GInputStream) istream_tmp = NULL; - g_autoptr(XbBuilderSourceCtx) ctx = xb_builder_source_ctx_new(file, priv->istream); + g_autoptr(XbBuilderSourceCtx) ctx = xb_builder_source_ctx_new(file, istream); /* get the content type of the stream */ xb_builder_source_ctx_set_filename(ctx, basename); content_type = xb_builder_source_ctx_get_content_type(ctx, cancellable, error); + g_debug("detected content type of %s to be %s", basename, content_type); if (content_type == NULL) return NULL; if (g_strcmp0(content_type, "application/xml") == 0) break; + /* Also accept the text/xml alias, just in case the user’s content-type database is + * slightly broken (application/xml should normally be what’s used): */ + if (g_strcmp0(content_type, "text/xml") == 0) + break; /* convert the stream */ item = xb_builder_source_get_adapter_by_mime(self, content_type); @@ -472,7 +490,7 @@ if (istream_tmp == NULL) return NULL; xb_builder_source_remove_last_extension(basename); - g_set_object(&priv->istream, istream_tmp); + g_set_object(&istream, istream_tmp); /* the #GFile is only useful for the outermost input stream, * for example it points to the .tar.gz file, while inner input @@ -483,7 +501,7 @@ if (item->is_simple) break; } while (TRUE); - return g_object_ref(priv->istream); + return g_steal_pointer(&istream); } GFile * @@ -515,6 +533,7 @@ return g_converter_input_stream_new(istream, conv); } +#ifdef HAVE_LZMA static GInputStream * xb_builder_source_load_lzma_cb(XbBuilderSource *self, XbBuilderSourceCtx *ctx, @@ -526,7 +545,21 @@ g_autoptr(GConverter) conv = G_CONVERTER(xb_lzma_decompressor_new()); return g_converter_input_stream_new(istream, conv); } +#endif +#ifdef HAVE_ZSTD +static GInputStream * +xb_builder_source_load_zstd_cb(XbBuilderSource *self, + XbBuilderSourceCtx *ctx, + gpointer user_data, + GCancellable *cancellable, + GError **error) +{ + GInputStream *istream = xb_builder_source_ctx_get_stream(ctx); + g_autoptr(GConverter) conv = G_CONVERTER(xb_zstd_decompressor_new()); + return g_converter_input_stream_new(istream, conv); +} +#endif static void xb_builder_source_adapter_free(XbBuilderSourceAdapter *item) { @@ -572,15 +605,24 @@ priv->adapters = g_ptr_array_new_with_free_func((GDestroyNotify)xb_builder_source_adapter_free); xb_builder_source_add_adapter(self, - "application/gzip,application/x-gzip", + "application/gzip,application/x-gzip,org.gnu.gnu-zip-archive", xb_builder_source_load_gzip_cb, NULL, NULL); +#ifdef HAVE_LZMA xb_builder_source_add_adapter(self, - "application/x-xz", + "application/x-xz,org.tukaani.xz-archive", xb_builder_source_load_lzma_cb, NULL, NULL); +#endif +#ifdef HAVE_ZSTD + xb_builder_source_add_adapter(self, + "application/zstd", + xb_builder_source_load_zstd_cb, + NULL, + NULL); +#endif } /** diff -Nru libxmlb-0.3.10/src/xb-builder-source.h libxmlb-0.3.22/src/xb-builder-source.h --- libxmlb-0.3.10/src/xb-builder-source.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-builder-source.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,16 +1,15 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include - #include "xb-builder-fixup.h" #include "xb-builder-node.h" #include "xb-builder-source-ctx.h" +#include "xb-compile.h" G_BEGIN_DECLS @@ -67,34 +66,34 @@ GFile *file, XbBuilderSourceFlags flags, GCancellable *cancellable, - GError **error); + GError **error) G_GNUC_NON_NULL(1, 2); gboolean xb_builder_source_load_xml(XbBuilderSource *self, const gchar *xml, XbBuilderSourceFlags flags, - GError **error); + GError **error) G_GNUC_NON_NULL(1, 2); gboolean xb_builder_source_load_bytes(XbBuilderSource *self, GBytes *bytes, XbBuilderSourceFlags flags, - GError **error); + GError **error) G_GNUC_NON_NULL(1, 2); void -xb_builder_source_set_info(XbBuilderSource *self, XbBuilderNode *info); +xb_builder_source_set_info(XbBuilderSource *self, XbBuilderNode *info) G_GNUC_NON_NULL(1); void -xb_builder_source_set_prefix(XbBuilderSource *self, const gchar *prefix); +xb_builder_source_set_prefix(XbBuilderSource *self, const gchar *prefix) G_GNUC_NON_NULL(1); void -xb_builder_source_add_fixup(XbBuilderSource *self, XbBuilderFixup *fixup); +xb_builder_source_add_fixup(XbBuilderSource *self, XbBuilderFixup *fixup) G_GNUC_NON_NULL(1, 2); void xb_builder_source_add_adapter(XbBuilderSource *self, const gchar *content_types, XbBuilderSourceAdapterFunc func, gpointer user_data, - GDestroyNotify user_data_free); + GDestroyNotify user_data_free) G_GNUC_NON_NULL(1, 2, 3); void xb_builder_source_add_simple_adapter(XbBuilderSource *self, const gchar *content_types, XbBuilderSourceAdapterFunc func, gpointer user_data, - GDestroyNotify user_data_free); + GDestroyNotify user_data_free) G_GNUC_NON_NULL(1, 2, 3); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-builder.c libxmlb-0.3.22/src/xb-builder.c --- libxmlb-0.3.10/src/xb-builder.c 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-builder.c 2025-03-12 09:35:38.000000000 +0000 @@ -1,13 +1,11 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #define G_LOG_DOMAIN "XbSilo" -#include "xb-builder.h" - #include "config.h" #include @@ -16,16 +14,17 @@ #include "xb-builder-fixup-private.h" #include "xb-builder-node-private.h" #include "xb-builder-source-private.h" +#include "xb-builder.h" #include "xb-opcode-private.h" #include "xb-silo-private.h" #include "xb-string-private.h" +#include "xb-version.h" typedef struct { GPtrArray *sources; /* of XbBuilderSource */ GPtrArray *nodes; /* of XbBuilderNode */ GPtrArray *fixups; /* of XbBuilderFixup */ GPtrArray *locales; /* of str */ - XbSilo *silo; XbSiloProfileFlags profile_flags; GString *guid; } XbBuilderPrivate; @@ -33,8 +32,6 @@ G_DEFINE_TYPE_WITH_PRIVATE(XbBuilder, xb_builder, G_TYPE_OBJECT) #define GET_PRIVATE(o) (xb_builder_get_instance_private(o)) -#define XB_SILO_APPENDBUF(str, data, sz) g_string_append_len(str, (const gchar *)data, sz); - typedef struct { XbSilo *silo; XbBuilderNode *root; /* transfer full */ @@ -42,7 +39,7 @@ XbBuilderCompileFlags compile_flags; XbBuilderSourceFlags source_flags; GHashTable *strtab_hash; - GString *strtab; + GByteArray *strtab; GPtrArray *locales; } XbBuilderCompileHelper; @@ -58,7 +55,7 @@ /* new */ idx = helper->strtab->len; - XB_SILO_APPENDBUF(helper->strtab, str, strlen(str) + 1); + g_byte_array_append(helper->strtab, (const guint8 *)str, strlen(str) + 1); g_hash_table_insert(helper->strtab_hash, g_strdup(str), GUINT_TO_POINTER(idx)); return idx; } @@ -466,7 +463,7 @@ } typedef struct { - GString *buf; + GByteArray *buf; } XbBuilderNodetabHelper; static void @@ -477,7 +474,7 @@ .attr_count = 0, }; // g_debug ("SENT @%u", (guint) helper->buf->len); - XB_SILO_APPENDBUF(helper->buf, &sn, xb_silo_node_get_size(&sn)); + g_byte_array_append(helper->buf, (const guint8 *)&sn, xb_silo_node_get_size(&sn)); } static void @@ -520,7 +517,7 @@ sn.token_count = MIN(token_idxs->len, XB_OPCODE_TOKEN_MAX); /* add to the buf */ - XB_SILO_APPENDBUF(helper->buf, &sn, sizeof(XbSiloNode)); + g_byte_array_append(helper->buf, (const guint8 *)&sn, sizeof(sn)); /* add to the buf */ for (guint i = 0; attrs != NULL && i < attrs->len; i++) { @@ -529,13 +526,13 @@ .attr_name = ba->name_idx, .attr_value = ba->value_idx, }; - XB_SILO_APPENDBUF(helper->buf, &attr, sizeof(attr)); + g_byte_array_append(helper->buf, (const guint8 *)&attr, sizeof(attr)); } /* add tokens */ for (guint i = 0; i < sn.token_count; i++) { guint32 idx = g_array_index(token_idxs, guint32, i); - XB_SILO_APPENDBUF(helper->buf, &idx, sizeof(idx)); + g_byte_array_append(helper->buf, (const guint8 *)&idx, sizeof(idx)); } } @@ -565,9 +562,9 @@ } static XbSiloNode * -xb_builder_get_node(GString *str, guint32 off) +xb_builder_get_node(GByteArray *str, guint32 off) { - return (XbSiloNode *)(str->str + off); + return (XbSiloNode *)(str->data + off); } static gboolean @@ -617,7 +614,8 @@ xb_builder_compile_helper_free(XbBuilderCompileHelper *helper) { g_hash_table_unref(helper->strtab_hash); - g_string_free(helper->strtab, TRUE); + g_byte_array_unref(helper->strtab); + g_clear_object(&helper->silo); g_object_unref(helper->root); g_free(helper); } @@ -697,10 +695,10 @@ static gboolean xb_builder_watch_source(XbBuilder *self, XbBuilderSource *source, + XbSilo *silo, GCancellable *cancellable, GError **error) { - XbBuilderPrivate *priv = GET_PRIVATE(self); GFile *file = xb_builder_source_get_file(source); g_autoptr(GFile) watched_file = NULL; if (file == NULL) @@ -714,18 +712,16 @@ else watched_file = g_object_ref(file); - if (!xb_silo_watch_file(priv->silo, watched_file, cancellable, error)) - return FALSE; - return TRUE; + return xb_silo_watch_file(silo, watched_file, cancellable, error); } static gboolean -xb_builder_watch_sources(XbBuilder *self, GCancellable *cancellable, GError **error) +xb_builder_watch_sources(XbBuilder *self, XbSilo *silo, GCancellable *cancellable, GError **error) { XbBuilderPrivate *priv = GET_PRIVATE(self); for (guint i = 0; i < priv->sources->len; i++) { XbBuilderSource *source = g_ptr_array_index(priv->sources, i); - if (!xb_builder_watch_source(self, source, cancellable, error)) + if (!xb_builder_watch_source(self, source, silo, cancellable, error)) return FALSE; } return TRUE; @@ -752,8 +748,9 @@ { XbBuilderPrivate *priv = GET_PRIVATE(self); guint32 nodetabsz = sizeof(XbSiloHeader); + g_autoptr(GByteArray) buf = NULL; g_autoptr(GBytes) blob = NULL; - g_autoptr(GString) buf = NULL; + XbSiloHeader *hdrptr; XbSiloHeader hdr = { .magic = XB_SILO_MAGIC_BYTES, .version = XB_SILO_VERSION, @@ -761,12 +758,14 @@ .strtab_ntags = 0, .padding = {0x0}, .guid = {0x0}, + .filesz = 0x0, }; XbBuilderNodetabHelper nodetab_helper = { .buf = NULL, }; - g_autoptr(GPtrArray) nodes_to_destroy = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref); - g_autoptr(GTimer) timer = xb_silo_start_profile(priv->silo); + g_autoptr(GPtrArray) nodes_to_destroy = + g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref); + g_autoptr(GTimer) timer = NULL; g_autoptr(XbBuilderCompileHelper) helper = NULL; g_return_val_if_fail(XB_IS_BUILDER(self), NULL); @@ -790,11 +789,15 @@ helper = g_new0(XbBuilderCompileHelper, 1); helper->compile_flags = flags; helper->root = xb_builder_node_new(NULL); - helper->silo = priv->silo; + helper->silo = xb_silo_new(); helper->locales = priv->locales; - helper->strtab = g_string_new(NULL); + helper->strtab = g_byte_array_new(); helper->strtab_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); + /* for profiling */ + xb_silo_set_profile_flags(helper->silo, priv->profile_flags); + timer = xb_silo_start_profile(helper->silo); + /* build node tree */ for (guint i = 0; i < priv->sources->len; i++) { XbBuilderSource *source = g_ptr_array_index(priv->sources, i); @@ -814,7 +817,7 @@ } /* watch the source */ - if (!xb_builder_watch_source(self, source, cancellable, error)) + if (!xb_builder_watch_source(self, source, helper->silo, cancellable, error)) return NULL; if (priv->profile_flags & XB_SILO_PROFILE_FLAG_DEBUG) @@ -853,7 +856,7 @@ XbBuilderNode *bn = g_ptr_array_index(nodes_to_destroy, i); xb_builder_node_unlink(bn); } - xb_silo_add_profile(priv->silo, timer, "filter single-lang"); + xb_silo_add_profile(helper->silo, timer, "filter single-lang"); } /* add any manually build nodes */ @@ -869,8 +872,8 @@ -1, xb_builder_nodetab_size_cb, &nodetabsz); - buf = g_string_sized_new(nodetabsz); - xb_silo_add_profile(priv->silo, timer, "get size nodetab"); + buf = g_byte_array_sized_new(nodetabsz); + xb_silo_add_profile(helper->silo, timer, "get size nodetab"); /* add everything to the strtab */ xb_builder_node_traverse(helper->root, @@ -880,35 +883,35 @@ xb_builder_strtab_element_names_cb, helper); hdr.strtab_ntags = g_hash_table_size(helper->strtab_hash); - xb_silo_add_profile(priv->silo, timer, "adding strtab element"); + xb_silo_add_profile(helper->silo, timer, "adding strtab element"); xb_builder_node_traverse(helper->root, G_PRE_ORDER, G_TRAVERSE_ALL, -1, xb_builder_strtab_attr_name_cb, helper); - xb_silo_add_profile(priv->silo, timer, "adding strtab attr name"); + xb_silo_add_profile(helper->silo, timer, "adding strtab attr name"); xb_builder_node_traverse(helper->root, G_PRE_ORDER, G_TRAVERSE_ALL, -1, xb_builder_strtab_attr_value_cb, helper); - xb_silo_add_profile(priv->silo, timer, "adding strtab attr value"); + xb_silo_add_profile(helper->silo, timer, "adding strtab attr value"); xb_builder_node_traverse(helper->root, G_PRE_ORDER, G_TRAVERSE_ALL, -1, xb_builder_strtab_text_cb, helper); - xb_silo_add_profile(priv->silo, timer, "adding strtab text"); + xb_silo_add_profile(helper->silo, timer, "adding strtab text"); xb_builder_node_traverse(helper->root, G_PRE_ORDER, G_TRAVERSE_ALL, -1, xb_builder_strtab_tokens_cb, helper); - xb_silo_add_profile(priv->silo, timer, "adding strtab tokens"); + xb_silo_add_profile(helper->silo, timer, "adding strtab tokens"); /* add the initial header */ hdr.strtab = nodetabsz; @@ -919,12 +922,12 @@ priv->guid->len); memcpy(&hdr.guid, &guid_tmp, sizeof(guid_tmp)); } - XB_SILO_APPENDBUF(buf, &hdr, sizeof(XbSiloHeader)); + g_byte_array_append(buf, (const guint8 *)&hdr, sizeof(hdr)); /* write nodes to the nodetab */ nodetab_helper.buf = buf; xb_builder_nodetab_write(&nodetab_helper, helper->root); - xb_silo_add_profile(priv->silo, timer, "writing nodetab"); + xb_silo_add_profile(helper->silo, timer, "writing nodetab"); /* set all the ->next and ->parent offsets */ xb_builder_node_traverse(helper->root, @@ -933,19 +936,23 @@ -1, xb_builder_nodetab_fix_cb, &nodetab_helper); - xb_silo_add_profile(priv->silo, timer, "fixing ->parent and ->next"); + xb_silo_add_profile(helper->silo, timer, "fixing ->parent and ->next"); /* append the string table */ - XB_SILO_APPENDBUF(buf, helper->strtab->str, helper->strtab->len); - xb_silo_add_profile(priv->silo, timer, "appending strtab"); + g_byte_array_append(buf, (const guint8 *)helper->strtab->data, helper->strtab->len); + xb_silo_add_profile(helper->silo, timer, "appending strtab"); + + /* update the file size */ + hdrptr = (XbSiloHeader *)buf->data; + hdrptr->filesz = buf->len; /* create data */ - blob = g_bytes_new(buf->str, buf->len); - if (!xb_silo_load_from_bytes(priv->silo, blob, XB_SILO_LOAD_FLAG_NONE, error)) + blob = g_bytes_new(buf->data, buf->len); + if (!xb_silo_load_from_bytes(helper->silo, blob, XB_SILO_LOAD_FLAG_NONE, error)) return NULL; /* success */ - return g_object_ref(priv->silo); + return g_steal_pointer(&helper->silo); } /** @@ -979,7 +986,7 @@ XbSiloLoadFlags load_flags = XB_SILO_LOAD_FLAG_NONE; g_autofree gchar *fn = NULL; g_autoptr(XbSilo) silo_tmp = xb_silo_new(); - g_autoptr(XbSilo) silo_new = NULL; + g_autoptr(XbSilo) silo = NULL; g_autoptr(GError) error_local = NULL; g_return_val_if_fail(XB_IS_BUILDER(self), NULL); @@ -988,11 +995,14 @@ g_return_val_if_fail(error == NULL || *error == NULL, NULL); /* watch the blob, so propagate flags */ - if (flags & XB_BUILDER_COMPILE_FLAG_WATCH_BLOB) + if (flags & XB_BUILDER_COMPILE_FLAG_WATCH_BLOB) { load_flags |= XB_SILO_LOAD_FLAG_WATCH_BLOB; + if (!xb_silo_watch_file(silo_tmp, file, cancellable, error)) + return NULL; + } /* ensure all the sources are watched */ - if (!xb_builder_watch_sources(self, cancellable, error)) + if (!xb_builder_watch_sources(self, silo_tmp, cancellable, error)) return NULL; /* profile new silo if needed */ @@ -1011,54 +1021,38 @@ g_autofree gchar *guid = xb_builder_generate_guid(self); if (priv->profile_flags & XB_SILO_PROFILE_FLAG_DEBUG) g_debug("GUID string: %s", priv->guid->str); - g_debug("file: %s, current:%s, cached: %s", - xb_silo_get_guid(silo_tmp), - guid, - xb_silo_get_guid(priv->silo)); - - /* GUIDs match exactly with the thing that's already loaded */ - if (g_strcmp0(xb_silo_get_guid(silo_tmp), xb_silo_get_guid(priv->silo)) == 0) { - g_debug("returning unchanged silo"); - xb_silo_uninvalidate(priv->silo); - return g_object_ref(priv->silo); - } + g_debug("file: %s, current:%s", xb_silo_get_guid(silo_tmp), guid); - /* reload the cached silo with the new file data */ + /* no compile required */ if (g_strcmp0(xb_silo_get_guid(silo_tmp), guid) == 0 || (flags & XB_BUILDER_COMPILE_FLAG_IGNORE_GUID) > 0) { - g_autoptr(GBytes) blob = xb_silo_get_bytes(silo_tmp); - - /* ensure backing file is watched for changes */ - if (flags & XB_BUILDER_COMPILE_FLAG_WATCH_BLOB) { - if (!xb_silo_watch_file(priv->silo, file, cancellable, error)) - return NULL; - } - - g_debug("loading silo with file contents"); - if (!xb_silo_load_from_bytes(priv->silo, blob, load_flags, error)) - return NULL; - - return g_object_ref(priv->silo); + g_debug("loading silo with existing file contents"); + return g_steal_pointer(&silo_tmp); } } /* fallback to just creating a new file */ - silo_new = xb_builder_compile(self, flags, cancellable, error); - if (silo_new == NULL) + silo = xb_builder_compile(self, flags, cancellable, error); + if (silo == NULL) return NULL; - if (!xb_silo_save_to_file(silo_new, file, NULL, error)) + + /* this might seem unnecessary, but windows cannot do _chsize() (introduced in GLib commit + * https://gitlab.gnome.org/GNOME/glib/-/commit/3f705ffa1230757b910a06a705104d4b0fee2c05) + * on a mmap'd file -- so manually tear that down before writing the new file */ + g_clear_object(&silo_tmp); + if (!xb_silo_save_to_file(silo, file, NULL, error)) return NULL; /* load from a file to re-mmap it */ - if (!xb_silo_load_from_file(priv->silo, file, load_flags, cancellable, error)) + if (!xb_silo_load_from_file(silo, file, load_flags, cancellable, error)) return NULL; /* ensure all the sources are watched on the reloaded silo */ - if (!xb_builder_watch_sources(self, cancellable, error)) + if (!xb_builder_watch_sources(self, silo, cancellable, error)) return NULL; /* success */ - return g_steal_pointer(&silo_new); + return g_steal_pointer(&silo); } /** @@ -1094,7 +1088,6 @@ XbBuilderPrivate *priv = GET_PRIVATE(self); g_return_if_fail(XB_IS_BUILDER(self)); priv->profile_flags = profile_flags; - xb_silo_set_profile_flags(priv->silo, profile_flags); } /** @@ -1133,7 +1126,6 @@ g_ptr_array_unref(priv->nodes); g_ptr_array_unref(priv->locales); g_ptr_array_unref(priv->fixups); - g_object_unref(priv->silo); g_string_free(priv->guid, TRUE); G_OBJECT_CLASS(xb_builder_parent_class)->finalize(obj); @@ -1154,8 +1146,7 @@ priv->nodes = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref); priv->fixups = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref); priv->locales = g_ptr_array_new_with_free_func(g_free); - priv->silo = xb_silo_new(); - priv->guid = g_string_new(NULL); + priv->guid = g_string_new(xb_version_string()); } /** diff -Nru libxmlb-0.3.10/src/xb-builder.h libxmlb-0.3.22/src/xb-builder.h --- libxmlb-0.3.10/src/xb-builder.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-builder.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,16 +1,15 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include - #include "xb-builder-fixup.h" #include "xb-builder-node.h" #include "xb-builder-source.h" +#include "xb-compile.h" #include "xb-silo.h" G_BEGIN_DECLS @@ -58,27 +57,27 @@ XbBuilder * xb_builder_new(void); void -xb_builder_append_guid(XbBuilder *self, const gchar *guid); +xb_builder_append_guid(XbBuilder *self, const gchar *guid) G_GNUC_NON_NULL(1, 2); void -xb_builder_import_source(XbBuilder *self, XbBuilderSource *source); +xb_builder_import_source(XbBuilder *self, XbBuilderSource *source) G_GNUC_NON_NULL(1, 2); void -xb_builder_import_node(XbBuilder *self, XbBuilderNode *bn); +xb_builder_import_node(XbBuilder *self, XbBuilderNode *bn) G_GNUC_NON_NULL(1, 2); XbSilo * xb_builder_compile(XbBuilder *self, XbBuilderCompileFlags flags, GCancellable *cancellable, - GError **error); + GError **error) G_GNUC_NON_NULL(1); XbSilo * xb_builder_ensure(XbBuilder *self, GFile *file, XbBuilderCompileFlags flags, GCancellable *cancellable, - GError **error); + GError **error) G_GNUC_NON_NULL(1, 2); void -xb_builder_add_locale(XbBuilder *self, const gchar *locale); +xb_builder_add_locale(XbBuilder *self, const gchar *locale) G_GNUC_NON_NULL(1, 2); void -xb_builder_add_fixup(XbBuilder *self, XbBuilderFixup *fixup); +xb_builder_add_fixup(XbBuilder *self, XbBuilderFixup *fixup) G_GNUC_NON_NULL(1, 2); void -xb_builder_set_profile_flags(XbBuilder *self, XbSiloProfileFlags profile_flags); +xb_builder_set_profile_flags(XbBuilder *self, XbSiloProfileFlags profile_flags) G_GNUC_NON_NULL(1); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-common-private.h libxmlb-0.3.22/src/xb-common-private.h --- libxmlb-0.3.10/src/xb-common-private.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-common-private.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,12 +1,12 @@ /* - * Copyright (C) 2020 Richard Hughes + * Copyright 2020 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include +#include "xb-compile.h" gchar * xb_content_type_guess(const gchar *filename, const guchar *buf, gsize bufsz); @@ -15,4 +15,4 @@ const guint8 *buf, gsize bufsz, GCancellable *cancellable, - GError **error); + GError **error) G_GNUC_NON_NULL(1); diff -Nru libxmlb-0.3.10/src/xb-common.c libxmlb-0.3.22/src/xb-common.c --- libxmlb-0.3.10/src/xb-common.c 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-common.c 2025-03-12 09:35:38.000000000 +0000 @@ -1,14 +1,13 @@ /* - * Copyright (C) 2020 Richard Hughes + * Copyright 2020 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #define G_LOG_DOMAIN "XbCommon" #include "config.h" -#include #include #include "xb-common-private.h" @@ -30,10 +29,14 @@ return "application/gzip"; if (g_strcmp0(ext, ".xz") == 0) return "application/x-xz"; - if (g_strcmp0(ext, ".txt") == 0 || g_strcmp0(ext, ".xml") == 0) + if (g_strcmp0(ext, ".zst") == 0) + return "application/zstd"; + if (g_strcmp0(ext, ".xml") == 0) return "application/xml"; if (g_strcmp0(ext, ".desktop") == 0) return "application/x-desktop"; + if (g_strcmp0(ext, ".quirk") == 0) + return "text/plain"; return NULL; } @@ -77,6 +80,8 @@ return g_strdup("application/gzip"); if (xb_content_type_match(buf, bufsz, 0x0, "\xfd\x37\x7a\x58\x5a\x00", 6)) return g_strdup("application/x-xz"); + if (xb_content_type_match(buf, bufsz, 0x0, "\x28\xb5\x2f\xfd", 4)) + return g_strdup("application/zstd"); if (xb_content_type_match(buf, bufsz, 0x0, " + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#pragma once + +#include + +/* see https://bugzilla.gnome.org/show_bug.cgi?id=113075 */ +#ifndef G_GNUC_NON_NULL +#if !defined(_WIN32) && (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) +#define G_GNUC_NON_NULL(params...) __attribute__((nonnull(params))) +#else +#define G_GNUC_NON_NULL(params...) +#endif +#endif diff -Nru libxmlb-0.3.10/src/xb-lzma-decompressor.c libxmlb-0.3.22/src/xb-lzma-decompressor.c --- libxmlb-0.3.10/src/xb-lzma-decompressor.c 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-lzma-decompressor.c 2025-03-12 09:35:38.000000000 +0000 @@ -1,13 +1,11 @@ /* - * Copyright (C) 2009 Red Hat, Inc. - * Copyright (C) 2009 Shaun McCance - * Copyright (C) 2021 Richard Hughes + * Copyright 2009 Red Hat, Inc. + * Copyright 2009 Shaun McCance + * Copyright 2021 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ -#include "xb-lzma-decompressor.h" - #include "config.h" #include @@ -15,6 +13,8 @@ #include #include +#include "xb-lzma-decompressor.h" + static void xb_lzma_decompressor_iface_init(GConverterIface *iface); @@ -117,10 +117,45 @@ "Invalid compressed data"); return G_CONVERTER_ERROR; } + if (res == LZMA_UNSUPPORTED_CHECK) { + g_set_error_literal(error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "Cannot calculate the integrity check"); + return G_CONVERTER_ERROR; + } if (res == LZMA_MEM_ERROR) { g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_FAILED, "Not enough memory"); return G_CONVERTER_ERROR; } + if (res == LZMA_FORMAT_ERROR) { + g_set_error_literal(error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "File format not recognized"); + return G_CONVERTER_ERROR; + } + if (res == LZMA_OPTIONS_ERROR) { + g_set_error_literal(error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "Invalid or unsupported options"); + return G_CONVERTER_ERROR; + } + if (res == LZMA_BUF_ERROR) { + g_set_error_literal(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "No progress is possible"); + return G_CONVERTER_ERROR; + } + if (res == LZMA_PROG_ERROR) { + g_set_error_literal(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + "Programming error"); + return G_CONVERTER_ERROR; + } if (res == LZMA_OK || res == LZMA_STREAM_END) { *bytes_read = inbuf_size - self->lzmastream.avail_in; *bytes_written = outbuf_size - self->lzmastream.avail_out; @@ -129,7 +164,9 @@ return G_CONVERTER_CONVERTED; } - g_assert_not_reached(); + /* fallback */ + g_set_error(error, G_IO_ERROR, G_IO_ERROR_FAILED, "Unhandled error code %u", res); + return G_CONVERTER_ERROR; } static void diff -Nru libxmlb-0.3.10/src/xb-lzma-decompressor.h libxmlb-0.3.22/src/xb-lzma-decompressor.h --- libxmlb-0.3.10/src/xb-lzma-decompressor.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-lzma-decompressor.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,9 +1,9 @@ /* - * Copyright (C) 2009 Red Hat, Inc. - * Copyright (C) 2009 Shaun McCance - * Copyright (C) 2021 Richard Hughes + * Copyright 2009 Red Hat, Inc. + * Copyright 2009 Shaun McCance + * Copyright 2021 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff -Nru libxmlb-0.3.10/src/xb-machine-private.h libxmlb-0.3.22/src/xb-machine-private.h --- libxmlb-0.3.10/src/xb-machine-private.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-machine-private.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2020 Richard Hughes + * Copyright 2020 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once @@ -15,8 +15,8 @@ XbStack *stack, XbOpcode *opcode1_out, XbOpcode *opcode2_out, - GError **error); + GError **error) G_GNUC_NON_NULL(1, 2, 3, 4); void -xb_machine_opcode_tokenize(XbMachine *self, XbOpcode *op); +xb_machine_opcode_tokenize(XbMachine *self, XbOpcode *op) G_GNUC_NON_NULL(1, 2); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-machine.c libxmlb-0.3.22/src/xb-machine.c --- libxmlb-0.3.10/src/xb-machine.c 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-machine.c 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #define G_LOG_DOMAIN "XbMachine" @@ -61,6 +61,8 @@ GDestroyNotify user_data_free; } XbMachineMethodItem; +#define XB_MACHINE_STACK_LEVELS_MAX 20 + /** * xb_machine_set_debug_flags: * @self: a #XbMachine @@ -248,7 +250,11 @@ } static gboolean -xb_machine_parse_add_func(XbMachine *self, XbStack *opcodes, const gchar *func_name, GError **error) +xb_machine_parse_add_func(XbMachine *self, + XbStack *opcodes, + const gchar *func_name, + guint8 level, + GError **error) { XbOpcode *opcode; @@ -257,14 +263,17 @@ /* match opcode, which should always exist */ if (!xb_machine_opcode_func_init(self, opcode, func_name)) { - g_set_error(error, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "built-in function not found: %s", - func_name); + if (error != NULL) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "built-in function not found: %s", + func_name); + } xb_stack_pop(opcodes, NULL, NULL); return FALSE; } + xb_opcode_set_level(opcode, level); return TRUE; } @@ -314,23 +323,27 @@ if (g_ascii_isspace(str[0]) || str_has_sign(str) || (base == 16 && str_has_hex_prefix(str)) || (saved_errno != 0 && saved_errno != ERANGE) || end_ptr == NULL || *end_ptr != '\0') { - g_set_error(error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "“%s” is not an unsigned number", - str); + if (error != NULL) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "“%s” is not an unsigned number", + str); + } return FALSE; } if (saved_errno == ERANGE || number < min || number > max) { - g_autofree gchar *min_str = g_strdup_printf("%" G_GUINT64_FORMAT, min); - g_autofree gchar *max_str = g_strdup_printf("%" G_GUINT64_FORMAT, max); - g_set_error(error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "Number “%s” is out of bounds [%s, %s]", - str, - min_str, - max_str); + if (error != NULL) { + g_autofree gchar *min_str = g_strdup_printf("%" G_GUINT64_FORMAT, min); + g_autofree gchar *max_str = g_strdup_printf("%" G_GUINT64_FORMAT, max); + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "Number “%s” is out of bounds [%s, %s]", + str, + min_str, + max_str); + } return FALSE; } if (out_num != NULL) @@ -344,6 +357,7 @@ XbStack *opcodes, const gchar *text, gssize text_len, + guint8 level, GError **error) { XbMachinePrivate *priv = GET_PRIVATE(self); @@ -370,10 +384,18 @@ for (guint i = 0; i < priv->text_handlers->len; i++) { XbMachineTextHandlerItem *item = g_ptr_array_index(priv->text_handlers, i); gboolean handled = FALSE; + guint opcodes_sz = xb_stack_get_size(opcodes); if (!item->handler_cb(self, opcodes, str, &handled, item->user_data, error)) return FALSE; - if (handled) + if (handled) { + /* ideally the XbMachineTextHandlerFunc would contain a `guint8 level` but + * that is now public ABI. Just fixup the level for any added opcodes */ + for (guint j = xb_stack_get_size(opcodes); j > opcodes_sz; j--) { + XbOpcode *op_tmp = xb_stack_peek(opcodes, j - 1); + xb_opcode_set_level(op_tmp, level); + } return TRUE; + } } /* quoted text */ @@ -384,6 +406,7 @@ if (!xb_stack_push(opcodes, &opcode, error)) return FALSE; xb_opcode_text_init_steal(opcode, g_steal_pointer(&tmp)); + xb_opcode_set_level(opcode, level); return TRUE; } } @@ -400,6 +423,7 @@ g_steal_pointer(&tmp), XB_SILO_UNSET, g_free); + xb_opcode_set_level(opcode, level); return TRUE; } } @@ -410,6 +434,7 @@ if (!xb_stack_push(opcodes, &opcode, error)) return FALSE; xb_opcode_bind_init(opcode); + xb_opcode_set_level(opcode, level); return TRUE; } @@ -419,15 +444,18 @@ if (!xb_stack_push(opcodes, &opcode, error)) return FALSE; xb_opcode_integer_init(opcode, val); + xb_opcode_set_level(opcode, level); return TRUE; } /* not supported */ - g_set_error(error, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "cannot parse text or number `%s`", - str); + if (error != NULL) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "cannot parse text or number `%s`", + str); + } return FALSE; } @@ -437,6 +465,7 @@ const gchar *text, gssize text_len, gboolean is_method, + guint8 level, GError **error) { XbMachinePrivate *priv = GET_PRIVATE(self); @@ -450,63 +479,90 @@ for (gssize i = 0; i < text_len; i++) { for (guint j = 0; j < priv->operators->len; j++) { XbMachineOperator *op = g_ptr_array_index(priv->operators, j); - if (strncmp(text + i, op->str, op->strsz) == 0) { - if (is_method) { - /* after then before */ + if (strncmp(text + i, op->str, op->strsz) != 0) + continue; + if (is_method) { + XbOpcode *op_tail; + const gchar *op_name = op->name; + + /* after then before */ + if (!xb_machine_parse_section(self, + opcodes, + text + i + op->strsz, + -1, + is_method, + level, + error)) + return FALSE; + if (i > 0) { if (!xb_machine_parse_section(self, opcodes, - text + i + op->strsz, - -1, - is_method, + text, + i, + FALSE, + level, error)) return FALSE; - if (i > 0) { - if (!xb_machine_parse_section(self, - opcodes, - text, - i, - FALSE, - error)) - return FALSE; - } - if (!xb_machine_parse_add_func(self, - opcodes, - op->name, - error)) - return FALSE; - } else { - /* before then after */ - if (i > 0) { - if (!xb_machine_parse_section(self, - opcodes, - text, - i, - FALSE, - error)) - return FALSE; - } + } + + /* multiple "eq" sections are converted to "in" */ + op_tail = xb_stack_peek_tail(opcodes); + if (op_tail != NULL && _xb_opcode_get_level(op_tail) != level && + g_strcmp0(op_name, "eq") == 0) + op_name = "in"; + if (!xb_machine_parse_add_func(self, + opcodes, + op_name, + level, + error)) + return FALSE; + } else { + /* before then after */ + if (i > 0) { if (!xb_machine_parse_section(self, opcodes, - text + i + op->strsz, - -1, - is_method, + text, + i, + FALSE, + level, error)) return FALSE; - if (!xb_machine_parse_add_func(self, - opcodes, - op->name, - error)) - return FALSE; } - return TRUE; + if (!xb_machine_parse_section(self, + opcodes, + text + i + op->strsz, + -1, + is_method, + level, + error)) + return FALSE; + if (!xb_machine_parse_add_func(self, + opcodes, + op->name, + level, + error)) + return FALSE; } + return TRUE; } } /* nothing matched */ - if (is_method) - return xb_machine_parse_add_func(self, opcodes, text, error); - return xb_machine_parse_add_text(self, opcodes, text, text_len, error); + if (is_method) { + g_autoptr(GError) error_local = NULL; + if (!xb_machine_parse_add_text(self, + opcodes, + text, + text_len, + level, + &error_local)) { + if (priv->debug_flags & XB_MACHINE_DEBUG_FLAG_SHOW_PARSING) + g_debug("Failed to add text %s, trying function", text); + return xb_machine_parse_add_func(self, opcodes, text, level, error); + } + return TRUE; + } + return xb_machine_parse_add_text(self, opcodes, text, text_len, level, error); } static gboolean @@ -515,6 +571,7 @@ const gchar *text, gsize text_len, gboolean is_method, + guint8 level, GError **error) { g_autofree gchar *tmp = NULL; @@ -531,7 +588,11 @@ if (tmp[i] == ',') { tmp[i] = '\0'; if (is_method) { - if (!xb_machine_parse_add_func(self, opcodes, tmp + i + 1, error)) + if (!xb_machine_parse_add_func(self, + opcodes, + tmp + i + 1, + level, + error)) return FALSE; is_method = FALSE; } else { @@ -540,13 +601,14 @@ tmp + i + 1, -1, TRUE, + level, error)) return FALSE; } } } if (tmp[0] != '\0') { - if (!xb_machine_parse_section(self, opcodes, tmp, -1, is_method, error)) + if (!xb_machine_parse_section(self, opcodes, tmp, -1, is_method, level, error)) return FALSE; } return TRUE; @@ -582,8 +644,8 @@ g_auto(XbOpcode) op_result = XB_OPCODE_INIT(); g_auto(XbOpcode) op_owned = op; - /* a function! lets check the arg length */ - if (xb_opcode_get_kind(&op) != XB_OPCODE_KIND_FUNCTION) { + /* not a function */ + if (_xb_opcode_get_kind(&op) != XB_OPCODE_KIND_FUNCTION) { XbOpcode *op_out; if (!xb_stack_push(results, &op_out, error)) return FALSE; @@ -592,7 +654,7 @@ } /* get function, check if we have enough arguments */ - item = g_ptr_array_index(priv->methods, xb_opcode_get_val(&op)); + item = g_ptr_array_index(priv->methods, _xb_opcode_get_val(&op)); if (item->n_opcodes > xb_stack_get_size(opcodes)) { g_set_error_literal(error, G_IO_ERROR, @@ -603,11 +665,11 @@ /* run the method. it's only supposed to pop its arguments off the stack * if it can complete successfully */ - stack_str = xb_stack_to_string(opcodes); if (!item->method_cb(self, opcodes, NULL, item->user_data, NULL, &error_local)) { XbOpcode *op_out; if (priv->debug_flags & XB_MACHINE_DEBUG_FLAG_SHOW_OPTIMIZER) { + stack_str = xb_stack_to_string(opcodes); g_debug("ignoring optimized call to %s(%s): %s", item->name, stack_str, @@ -622,8 +684,8 @@ /* the method ran, add the result. the arguments have already been popped */ if (!xb_machine_stack_pop(self, opcodes, &op_result, error)) return FALSE; - if (xb_opcode_get_kind(&op_result) != XB_OPCODE_KIND_BOOLEAN || - xb_opcode_get_val(&op_result)) { + if (_xb_opcode_get_kind(&op_result) != XB_OPCODE_KIND_BOOLEAN || + _xb_opcode_get_val(&op_result)) { XbOpcode *op_out; if (priv->debug_flags & XB_MACHINE_DEBUG_FLAG_SHOW_OPTIMIZER) { @@ -632,17 +694,21 @@ } if (!xb_stack_push(results, &op_out, error)) return FALSE; + xb_opcode_set_level(&op_result, _xb_opcode_get_level(&op)); *op_out = xb_opcode_steal(&op_result); return TRUE; } /* the predicate will always evalulate to FALSE */ - g_set_error(error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "the predicate will always evalulate to FALSE: %s", - stack_str); + if (error != NULL) { + stack_str = xb_stack_to_string(opcodes); + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "the predicate will always evalulate to FALSE: %s", + stack_str); + } return FALSE; } @@ -691,20 +757,22 @@ XbStack *opcodes, const gchar *text, gsize text_len, - guint level, + guint8 level, GError **error) { XbMachinePrivate *priv = GET_PRIVATE(self); guint tail = 0; /* sanity check */ - if (level > 20) { - g_autofree gchar *tmp = g_strndup(text, text_len); - g_set_error(error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "nesting deeper than 20 levels supported: %s", - tmp); + if (level > XB_MACHINE_STACK_LEVELS_MAX) { + if (error != NULL) { + g_autofree gchar *tmp = g_strndup(text, text_len); + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "nesting deeper than 20 levels supported: %s", + tmp); + } return G_MAXSIZE; } for (guint i = 0; i < text_len; i++) { @@ -725,6 +793,7 @@ text + tail, i - tail, TRUE, + level, error)) return G_MAXSIZE; i += j; @@ -737,21 +806,30 @@ text + tail, i - tail, FALSE, + level, error)) return G_MAXSIZE; return i + 1; } } if (tail != text_len && level > 0) { - g_autofree gchar *tmp = g_strndup(text, text_len); - g_set_error(error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "brackets did not match: %s", - tmp); + if (error != NULL) { + g_autofree gchar *tmp = g_strndup(text, text_len); + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "brackets did not match: %s", + tmp); + } return G_MAXSIZE; } - if (!xb_machine_parse_sections(self, opcodes, text + tail, text_len - tail, FALSE, error)) + if (!xb_machine_parse_sections(self, + opcodes, + text + tail, + text_len - tail, + FALSE, + level, + error)) return G_MAXSIZE; return 0; } @@ -781,7 +859,7 @@ { XbMachineOpcodeFixupItem *item; XbMachinePrivate *priv = GET_PRIVATE(self); - guint level = 0; + guint8 level = 0; g_autoptr(XbStack) opcodes = NULL; g_autofree gchar *opcodes_sig = NULL; @@ -876,7 +954,7 @@ GError **error) { XbMachinePrivate *priv = GET_PRIVATE(self); - XbMachineMethodItem *item = g_ptr_array_index(priv->methods, xb_opcode_get_val(opcode)); + XbMachineMethodItem *item = g_ptr_array_index(priv->methods, _xb_opcode_get_val(opcode)); /* optional debugging */ if (priv->debug_flags & XB_MACHINE_DEBUG_FLAG_SHOW_STACK) { @@ -887,12 +965,14 @@ /* check we have enough stack elements */ if (item->n_opcodes > xb_stack_get_size(stack)) { - g_set_error(error, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "function required %u arguments, stack only has %u", - item->n_opcodes, - xb_stack_get_size(stack)); + if (error != NULL) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "function required %u arguments, stack only has %u", + item->n_opcodes, + xb_stack_get_size(stack)); + } return FALSE; } if (!item->method_cb(self, stack, NULL, item->user_data, exec_data, error)) { @@ -974,17 +1054,35 @@ stack = xb_stack_new_inline(priv->stack_size); for (guint i = 0; i < opcodes_stack_size; i++) { XbOpcode *opcode = xb_stack_peek(opcodes, i); - XbOpcodeKind kind = xb_opcode_get_kind(opcode); + XbOpcodeKind kind = _xb_opcode_get_kind(opcode); /* replace post-0.3.0-style bound opcodes with their bound values */ - if (bindings != NULL && - (kind == XB_OPCODE_KIND_BOUND_TEXT || kind == XB_OPCODE_KIND_BOUND_INTEGER)) { + if (bindings != NULL && (kind == XB_OPCODE_KIND_BOUND_TEXT || + kind == XB_OPCODE_KIND_BOUND_INDEXED_TEXT || + kind == XB_OPCODE_KIND_BOUND_INTEGER)) { XbOpcode *machine_opcode; if (!xb_machine_stack_push(self, stack, &machine_opcode, error)) return FALSE; if (!xb_value_bindings_lookup_opcode(bindings, bound_opcode_idx++, machine_opcode)) { + if (error != NULL) { + g_autofree gchar *tmp1 = xb_stack_to_string(stack); + g_autofree gchar *tmp2 = xb_stack_to_string(opcodes); + g_set_error( + error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "opcode was not bound at runtime, stack:%s, opcodes:%s", + tmp1, + tmp2); + } + return FALSE; + } + continue; + } + if (kind == XB_OPCODE_KIND_BOUND_UNSET) { + if (error != NULL) { g_autofree gchar *tmp1 = xb_stack_to_string(stack); g_autofree gchar *tmp2 = xb_stack_to_string(opcodes); g_set_error(error, @@ -993,18 +1091,7 @@ "opcode was not bound at runtime, stack:%s, opcodes:%s", tmp1, tmp2); - return FALSE; } - continue; - } else if (kind == XB_OPCODE_KIND_BOUND_UNSET) { - g_autofree gchar *tmp1 = xb_stack_to_string(stack); - g_autofree gchar *tmp2 = xb_stack_to_string(opcodes); - g_set_error(error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "opcode was not bound at runtime, stack:%s, opcodes:%s", - tmp1, - tmp2); return FALSE; } @@ -1020,8 +1107,9 @@ * the caller */ if (kind == XB_OPCODE_KIND_TEXT || kind == XB_OPCODE_KIND_BOOLEAN || kind == XB_OPCODE_KIND_INTEGER || kind == XB_OPCODE_KIND_INDEXED_TEXT || - (bindings == NULL && - (kind == XB_OPCODE_KIND_BOUND_TEXT || kind == XB_OPCODE_KIND_BOUND_INTEGER))) { + (bindings == NULL && (kind == XB_OPCODE_KIND_BOUND_TEXT || + kind == XB_OPCODE_KIND_BOUND_INDEXED_TEXT || + kind == XB_OPCODE_KIND_BOUND_INTEGER))) { XbOpcode *machine_opcode; if (!xb_machine_stack_push(self, stack, &machine_opcode, error)) return FALSE; @@ -1031,37 +1119,43 @@ } /* invalid */ - g_set_error(error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "opcode kind %u not recognised", - kind); + if (error != NULL) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "opcode kind %u not recognised", + kind); + } return FALSE; } /* the stack should have one boolean left on the stack */ if (xb_stack_get_size(stack) != 1) { - g_autofree gchar *tmp = xb_stack_to_string(stack); - g_set_error(error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "%u opcodes remain on the stack (%s)", - xb_stack_get_size(stack), - tmp); + if (error != NULL) { + g_autofree gchar *tmp = xb_stack_to_string(stack); + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "%u opcodes remain on the stack (%s)", + xb_stack_get_size(stack), + tmp); + } return FALSE; } if (!xb_stack_pop(stack, &opcode_success, error)) return FALSE; - if (xb_opcode_get_kind(&opcode_success) != XB_OPCODE_KIND_BOOLEAN) { - g_autofree gchar *tmp = xb_stack_to_string(stack); - g_set_error(error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "Expected boolean, got: %s", - tmp); + if (_xb_opcode_get_kind(&opcode_success) != XB_OPCODE_KIND_BOOLEAN) { + if (error != NULL) { + g_autofree gchar *tmp = xb_stack_to_string(stack); + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "Expected boolean, got: %s", + tmp); + } return FALSE; } - *result = xb_opcode_get_val(&opcode_success); + *result = _xb_opcode_get_val(&opcode_success); /* success */ return TRUE; @@ -1159,7 +1253,7 @@ { XbMachinePrivate *priv = GET_PRIVATE(self); - if (priv->debug_flags & XB_MACHINE_DEBUG_FLAG_SHOW_STACK) { + if (G_UNLIKELY(priv->debug_flags & XB_MACHINE_DEBUG_FLAG_SHOW_STACK)) { g_debug("pushing generic opcode"); } @@ -1186,13 +1280,13 @@ XbMachinePrivate *priv = GET_PRIVATE(self); XbOpcode *opcode; - if (priv->debug_flags & XB_MACHINE_DEBUG_FLAG_SHOW_STACK) + if (G_UNLIKELY(priv->debug_flags & XB_MACHINE_DEBUG_FLAG_SHOW_STACK)) g_debug("pushing: %s", str); if (!xb_stack_push(stack, &opcode, error)) return FALSE; xb_opcode_text_init(opcode, str); - if (priv->debug_flags & XB_MACHINE_DEBUG_FLAG_SHOW_STACK) + if (G_UNLIKELY(priv->debug_flags & XB_MACHINE_DEBUG_FLAG_SHOW_STACK)) xb_machine_debug_show_stack(self, stack); return TRUE; @@ -1218,7 +1312,7 @@ XbOpcode *opcode; XbMachinePrivate *priv = GET_PRIVATE(self); - if (priv->debug_flags & XB_MACHINE_DEBUG_FLAG_SHOW_STACK) + if (G_UNLIKELY(priv->debug_flags & XB_MACHINE_DEBUG_FLAG_SHOW_STACK)) g_debug("pushing: %s", str); if (!xb_stack_push(stack, &opcode, error)) @@ -1251,7 +1345,7 @@ XbOpcode *opcode; g_autofree gchar *str_stolen = g_steal_pointer(&str); - if (priv->debug_flags & XB_MACHINE_DEBUG_FLAG_SHOW_STACK) + if (G_UNLIKELY(priv->debug_flags & XB_MACHINE_DEBUG_FLAG_SHOW_STACK)) g_debug("pushing: %s", str_stolen); if (!xb_stack_push(stack, &opcode, error)) @@ -1283,7 +1377,7 @@ XbMachinePrivate *priv = GET_PRIVATE(self); XbOpcode *opcode; - if (priv->debug_flags & XB_MACHINE_DEBUG_FLAG_SHOW_STACK) + if (G_UNLIKELY(priv->debug_flags & XB_MACHINE_DEBUG_FLAG_SHOW_STACK)) g_debug("pushing: %u", val); if (!xb_stack_push(stack, &opcode, error)) @@ -1363,7 +1457,7 @@ /* use the fast token path even if there are no valid tokens */ xb_opcode_add_flag(op, XB_OPCODE_FLAG_TOKENIZED); - str = xb_opcode_get_str(op); + str = _xb_opcode_get_str(op); tokens = g_str_tokenize_and_fold(str, NULL, &ascii_tokens); for (guint i = 0; tokens[i] != NULL; i++) { if (!xb_string_token_valid(tokens[i])) @@ -1380,9 +1474,9 @@ typedef gboolean (*OpcodeCheckFunc)(XbOpcode *op); static gboolean -xb_opcode_cmp_val_or_str(XbOpcode *op) +_xb_opcode_cmp_val_or_str(XbOpcode *op) { - return xb_opcode_cmp_str(op) || xb_opcode_cmp_val(op); + return xb_opcode_cmp_str(op) || _xb_opcode_cmp_int(op) || _xb_opcode_cmp_itx(op); } static gboolean @@ -1392,12 +1486,15 @@ head = xb_stack_peek_tail(stack); if (head == NULL || !f(head)) { - g_set_error(error, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "%s type not supported", - (head != NULL) ? xb_opcode_kind_to_string(xb_opcode_get_kind(head)) - : "(null)"); + if (error != NULL) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "%s type not supported", + (head != NULL) + ? xb_opcode_kind_to_string(_xb_opcode_get_kind(head)) + : "(null)"); + } return FALSE; } @@ -1416,14 +1513,17 @@ head2 = xb_stack_peek(stack, stack_size - 2); } if (head1 == NULL || head2 == NULL || !f1(head1) || !f2(head2)) { - g_set_error(error, + if (error != NULL) { + g_set_error( + error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "%s:%s types not supported", - (head1 != NULL) ? xb_opcode_kind_to_string(xb_opcode_get_kind(head1)) + (head1 != NULL) ? xb_opcode_kind_to_string(_xb_opcode_get_kind(head1)) : "(null)", - (head2 != NULL) ? xb_opcode_kind_to_string(xb_opcode_get_kind(head2)) + (head2 != NULL) ? xb_opcode_kind_to_string(_xb_opcode_get_kind(head2)) : "(null)"); + } return FALSE; } @@ -1441,13 +1541,15 @@ g_auto(XbOpcode) op1 = XB_OPCODE_INIT(); g_auto(XbOpcode) op2 = XB_OPCODE_INIT(); - if (!xb_machine_check_two_args(stack, xb_opcode_cmp_val, xb_opcode_cmp_val, error)) + if (!xb_machine_check_two_args(stack, _xb_opcode_cmp_int, _xb_opcode_cmp_int, error)) return FALSE; if (!xb_machine_stack_pop_two(self, stack, &op1, &op2, error)) return FALSE; /* INTE:INTE */ - return xb_stack_push_bool(stack, xb_opcode_get_val(&op1) && xb_opcode_get_val(&op2), error); + return xb_stack_push_bool(stack, + _xb_opcode_get_val(&op1) && _xb_opcode_get_val(&op2), + error); } static gboolean @@ -1461,13 +1563,15 @@ g_auto(XbOpcode) op1 = XB_OPCODE_INIT(); g_auto(XbOpcode) op2 = XB_OPCODE_INIT(); - if (!xb_machine_check_two_args(stack, xb_opcode_cmp_val, xb_opcode_cmp_val, error)) + if (!xb_machine_check_two_args(stack, _xb_opcode_cmp_int, _xb_opcode_cmp_int, error)) return FALSE; if (!xb_machine_stack_pop_two(self, stack, &op1, &op2, error)) return FALSE; /* INTE:INTE */ - return xb_stack_push_bool(stack, xb_opcode_get_val(&op1) || xb_opcode_get_val(&op2), error); + return xb_stack_push_bool(stack, + _xb_opcode_get_val(&op1) || _xb_opcode_get_val(&op2), + error); } static gboolean @@ -1478,36 +1582,49 @@ gpointer exec_data, GError **error) { + XbMachinePrivate *priv = GET_PRIVATE(self); g_auto(XbOpcode) op1 = XB_OPCODE_INIT(); g_auto(XbOpcode) op2 = XB_OPCODE_INIT(); if (!xb_machine_check_two_args(stack, - xb_opcode_cmp_val_or_str, - xb_opcode_cmp_val_or_str, + _xb_opcode_cmp_val_or_str, + _xb_opcode_cmp_val_or_str, error)) return FALSE; if (!xb_machine_stack_pop_two(self, stack, &op1, &op2, error)) return FALSE; /* INTE:INTE */ - if (xb_opcode_cmp_val(&op1) && xb_opcode_cmp_val(&op2)) + if ((_xb_opcode_cmp_int(&op1) && _xb_opcode_cmp_int(&op2)) || + (_xb_opcode_cmp_itx(&op1) && _xb_opcode_cmp_itx(&op2))) return xb_stack_push_bool(stack, - xb_opcode_get_val(&op1) == xb_opcode_get_val(&op2), + _xb_opcode_get_val(&op1) == _xb_opcode_get_val(&op2), error); /* TEXT:TEXT */ - if (xb_opcode_cmp_str(&op1) && xb_opcode_cmp_str(&op2)) + if (xb_opcode_cmp_str(&op1) && xb_opcode_cmp_str(&op2)) { + if (priv->debug_flags & XB_MACHINE_DEBUG_FLAG_SHOW_SLOW_PATH) { + g_autofree gchar *str1 = xb_opcode_to_string(&op1); + g_autofree gchar *str2 = xb_opcode_to_string(&op2); + g_debug("slow strcmp fallback of %s:%s", str1, str2); + } return xb_stack_push_bool( stack, - g_strcmp0(xb_opcode_get_str(&op1), xb_opcode_get_str(&op2)) == 0, + g_strcmp0(_xb_opcode_get_str(&op1), _xb_opcode_get_str(&op2)) == 0, error); + } /* INTE:TEXT */ - if (xb_opcode_cmp_val(&op1) && xb_opcode_cmp_str(&op2)) { + if (_xb_opcode_cmp_int(&op1) && xb_opcode_cmp_str(&op2)) { guint64 val = 0; - if (xb_opcode_get_str(&op2) == NULL) + if (_xb_opcode_get_str(&op2) == NULL) return xb_stack_push_bool(stack, FALSE, error); - if (!g_ascii_string_to_unsigned(xb_opcode_get_str(&op2), + if (priv->debug_flags & XB_MACHINE_DEBUG_FLAG_SHOW_SLOW_PATH) { + g_autofree gchar *str1 = xb_opcode_to_string(&op1); + g_autofree gchar *str2 = xb_opcode_to_string(&op2); + g_debug("slow atoi fallback of %s:%s", str1, str2); + } + if (!g_ascii_string_to_unsigned(_xb_opcode_get_str(&op2), 10, 0, G_MAXUINT32, @@ -1515,15 +1632,20 @@ error)) { return FALSE; } - return xb_stack_push_bool(stack, val == xb_opcode_get_val(&op1), error); + return xb_stack_push_bool(stack, val == _xb_opcode_get_val(&op1), error); } /* TEXT:INTE */ - if (xb_opcode_cmp_str(&op1) && xb_opcode_cmp_val(&op2)) { + if (xb_opcode_cmp_str(&op1) && _xb_opcode_cmp_int(&op2)) { guint64 val = 0; - if (xb_opcode_get_str(&op1) == NULL) + if (_xb_opcode_get_str(&op1) == NULL) return xb_stack_push_bool(stack, FALSE, error); - if (!g_ascii_string_to_unsigned(xb_opcode_get_str(&op1), + if (priv->debug_flags & XB_MACHINE_DEBUG_FLAG_SHOW_SLOW_PATH) { + g_autofree gchar *str1 = xb_opcode_to_string(&op1); + g_autofree gchar *str2 = xb_opcode_to_string(&op2); + g_debug("slow atoi fallback of %s:%s", str1, str2); + } + if (!g_ascii_string_to_unsigned(_xb_opcode_get_str(&op1), 10, 0, G_MAXUINT32, @@ -1531,16 +1653,18 @@ error)) { return FALSE; } - return xb_stack_push_bool(stack, val == xb_opcode_get_val(&op2), error); + return xb_stack_push_bool(stack, val == _xb_opcode_get_val(&op2), error); } /* should have been checked above */ - g_set_error(error, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "cannot compare %s and %s", - xb_opcode_kind_to_string(xb_opcode_get_kind(&op1)), - xb_opcode_kind_to_string(xb_opcode_get_kind(&op2))); + if (error != NULL) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "cannot compare %s and %s", + xb_opcode_kind_to_string(_xb_opcode_get_kind(&op1)), + xb_opcode_kind_to_string(_xb_opcode_get_kind(&op2))); + } return FALSE; } @@ -1556,17 +1680,18 @@ g_auto(XbOpcode) op2 = XB_OPCODE_INIT(); if (!xb_machine_check_two_args(stack, - xb_opcode_cmp_val_or_str, - xb_opcode_cmp_val_or_str, + _xb_opcode_cmp_val_or_str, + _xb_opcode_cmp_val_or_str, error)) return FALSE; if (!xb_machine_stack_pop_two(self, stack, &op1, &op2, error)) return FALSE; /* INTE:INTE */ - if (xb_opcode_cmp_val(&op1) && xb_opcode_cmp_val(&op2)) { + if ((_xb_opcode_cmp_int(&op1) && _xb_opcode_cmp_int(&op2)) || + (_xb_opcode_cmp_itx(&op1) && _xb_opcode_cmp_itx(&op2))) { return xb_stack_push_bool(stack, - xb_opcode_get_val(&op1) != xb_opcode_get_val(&op2), + _xb_opcode_get_val(&op1) != _xb_opcode_get_val(&op2), error); } @@ -1574,16 +1699,16 @@ if (xb_opcode_cmp_str(&op1) && xb_opcode_cmp_str(&op2)) { return xb_stack_push_bool( stack, - g_strcmp0(xb_opcode_get_str(&op1), xb_opcode_get_str(&op2)) != 0, + g_strcmp0(_xb_opcode_get_str(&op1), _xb_opcode_get_str(&op2)) != 0, error); } /* INTE:TEXT */ - if (xb_opcode_cmp_val(&op1) && xb_opcode_cmp_str(&op2)) { + if (_xb_opcode_cmp_int(&op1) && xb_opcode_cmp_str(&op2)) { guint64 val = 0; - if (xb_opcode_get_str(&op2) == NULL) + if (_xb_opcode_get_str(&op2) == NULL) return xb_stack_push_bool(stack, FALSE, error); - if (!g_ascii_string_to_unsigned(xb_opcode_get_str(&op2), + if (!g_ascii_string_to_unsigned(_xb_opcode_get_str(&op2), 10, 0, G_MAXUINT32, @@ -1591,15 +1716,15 @@ error)) { return FALSE; } - return xb_stack_push_bool(stack, val != xb_opcode_get_val(&op1), error); + return xb_stack_push_bool(stack, val != _xb_opcode_get_val(&op1), error); } /* TEXT:INTE */ - if (xb_opcode_cmp_str(&op1) && xb_opcode_cmp_val(&op2)) { + if (xb_opcode_cmp_str(&op1) && _xb_opcode_cmp_int(&op2)) { guint64 val = 0; - if (xb_opcode_get_str(&op1) == NULL) + if (_xb_opcode_get_str(&op1) == NULL) return xb_stack_push_bool(stack, FALSE, error); - if (!g_ascii_string_to_unsigned(xb_opcode_get_str(&op1), + if (!g_ascii_string_to_unsigned(_xb_opcode_get_str(&op1), 10, 0, G_MAXUINT32, @@ -1607,16 +1732,18 @@ error)) { return FALSE; } - return xb_stack_push_bool(stack, val != xb_opcode_get_val(&op2), error); + return xb_stack_push_bool(stack, val != _xb_opcode_get_val(&op2), error); } /* should have been checked above */ - g_set_error(error, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "cannot compare %s and %s", - xb_opcode_kind_to_string(xb_opcode_get_kind(&op1)), - xb_opcode_kind_to_string(xb_opcode_get_kind(&op2))); + if (error != NULL) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "cannot compare %s and %s", + xb_opcode_kind_to_string(_xb_opcode_get_kind(&op1)), + xb_opcode_kind_to_string(_xb_opcode_get_kind(&op2))); + } return FALSE; } @@ -1632,17 +1759,17 @@ g_auto(XbOpcode) op2 = XB_OPCODE_INIT(); if (!xb_machine_check_two_args(stack, - xb_opcode_cmp_val_or_str, - xb_opcode_cmp_val_or_str, + _xb_opcode_cmp_val_or_str, + _xb_opcode_cmp_val_or_str, error)) return FALSE; if (!xb_machine_stack_pop_two(self, stack, &op1, &op2, error)) return FALSE; /* INTE:INTE */ - if (xb_opcode_cmp_val(&op1) && xb_opcode_cmp_val(&op2)) { + if (_xb_opcode_cmp_int(&op1) && _xb_opcode_cmp_int(&op2)) { return xb_stack_push_bool(stack, - xb_opcode_get_val(&op2) < xb_opcode_get_val(&op1), + _xb_opcode_get_val(&op2) < _xb_opcode_get_val(&op1), error); } @@ -1650,16 +1777,16 @@ if (xb_opcode_cmp_str(&op1) && xb_opcode_cmp_str(&op2)) { return xb_stack_push_bool( stack, - g_strcmp0(xb_opcode_get_str(&op2), xb_opcode_get_str(&op1)) < 0, + g_strcmp0(_xb_opcode_get_str(&op2), _xb_opcode_get_str(&op1)) < 0, error); } /* INTE:TEXT */ - if (xb_opcode_cmp_val(&op1) && xb_opcode_cmp_str(&op2)) { + if (_xb_opcode_cmp_int(&op1) && xb_opcode_cmp_str(&op2)) { guint64 val = 0; - if (xb_opcode_get_str(&op2) == NULL) + if (_xb_opcode_get_str(&op2) == NULL) return xb_stack_push_bool(stack, FALSE, error); - if (!g_ascii_string_to_unsigned(xb_opcode_get_str(&op2), + if (!g_ascii_string_to_unsigned(_xb_opcode_get_str(&op2), 10, 0, G_MAXUINT32, @@ -1667,15 +1794,15 @@ error)) { return FALSE; } - return xb_stack_push_bool(stack, val < xb_opcode_get_val(&op1), error); + return xb_stack_push_bool(stack, val < _xb_opcode_get_val(&op1), error); } /* TEXT:INTE */ - if (xb_opcode_cmp_str(&op1) && xb_opcode_cmp_val(&op2)) { + if (xb_opcode_cmp_str(&op1) && _xb_opcode_cmp_int(&op2)) { guint64 val = 0; - if (xb_opcode_get_str(&op1) == NULL) + if (_xb_opcode_get_str(&op1) == NULL) return xb_stack_push_bool(stack, FALSE, error); - if (!g_ascii_string_to_unsigned(xb_opcode_get_str(&op1), + if (!g_ascii_string_to_unsigned(_xb_opcode_get_str(&op1), 10, 0, G_MAXUINT32, @@ -1683,16 +1810,18 @@ error)) { return FALSE; } - return xb_stack_push_bool(stack, val < xb_opcode_get_val(&op2), error); + return xb_stack_push_bool(stack, val < _xb_opcode_get_val(&op2), error); } /* should have been checked above */ - g_set_error(error, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "cannot compare %s and %s", - xb_opcode_kind_to_string(xb_opcode_get_kind(&op1)), - xb_opcode_kind_to_string(xb_opcode_get_kind(&op2))); + if (error != NULL) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "cannot compare %s and %s", + xb_opcode_kind_to_string(_xb_opcode_get_kind(&op1)), + xb_opcode_kind_to_string(_xb_opcode_get_kind(&op2))); + } return FALSE; } @@ -1708,17 +1837,17 @@ g_auto(XbOpcode) op2 = XB_OPCODE_INIT(); if (!xb_machine_check_two_args(stack, - xb_opcode_cmp_val_or_str, - xb_opcode_cmp_val_or_str, + _xb_opcode_cmp_val_or_str, + _xb_opcode_cmp_val_or_str, error)) return FALSE; if (!xb_machine_stack_pop_two(self, stack, &op1, &op2, error)) return FALSE; /* INTE:INTE */ - if (xb_opcode_cmp_val(&op1) && xb_opcode_cmp_val(&op2)) { + if (_xb_opcode_cmp_int(&op1) && _xb_opcode_cmp_int(&op2)) { return xb_stack_push_bool(stack, - xb_opcode_get_val(&op2) > xb_opcode_get_val(&op1), + _xb_opcode_get_val(&op2) > _xb_opcode_get_val(&op1), error); } @@ -1726,16 +1855,16 @@ if (xb_opcode_cmp_str(&op1) && xb_opcode_cmp_str(&op2)) { return xb_stack_push_bool( stack, - g_strcmp0(xb_opcode_get_str(&op2), xb_opcode_get_str(&op1)) > 0, + g_strcmp0(_xb_opcode_get_str(&op2), _xb_opcode_get_str(&op1)) > 0, error); } /* INTE:TEXT */ - if (xb_opcode_cmp_val(&op1) && xb_opcode_cmp_str(&op2)) { + if (_xb_opcode_cmp_int(&op1) && xb_opcode_cmp_str(&op2)) { guint64 val = 0; - if (xb_opcode_get_str(&op2) == NULL) + if (_xb_opcode_get_str(&op2) == NULL) return xb_stack_push_bool(stack, FALSE, error); - if (!g_ascii_string_to_unsigned(xb_opcode_get_str(&op2), + if (!g_ascii_string_to_unsigned(_xb_opcode_get_str(&op2), 10, 0, G_MAXUINT32, @@ -1743,15 +1872,15 @@ error)) { return FALSE; } - return xb_stack_push_bool(stack, val > xb_opcode_get_val(&op1), error); + return xb_stack_push_bool(stack, val > _xb_opcode_get_val(&op1), error); } /* TEXT:INTE */ - if (xb_opcode_cmp_str(&op1) && xb_opcode_cmp_val(&op2)) { + if (xb_opcode_cmp_str(&op1) && _xb_opcode_cmp_int(&op2)) { guint64 val = 0; - if (xb_opcode_get_str(&op1) == NULL) + if (_xb_opcode_get_str(&op1) == NULL) return xb_stack_push_bool(stack, FALSE, error); - if (!g_ascii_string_to_unsigned(xb_opcode_get_str(&op1), + if (!g_ascii_string_to_unsigned(_xb_opcode_get_str(&op1), 10, 0, G_MAXUINT32, @@ -1759,16 +1888,18 @@ error)) { return FALSE; } - return xb_stack_push_bool(stack, val > xb_opcode_get_val(&op2), error); + return xb_stack_push_bool(stack, val > _xb_opcode_get_val(&op2), error); } /* should have been checked above */ - g_set_error(error, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "cannot compare %s and %s", - xb_opcode_kind_to_string(xb_opcode_get_kind(&op1)), - xb_opcode_kind_to_string(xb_opcode_get_kind(&op2))); + if (error != NULL) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "cannot compare %s and %s", + xb_opcode_kind_to_string(_xb_opcode_get_kind(&op1)), + xb_opcode_kind_to_string(_xb_opcode_get_kind(&op2))); + } return FALSE; } @@ -1784,17 +1915,17 @@ g_auto(XbOpcode) op2 = XB_OPCODE_INIT(); if (!xb_machine_check_two_args(stack, - xb_opcode_cmp_val_or_str, - xb_opcode_cmp_val_or_str, + _xb_opcode_cmp_val_or_str, + _xb_opcode_cmp_val_or_str, error)) return FALSE; if (!xb_machine_stack_pop_two(self, stack, &op1, &op2, error)) return FALSE; /* INTE:INTE */ - if (xb_opcode_cmp_val(&op1) && xb_opcode_cmp_val(&op2)) { + if (_xb_opcode_cmp_int(&op1) && _xb_opcode_cmp_int(&op2)) { return xb_stack_push_bool(stack, - xb_opcode_get_val(&op2) <= xb_opcode_get_val(&op1), + _xb_opcode_get_val(&op2) <= _xb_opcode_get_val(&op1), error); } @@ -1802,17 +1933,17 @@ if (xb_opcode_cmp_str(&op1) && xb_opcode_cmp_str(&op2)) { return xb_stack_push_bool( stack, - g_strcmp0(xb_opcode_get_str(&op2), xb_opcode_get_str(&op1)) <= 0, + g_strcmp0(_xb_opcode_get_str(&op2), _xb_opcode_get_str(&op1)) <= 0, error); return TRUE; } /* INTE:TEXT */ - if (xb_opcode_cmp_val(&op1) && xb_opcode_cmp_str(&op2)) { + if (_xb_opcode_cmp_int(&op1) && xb_opcode_cmp_str(&op2)) { guint64 val = 0; - if (xb_opcode_get_str(&op2) == NULL) + if (_xb_opcode_get_str(&op2) == NULL) return xb_stack_push_bool(stack, FALSE, error); - if (!g_ascii_string_to_unsigned(xb_opcode_get_str(&op2), + if (!g_ascii_string_to_unsigned(_xb_opcode_get_str(&op2), 10, 0, G_MAXUINT32, @@ -1820,15 +1951,15 @@ error)) { return FALSE; } - return xb_stack_push_bool(stack, val <= xb_opcode_get_val(&op1), error); + return xb_stack_push_bool(stack, val <= _xb_opcode_get_val(&op1), error); } /* TEXT:INTE */ - if (xb_opcode_cmp_str(&op1) && xb_opcode_cmp_val(&op2)) { + if (xb_opcode_cmp_str(&op1) && _xb_opcode_cmp_int(&op2)) { guint64 val = 0; - if (xb_opcode_get_str(&op1) == NULL) + if (_xb_opcode_get_str(&op1) == NULL) return xb_stack_push_bool(stack, FALSE, error); - if (!g_ascii_string_to_unsigned(xb_opcode_get_str(&op1), + if (!g_ascii_string_to_unsigned(_xb_opcode_get_str(&op1), 10, 0, G_MAXUINT32, @@ -1836,16 +1967,18 @@ error)) { return FALSE; } - return xb_stack_push_bool(stack, val <= xb_opcode_get_val(&op2), error); + return xb_stack_push_bool(stack, val <= _xb_opcode_get_val(&op2), error); } /* should have been checked above */ - g_set_error(error, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "cannot compare %s and %s", - xb_opcode_kind_to_string(xb_opcode_get_kind(&op1)), - xb_opcode_kind_to_string(xb_opcode_get_kind(&op2))); + if (error != NULL) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "cannot compare %s and %s", + xb_opcode_kind_to_string(_xb_opcode_get_kind(&op1)), + xb_opcode_kind_to_string(_xb_opcode_get_kind(&op2))); + } return FALSE; } @@ -1867,7 +2000,7 @@ /* TEXT */ return xb_machine_stack_push_text_steal(self, stack, - g_utf8_strdown(xb_opcode_get_str(&op), -1), + g_utf8_strdown(_xb_opcode_get_str(&op), -1), error); } @@ -1889,7 +2022,7 @@ /* TEXT */ return xb_machine_stack_push_text_steal(self, stack, - g_utf8_strup(xb_opcode_get_str(&op), -1), + g_utf8_strup(_xb_opcode_get_str(&op), -1), error); } @@ -1903,25 +2036,27 @@ { g_auto(XbOpcode) op = XB_OPCODE_INIT(); - if (!xb_machine_check_one_arg(stack, xb_opcode_cmp_val_or_str, error)) + if (!xb_machine_check_one_arg(stack, _xb_opcode_cmp_val_or_str, error)) return FALSE; if (!xb_machine_stack_pop(self, stack, &op, error)) return FALSE; /* TEXT */ if (xb_opcode_cmp_str(&op)) - return xb_stack_push_bool(stack, xb_opcode_get_str(&op) == NULL, error); + return xb_stack_push_bool(stack, _xb_opcode_get_str(&op) == NULL, error); /* INTE */ - if (xb_opcode_cmp_val(&op)) - return xb_stack_push_bool(stack, xb_opcode_get_val(&op) == 0, error); + if (_xb_opcode_cmp_int(&op)) + return xb_stack_push_bool(stack, _xb_opcode_get_val(&op) == 0, error); /* should have been checked above */ - g_set_error(error, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "cannot invert %s", - xb_opcode_kind_to_string(xb_opcode_get_kind(&op))); + if (error != NULL) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "cannot invert %s", + xb_opcode_kind_to_string(_xb_opcode_get_kind(&op))); + } return FALSE; } @@ -1937,8 +2072,8 @@ g_auto(XbOpcode) op2 = XB_OPCODE_INIT(); if (!xb_machine_check_two_args(stack, - xb_opcode_cmp_val_or_str, - xb_opcode_cmp_val_or_str, + _xb_opcode_cmp_val_or_str, + _xb_opcode_cmp_val_or_str, error)) return FALSE; if (!xb_machine_stack_pop_two(self, stack, &op1, &op2, error)) @@ -1948,23 +2083,23 @@ if (xb_opcode_cmp_str(&op1) && xb_opcode_cmp_str(&op2)) { return xb_stack_push_bool( stack, - g_strcmp0(xb_opcode_get_str(&op2), xb_opcode_get_str(&op1)) >= 0, + g_strcmp0(_xb_opcode_get_str(&op2), _xb_opcode_get_str(&op1)) >= 0, error); } /* INTE:INTE */ - if (xb_opcode_cmp_val(&op1) && xb_opcode_cmp_val(&op2)) { + if (_xb_opcode_cmp_int(&op1) && _xb_opcode_cmp_int(&op2)) { return xb_stack_push_bool(stack, - xb_opcode_get_val(&op2) >= xb_opcode_get_val(&op1), + _xb_opcode_get_val(&op2) >= _xb_opcode_get_val(&op1), error); } /* INTE:TEXT */ - if (xb_opcode_cmp_val(&op1) && xb_opcode_cmp_str(&op2)) { + if (_xb_opcode_cmp_int(&op1) && xb_opcode_cmp_str(&op2)) { guint64 val = 0; - if (xb_opcode_get_str(&op2) == NULL) + if (_xb_opcode_get_str(&op2) == NULL) return xb_stack_push_bool(stack, FALSE, error); - if (!g_ascii_string_to_unsigned(xb_opcode_get_str(&op2), + if (!g_ascii_string_to_unsigned(_xb_opcode_get_str(&op2), 10, 0, G_MAXUINT32, @@ -1972,15 +2107,15 @@ error)) { return FALSE; } - return xb_stack_push_bool(stack, val >= xb_opcode_get_val(&op1), error); + return xb_stack_push_bool(stack, val >= _xb_opcode_get_val(&op1), error); } /* TEXT:INTE */ - if (xb_opcode_cmp_str(&op1) && xb_opcode_cmp_val(&op2)) { + if (xb_opcode_cmp_str(&op1) && _xb_opcode_cmp_int(&op2)) { guint64 val = 0; - if (xb_opcode_get_str(&op1) == NULL) + if (_xb_opcode_get_str(&op1) == NULL) return xb_stack_push_bool(stack, FALSE, error); - if (!g_ascii_string_to_unsigned(xb_opcode_get_str(&op1), + if (!g_ascii_string_to_unsigned(_xb_opcode_get_str(&op1), 10, 0, G_MAXUINT32, @@ -1988,16 +2123,18 @@ error)) { return FALSE; } - return xb_stack_push_bool(stack, val >= xb_opcode_get_val(&op2), error); + return xb_stack_push_bool(stack, val >= _xb_opcode_get_val(&op2), error); } /* should have been checked above */ - g_set_error(error, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "cannot compare %s and %s", - xb_opcode_kind_to_string(xb_opcode_get_kind(&op1)), - xb_opcode_kind_to_string(xb_opcode_get_kind(&op2))); + if (error != NULL) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "cannot compare %s and %s", + xb_opcode_kind_to_string(_xb_opcode_get_kind(&op1)), + xb_opcode_kind_to_string(_xb_opcode_get_kind(&op2))); + } return FALSE; } @@ -2020,7 +2157,7 @@ /* TEXT:TEXT */ return xb_stack_push_bool( stack, - xb_string_contains(xb_opcode_get_str(&op2), xb_opcode_get_str(&op1)), + xb_string_contains(_xb_opcode_get_str(&op2), _xb_opcode_get_str(&op1)), error); } @@ -2043,7 +2180,7 @@ /* TEXT:TEXT */ return xb_stack_push_bool( stack, - g_str_has_prefix(xb_opcode_get_str(&op2), xb_opcode_get_str(&op1)), + g_str_has_prefix(_xb_opcode_get_str(&op2), _xb_opcode_get_str(&op1)), error); } @@ -2066,7 +2203,7 @@ /* TEXT:TEXT */ return xb_stack_push_bool( stack, - g_str_has_suffix(xb_opcode_get_str(&op2), xb_opcode_get_str(&op1)), + g_str_has_suffix(_xb_opcode_get_str(&op2), _xb_opcode_get_str(&op1)), error); } @@ -2087,9 +2224,9 @@ return FALSE; /* TEXT */ - if (xb_opcode_get_str(&op) == NULL) + if (_xb_opcode_get_str(&op) == NULL) return xb_stack_push_bool(stack, FALSE, error); - if (!g_ascii_string_to_unsigned(xb_opcode_get_str(&op), 10, 0, G_MAXUINT32, &val, error)) { + if (!g_ascii_string_to_unsigned(_xb_opcode_get_str(&op), 10, 0, G_MAXUINT32, &val, error)) { return FALSE; } return xb_machine_stack_push_integer(self, stack, val, error); @@ -2111,9 +2248,9 @@ return FALSE; /* TEXT */ - if (xb_opcode_get_str(&op) == NULL) + if (_xb_opcode_get_str(&op) == NULL) return xb_stack_push_bool(stack, FALSE, error); - return xb_machine_stack_push_integer(self, stack, strlen(xb_opcode_get_str(&op)), error); + return xb_machine_stack_push_integer(self, stack, strlen(_xb_opcode_get_str(&op)), error); } static gboolean @@ -2127,16 +2264,83 @@ gchar *tmp; g_auto(XbOpcode) op = XB_OPCODE_INIT(); - if (!xb_machine_check_one_arg(stack, xb_opcode_cmp_val, error)) + if (!xb_machine_check_one_arg(stack, _xb_opcode_cmp_int, error)) return FALSE; if (!xb_machine_stack_pop(self, stack, &op, error)) return FALSE; /* INTE */ - tmp = g_strdup_printf("%" G_GUINT32_FORMAT, xb_opcode_get_val(&op)); + tmp = g_strdup_printf("%" G_GUINT32_FORMAT, _xb_opcode_get_val(&op)); return xb_machine_stack_push_text_steal(self, stack, tmp, error); } +static gboolean +xb_machine_func_in_cb(XbMachine *self, + XbStack *stack, + gboolean *result, + gpointer user_data, + gpointer exec_data, + GError **error) +{ + XbOpcode *op_needle; + const gchar *haystack[XB_MACHINE_STACK_LEVELS_MAX + 1] = {NULL}; + g_auto(XbOpcode) op = XB_OPCODE_INIT(); + guint8 level = G_MAXUINT8; + guint nr_args = 0; + + /* get the size of the haystack, ensuring we only have strings */ + for (guint i = xb_stack_get_size(stack) - 1; i > 0; i--) { + XbOpcode *op_tmp = xb_stack_peek(stack, i); + + /* this is a hack as we do not get the current @level */ + if (level != G_MAXUINT8) { + if (_xb_opcode_get_level(op_tmp) != level) + break; + } else { + level = _xb_opcode_get_level(op_tmp); + } + if (!xb_opcode_cmp_str(op_tmp)) { + if (error != NULL) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "%s type not supported", + xb_opcode_kind_to_string(_xb_opcode_get_kind(op_tmp))); + } + return FALSE; + } + nr_args++; + } + + /* ensure the needle is also a string */ + op_needle = xb_stack_peek(stack, xb_stack_get_size(stack) - (nr_args + 1)); + if (!xb_opcode_cmp_str(op_needle)) { + if (error != NULL) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "%s type not supported", + xb_opcode_kind_to_string(_xb_opcode_get_kind(op_needle))); + } + return FALSE; + } + + /* build the haystack */ + for (guint i = 0; i < nr_args; i++) { + g_auto(XbOpcode) op_tmp = XB_OPCODE_INIT(); + if (!xb_machine_stack_pop(self, stack, &op_tmp, error)) + return FALSE; + haystack[i] = _xb_opcode_get_str(&op_tmp); + } + + /* get the needle */ + if (!xb_machine_stack_pop(self, stack, &op, error)) + return FALSE; + + /* found */ + return xb_stack_push_bool(stack, g_strv_contains(haystack, _xb_opcode_get_str(&op)), error); +} + static void xb_machine_opcode_fixup_free(XbMachineOpcodeFixupItem *item) { @@ -2203,6 +2407,7 @@ xb_machine_add_method(self, "string", 1, xb_machine_func_string_cb, NULL, NULL); xb_machine_add_method(self, "number", 1, xb_machine_func_number_cb, NULL, NULL); xb_machine_add_method(self, "string-length", 1, xb_machine_func_strlen_cb, NULL, NULL); + xb_machine_add_method(self, "in", 0, xb_machine_func_in_cb, NULL, NULL); /* built-in operators */ xb_machine_add_operator(self, " and ", "and"); diff -Nru libxmlb-0.3.10/src/xb-machine.h libxmlb-0.3.22/src/xb-machine.h --- libxmlb-0.3.10/src/xb-machine.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-machine.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,13 +1,11 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include - #include "xb-opcode.h" #include "xb-stack.h" #include "xb-value-bindings.h" @@ -35,6 +33,7 @@ * @XB_MACHINE_DEBUG_FLAG_SHOW_STACK: Show the stack addition and removal * @XB_MACHINE_DEBUG_FLAG_SHOW_PARSING: Show the XPath predicate parsing * @XB_MACHINE_DEBUG_FLAG_SHOW_OPTIMIZER: Show the optimizer operation + * @XB_MACHINE_DEBUG_FLAG_SHOW_SLOW_PATH: Show the query slow paths * * The flags to control the amount of debugging is generated. **/ @@ -43,6 +42,7 @@ XB_MACHINE_DEBUG_FLAG_SHOW_STACK = 1 << 0, XB_MACHINE_DEBUG_FLAG_SHOW_PARSING = 1 << 1, XB_MACHINE_DEBUG_FLAG_SHOW_OPTIMIZER = 1 << 2, + XB_MACHINE_DEBUG_FLAG_SHOW_SLOW_PATH = 1 << 3, /*< private >*/ XB_MACHINE_DEBUG_FLAG_LAST } XbMachineDebugFlags; @@ -65,12 +65,14 @@ XbStack *opcodes, gpointer user_data, GError **error); +/* when next breaking API add @level here */ typedef gboolean (*XbMachineTextHandlerFunc)(XbMachine *self, XbStack *opcodes, const gchar *text, gboolean *handled, gpointer user_data, GError **error); +/* when next breaking API add @level here */ typedef gboolean (*XbMachineMethodFunc)(XbMachine *self, XbStack *stack, gboolean *result_unused, @@ -81,16 +83,17 @@ XbMachine * xb_machine_new(void); void -xb_machine_set_debug_flags(XbMachine *self, XbMachineDebugFlags flags); +xb_machine_set_debug_flags(XbMachine *self, XbMachineDebugFlags flags) G_GNUC_NON_NULL(1); +G_DEPRECATED_FOR(xb_machine_parse_full) XbStack * xb_machine_parse(XbMachine *self, const gchar *text, gssize text_len, GError **error) - G_DEPRECATED_FOR(xb_machine_parse_full); + G_GNUC_NON_NULL(1, 2); XbStack * xb_machine_parse_full(XbMachine *self, const gchar *text, gssize text_len, XbMachineParseFlags flags, - GError **error); + GError **error) G_GNUC_NON_NULL(1, 2); G_DEPRECATED_FOR(xb_machine_run_with_bindings) gboolean @@ -98,57 +101,62 @@ XbStack *opcodes, gboolean *result, gpointer exec_data, - GError **error); + GError **error) G_GNUC_NON_NULL(1, 2, 3); gboolean xb_machine_run_with_bindings(XbMachine *self, XbStack *opcodes, XbValueBindings *bindings, gboolean *result, gpointer exec_data, - GError **error); + GError **error) G_GNUC_NON_NULL(1, 2); void xb_machine_add_opcode_fixup(XbMachine *self, const gchar *opcodes_sig, XbMachineOpcodeFixupFunc fixup_cb, gpointer user_data, - GDestroyNotify user_data_free); + GDestroyNotify user_data_free) G_GNUC_NON_NULL(1, 2, 3); void xb_machine_add_text_handler(XbMachine *self, XbMachineTextHandlerFunc handler_cb, gpointer user_data, - GDestroyNotify user_data_free); + GDestroyNotify user_data_free) G_GNUC_NON_NULL(1, 2); void xb_machine_add_method(XbMachine *self, const gchar *name, guint n_opcodes, XbMachineMethodFunc method_cb, gpointer user_data, - GDestroyNotify user_data_free); + GDestroyNotify user_data_free) G_GNUC_NON_NULL(1, 2, 4); void -xb_machine_add_operator(XbMachine *self, const gchar *str, const gchar *name); +xb_machine_add_operator(XbMachine *self, const gchar *str, const gchar *name) + G_GNUC_NON_NULL(1, 2, 3); gboolean -xb_machine_opcode_func_init(XbMachine *self, XbOpcode *opcode, const gchar *func_name); +xb_machine_opcode_func_init(XbMachine *self, XbOpcode *opcode, const gchar *func_name) + G_GNUC_NON_NULL(1, 2, 3); gboolean -xb_machine_stack_pop(XbMachine *self, XbStack *stack, XbOpcode *opcode_out, GError **error); +xb_machine_stack_pop(XbMachine *self, XbStack *stack, XbOpcode *opcode_out, GError **error) + G_GNUC_NON_NULL(1, 2, 3); gboolean -xb_machine_stack_push(XbMachine *self, XbStack *stack, XbOpcode **opcode_out, GError **error); +xb_machine_stack_push(XbMachine *self, XbStack *stack, XbOpcode **opcode_out, GError **error) + G_GNUC_NON_NULL(1, 2, 3); gboolean -xb_machine_stack_push_text(XbMachine *self, XbStack *stack, const gchar *str, GError **error); +xb_machine_stack_push_text(XbMachine *self, XbStack *stack, const gchar *str, GError **error) + G_GNUC_NON_NULL(1, 2); gboolean -xb_machine_stack_push_text_static(XbMachine *self, - XbStack *stack, - const gchar *str, - GError **error); +xb_machine_stack_push_text_static(XbMachine *self, XbStack *stack, const gchar *str, GError **error) + G_GNUC_NON_NULL(1, 2); gboolean -xb_machine_stack_push_text_steal(XbMachine *self, XbStack *stack, gchar *str, GError **error); +xb_machine_stack_push_text_steal(XbMachine *self, XbStack *stack, gchar *str, GError **error) + G_GNUC_NON_NULL(1, 2, 3); gboolean -xb_machine_stack_push_integer(XbMachine *self, XbStack *stack, guint32 val, GError **error); +xb_machine_stack_push_integer(XbMachine *self, XbStack *stack, guint32 val, GError **error) + G_GNUC_NON_NULL(1, 2); void -xb_machine_set_stack_size(XbMachine *self, guint stack_size); +xb_machine_set_stack_size(XbMachine *self, guint stack_size) G_GNUC_NON_NULL(1); guint -xb_machine_get_stack_size(XbMachine *self); +xb_machine_get_stack_size(XbMachine *self) G_GNUC_NON_NULL(1); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-node-private.h libxmlb-0.3.22/src/xb-node-private.h --- libxmlb-0.3.10/src/xb-node-private.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-node-private.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,21 +1,19 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include - #include "xb-node.h" #include "xb-silo-private.h" G_BEGIN_DECLS XbNode * -xb_node_new(XbSilo *silo, XbSiloNode *sn); +xb_node_new(XbSilo *silo, XbSiloNode *sn) G_GNUC_NON_NULL(1); XbSiloNode * -xb_node_get_sn(XbNode *self); +xb_node_get_sn(XbNode *self) G_GNUC_NON_NULL(1); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-node-query.c libxmlb-0.3.22/src/xb-node-query.c --- libxmlb-0.3.10/src/xb-node-query.c 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-node-query.c 2025-03-12 09:35:38.000000000 +0000 @@ -1,18 +1,17 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #define G_LOG_DOMAIN "XbNode" -#include "xb-node-query.h" - #include "config.h" #include #include +#include "xb-node-query.h" #include "xb-node-silo.h" #include "xb-silo-export-private.h" #include "xb-silo-query-private.h" @@ -227,7 +226,6 @@ const gchar * xb_node_query_text(XbNode *self, const gchar *xpath, GError **error) { - const gchar *tmp; XbSilo *silo; g_autoptr(GPtrArray) results = NULL; XbSiloNode *sn; @@ -241,13 +239,11 @@ if (results == NULL) return NULL; sn = g_ptr_array_index(results, 0); - - tmp = xb_silo_get_node_text(silo, sn); - if (tmp == NULL) { + if (xb_silo_node_get_text_idx(sn) == XB_SILO_UNSET) { g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "no text data"); return NULL; } - return tmp; + return xb_silo_from_strtab(silo, xb_silo_node_get_text_idx(sn), error); } /** @@ -291,7 +287,7 @@ g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "no text data"); return NULL; } - return xb_silo_from_strtab(silo, a->attr_value); + return xb_silo_from_strtab(silo, a->attr_value, error); } /** diff -Nru libxmlb-0.3.10/src/xb-node-query.h libxmlb-0.3.22/src/xb-node-query.h --- libxmlb-0.3.10/src/xb-node-query.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-node-query.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once @@ -15,33 +15,36 @@ G_BEGIN_DECLS GPtrArray * -xb_node_query(XbNode *self, const gchar *xpath, guint limit, GError **error); +xb_node_query(XbNode *self, const gchar *xpath, guint limit, GError **error) G_GNUC_NON_NULL(1, 2); GPtrArray * -xb_node_query_full(XbNode *self, XbQuery *query, GError **error); +xb_node_query_full(XbNode *self, XbQuery *query, GError **error) G_GNUC_NON_NULL(1, 2); GPtrArray * -xb_node_query_with_context(XbNode *self, XbQuery *query, XbQueryContext *context, GError **error); +xb_node_query_with_context(XbNode *self, XbQuery *query, XbQueryContext *context, GError **error) + G_GNUC_NON_NULL(1, 2, 3); XbNode * -xb_node_query_first(XbNode *self, const gchar *xpath, GError **error); +xb_node_query_first(XbNode *self, const gchar *xpath, GError **error) G_GNUC_NON_NULL(1, 2); XbNode * -xb_node_query_first_full(XbNode *self, XbQuery *query, GError **error); +xb_node_query_first_full(XbNode *self, XbQuery *query, GError **error) G_GNUC_NON_NULL(1, 2); XbNode * xb_node_query_first_with_context(XbNode *self, XbQuery *query, XbQueryContext *context, - GError **error); + GError **error) G_GNUC_NON_NULL(1, 2); const gchar * -xb_node_query_text(XbNode *self, const gchar *xpath, GError **error); +xb_node_query_text(XbNode *self, const gchar *xpath, GError **error) G_GNUC_NON_NULL(1, 2); guint64 -xb_node_query_text_as_uint(XbNode *self, const gchar *xpath, GError **error); +xb_node_query_text_as_uint(XbNode *self, const gchar *xpath, GError **error) G_GNUC_NON_NULL(1, 2); const gchar * -xb_node_query_attr(XbNode *self, const gchar *xpath, const gchar *name, GError **error); +xb_node_query_attr(XbNode *self, const gchar *xpath, const gchar *name, GError **error) + G_GNUC_NON_NULL(1, 2, 3); guint64 -xb_node_query_attr_as_uint(XbNode *self, const gchar *xpath, const gchar *name, GError **error); +xb_node_query_attr_as_uint(XbNode *self, const gchar *xpath, const gchar *name, GError **error) + G_GNUC_NON_NULL(1, 2, 3); gchar * -xb_node_query_export(XbNode *self, const gchar *xpath, GError **error); +xb_node_query_export(XbNode *self, const gchar *xpath, GError **error) G_GNUC_NON_NULL(1); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-node-silo.h libxmlb-0.3.22/src/xb-node-silo.h --- libxmlb-0.3.10/src/xb-node-silo.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-node-silo.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,19 +1,17 @@ /* - * Copyright (C) 2020 Richard Hughes + * Copyright 2020 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include - #include "xb-node.h" #include "xb-silo.h" G_BEGIN_DECLS XbSilo * -xb_node_get_silo(XbNode *self); +xb_node_get_silo(XbNode *self) G_GNUC_NON_NULL(1); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-node.c libxmlb-0.3.22/src/xb-node.c --- libxmlb-0.3.10/src/xb-node.c 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-node.c 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #define G_LOG_DOMAIN "XbNode" @@ -176,7 +176,7 @@ g_return_val_if_fail(XB_IS_NODE(self), NULL); - sn = xb_silo_get_root_node(priv->silo); + sn = xb_silo_get_root_node(priv->silo, NULL); if (sn == NULL) return NULL; return xb_silo_create_node(priv->silo, sn, FALSE); @@ -202,7 +202,7 @@ if (priv->sn == NULL) return NULL; - sn = xb_silo_get_parent_node(priv->silo, priv->sn); + sn = xb_silo_get_parent_node(priv->silo, priv->sn, NULL); if (sn == NULL) return NULL; return xb_silo_create_node(priv->silo, sn, FALSE); @@ -228,7 +228,7 @@ if (priv->sn == NULL) return NULL; - sn = xb_silo_get_next_node(priv->silo, priv->sn); + sn = xb_silo_get_next_node(priv->silo, priv->sn, NULL); if (sn == NULL) return NULL; return xb_silo_create_node(priv->silo, sn, FALSE); @@ -254,7 +254,7 @@ if (priv->sn == NULL) return NULL; - sn = xb_silo_get_child_node(priv->silo, priv->sn); + sn = xb_silo_get_child_node(priv->silo, priv->sn, NULL); if (sn == NULL) return NULL; return xb_silo_create_node(priv->silo, sn, FALSE); @@ -307,7 +307,7 @@ g_return_if_fail(XB_IS_NODE(self)); ri->node = self; - ri->position = priv->sn != NULL ? xb_silo_get_child_node(priv->silo, priv->sn) : NULL; + ri->position = priv->sn != NULL ? xb_silo_get_child_node(priv->silo, priv->sn, NULL) : NULL; ri->first_iter = TRUE; } @@ -351,7 +351,7 @@ } *child = xb_silo_create_node(priv->silo, ri->position, FALSE); - ri->position = xb_silo_get_next_node(priv->silo, ri->position); + ri->position = xb_silo_get_next_node(priv->silo, ri->position, NULL); return TRUE; } @@ -408,7 +408,7 @@ } *child = xb_silo_create_node(priv->silo, ri->position, FALSE); - ri->position = xb_silo_get_next_node(priv->silo, ri->position); + ri->position = xb_silo_get_next_node(priv->silo, ri->position, NULL); return TRUE; } @@ -430,7 +430,9 @@ g_return_val_if_fail(XB_IS_NODE(self), NULL); if (priv->sn == NULL) return NULL; - return xb_silo_get_node_text(priv->silo, priv->sn); + if (xb_silo_node_get_text_idx(priv->sn) == XB_SILO_UNSET) + return NULL; + return xb_silo_from_strtab(priv->silo, xb_silo_node_get_text_idx(priv->sn), NULL); } /** @@ -446,14 +448,9 @@ guint64 xb_node_get_text_as_uint(XbNode *self) { - XbNodePrivate *priv = GET_PRIVATE(self); const gchar *tmp; - g_return_val_if_fail(XB_IS_NODE(self), G_MAXUINT64); - - if (priv->sn == NULL) - return G_MAXUINT64; - tmp = xb_silo_get_node_text(priv->silo, priv->sn); + tmp = xb_node_get_text(self); if (tmp == NULL) return G_MAXUINT64; if (g_str_has_prefix(tmp, "0x")) @@ -478,7 +475,9 @@ g_return_val_if_fail(XB_IS_NODE(self), NULL); if (priv->sn == NULL) return NULL; - return xb_silo_get_node_tail(priv->silo, priv->sn); + if (xb_silo_node_get_tail_idx(priv->sn) == XB_SILO_UNSET) + return NULL; + return xb_silo_from_strtab(priv->silo, xb_silo_node_get_tail_idx(priv->sn), NULL); } /** @@ -498,7 +497,7 @@ g_return_val_if_fail(XB_IS_NODE(self), NULL); if (priv->sn == NULL) return NULL; - return xb_silo_get_node_element(priv->silo, priv->sn); + return xb_silo_get_node_element(priv->silo, priv->sn, NULL); } /** @@ -526,7 +525,7 @@ a = xb_silo_get_node_attr_by_str(priv->silo, priv->sn, name); if (a == NULL) return NULL; - return xb_silo_from_strtab(priv->silo, a->attr_value); + return xb_silo_from_strtab(priv->silo, a->attr_value, NULL); } /** @@ -625,9 +624,9 @@ ri->position--; a = xb_silo_node_get_attr(priv->sn, ri->position); if (name != NULL) - *name = xb_silo_from_strtab(priv->silo, a->attr_name); + *name = xb_silo_from_strtab(priv->silo, a->attr_name, NULL); if (value != NULL) - *value = xb_silo_from_strtab(priv->silo, a->attr_value); + *value = xb_silo_from_strtab(priv->silo, a->attr_value, NULL); return TRUE; } diff -Nru libxmlb-0.3.10/src/xb-node.h libxmlb-0.3.22/src/xb-node.h --- libxmlb-0.3.10/src/xb-node.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-node.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,12 +1,12 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include +#include "xb-compile.h" G_BEGIN_DECLS @@ -75,50 +75,51 @@ xb_node_transmogrify(XbNode *self, XbNodeTransmogrifyFunc func_text, XbNodeTransmogrifyFunc func_tail, - gpointer user_data); + gpointer user_data) G_GNUC_NON_NULL(1); gchar * -xb_node_export(XbNode *self, XbNodeExportFlags flags, GError **error); +xb_node_export(XbNode *self, XbNodeExportFlags flags, GError **error) G_GNUC_NON_NULL(1); GBytes * -xb_node_get_data(XbNode *self, const gchar *key); +xb_node_get_data(XbNode *self, const gchar *key) G_GNUC_NON_NULL(1, 2); void -xb_node_set_data(XbNode *self, const gchar *key, GBytes *data); +xb_node_set_data(XbNode *self, const gchar *key, GBytes *data) G_GNUC_NON_NULL(1, 2); XbNode * -xb_node_get_root(XbNode *self); +xb_node_get_root(XbNode *self) G_GNUC_NON_NULL(1); XbNode * -xb_node_get_parent(XbNode *self); +xb_node_get_parent(XbNode *self) G_GNUC_NON_NULL(1); XbNode * -xb_node_get_next(XbNode *self); +xb_node_get_next(XbNode *self) G_GNUC_NON_NULL(1); XbNode * -xb_node_get_child(XbNode *self); +xb_node_get_child(XbNode *self) G_GNUC_NON_NULL(1); GPtrArray * -xb_node_get_children(XbNode *self); +xb_node_get_children(XbNode *self) G_GNUC_NON_NULL(1); const gchar * -xb_node_get_element(XbNode *self); +xb_node_get_element(XbNode *self) G_GNUC_NON_NULL(1); const gchar * -xb_node_get_text(XbNode *self); +xb_node_get_text(XbNode *self) G_GNUC_NON_NULL(1); guint64 -xb_node_get_text_as_uint(XbNode *self); +xb_node_get_text_as_uint(XbNode *self) G_GNUC_NON_NULL(1); const gchar * -xb_node_get_tail(XbNode *self); +xb_node_get_tail(XbNode *self) G_GNUC_NON_NULL(1); const gchar * -xb_node_get_attr(XbNode *self, const gchar *name); +xb_node_get_attr(XbNode *self, const gchar *name) G_GNUC_NON_NULL(1, 2); guint64 -xb_node_get_attr_as_uint(XbNode *self, const gchar *name); +xb_node_get_attr_as_uint(XbNode *self, const gchar *name) G_GNUC_NON_NULL(1, 2); guint -xb_node_get_depth(XbNode *self); +xb_node_get_depth(XbNode *self) G_GNUC_NON_NULL(1); void -xb_node_attr_iter_init(XbNodeAttrIter *iter, XbNode *self); +xb_node_attr_iter_init(XbNodeAttrIter *iter, XbNode *self) G_GNUC_NON_NULL(1, 2); gboolean -xb_node_attr_iter_next(XbNodeAttrIter *iter, const gchar **name, const gchar **value); +xb_node_attr_iter_next(XbNodeAttrIter *iter, const gchar **name, const gchar **value) + G_GNUC_NON_NULL(1); void -xb_node_child_iter_init(XbNodeChildIter *iter, XbNode *self); +xb_node_child_iter_init(XbNodeChildIter *iter, XbNode *self) G_GNUC_NON_NULL(1, 2); gboolean -xb_node_child_iter_next(XbNodeChildIter *iter, XbNode **child); +xb_node_child_iter_next(XbNodeChildIter *iter, XbNode **child) G_GNUC_NON_NULL(1, 2); gboolean -xb_node_child_iter_loop(XbNodeChildIter *iter, XbNode **child); +xb_node_child_iter_loop(XbNodeChildIter *iter, XbNode **child) G_GNUC_NON_NULL(1, 2); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-opcode-private.h libxmlb-0.3.22/src/xb-opcode-private.h --- libxmlb-0.3.10/src/xb-opcode-private.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-opcode-private.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once @@ -23,12 +23,10 @@ guint8 tokens_len; const gchar *tokens[XB_OPCODE_TOKEN_MAX + 1]; GDestroyNotify destroy_func; + guint8 level; }; -#define XB_OPCODE_INIT() \ - { \ - 0, 0, NULL, 0, {NULL}, NULL \ - } +#define XB_OPCODE_INIT() {0, 0, NULL, 0, {NULL}, NULL, 0} /** * xb_opcode_steal: @@ -49,39 +47,88 @@ } void -xb_opcode_init(XbOpcode *opcode, +xb_opcode_init(XbOpcode *self, XbOpcodeKind kind, const gchar *str, guint32 val, - GDestroyNotify destroy_func); + GDestroyNotify destroy_func) G_GNUC_NON_NULL(1); void -xb_opcode_clear(XbOpcode *opcode); +xb_opcode_clear(XbOpcode *self) G_GNUC_NON_NULL(1); void -xb_opcode_bind_init(XbOpcode *opcode); +xb_opcode_bind_init(XbOpcode *self) G_GNUC_NON_NULL(1); gboolean -xb_opcode_is_binding(XbOpcode *self); +xb_opcode_is_binding(XbOpcode *self) G_GNUC_NON_NULL(1); G_DEPRECATED_FOR(xb_value_bindings_bind_str) void -xb_opcode_bind_str(XbOpcode *self, gchar *str, GDestroyNotify destroy_func); +xb_opcode_bind_str(XbOpcode *self, gchar *str, GDestroyNotify destroy_func) G_GNUC_NON_NULL(1); G_DEPRECATED_FOR(xb_value_bindings_bind_val) void -xb_opcode_bind_val(XbOpcode *self, guint32 val); +xb_opcode_bind_val(XbOpcode *self, guint32 val) G_GNUC_NON_NULL(1); void -xb_opcode_set_kind(XbOpcode *self, XbOpcodeKind kind); +xb_opcode_set_kind(XbOpcode *self, XbOpcodeKind kind) G_GNUC_NON_NULL(1); void -xb_opcode_set_val(XbOpcode *self, guint32 val); +xb_opcode_set_val(XbOpcode *self, guint32 val) G_GNUC_NON_NULL(1); gboolean -xb_opcode_append_token(XbOpcode *self, const gchar *val); +xb_opcode_append_token(XbOpcode *self, const gchar *val) G_GNUC_NON_NULL(1, 2); const gchar ** -xb_opcode_get_tokens(XbOpcode *self); +xb_opcode_get_tokens(XbOpcode *self) G_GNUC_NON_NULL(1); gchar * -xb_opcode_get_sig(XbOpcode *self); +xb_opcode_get_sig(XbOpcode *self) G_GNUC_NON_NULL(1); void -xb_opcode_bool_init(XbOpcode *opcode, gboolean val); +xb_opcode_bool_init(XbOpcode *self, gboolean val) G_GNUC_NON_NULL(1); gboolean -xb_opcode_has_flag(XbOpcode *self, XbOpcodeFlags flag); +xb_opcode_has_flag(XbOpcode *self, XbOpcodeFlags flag) G_GNUC_NON_NULL(1); void -xb_opcode_add_flag(XbOpcode *self, XbOpcodeFlags flag); +xb_opcode_add_flag(XbOpcode *self, XbOpcodeFlags flag) G_GNUC_NON_NULL(1); + +void +xb_opcode_set_level(XbOpcode *self, guint8 level) G_GNUC_NON_NULL(1); +guint8 +xb_opcode_get_level(XbOpcode *self) G_GNUC_NON_NULL(1); + +static inline gboolean +_xb_opcode_has_flag(const XbOpcode *self, XbOpcodeFlags flag) +{ + return (self->kind & flag) > 0; +} + +static inline XbOpcodeKind +_xb_opcode_get_kind(const XbOpcode *self) +{ + return self->kind & ~XB_OPCODE_FLAG_TOKENIZED; +} + +static inline const gchar * +_xb_opcode_get_str(const XbOpcode *self) +{ + return self->ptr; +} + +static inline guint8 +_xb_opcode_get_level(const XbOpcode *self) +{ + return self->level; +} + +static inline guint32 +_xb_opcode_get_val(const XbOpcode *self) +{ + return self->val; +} + +static inline gboolean +_xb_opcode_cmp_int(XbOpcode *self) +{ + return self->kind == XB_OPCODE_KIND_INTEGER || self->kind == XB_OPCODE_KIND_BOOLEAN || + self->kind == XB_OPCODE_KIND_BOUND_INTEGER; +} + +static inline gboolean +_xb_opcode_cmp_itx(XbOpcode *self) +{ + return self->kind == XB_OPCODE_KIND_INDEXED_TEXT || + self->kind == XB_OPCODE_KIND_BOUND_INDEXED_TEXT; +} G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(XbOpcode, xb_opcode_clear) diff -Nru libxmlb-0.3.10/src/xb-opcode.c libxmlb-0.3.22/src/xb-opcode.c --- libxmlb-0.3.10/src/xb-opcode.c 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-opcode.c 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #define G_LOG_DOMAIN "XbMachine" @@ -32,6 +32,8 @@ return "BIND"; if (kind == XB_OPCODE_KIND_BOUND_TEXT) return "?TXT"; + if (kind == XB_OPCODE_KIND_BOUND_INDEXED_TEXT) + return "?ITX"; if (kind == XB_OPCODE_KIND_BOUND_INTEGER) return "?INT"; if (kind == XB_OPCODE_KIND_INDEXED_TEXT) @@ -70,6 +72,8 @@ return XB_OPCODE_KIND_BOUND_INTEGER; if (g_strcmp0(str, "?TXT") == 0) return XB_OPCODE_KIND_BOUND_TEXT; + if (g_strcmp0(str, "?ITX") == 0) + return XB_OPCODE_KIND_BOUND_INDEXED_TEXT; if (g_strcmp0(str, "?INT") == 0) return XB_OPCODE_KIND_BOUND_INTEGER; if (g_strcmp0(str, "TEXI") == 0) @@ -98,28 +102,40 @@ return self->ptr; } +void +xb_opcode_set_level(XbOpcode *self, guint8 level) +{ + self->level = level; +} + static gchar * xb_opcode_to_string_internal(XbOpcode *self) { - /* special cases */ + g_autoptr(GString) str = g_string_new(NULL); + + /* special cases then bitwise fallbacks */ if (self->kind == XB_OPCODE_KIND_INDEXED_TEXT) - return g_strdup_printf("$'%s'", xb_opcode_get_str_for_display(self)); - if (self->kind == XB_OPCODE_KIND_INTEGER) - return g_strdup_printf("%u", xb_opcode_get_val(self)); - if (self->kind == XB_OPCODE_KIND_BOUND_TEXT) - return g_strdup_printf("?'%s'", xb_opcode_get_str_for_display(self)); - if (self->kind == XB_OPCODE_KIND_BOUND_INTEGER) - return g_strdup_printf("?%u", xb_opcode_get_val(self)); - if (self->kind == XB_OPCODE_KIND_BOOLEAN) + g_string_append_printf(str, "$'%s'", xb_opcode_get_str_for_display(self)); + else if (self->kind == XB_OPCODE_KIND_INTEGER) + g_string_append_printf(str, "%u", xb_opcode_get_val(self)); + else if (self->kind == XB_OPCODE_KIND_BOUND_TEXT || + self->kind == XB_OPCODE_KIND_BOUND_INDEXED_TEXT) + g_string_append_printf(str, "?'%s'", xb_opcode_get_str_for_display(self)); + else if (self->kind == XB_OPCODE_KIND_BOUND_INTEGER) + g_string_append_printf(str, "?%u", xb_opcode_get_val(self)); + else if (self->kind == XB_OPCODE_KIND_BOOLEAN) return g_strdup(xb_opcode_get_val(self) ? "True" : "False"); - - /* bitwise fallbacks */ - if (self->kind & XB_OPCODE_FLAG_FUNCTION) - return g_strdup_printf("%s()", xb_opcode_get_str_for_display(self)); - if (self->kind & XB_OPCODE_FLAG_TEXT) - return g_strdup_printf("'%s'", xb_opcode_get_str_for_display(self)); - g_critical("no to_string for kind 0x%x", self->kind); - return NULL; + else if (self->kind & XB_OPCODE_FLAG_FUNCTION) + g_string_append_printf(str, "%s()", xb_opcode_get_str_for_display(self)); + else if (self->kind & XB_OPCODE_FLAG_TEXT) + g_string_append_printf(str, "'%s'", xb_opcode_get_str_for_display(self)); + else + g_string_append_printf(str, "kind:0x%x", self->kind); + + /* add level */ + if (self->level > 0) + g_string_append_printf(str, "^%u", self->level); + return g_string_free(g_steal_pointer(&str), FALSE); } /** @@ -204,11 +220,10 @@ * * Since: 0.1.1 **/ -inline gboolean +gboolean xb_opcode_cmp_val(XbOpcode *self) { - return self->kind == XB_OPCODE_KIND_INTEGER || self->kind == XB_OPCODE_KIND_BOOLEAN || - self->kind == XB_OPCODE_KIND_BOUND_INTEGER; + return _xb_opcode_cmp_int(self) || _xb_opcode_cmp_itx(self); } /** @@ -221,7 +236,7 @@ * * Since: 0.1.1 **/ -inline gboolean +gboolean xb_opcode_cmp_str(XbOpcode *self) { return xb_opcode_has_flag(self, XB_OPCODE_FLAG_TEXT); @@ -264,7 +279,7 @@ const gchar * xb_opcode_get_str(XbOpcode *self) { - return self->ptr; + return _xb_opcode_get_str(self); } /** @@ -302,7 +317,7 @@ /** * xb_opcode_text_init: - * @opcode: a stack allocated #XbOpcode to initialise + * @self: a stack allocated #XbOpcode to initialise * @str: a string * * Initialises a stack allocated #XbOpcode to contain a text literal. @@ -312,14 +327,14 @@ * Since: 0.2.0 **/ void -xb_opcode_text_init(XbOpcode *opcode, const gchar *str) +xb_opcode_text_init(XbOpcode *self, const gchar *str) { - xb_opcode_init(opcode, XB_OPCODE_KIND_TEXT, g_strdup(str), 0, g_free); + xb_opcode_init(self, XB_OPCODE_KIND_TEXT, g_strdup(str), 0, g_free); } /** * xb_opcode_init: - * @opcode: allocated opcode to fill + * @self: allocated opcode to fill * @kind: a #XbOpcodeKind, e.g. %XB_OPCODE_KIND_INTEGER * @str: a string * @val: a integer value @@ -330,22 +345,24 @@ * Since: 0.2.0 **/ void -xb_opcode_init(XbOpcode *opcode, +xb_opcode_init(XbOpcode *self, XbOpcodeKind kind, const gchar *str, guint32 val, GDestroyNotify destroy_func) { - opcode->kind = kind; - opcode->ptr = (gpointer)str; - opcode->val = val; - opcode->tokens_len = 0; - opcode->destroy_func = destroy_func; + self->level = G_MAXUINT8; + self->kind = kind; + self->ptr = (gpointer)str; + self->val = val; + self->tokens_len = 0; + self->destroy_func = destroy_func; + memset(self->tokens, 0, sizeof(self->tokens)); } /** * xb_opcode_text_init_static: - * @opcode: a stack allocated #XbOpcode to initialise + * @self: a stack allocated #XbOpcode to initialise * @str: a string * * Initialises a stack allocated #XbOpcode to contain a text literal, where @@ -354,14 +371,14 @@ * Since: 0.2.0 **/ void -xb_opcode_text_init_static(XbOpcode *opcode, const gchar *str) +xb_opcode_text_init_static(XbOpcode *self, const gchar *str) { - xb_opcode_init(opcode, XB_OPCODE_KIND_TEXT, str, 0, NULL); + xb_opcode_init(self, XB_OPCODE_KIND_TEXT, str, 0, NULL); } /** * xb_opcode_text_init_steal: - * @opcode: a stack allocated #XbOpcode to initialise + * @self: a stack allocated #XbOpcode to initialise * @str: a string * * Initialises a stack allocated #XbOpcode to contain a text literal, stealing @@ -370,14 +387,14 @@ * Since: 0.2.0 **/ void -xb_opcode_text_init_steal(XbOpcode *opcode, gchar *str) +xb_opcode_text_init_steal(XbOpcode *self, gchar *str) { - xb_opcode_init(opcode, XB_OPCODE_KIND_TEXT, g_steal_pointer(&str), 0, g_free); + xb_opcode_init(self, XB_OPCODE_KIND_TEXT, g_steal_pointer(&str), 0, g_free); } /** * xb_opcode_func_init: - * @opcode: a stack allocated #XbOpcode to initialise + * @self: a stack allocated #XbOpcode to initialise * @func: a function index * * Initialises a stack allocated #XbOpcode to contain a specific function. @@ -387,14 +404,14 @@ * Since: 0.2.0 **/ void -xb_opcode_func_init(XbOpcode *opcode, guint32 func) +xb_opcode_func_init(XbOpcode *self, guint32 func) { - xb_opcode_init(opcode, XB_OPCODE_KIND_FUNCTION, NULL, func, NULL); + xb_opcode_init(self, XB_OPCODE_KIND_FUNCTION, NULL, func, NULL); } /** * xb_opcode_bind_init: - * @opcode: a stack allocated #XbOpcode to initialise + * @self: a stack allocated #XbOpcode to initialise * * Initialises a stack allocated #XbOpcode to contain a bind variable. A value * needs to be assigned to this opcode at runtime using @@ -403,9 +420,9 @@ * Since: 0.2.0 **/ void -xb_opcode_bind_init(XbOpcode *opcode) +xb_opcode_bind_init(XbOpcode *self) { - xb_opcode_init(opcode, XB_OPCODE_KIND_BOUND_INTEGER, NULL, 0, NULL); + xb_opcode_init(self, XB_OPCODE_KIND_BOUND_INTEGER, NULL, 0, NULL); } /* private */ @@ -462,7 +479,7 @@ /** * xb_opcode_integer_init: - * @opcode: a stack allocated #XbOpcode to initialise + * @self: a stack allocated #XbOpcode to initialise * @val: a integer value * * Initialises a stack allocated #XbOpcode to contain an integer literal. @@ -470,14 +487,14 @@ * Since: 0.2.0 **/ void -xb_opcode_integer_init(XbOpcode *opcode, guint32 val) +xb_opcode_integer_init(XbOpcode *self, guint32 val) { - xb_opcode_init(opcode, XB_OPCODE_KIND_INTEGER, NULL, val, NULL); + xb_opcode_init(self, XB_OPCODE_KIND_INTEGER, NULL, val, NULL); } /* private */ void -xb_opcode_bool_init(XbOpcode *opcode, gboolean val) +xb_opcode_bool_init(XbOpcode *self, gboolean val) { - xb_opcode_init(opcode, XB_OPCODE_KIND_BOOLEAN, NULL, !!val, NULL); + xb_opcode_init(self, XB_OPCODE_KIND_BOOLEAN, NULL, !!val, NULL); } diff -Nru libxmlb-0.3.10/src/xb-opcode.h libxmlb-0.3.22/src/xb-opcode.h --- libxmlb-0.3.10/src/xb-opcode.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-opcode.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,12 +1,12 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include +#include "xb-compile.h" G_BEGIN_DECLS @@ -49,6 +49,7 @@ * @XB_OPCODE_KIND_BOUND_INTEGER: A bound integer value * @XB_OPCODE_KIND_BOUND_TEXT: A bound text value * @XB_OPCODE_KIND_INDEXED_TEXT: An indexed text value + * @XB_OPCODE_KIND_BOUND_INDEXED_TEXT: An bound indexed text value **/ typedef enum { XB_OPCODE_KIND_UNKNOWN = 0x0, /* Since: 0.1.1 */ @@ -64,6 +65,8 @@ XB_OPCODE_FLAG_INTEGER | XB_OPCODE_FLAG_TEXT, /* Since: 0.1.4 */ XB_OPCODE_KIND_BOOLEAN = XB_OPCODE_FLAG_INTEGER | XB_OPCODE_FLAG_BOOLEAN, /* Since: 0.1.11 */ + XB_OPCODE_KIND_BOUND_INDEXED_TEXT = + XB_OPCODE_FLAG_BOUND | XB_OPCODE_FLAG_INTEGER | XB_OPCODE_FLAG_TEXT, /* Since: 0.3.12 */ /*< private >*/ XB_OPCODE_KIND_LAST } XbOpcodeKind; @@ -71,33 +74,33 @@ typedef struct _XbOpcode XbOpcode; gboolean -xb_opcode_cmp_val(XbOpcode *self); +xb_opcode_cmp_val(XbOpcode *self) G_GNUC_NON_NULL(1); gboolean -xb_opcode_cmp_str(XbOpcode *self); +xb_opcode_cmp_str(XbOpcode *self) G_GNUC_NON_NULL(1); gchar * -xb_opcode_to_string(XbOpcode *self); +xb_opcode_to_string(XbOpcode *self) G_GNUC_NON_NULL(1); const gchar * xb_opcode_kind_to_string(XbOpcodeKind kind); XbOpcodeKind xb_opcode_kind_from_string(const gchar *str); XbOpcodeKind -xb_opcode_get_kind(XbOpcode *self); +xb_opcode_get_kind(XbOpcode *self) G_GNUC_NON_NULL(1); const gchar * -xb_opcode_get_str(XbOpcode *self); +xb_opcode_get_str(XbOpcode *self) G_GNUC_NON_NULL(1); guint32 -xb_opcode_get_val(XbOpcode *self); +xb_opcode_get_val(XbOpcode *self) G_GNUC_NON_NULL(1); void -xb_opcode_func_init(XbOpcode *opcode, guint32 func); +xb_opcode_func_init(XbOpcode *self, guint32 func) G_GNUC_NON_NULL(1); void -xb_opcode_integer_init(XbOpcode *opcode, guint32 val); +xb_opcode_integer_init(XbOpcode *self, guint32 val) G_GNUC_NON_NULL(1); void -xb_opcode_text_init(XbOpcode *opcode, const gchar *str); +xb_opcode_text_init(XbOpcode *self, const gchar *str) G_GNUC_NON_NULL(1); void -xb_opcode_text_init_static(XbOpcode *opcode, const gchar *str); +xb_opcode_text_init_static(XbOpcode *self, const gchar *str) G_GNUC_NON_NULL(1); void -xb_opcode_text_init_steal(XbOpcode *opcode, gchar *str); +xb_opcode_text_init_steal(XbOpcode *self, gchar *str) G_GNUC_NON_NULL(1); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-query-context.c libxmlb-0.3.22/src/xb-query-context.c --- libxmlb-0.3.10/src/xb-query-context.c 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-query-context.c 2025-03-12 09:35:38.000000000 +0000 @@ -1,21 +1,20 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * vi:set noexpandtab tabstop=8 shiftwidth=8: * - * Copyright (C) 2020 Endless OS Foundation LLC + * Copyright 2020 Endless OS Foundation LLC * * Author: Philip Withnall * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #define G_LOG_DOMAIN "XbQueryContext" -#include "xb-query-context.h" - #include "config.h" #include +#include "xb-query-context.h" #include "xb-query.h" #include "xb-value-bindings.h" diff -Nru libxmlb-0.3.10/src/xb-query-context.h libxmlb-0.3.22/src/xb-query-context.h --- libxmlb-0.3.10/src/xb-query-context.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-query-context.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,11 +1,11 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * vi:set noexpandtab tabstop=8 shiftwidth=8: * - * Copyright (C) 2020 Endless OS Foundation LLC + * Copyright 2020 Endless OS Foundation LLC * * Author: Philip Withnall * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once @@ -53,34 +53,37 @@ */ #define XB_QUERY_CONTEXT_INIT() \ { \ - 0, 0, XB_VALUE_BINDINGS_INIT(), { NULL, NULL, NULL, NULL, NULL } \ + 0, 0, XB_VALUE_BINDINGS_INIT(), \ + { \ + NULL, NULL, NULL, NULL, NULL \ + } \ } void -xb_query_context_init(XbQueryContext *self); +xb_query_context_init(XbQueryContext *self) G_GNUC_NON_NULL(1); void -xb_query_context_clear(XbQueryContext *self); +xb_query_context_clear(XbQueryContext *self) G_GNUC_NON_NULL(1); G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(XbQueryContext, xb_query_context_clear) XbQueryContext * -xb_query_context_copy(XbQueryContext *self); +xb_query_context_copy(XbQueryContext *self) G_GNUC_NON_NULL(1); void -xb_query_context_free(XbQueryContext *self); +xb_query_context_free(XbQueryContext *self) G_GNUC_NON_NULL(1); G_DEFINE_AUTOPTR_CLEANUP_FUNC(XbQueryContext, xb_query_context_free) XbValueBindings * -xb_query_context_get_bindings(XbQueryContext *self); +xb_query_context_get_bindings(XbQueryContext *self) G_GNUC_NON_NULL(1); guint -xb_query_context_get_limit(XbQueryContext *self); +xb_query_context_get_limit(XbQueryContext *self) G_GNUC_NON_NULL(1); void -xb_query_context_set_limit(XbQueryContext *self, guint limit); +xb_query_context_set_limit(XbQueryContext *self, guint limit) G_GNUC_NON_NULL(1); XbQueryFlags -xb_query_context_get_flags(XbQueryContext *self); +xb_query_context_get_flags(XbQueryContext *self) G_GNUC_NON_NULL(1); void -xb_query_context_set_flags(XbQueryContext *self, XbQueryFlags flags); +xb_query_context_set_flags(XbQueryContext *self, XbQueryFlags flags) G_GNUC_NON_NULL(1); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-query-private.h libxmlb-0.3.22/src/xb-query-private.h --- libxmlb-0.3.10/src/xb-query-private.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-query-private.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once @@ -27,8 +27,8 @@ } XbQuerySection; GPtrArray * -xb_query_get_sections(XbQuery *self); +xb_query_get_sections(XbQuery *self) G_GNUC_NON_NULL(1); gchar * -xb_query_to_string(XbQuery *self); +xb_query_to_string(XbQuery *self) G_GNUC_NON_NULL(1); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-query.c libxmlb-0.3.22/src/xb-query.c --- libxmlb-0.3.10/src/xb-query.c 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-query.c 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #define G_LOG_DOMAIN "XbSilo" diff -Nru libxmlb-0.3.10/src/xb-query.h libxmlb-0.3.22/src/xb-query.h --- libxmlb-0.3.10/src/xb-query.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-query.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once @@ -48,31 +48,32 @@ #include "xb-silo.h" XbQuery * -xb_query_new(XbSilo *silo, const gchar *xpath, GError **error); +xb_query_new(XbSilo *silo, const gchar *xpath, GError **error) G_GNUC_NON_NULL(1, 2); XbQuery * -xb_query_new_full(XbSilo *silo, const gchar *xpath, XbQueryFlags flags, GError **error); +xb_query_new_full(XbSilo *silo, const gchar *xpath, XbQueryFlags flags, GError **error) + G_GNUC_NON_NULL(1, 2); const gchar * -xb_query_get_xpath(XbQuery *self); +xb_query_get_xpath(XbQuery *self) G_GNUC_NON_NULL(1); G_DEPRECATED_FOR(xb_query_context_get_limit) guint -xb_query_get_limit(XbQuery *self); +xb_query_get_limit(XbQuery *self) G_GNUC_NON_NULL(1); G_DEPRECATED_FOR(xb_query_context_set_limit) void -xb_query_set_limit(XbQuery *self, guint limit); +xb_query_set_limit(XbQuery *self, guint limit) G_GNUC_NON_NULL(1); G_DEPRECATED_FOR(xb_query_context_get_flags) XbQueryFlags -xb_query_get_flags(XbQuery *self); +xb_query_get_flags(XbQuery *self) G_GNUC_NON_NULL(1); G_DEPRECATED_FOR(xb_query_context_set_flags) void -xb_query_set_flags(XbQuery *self, XbQueryFlags flags); +xb_query_set_flags(XbQuery *self, XbQueryFlags flags) G_GNUC_NON_NULL(1); G_DEPRECATED_FOR(xb_value_bindings_bind_str) gboolean -xb_query_bind_str(XbQuery *self, guint idx, const gchar *str, GError **error); +xb_query_bind_str(XbQuery *self, guint idx, const gchar *str, GError **error) G_GNUC_NON_NULL(1); G_DEPRECATED_FOR(xb_value_bindings_bind_val) gboolean -xb_query_bind_val(XbQuery *self, guint idx, guint32 val, GError **error); +xb_query_bind_val(XbQuery *self, guint idx, guint32 val, GError **error) G_GNUC_NON_NULL(1); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-self-test.c libxmlb-0.3.22/src/xb-self-test.c --- libxmlb-0.3.10/src/xb-self-test.c 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-self-test.c 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "config.h" @@ -11,6 +11,7 @@ #include "xb-builder-node.h" #include "xb-builder.h" +#include "xb-common-private.h" #include "xb-machine.h" #include "xb-node-query.h" #include "xb-opcode-private.h" @@ -164,6 +165,34 @@ } static void +xb_common_content_type_func(void) +{ + struct { + const gchar *fn; + const gchar *ctype; + } items[] = {{"test.desktop", "application/x-desktop"}, + {"test.quirk", "text/plain"}, + {"test.xml", "application/xml"}, + {"test.xml.gz.gz.gz", "application/gzip"}, + {"test.xml.xz", "application/x-xz"}, + {"test.xml.zst", "application/zstd"}, + {NULL, NULL}}; + for (guint i = 0; items[i].fn != NULL; i++) { + gboolean ret; + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + g_autofree gchar *ctype = NULL; + g_autofree gchar *fn = g_test_build_filename(G_TEST_DIST, items[i].fn, NULL); + g_autoptr(GError) error = NULL; + ret = g_file_get_contents(fn, &buf, &bufsz, &error); + g_assert_no_error(error); + g_assert_true(ret); + ctype = xb_content_type_guess(fn, (const guchar *)buf, bufsz); + g_assert_cmpstr(ctype, ==, items[i].ctype); + } +} + +static void xb_common_searchv_func(void) { const gchar *haystack[] = {"these", "words", "ready", NULL}; @@ -224,9 +253,9 @@ {"@a=='b'", "'a',attr(),'b',eq()"}, {"'a'<'b'", "'a','b',lt()"}, {"999>=123", "999,123,ge()"}, - {"not(0)", "0,not()"}, + {"not(0)", "0^1,not()"}, {"@a", "'a',attr(),'(null)',ne()"}, - {"not(@a)", "'a',attr(),not()"}, + {"not(@a)", "'a'^1,attr()^1,not()"}, {"'a'=", "'a',eq()"}, {"='b'", "'b',eq()"}, {"999=\'b\'", "999,'b',eq()"}, @@ -235,9 +264,10 @@ {"text()~='beef'", "text(),'beef'[beef],search()"}, {"@type~='dead'", "'type',attr(),'dead',search()"}, {"2", "2,position(),eq()"}, - {"text()=lower-case('firefox')", "text(),'firefox',lower-case(),eq()"}, + {"text()=lower-case('firefox')", "text(),'firefox'^1,lower-case(),eq()"}, {"$'a'=$'b'", "$'a',$'b',eq()"}, - {"('a'='b')&&('c'='d')", "'a','b',eq(),'c','d',eq(),and()"}, + {"('a'='b')&&('c'='d')", "'a'^1,'b'^1,eq()^1,'c'^1,'d'^1,eq()^1,and()"}, + {"text()==('a','b','c')", "text(),'c'^1,'b'^1,'a'^1,in()"}, /* sentinel */ {NULL, NULL}}; const gchar *invalid[] = {"text(", @@ -291,6 +321,7 @@ {"lower-case('Fire')", "'fire'"}, {"upper-case('Τάχιστη')", "'ΤΆΧΙΣΤΗ'"}, {"upper-case(lower-case('Fire'))", "'FIRE'"}, /* 2nd pass */ + {"text()==('a','b','c')", "text(),'c'^1,'b'^1,'a'^1,in()"}, /* sentinel */ {NULL, NULL}}; const gchar *invalid[] = {"'a'='b'", "123>=999", "not(1)", NULL}; @@ -377,7 +408,7 @@ /* check size */ bytes = xb_silo_get_bytes(silo); - g_assert_cmpint(g_bytes_get_size(bytes), ==, 620); + g_assert_cmpint(g_bytes_get_size(bytes), ==, 628); } static void @@ -466,6 +497,12 @@ g_autoptr(XbBuilderSource) source = xb_builder_source_new(); g_autoptr(XbSilo) silo = NULL; +#ifndef HAVE_LZMA + /* not supported */ + g_test_skip("compiled without -Dlzma"); + return; +#endif + /* import a source file */ path = g_test_build_filename(G_TEST_DIST, "test.xml.xz", NULL); file_src = g_file_new_for_path(path); @@ -488,6 +525,40 @@ } static void +xb_builder_source_zstd_func(void) +{ + gboolean ret; + g_autofree gchar *path = NULL; + g_autofree gchar *tmp_xmlb = g_build_filename(g_get_tmp_dir(), "temp.xmlb", NULL); + g_autoptr(GError) error = NULL; + g_autoptr(GFile) file = NULL; + g_autoptr(GFile) file_src = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new(); + g_autoptr(XbBuilderSource) source = xb_builder_source_new(); + g_autoptr(XbSilo) silo = NULL; + + /* import a source file */ + path = g_test_build_filename(G_TEST_DIST, "test.xml.zst", NULL); + file_src = g_file_new_for_path(path); + if (!g_file_query_exists(file_src, NULL)) { + g_test_skip("does not work in subproject test"); + return; + } + ret = xb_builder_source_load_file(source, + file_src, + XB_BUILDER_SOURCE_FLAG_NONE, + NULL, + &error); + g_assert_no_error(error); + g_assert_true(ret); + xb_builder_import_source(builder, source); + file = g_file_new_for_path(tmp_xmlb); + silo = xb_builder_ensure(builder, file, XB_BUILDER_COMPILE_FLAG_NONE, NULL, &error); + g_assert_no_error(error); + g_assert_nonnull(silo); +} + +static void xb_builder_chained_adapters_func(void) { gboolean ret; @@ -596,6 +667,9 @@ { gboolean ret; guint invalidate_cnt = 0; + g_autofree gchar *bytes1str = NULL; + g_autofree gchar *bytes2str = NULL; + g_autofree gchar *bytes3str = NULL; g_autofree gchar *tmp_xmlb = g_build_filename(g_get_tmp_dir(), "temp.xmlb", NULL); g_autoptr(GBytes) bytes1 = NULL; g_autoptr(GBytes) bytes2 = NULL; @@ -648,6 +722,7 @@ &invalidate_cnt); g_assert_cmpint(invalidate_cnt, ==, 0); bytes1 = xb_silo_get_bytes(silo); + bytes1str = g_compute_checksum_for_bytes(G_CHECKSUM_SHA1, bytes1); /* recreate file if it is invalid */ ret = g_file_replace_contents(file, @@ -671,7 +746,8 @@ g_assert_nonnull(silo); g_assert_true(xb_silo_is_valid(silo)); bytes2 = xb_silo_get_bytes(silo); - g_assert(bytes1 != bytes2); + bytes2str = g_compute_checksum_for_bytes(G_CHECKSUM_SHA1, bytes2); + g_assert_cmpstr(bytes1str, !=, bytes2str); g_clear_object(&silo); /* don't recreate file if perfectly valid */ @@ -680,7 +756,8 @@ g_assert_nonnull(silo); g_assert_true(xb_silo_is_valid(silo)); bytes3 = xb_silo_get_bytes(silo); - g_assert(bytes2 == bytes3); + bytes3str = g_compute_checksum_for_bytes(G_CHECKSUM_SHA1, bytes3); + g_assert_cmpstr(bytes2str, ==, bytes3str); g_clear_object(&silo); g_clear_object(&builder); @@ -856,7 +933,7 @@ { if (g_strcmp0(xb_builder_node_get_element(bn), "component") == 0) { g_autoptr(XbBuilderNode) id = xb_builder_node_get_child(bn, "id", NULL); - if (g_strcmp0(xb_builder_node_get_text(id), "gimp.desktop") == 0) + if (id != NULL && g_strcmp0(xb_builder_node_get_text(id), "gimp.desktop") == 0) xb_builder_node_add_flag(bn, XB_BUILDER_NODE_FLAG_IGNORE); } else { g_debug("ignoring %s", xb_builder_node_get_element(bn)); @@ -1002,7 +1079,7 @@ /* check size */ bytes = xb_silo_get_bytes(silo); - g_assert_cmpint(g_bytes_get_size(bytes), ==, 32); + g_assert_cmpint(g_bytes_get_size(bytes), ==, 40); /* try to dump */ str = xb_silo_to_string(silo, &error); @@ -1120,6 +1197,28 @@ } static void +xb_node_export_collapse_func(void) +{ + const gchar *xml = ""; + g_autofree gchar *xml_collapsed = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(XbNode) n = NULL; + g_autoptr(XbSilo) silo = NULL; + + /* import from XML */ + silo = xb_silo_new_from_xml(xml, &error); + g_assert_no_error(error); + g_assert_nonnull(silo); + + /* export collapsed */ + n = xb_silo_get_root(silo); + g_assert_nonnull(n); + xml_collapsed = xb_node_export(n, XB_NODE_EXPORT_FLAG_COLLAPSE_EMPTY, &error); + g_assert_no_error(error); + g_assert_cmpstr(xml_collapsed, ==, xml); +} + +static void xb_xpath_parent_subnode_func(void) { g_autofree gchar *xml2 = NULL; @@ -1141,9 +1240,9 @@ /* import from XML */ silo = xb_silo_new_from_xml(xml, &error); - xb_silo_set_enable_node_cache(silo, TRUE); g_assert_no_error(error); g_assert_nonnull(silo); + xb_silo_set_enable_node_cache(silo, TRUE); /* get node */ n = xb_silo_query_first(silo, "components/component", &error); @@ -1220,7 +1319,7 @@ g_autoptr(XbNode) n = NULL; g_autoptr(XbSilo) silo = NULL; const gchar *xml = "\n" - " \n" + " \n" " n/a\n" " \n" "\n"; @@ -1251,6 +1350,13 @@ g_assert_cmpstr(xb_node_get_text(n), ==, "n/a"); g_clear_object(&n); + /* query using an integer */ + n = xb_silo_query_first(silo, "components/component[@timestamp=1631923200]", &error); + g_assert_no_error(error); + g_assert_nonnull(n); + g_assert_cmpstr(xb_node_get_attr(n, "timestamp"), ==, "1631923200"); + g_clear_object(&n); + /* query with an OR, all sections contains an unknown element */ n = xb_silo_query_first(silo, "components/dave|components/mike", &error); g_assert_error(error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); @@ -1364,6 +1470,25 @@ g_assert_nonnull(str); g_debug("\n%s", str); + /* query with predicate 'in' */ + xb_silo_set_profile_flags(silo, XB_SILO_PROFILE_FLAG_OPTIMIZER); + n = xb_silo_query_first( + silo, + "components/component/id[text()=('gimp.desktop','another.desktop','dave.desktop')]", + &error); + g_assert_no_error(error); + g_assert_nonnull(n); + g_assert_cmpstr(xb_node_get_text(n), ==, "gimp.desktop"); + g_clear_object(&n); + + /* query with predicate 'in' -- single-entry tuple */ + xb_silo_set_profile_flags(silo, XB_SILO_PROFILE_FLAG_OPTIMIZER); + n = xb_silo_query_first(silo, "components/component/id[text()=('gimp.desktop')]", &error); + g_assert_no_error(error); + g_assert_nonnull(n); + g_assert_cmpstr(xb_node_get_text(n), ==, "gimp.desktop"); + g_clear_object(&n); + /* query with predicate logical and */ n = xb_silo_query_first( silo, @@ -1636,6 +1761,79 @@ } static void +xb_manual_token_search_func(void) +{ + XbNode *n; + g_autoptr(XbNode) cpt_node = NULL; + g_autoptr(XbBuilder) builder = NULL; + g_autoptr(XbBuilderNode) bn_root = NULL; + g_autoptr(XbBuilderNode) bn = NULL; + g_autoptr(XbSilo) silo = NULL; + g_autofree gchar *str = NULL; + g_autoptr(XbQuery) query = NULL; + g_autoptr(GPtrArray) result = NULL; + g_autoptr(GError) error = NULL; + g_auto(XbQueryContext) context = XB_QUERY_CONTEXT_INIT(); + + /* create node tree and add a dummy token manually */ + bn_root = xb_builder_node_new("component"); + bn = xb_builder_node_new("summary"); + xb_builder_node_set_text(bn, "A strategy game", -1); + xb_builder_node_add_token(bn, "strategy"); /* or use XB_BUILDER_NODE_FLAG_TOKENIZE_TEXT */ + xb_builder_node_add_token(bn, "strategi"); + xb_builder_node_add_child(bn_root, bn); + + builder = xb_builder_new(); + xb_builder_import_node(builder, bn_root); + + silo = xb_builder_compile(builder, XB_BUILDER_COMPILE_FLAG_NONE, NULL, &error); + g_assert_no_error(error); + g_assert_nonnull(silo); + + /* dump to screen */ + str = xb_silo_to_string(silo, &error); + g_assert_no_error(error); + g_assert_nonnull(str); + g_debug("\n%s", str); + + /* get component node */ + cpt_node = xb_silo_query_first(silo, "component", &error); + g_assert_no_error(error); + g_assert_nonnull(cpt_node); + + /* search using the slow, token-less path */ + query = xb_query_new(silo, "summary[text()~=?]", &error); + g_assert_no_error(error); + g_assert_nonnull(query); + + xb_value_bindings_bind_str(xb_query_context_get_bindings(&context), 0, "strategy", NULL); + result = xb_node_query_with_context(cpt_node, query, &context, &error); + g_assert_no_error(error); + g_assert_nonnull(result); + + n = XB_NODE(g_ptr_array_index(result, 0)); + g_assert_nonnull(n); + g_assert_cmpstr(xb_node_get_text(n), ==, "A strategy game"); + g_clear_object(&query); + g_ptr_array_unref(g_steal_pointer(&result)); + + /* search for token */ + xb_silo_set_profile_flags(silo, ~0); + query = xb_query_new(silo, "summary[text()~=?]", &error); + g_assert_no_error(error); + g_assert_nonnull(query); + + xb_value_bindings_bind_str(xb_query_context_get_bindings(&context), 0, "strategi", NULL); + result = xb_node_query_with_context(cpt_node, query, &context, &error); + g_assert_no_error(error); + g_assert_nonnull(result); + + n = XB_NODE(g_ptr_array_index(result, 0)); + g_assert_nonnull(n); + g_assert_cmpstr(xb_node_get_text(n), ==, "A strategy game"); +} + +static void xb_builder_native_lang_func(void) { gboolean ret; @@ -2169,7 +2367,7 @@ xb_builder_node_add_child(component, description); /* no text contents */ - empty = xb_builder_node_new("empty"); + empty = xb_builder_node_insert(component, "empty", NULL); xb_builder_node_set_text(empty, NULL, -1); xb_builder_node_set_tail(empty, NULL, -1); @@ -2182,7 +2380,10 @@ g_assert_cmpstr(xb_builder_node_get_element(child_by_text), ==, "id"); /* check the source XML */ - xml_src = xb_builder_node_export(components, XB_NODE_EXPORT_FLAG_FORMAT_MULTILINE, &error); + xml_src = xb_builder_node_export(components, + XB_NODE_EXPORT_FLAG_FORMAT_MULTILINE | + XB_NODE_EXPORT_FLAG_COLLAPSE_EMPTY, + &error); g_assert_no_error(error); g_assert_nonnull(xml_src); g_print("%s", xml_src); @@ -2192,6 +2393,7 @@ "dave\n" "hello world! \n" "\n" + "\n" "\n" "\n", ==, @@ -2203,7 +2405,10 @@ g_assert_nonnull(silo); /* check the XML */ - xml = xb_silo_export(silo, XB_NODE_EXPORT_FLAG_INCLUDE_SIBLINGS, &error); + xml = xb_silo_export(silo, + XB_NODE_EXPORT_FLAG_INCLUDE_SIBLINGS | + XB_NODE_EXPORT_FLAG_COLLAPSE_EMPTY, + &error); g_assert_no_error(error); g_assert_nonnull(xml); g_print("%s", xml); @@ -2213,6 +2418,7 @@ "dave" "hello world!" "" + "" "" "", ==, @@ -2706,6 +2912,8 @@ int main(int argc, char **argv) { + g_setenv("G_TEST_SRCDIR", SRCDIR, FALSE); + g_test_init(&argc, &argv, NULL); /* only critical and error are fatal */ @@ -2716,6 +2924,7 @@ /* tests go here */ g_test_add_func("/libxmlb/common", xb_common_func); + g_test_add_func("/libxmlb/common{content-type}", xb_common_content_type_func); g_test_add_func("/libxmlb/common{searchv}", xb_common_searchv_func); g_test_add_func("/libxmlb/common{union}", xb_common_union_func); g_test_add_func("/libxmlb/opcodes", xb_predicate_func); @@ -2725,6 +2934,7 @@ g_test_add_func("/libxmlb/stack{peek}", xb_stack_peek_func); g_test_add_func("/libxmlb/node{data}", xb_node_data_func); g_test_add_func("/libxmlb/node{export}", xb_node_export_func); + g_test_add_func("/libxmlb/node{export-collapse}", xb_node_export_collapse_func); g_test_add_func("/libxmlb/builder", xb_builder_func); g_test_add_func("/libxmlb/builder{comments}", xb_builder_comments_func); g_test_add_func("/libxmlb/builder{native-lang}", xb_builder_native_lang_func); @@ -2744,12 +2954,14 @@ g_test_add_func("/libxmlb/builder{custom-mime}", xb_builder_custom_mime_func); g_test_add_func("/libxmlb/builder{chained-adapters}", xb_builder_chained_adapters_func); g_test_add_func("/libxmlb/builder{source-lzma}", xb_builder_source_lzma_func); + g_test_add_func("/libxmlb/builder{source-zstd}", xb_builder_source_zstd_func); g_test_add_func("/libxmlb/builder-node", xb_builder_node_func); g_test_add_func("/libxmlb/builder-node{token-max}", xb_builder_node_token_max_func); g_test_add_func("/libxmlb/builder-node{info}", xb_builder_node_info_func); g_test_add_func("/libxmlb/builder-node{literal-text}", xb_builder_node_literal_text_func); g_test_add_func("/libxmlb/builder-node{source-text}", xb_builder_node_source_text_func); g_test_add_func("/libxmlb/markup", xb_markup_func); + g_test_add_func("/libxmlb/token-search", xb_manual_token_search_func); g_test_add_func("/libxmlb/xpath", xb_xpath_func); g_test_add_func("/libxmlb/xpath-query", xb_xpath_query_func); g_test_add_func("/libxmlb/xpath-query{reverse}", xb_xpath_query_reverse_func); diff -Nru libxmlb-0.3.10/src/xb-silo-export-private.h libxmlb-0.3.22/src/xb-silo-export-private.h --- libxmlb-0.3.10/src/xb-silo-export-private.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-silo-export-private.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once @@ -12,6 +12,7 @@ G_BEGIN_DECLS GString * -xb_silo_export_with_root(XbSilo *self, XbSiloNode *sroot, XbNodeExportFlags flags, GError **error); +xb_silo_export_with_root(XbSilo *self, XbSiloNode *sroot, XbNodeExportFlags flags, GError **error) + G_GNUC_NON_NULL(1); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-silo-export.c libxmlb-0.3.22/src/xb-silo-export.c --- libxmlb-0.3.10/src/xb-silo-export.c 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-silo-export.c 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #define G_LOG_DOMAIN "XbSilo" @@ -26,6 +26,7 @@ xb_silo_export_node(XbSilo *self, XbSiloExportHelper *helper, XbSiloNode *sn, GError **error) { XbSiloNode *sn2; + const gchar *element_name; helper->off = xb_silo_get_offset_for_node(self, sn); @@ -34,28 +35,55 @@ for (guint i = 0; i < helper->level; i++) g_string_append(helper->xml, " "); } - g_string_append_printf(helper->xml, "<%s", xb_silo_from_strtab(self, sn->element_name)); + element_name = xb_silo_from_strtab(self, sn->element_name, error); + if (element_name == NULL) + return FALSE; + g_string_append_printf(helper->xml, "<%s", element_name); /* add any attributes */ for (guint8 i = 0; i < xb_silo_node_get_attr_count(sn); i++) { XbSiloNodeAttr *a = xb_silo_node_get_attr(sn, i); - g_autofree gchar *key = - xb_string_xml_escape(xb_silo_from_strtab(self, a->attr_name)); - g_autofree gchar *val = - xb_string_xml_escape(xb_silo_from_strtab(self, a->attr_value)); - g_string_append_printf(helper->xml, " %s=\"%s\"", key, val); + const gchar *name_unsafe; + const gchar *value_unsafe; + g_autofree gchar *name = NULL; + g_autofree gchar *value = NULL; + + name_unsafe = xb_silo_from_strtab(self, a->attr_name, error); + if (name_unsafe == NULL) + return FALSE; + name = xb_string_xml_escape(name_unsafe); + + value_unsafe = xb_silo_from_strtab(self, a->attr_value, error); + if (value_unsafe == NULL) + return FALSE; + value = xb_string_xml_escape(value_unsafe); + + g_string_append_printf(helper->xml, " %s=\"%s\"", name, value); } /* collapse open/close tags together if no text or children */ if (helper->flags & XB_NODE_EXPORT_FLAG_COLLAPSE_EMPTY && xb_silo_node_get_text_idx(sn) == XB_SILO_UNSET && - xb_silo_get_child_node(self, sn) == NULL) { + xb_silo_get_child_node(self, sn, NULL) == NULL) { g_string_append(helper->xml, " />"); + + /* offset by opening tag and single byte sentinel */ + helper->off += xb_silo_node_get_size(sn); + sn2 = xb_silo_get_node(self, helper->off, error); + if (sn2 == NULL) + return FALSE; + helper->off += xb_silo_node_get_size(sn2); } else { /* finish the opening tag and add any text if it exists */ if (xb_silo_node_get_text_idx(sn) != XB_SILO_UNSET) { - g_autofree gchar *text = - xb_string_xml_escape(xb_silo_get_node_text(self, sn)); + const gchar *text_unsafe; + g_autofree gchar *text = NULL; + + text_unsafe = + xb_silo_from_strtab(self, xb_silo_node_get_text_idx(sn), error); + if (text_unsafe == NULL) + return FALSE; + text = xb_string_xml_escape(text_unsafe); g_string_append(helper->xml, ">"); g_string_append(helper->xml, text); } else { @@ -66,9 +94,12 @@ helper->off += xb_silo_node_get_size(sn); /* recurse deeper */ - while (xb_silo_node_has_flag(xb_silo_get_node(self, helper->off), - XB_SILO_NODE_FLAG_IS_ELEMENT)) { - XbSiloNode *child = xb_silo_get_node(self, helper->off); + while (TRUE) { + XbSiloNode *child = xb_silo_get_node(self, helper->off, error); + if (child == NULL) + return FALSE; + if (!xb_silo_node_has_flag(child, XB_SILO_NODE_FLAG_IS_ELEMENT)) + break; helper->level++; if (!xb_silo_export_node(self, helper, child, error)) return FALSE; @@ -76,7 +107,9 @@ } /* check for the single byte sentinel */ - sn2 = xb_silo_get_node(self, helper->off); + sn2 = xb_silo_get_node(self, helper->off, error); + if (sn2 == NULL) + return FALSE; if (xb_silo_node_has_flag(sn2, XB_SILO_NODE_FLAG_IS_ELEMENT)) { g_set_error(error, G_IO_ERROR, @@ -93,14 +126,18 @@ for (guint i = 0; i < helper->level; i++) g_string_append(helper->xml, " "); } - g_string_append_printf(helper->xml, - "", - xb_silo_from_strtab(self, sn->element_name)); + g_string_append_printf(helper->xml, "", element_name); } /* add any optional tail */ if (xb_silo_node_get_tail_idx(sn) != XB_SILO_UNSET) { - g_autofree gchar *tail = xb_string_xml_escape(xb_silo_get_node_tail(self, sn)); + const gchar *tail_unsafe; + g_autofree gchar *tail = NULL; + + tail_unsafe = xb_silo_from_strtab(self, xb_silo_node_get_tail_idx(sn), error); + if (tail_unsafe == NULL) + return FALSE; + tail = xb_string_xml_escape(tail_unsafe); g_string_append(helper->xml, tail); } @@ -130,10 +167,22 @@ /* optional subtree export */ if (sroot != NULL) { sn = sroot; - if (sn != NULL && flags & XB_NODE_EXPORT_FLAG_ONLY_CHILDREN) - sn = xb_silo_get_child_node(self, sn); + if (sn != NULL && flags & XB_NODE_EXPORT_FLAG_ONLY_CHILDREN) { + g_autoptr(GError) error_local = NULL; + sn = xb_silo_get_child_node(self, sn, &error_local); + if (sn == NULL) { + if (!g_error_matches(error_local, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT)) { + g_propagate_error(error, g_steal_pointer(&error_local)); + return NULL; + } + } + } } else { - sn = xb_silo_get_root_node(self); + sn = xb_silo_get_root_node(self, error); + if (sn == NULL) + return NULL; } /* no root */ @@ -147,14 +196,21 @@ if ((flags & XB_NODE_EXPORT_FLAG_ADD_HEADER) > 0) g_string_append(helper.xml, "\n"); do { + g_autoptr(GError) error_local = NULL; if (!xb_silo_export_node(self, &helper, sn, error)) { g_string_free(helper.xml, TRUE); return NULL; } if ((flags & XB_NODE_EXPORT_FLAG_INCLUDE_SIBLINGS) == 0) break; - sn = xb_silo_get_next_node(self, sn); - } while (sn != NULL); + sn = xb_silo_get_next_node(self, sn, &error_local); + if (sn == NULL) { + if (g_error_matches(error_local, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) + break; + g_propagate_error(error, g_steal_pointer(&error_local)); + return NULL; + } + } while (TRUE); /* success */ return helper.xml; diff -Nru libxmlb-0.3.10/src/xb-silo-export.h libxmlb-0.3.22/src/xb-silo-export.h --- libxmlb-0.3.10/src/xb-silo-export.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-silo-export.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once @@ -14,12 +14,12 @@ G_BEGIN_DECLS gchar * -xb_silo_export(XbSilo *self, XbNodeExportFlags flags, GError **error); +xb_silo_export(XbSilo *self, XbNodeExportFlags flags, GError **error) G_GNUC_NON_NULL(1); gboolean xb_silo_export_file(XbSilo *self, GFile *file, XbNodeExportFlags flags, GCancellable *cancellable, - GError **error); + GError **error) G_GNUC_NON_NULL(1, 2); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-silo-node.c libxmlb-0.3.22/src/xb-silo-node.c --- libxmlb-0.3.10/src/xb-silo-node.c 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-silo-node.c 2025-03-12 09:35:38.000000000 +0000 @@ -1,98 +1,33 @@ /* - * Copyright (C) 2021 Richard Hughes + * Copyright 2025 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ -#define G_LOG_DOMAIN "XbSilo" - #include "xb-silo-node.h" -#include - /* private */ -guint32 -xb_silo_node_get_size(XbSiloNode *self) +gchar * +xb_silo_node_to_string(const XbSiloNode *self) { - if (xb_silo_node_has_flag(self, XB_SILO_NODE_FLAG_IS_ELEMENT)) { - guint8 sz = sizeof(XbSiloNode); - sz += self->attr_count * sizeof(XbSiloNodeAttr); - sz += self->token_count * sizeof(guint32); - return sz; + GString *str = g_string_new("XbSiloNode:\n"); + g_string_append_printf(str, " flags: 0x%x\n", self->flags); + g_string_append_printf(str, " attr_count: %u\n", self->attr_count); + if (self->flags & XB_SILO_NODE_FLAG_IS_ELEMENT) { + if (self->element_name != XB_SILO_UNSET) + g_string_append_printf(str, " element_name: %u\n", self->element_name); + if (self->parent != XB_SILO_UNSET) + g_string_append_printf(str, " parent: @%u\n", self->parent); + if (self->next != XB_SILO_UNSET) + g_string_append_printf(str, " next: @%u\n", self->next); + if (self->text != XB_SILO_UNSET) + g_string_append_printf(str, " text: %u\n", self->text); + if (self->tail != XB_SILO_UNSET) + g_string_append_printf(str, " tail: %u\n", self->tail); } - - /* sentinel */ - return sizeof(guint8); -} - -/* private */ -guint8 -xb_silo_node_get_flags(XbSiloNode *self) -{ - return self->flags; -} - -/* private */ -gboolean -xb_silo_node_has_flag(XbSiloNode *self, XbSiloNodeFlag flag) -{ - return (self->flags & flag) > 0; -} - -/* private */ -guint32 -xb_silo_node_get_text_idx(XbSiloNode *self) -{ - return self->text; -} - -/* private */ -guint32 -xb_silo_node_get_tail_idx(XbSiloNode *self) -{ - return self->tail; -} - -/* private */ -guint8 -xb_silo_node_get_attr_count(XbSiloNode *self) -{ - return self->attr_count; -} - -/* private */ -XbSiloNodeAttr * -xb_silo_node_get_attr(XbSiloNode *self, guint8 idx) -{ - guint32 off = sizeof(XbSiloNode); - off += sizeof(XbSiloNodeAttr) * idx; - return (XbSiloNodeAttr *)(((guint8 *)self) + off); -} - -/* private */ -guint8 -xb_silo_node_get_token_count(XbSiloNode *self) -{ - return self->token_count; -} - -/* private */ -guint32 -xb_silo_node_get_token_idx(XbSiloNode *self, guint idx) -{ - guint32 off = 0; - guint32 stridx; - - /* not valid */ - if (!xb_silo_node_has_flag(self, XB_SILO_NODE_FLAG_IS_ELEMENT)) - return XB_SILO_UNSET; - if (!xb_silo_node_has_flag(self, XB_SILO_NODE_FLAG_IS_TOKENIZED)) - return XB_SILO_UNSET; - - /* calculate offset to token */ - off += sizeof(XbSiloNode); - off += self->attr_count * sizeof(XbSiloNodeAttr); - off += idx * sizeof(guint32); - memcpy(&stridx, (guint8 *)self + off, sizeof(stridx)); - return stridx; + for (guint idx = 0; idx < self->attr_count; idx++) { + XbSiloNodeAttr *attr = xb_silo_node_get_attr(self, idx); + g_string_append_printf(str, " attr: %u=%u\n", attr->attr_name, attr->attr_value); + } + return g_string_free(str, FALSE); } diff -Nru libxmlb-0.3.10/src/xb-silo-node.h libxmlb-0.3.22/src/xb-silo-node.h --- libxmlb-0.3.10/src/xb-silo-node.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-silo-node.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,12 +1,12 @@ /* - * Copyright (C) 2021 Richard Hughes + * Copyright 2021 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include +#include "xb-compile.h" #define XB_SILO_UNSET 0xffffffff @@ -19,12 +19,12 @@ typedef struct __attribute__((packed)) { guint8 flags : 2; guint8 attr_count : 6; - guint8 token_count; /* ONLY when is_node */ - guint32 element_name; /* ONLY when is_node: from strtab */ - guint32 parent; /* ONLY when is_node: from 0 */ - guint32 next; /* ONLY when is_node: from 0 */ - guint32 text; /* ONLY when is_node: from strtab */ - guint32 tail; /* ONLY when is_node: from strtab */ + guint8 token_count; /* ONLY when is_element */ + guint32 element_name; /* ONLY when is_element: from strtab */ + guint32 parent; /* ONLY when is_element: from 0 */ + guint32 next; /* ONLY when is_element: from 0 */ + guint32 text; /* ONLY when is_element: from strtab */ + guint32 tail; /* ONLY when is_element: from strtab */ /* guint32 attrs[attr_count]; guint32 tokens[token_count]; @@ -36,21 +36,91 @@ guint32 attr_value; /* from strtab */ } XbSiloNodeAttr; -guint32 -xb_silo_node_get_size(XbSiloNode *self); -guint32 -xb_silo_node_get_text_idx(XbSiloNode *self); -guint32 -xb_silo_node_get_tail_idx(XbSiloNode *self); -guint8 -xb_silo_node_get_token_count(XbSiloNode *self); -guint32 -xb_silo_node_get_token_idx(XbSiloNode *self, guint idx); -guint8 -xb_silo_node_get_flags(XbSiloNode *self); -gboolean -xb_silo_node_has_flag(XbSiloNode *self, XbSiloNodeFlag flags); -guint8 -xb_silo_node_get_attr_count(XbSiloNode *self); -XbSiloNodeAttr * -xb_silo_node_get_attr(XbSiloNode *self, guint8 idx); +gchar * +xb_silo_node_to_string(const XbSiloNode *self) G_GNUC_NON_NULL(1); + +/* private */ +static inline gboolean +xb_silo_node_has_flag(const XbSiloNode *self, XbSiloNodeFlag flag) +{ + return (self->flags & flag) > 0; +} + +static inline guint32 +xb_silo_node_get_size(const XbSiloNode *self) +{ + if (xb_silo_node_has_flag(self, XB_SILO_NODE_FLAG_IS_ELEMENT)) { + guint8 sz = sizeof(XbSiloNode); + sz += self->attr_count * sizeof(XbSiloNodeAttr); + sz += self->token_count * sizeof(guint32); + return sz; + } + + /* sentinel */ + return sizeof(guint8); +} + +/* private */ +static inline guint8 +xb_silo_node_get_flags(const XbSiloNode *self) +{ + return self->flags; +} + +/* private */ +static inline guint32 +xb_silo_node_get_text_idx(const XbSiloNode *self) +{ + return self->text; +} + +/* private */ +static inline guint32 +xb_silo_node_get_tail_idx(const XbSiloNode *self) +{ + return self->tail; +} + +/* private */ +static inline guint8 +xb_silo_node_get_attr_count(const XbSiloNode *self) +{ + return self->attr_count; +} + +/* private */ +static inline XbSiloNodeAttr * +xb_silo_node_get_attr(const XbSiloNode *self, guint8 idx) +{ + guint32 off = sizeof(XbSiloNode); + off += sizeof(XbSiloNodeAttr) * idx; + return (XbSiloNodeAttr *)(((guint8 *)self) + off); +} + +/* private */ +static inline guint8 +xb_silo_node_get_token_count(const XbSiloNode *self) +{ + return self->token_count; +} + +/* private */ +static inline guint32 +xb_silo_node_get_token_idx(const XbSiloNode *self, guint idx) +{ + guint32 off = 0; + guint32 stridx; + + /* not valid */ + if (!xb_silo_node_has_flag(self, XB_SILO_NODE_FLAG_IS_ELEMENT)) + return XB_SILO_UNSET; + if (!xb_silo_node_has_flag(self, XB_SILO_NODE_FLAG_IS_TOKENIZED)) + return XB_SILO_UNSET; + + /* calculate offset to token */ + off += sizeof(XbSiloNode); + off += self->attr_count * sizeof(XbSiloNodeAttr); + off += idx * sizeof(guint32); + memcpy(&stridx, (guint8 *)self + off, sizeof(stridx)); + return stridx; +} diff -Nru libxmlb-0.3.10/src/xb-silo-private.h libxmlb-0.3.22/src/xb-silo-private.h --- libxmlb-0.3.10/src/xb-silo-private.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-silo-private.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once @@ -23,10 +23,11 @@ guint16 strtab_ntags; guint8 padding[2]; guint32 strtab; + guint64 filesz; } XbSiloHeader; #define XB_SILO_MAGIC_BYTES 0x624c4d58 -#define XB_SILO_VERSION 0x00000008 +#define XB_SILO_VERSION 0x00000009 typedef struct { /*< private >*/ @@ -35,50 +36,48 @@ } XbSiloQueryData; const gchar * -xb_silo_from_strtab(XbSilo *self, guint32 offset); -void -xb_silo_strtab_index_insert(XbSilo *self, guint32 offset); +xb_silo_from_strtab(XbSilo *self, guint32 offset, GError **error) G_GNUC_NON_NULL(1); +gboolean +xb_silo_strtab_index_insert(XbSilo *self, guint32 offset, GError **error) G_GNUC_NON_NULL(1); guint32 -xb_silo_strtab_index_lookup(XbSilo *self, const gchar *str); +xb_silo_strtab_index_lookup(XbSilo *self, const gchar *str) G_GNUC_NON_NULL(1); XbSiloNode * -xb_silo_get_node(XbSilo *self, guint32 off); +xb_silo_get_node(XbSilo *self, guint32 off, GError **error) G_GNUC_NON_NULL(1); XbMachine * -xb_silo_get_machine(XbSilo *self); +xb_silo_get_machine(XbSilo *self) G_GNUC_NON_NULL(1); guint32 -xb_silo_get_strtab(XbSilo *self); +xb_silo_get_strtab(XbSilo *self) G_GNUC_NON_NULL(1); guint32 -xb_silo_get_strtab_idx(XbSilo *self, const gchar *element); +xb_silo_get_strtab_idx(XbSilo *self, const gchar *element) G_GNUC_NON_NULL(1); guint32 -xb_silo_get_offset_for_node(XbSilo *self, XbSiloNode *n); +xb_silo_get_offset_for_node(XbSilo *self, XbSiloNode *n) G_GNUC_NON_NULL(1, 2); XbSiloNode * -xb_silo_get_root_node(XbSilo *self); +xb_silo_get_root_node(XbSilo *self, GError **error) G_GNUC_NON_NULL(1); XbSiloNode * -xb_silo_get_parent_node(XbSilo *self, XbSiloNode *n); +xb_silo_get_parent_node(XbSilo *self, XbSiloNode *n, GError **error) G_GNUC_NON_NULL(1, 2); XbSiloNode * -xb_silo_get_next_node(XbSilo *self, XbSiloNode *n); +xb_silo_get_next_node(XbSilo *self, XbSiloNode *n, GError **error) G_GNUC_NON_NULL(1, 2); XbSiloNode * -xb_silo_get_child_node(XbSilo *self, XbSiloNode *n); -const gchar * -xb_silo_get_node_element(XbSilo *self, XbSiloNode *n); -const gchar * -xb_silo_get_node_text(XbSilo *self, XbSiloNode *n); +xb_silo_get_child_node(XbSilo *self, XbSiloNode *n, GError **error) G_GNUC_NON_NULL(1, 2); const gchar * -xb_silo_get_node_tail(XbSilo *self, XbSiloNode *n); +xb_silo_get_node_element(XbSilo *self, XbSiloNode *n, GError **error) G_GNUC_NON_NULL(1, 2); XbSiloNodeAttr * -xb_silo_get_node_attr_by_str(XbSilo *self, XbSiloNode *n, const gchar *name); +xb_silo_get_node_attr_by_str(XbSilo *self, XbSiloNode *n, const gchar *name) + G_GNUC_NON_NULL(1, 2, 3); guint -xb_silo_get_node_depth(XbSilo *self, XbSiloNode *n); +xb_silo_get_node_depth(XbSilo *self, XbSiloNode *n) G_GNUC_NON_NULL(1, 2); XbNode * -xb_silo_create_node(XbSilo *self, XbSiloNode *sn, gboolean force_node_cache); +xb_silo_create_node(XbSilo *self, XbSiloNode *sn, gboolean force_node_cache) G_GNUC_NON_NULL(1); GTimer * -xb_silo_start_profile(XbSilo *self); +xb_silo_start_profile(XbSilo *self) G_GNUC_NON_NULL(1); void -xb_silo_add_profile(XbSilo *self, GTimer *timer, const gchar *fmt, ...) G_GNUC_PRINTF(3, 4); +xb_silo_add_profile(XbSilo *self, GTimer *timer, const gchar *fmt, ...) G_GNUC_PRINTF(3, 4) + G_GNUC_NON_NULL(1); gboolean -xb_silo_is_empty(XbSilo *self); +xb_silo_is_empty(XbSilo *self) G_GNUC_NON_NULL(1); void -xb_silo_uninvalidate(XbSilo *self); +xb_silo_uninvalidate(XbSilo *self) G_GNUC_NON_NULL(1); XbSiloProfileFlags -xb_silo_get_profile_flags(XbSilo *self); +xb_silo_get_profile_flags(XbSilo *self) G_GNUC_NON_NULL(1); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-silo-query-private.h libxmlb-0.3.22/src/xb-silo-query-private.h --- libxmlb-0.3.10/src/xb-silo-query-private.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-silo-query-private.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once @@ -15,19 +15,17 @@ G_BEGIN_DECLS GPtrArray * -xb_silo_query_sn_with_root(XbSilo *self, - XbNode *n, - const gchar *xpath, - guint limit, - GError **error); +xb_silo_query_sn_with_root(XbSilo *self, XbNode *n, const gchar *xpath, guint limit, GError **error) + G_GNUC_NON_NULL(1, 3); GPtrArray * -xb_silo_query_with_root(XbSilo *self, XbNode *n, const gchar *xpath, guint limit, GError **error); +xb_silo_query_with_root(XbSilo *self, XbNode *n, const gchar *xpath, guint limit, GError **error) + G_GNUC_NON_NULL(1, 3); GPtrArray * xb_silo_query_with_root_full(XbSilo *self, XbNode *n, XbQuery *query, XbQueryContext *context, gboolean first_result_only, - GError **error); + GError **error) G_GNUC_NON_NULL(1, 3); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-silo-query.c libxmlb-0.3.22/src/xb-silo-query.c --- libxmlb-0.3.10/src/xb-silo-query.c 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-silo-query.c 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #define G_LOG_DOMAIN "XbSilo" @@ -157,15 +157,9 @@ "cannot obtain parent for root"); return FALSE; } - parent = xb_silo_get_parent_node(self, sn); - if (parent == NULL) { - g_set_error(error, - G_IO_ERROR, - G_IO_ERROR_INVALID_ARGUMENT, - "no parent set for %s", - xb_silo_get_node_element(self, sn)); + parent = xb_silo_get_parent_node(self, sn, error); + if (parent == NULL) return FALSE; - } if (i == helper->sections->len - 1) { xb_silo_query_section_add_result(self, helper, parent); return TRUE; @@ -180,18 +174,18 @@ /* no node means root */ if (sn == NULL) { - sn = xb_silo_get_root_node(self); + sn = xb_silo_get_root_node(self, error); + if (sn == NULL) + return FALSE; + } else { + g_autoptr(GError) error_local = NULL; + sn = xb_silo_get_child_node(self, sn, &error_local); if (sn == NULL) { - g_set_error_literal(error, - G_IO_ERROR, - G_IO_ERROR_NOT_FOUND, - "silo root not found"); + if (g_error_matches(error_local, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) + return TRUE; + g_propagate_error(error, g_steal_pointer(&error_local)); return FALSE; } - } else { - sn = xb_silo_get_child_node(self, sn); - if (sn == NULL) - return TRUE; } /* set up level pointer */ @@ -199,8 +193,9 @@ /* continue matching children ".." */ do { + XbSiloNode *sn_new; gboolean result = TRUE; - guint bindings_offset_end; + guint bindings_offset_end = 0; query_data->sn = sn; if (!xb_silo_query_node_matches(self, machine, @@ -232,7 +227,19 @@ } if (sn->next == 0x0) break; - sn = xb_silo_get_node(self, sn->next); + sn_new = xb_silo_get_node(self, sn->next, error); + if (sn_new == NULL) + return FALSE; + if (sn_new <= sn) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "silo node was invalid: %p -> %p", + sn, + sn_new); + return FALSE; + } + sn = sn_new; } while (TRUE); return TRUE; } @@ -486,6 +493,13 @@ : xb_query_get_flags(query); G_GNUC_END_IGNORE_DEPRECATIONS + /* convert the XB_OPCODE_KIND_BOUND_TEXT into a XB_OPCODE_KIND_BOUND_INDEXED_TEXT */ + if (context != NULL && query_flags & XB_QUERY_FLAG_USE_INDEXES) { + XbValueBindings *bindings = xb_query_context_get_bindings(context); + if (!xb_value_bindings_indexed_text_lookup(bindings, self, error)) + return NULL; + } + /* empty silo */ if (xb_silo_is_empty(self)) { g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "silo has no data"); @@ -536,12 +550,14 @@ /* nothing found */ if (results->len == 0) { - g_autofree gchar *tmp = xb_query_to_string(query); - g_set_error(error, - G_IO_ERROR, - G_IO_ERROR_NOT_FOUND, - "no results for XPath query '%s'", - tmp); + if (error != NULL) { + g_autofree gchar *tmp = xb_query_to_string(query); + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "no results for XPath query '%s'", + tmp); + } return NULL; } @@ -617,7 +633,7 @@ * * Please note: Only a tiny subset of XPath 1.0 is supported. * - * Returns: (transfer none): a #XbNode, or %NULL if unfound + * Returns: (transfer full): a #XbNode, or %NULL if unfound * * Since: 0.1.13 **/ @@ -702,7 +718,7 @@ * * Please note: Only a tiny subset of XPath 1.0 is supported. * - * Returns: (transfer none): a #XbNode, or %NULL if unfound + * Returns: (transfer full): a #XbNode, or %NULL if unfound * * Since: 0.1.0 **/ @@ -759,11 +775,16 @@ guint8 attr_count = xb_silo_node_get_attr_count(sn); for (guint8 j = 0; j < attr_count; j++) { XbSiloNodeAttr *a = xb_silo_node_get_attr(sn, j); - xb_silo_strtab_index_insert(self, a->attr_name); - xb_silo_strtab_index_insert(self, a->attr_value); + if (!xb_silo_strtab_index_insert(self, a->attr_name, error)) + return FALSE; + if (!xb_silo_strtab_index_insert(self, a->attr_value, error)) + return FALSE; } } else { - xb_silo_strtab_index_insert(self, xb_silo_node_get_text_idx(sn)); + if (!xb_silo_strtab_index_insert(self, + xb_silo_node_get_text_idx(sn), + error)) + return FALSE; } } diff -Nru libxmlb-0.3.10/src/xb-silo-query.h libxmlb-0.3.22/src/xb-silo-query.h --- libxmlb-0.3.10/src/xb-silo-query.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-silo-query.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once @@ -16,25 +16,27 @@ G_BEGIN_DECLS GPtrArray * -xb_silo_query(XbSilo *self, const gchar *xpath, guint limit, GError **error); +xb_silo_query(XbSilo *self, const gchar *xpath, guint limit, GError **error) G_GNUC_NON_NULL(1, 2); GPtrArray * -xb_silo_query_full(XbSilo *self, XbQuery *query, GError **error); +xb_silo_query_full(XbSilo *self, XbQuery *query, GError **error) G_GNUC_NON_NULL(1, 2); GPtrArray * -xb_silo_query_with_context(XbSilo *self, XbQuery *query, XbQueryContext *context, GError **error); +xb_silo_query_with_context(XbSilo *self, XbQuery *query, XbQueryContext *context, GError **error) + G_GNUC_NON_NULL(1, 2); XbNode * -xb_silo_query_first(XbSilo *self, const gchar *xpath, GError **error); +xb_silo_query_first(XbSilo *self, const gchar *xpath, GError **error) G_GNUC_NON_NULL(1, 2); XbNode * -xb_silo_query_first_full(XbSilo *self, XbQuery *query, GError **error); +xb_silo_query_first_full(XbSilo *self, XbQuery *query, GError **error) G_GNUC_NON_NULL(1, 2); XbNode * xb_silo_query_first_with_context(XbSilo *self, XbQuery *query, XbQueryContext *context, - GError **error); + GError **error) G_GNUC_NON_NULL(1); gboolean -xb_silo_query_build_index(XbSilo *self, const gchar *xpath, const gchar *attr, GError **error); +xb_silo_query_build_index(XbSilo *self, const gchar *xpath, const gchar *attr, GError **error) + G_GNUC_NON_NULL(1, 2); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-silo.c libxmlb-0.3.22/src/xb-silo.c --- libxmlb-0.3.10/src/xb-silo.c 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-silo.c 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ /** @@ -175,32 +175,39 @@ /* private */ const gchar * -xb_silo_from_strtab(XbSilo *self, guint32 offset) +xb_silo_from_strtab(XbSilo *self, guint32 offset, GError **error) { XbSiloPrivate *priv = GET_PRIVATE(self); - if (offset == XB_SILO_UNSET) + if (G_UNLIKELY(offset == XB_SILO_UNSET)) { + g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "offset was unset"); return NULL; + } if (offset >= priv->datasz - priv->strtab) { - g_critical("strtab+offset is outside the data range for %u", offset); + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "strtab+offset is outside the data range for %u", + offset); return NULL; } return (const gchar *)(priv->data + priv->strtab + offset); } /* private */ -void -xb_silo_strtab_index_insert(XbSilo *self, guint32 offset) +gboolean +xb_silo_strtab_index_insert(XbSilo *self, guint32 offset, GError **error) { XbSiloPrivate *priv = GET_PRIVATE(self); const gchar *tmp; /* get the string version */ - tmp = xb_silo_from_strtab(self, offset); + tmp = xb_silo_from_strtab(self, offset, error); if (tmp == NULL) - return; + return FALSE; if (g_hash_table_lookup(priv->strindex, tmp) != NULL) - return; + return TRUE; g_hash_table_insert(priv->strindex, (gpointer)tmp, GUINT_TO_POINTER(offset)); + return TRUE; } /* private */ @@ -215,10 +222,18 @@ } /* private */ -inline XbSiloNode * -xb_silo_get_node(XbSilo *self, guint32 off) +XbSiloNode * +xb_silo_get_node(XbSilo *self, guint32 off, GError **error) { XbSiloPrivate *priv = GET_PRIVATE(self); + if (G_UNLIKELY(off >= priv->strtab)) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "offset %u is outside the expected range", + off); + return NULL; + } return (XbSiloNode *)(priv->data + off); } @@ -240,46 +255,73 @@ /* private */ XbSiloNode * -xb_silo_get_root_node(XbSilo *self) +xb_silo_get_root_node(XbSilo *self, GError **error) { XbSiloPrivate *priv = GET_PRIVATE(self); - if (priv->blob == NULL) + if (G_UNLIKELY(priv->blob == NULL)) { + g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "no blob loaded"); + return NULL; + } + if (G_UNLIKELY(g_bytes_get_size(priv->blob) < sizeof(XbSiloHeader))) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "blob too small: 0x%x", + (guint)g_bytes_get_size(priv->blob)); return NULL; - if (g_bytes_get_size(priv->blob) <= sizeof(XbSiloHeader)) + } + if (G_UNLIKELY(g_bytes_get_size(priv->blob) == sizeof(XbSiloHeader))) { + g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "no node data"); return NULL; - return xb_silo_get_node(self, sizeof(XbSiloHeader)); + } + return xb_silo_get_node(self, sizeof(XbSiloHeader), error); } /* private */ XbSiloNode * -xb_silo_get_parent_node(XbSilo *self, XbSiloNode *n) +xb_silo_get_parent_node(XbSilo *self, XbSiloNode *n, GError **error) { - if (n->parent == 0x0) + if (G_UNLIKELY(n->parent == 0x0)) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + "no parent set for %s", + xb_silo_get_node_element(self, n, NULL)); return NULL; - return xb_silo_get_node(self, n->parent); + } + return xb_silo_get_node(self, n->parent, error); } /* private */ XbSiloNode * -xb_silo_get_next_node(XbSilo *self, XbSiloNode *n) +xb_silo_get_next_node(XbSilo *self, XbSiloNode *n, GError **error) { - if (n->next == 0x0) + if (n->next == 0x0) { + g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "no next node"); return NULL; - return xb_silo_get_node(self, n->next); + } + return xb_silo_get_node(self, n->next, error); } /* private */ XbSiloNode * -xb_silo_get_child_node(XbSilo *self, XbSiloNode *n) +xb_silo_get_child_node(XbSilo *self, XbSiloNode *n, GError **error) { XbSiloNode *c; guint32 off = xb_silo_get_offset_for_node(self, n); off += xb_silo_node_get_size(n); /* check for sentinel */ - c = xb_silo_get_node(self, off); - if (!xb_silo_node_has_flag(c, XB_SILO_NODE_FLAG_IS_ELEMENT)) + c = xb_silo_get_node(self, off, error); + if (c == NULL) return NULL; + if (!xb_silo_node_has_flag(c, XB_SILO_NODE_FLAG_IS_ELEMENT)) { + g_set_error_literal(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + "no child element"); + return NULL; + } return c; } @@ -296,8 +338,19 @@ XbNode * xb_silo_get_root(XbSilo *self) { + XbSiloNode *sn; + g_autoptr(GError) error_local = NULL; + g_return_val_if_fail(XB_IS_SILO(self), NULL); - return xb_silo_create_node(self, xb_silo_get_root_node(self), FALSE); + + sn = xb_silo_get_root_node(self, &error_local); + if (sn == NULL) { + /* if there are no XbSiloNodes, still build a root XbNode */ + if (!g_error_matches(error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + return NULL; + g_debug("ignoring: %s", error_local->message); + } + return xb_silo_create_node(self, sn, FALSE); } /* private */ @@ -342,12 +395,16 @@ g_string_append_printf(str, "magic: %08x\n", (guint)hdr->magic); g_string_append_printf(str, "guid: %s\n", priv->guid); + g_string_append_printf(str, "filesz: @%" G_GUINT64_FORMAT "\n", hdr->filesz); g_string_append_printf(str, "strtab: @%" G_GUINT32_FORMAT "\n", hdr->strtab); g_string_append_printf(str, "strtab_ntags: %" G_GUINT16_FORMAT "\n", hdr->strtab_ntags); while (off < priv->strtab) { - XbSiloNode *n = xb_silo_get_node(self, off); + XbSiloNode *n = xb_silo_get_node(self, off, error); + if (n == NULL) + return NULL; if (xb_silo_node_has_flag(n, XB_SILO_NODE_FLAG_IS_ELEMENT)) { guint32 idx; + const gchar *element_name; g_string_append_printf(str, "NODE @%" G_GUINT32_FORMAT "\n", off); g_string_append_printf(str, "size: %" G_GUINT32_FORMAT "\n", @@ -355,9 +412,12 @@ g_string_append_printf(str, "flags: %x\n", xb_silo_node_get_flags(n)); + element_name = xb_silo_from_strtab(self, n->element_name, error); + if (element_name == NULL) + return NULL; g_string_append_printf(str, "element_name: %s [%03u]\n", - xb_silo_from_strtab(self, n->element_name), + element_name, n->element_name); g_string_append_printf(str, "next: %" G_GUINT32_FORMAT "\n", @@ -367,34 +427,46 @@ n->parent); idx = xb_silo_node_get_text_idx(n); if (idx != XB_SILO_UNSET) { - g_string_append_printf(str, - "text: %s [%03u]\n", - xb_silo_from_strtab(self, idx), - idx); + const gchar *text = xb_silo_from_strtab(self, idx, error); + if (text == NULL) + return NULL; + g_string_append_printf(str, "text: %s [%03u]\n", text, idx); } idx = xb_silo_node_get_tail_idx(n); if (idx != XB_SILO_UNSET) { - g_string_append_printf(str, - "tail: %s [%03u]\n", - xb_silo_from_strtab(self, idx), - idx); + const gchar *tail = xb_silo_from_strtab(self, idx, error); + if (tail == NULL) + return NULL; + g_string_append_printf(str, "tail: %s [%03u]\n", tail, idx); } for (guint8 i = 0; i < xb_silo_node_get_attr_count(n); i++) { XbSiloNodeAttr *a = xb_silo_node_get_attr(n, i); + const gchar *attr_name; + const gchar *attr_value; + + attr_name = xb_silo_from_strtab(self, a->attr_name, error); + if (attr_name == NULL) + return NULL; g_string_append_printf(str, "attr_name: %s [%03u]\n", - xb_silo_from_strtab(self, a->attr_name), + attr_name, a->attr_name); + attr_value = xb_silo_from_strtab(self, a->attr_value, error); + if (attr_value == NULL) + return NULL; g_string_append_printf(str, "attr_value: %s [%03u]\n", - xb_silo_from_strtab(self, a->attr_value), + attr_value, a->attr_value); } for (guint8 i = 0; i < xb_silo_node_get_token_count(n); i++) { guint32 idx_tmp = xb_silo_node_get_token_idx(n, i); + const gchar *token = xb_silo_from_strtab(self, idx_tmp, error); + if (token == NULL) + return NULL; g_string_append_printf(str, "token: %s [%03u]\n", - xb_silo_from_strtab(self, idx_tmp), + token, idx_tmp); } } else { @@ -406,7 +478,7 @@ /* add strtab */ g_string_append_printf(str, "STRTAB @%" G_GUINT32_FORMAT "\n", hdr->strtab); for (off = 0; off < priv->datasz - hdr->strtab;) { - const gchar *tmp = xb_silo_from_strtab(self, off); + const gchar *tmp = xb_silo_from_strtab(self, off, NULL); if (tmp == NULL) break; g_string_append_printf(str, "[%03u]: %s\n", off, tmp); @@ -419,29 +491,9 @@ /* private */ const gchar * -xb_silo_get_node_text(XbSilo *self, XbSiloNode *n) +xb_silo_get_node_element(XbSilo *self, XbSiloNode *n, GError **error) { - guint32 idx = xb_silo_node_get_text_idx(n); - if (idx == XB_SILO_UNSET) - return NULL; - return xb_silo_from_strtab(self, idx); -} - -/* private */ -const gchar * -xb_silo_get_node_tail(XbSilo *self, XbSiloNode *n) -{ - guint idx = xb_silo_node_get_tail_idx(n); - if (idx == XB_SILO_UNSET) - return NULL; - return xb_silo_from_strtab(self, idx); -} - -/* private */ -const gchar * -xb_silo_get_node_element(XbSilo *self, XbSiloNode *n) -{ - return xb_silo_from_strtab(self, n->element_name); + return xb_silo_from_strtab(self, n->element_name, error); } /* private */ @@ -454,7 +506,10 @@ attr_count = xb_silo_node_get_attr_count(n); for (guint8 i = 0; i < attr_count; i++) { XbSiloNodeAttr *a = xb_silo_node_get_attr(n, i); - if (g_strcmp0(xb_silo_from_strtab(self, a->attr_name), name) == 0) + const gchar *name_tmp = xb_silo_from_strtab(self, a->attr_name, NULL); + if (name_tmp == NULL) + return NULL; + if (g_strcmp0(name_tmp, name) == 0) return a; } @@ -499,7 +554,9 @@ g_return_val_if_fail(XB_IS_SILO(self), 0); while (off < priv->strtab) { - XbSiloNode *n = xb_silo_get_node(self, off); + XbSiloNode *n = xb_silo_get_node(self, off, NULL); + if (n == NULL) + return 0; if (xb_silo_node_has_flag(n, XB_SILO_NODE_FLAG_IS_ELEMENT)) nodes_cnt += 1; off += xb_silo_node_get_size(n); @@ -613,7 +670,9 @@ guint depth = 0; while (n->parent != 0) { depth++; - n = xb_silo_get_node(self, n->parent); + n = xb_silo_get_node(self, n->parent, NULL); + if (n == NULL) + break; } return depth; } @@ -741,6 +800,12 @@ } } + /* check size */ + if (hdr->filesz != sz) { + g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "filesz incorrect"); + return FALSE; + } + /* get GUID */ memcpy(&guid_tmp, &hdr->guid, sizeof(guid_tmp)); priv->guid = xb_guid_to_string(&guid_tmp); @@ -751,15 +816,19 @@ g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "strtab incorrect"); return FALSE; } + if (hdr->strtab_ntags > 0 && priv->data[sz - 1] != '\0') { + g_set_error_literal(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "strtab invalid, trailing NUL not found"); + return FALSE; + } /* load strtab_tags */ for (guint16 i = 0; i < hdr->strtab_ntags; i++) { - const gchar *tmp = xb_silo_from_strtab(self, off); + const gchar *tmp = xb_silo_from_strtab(self, off, error); if (tmp == NULL) { - g_set_error_literal(error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "strtab_ntags incorrect"); + g_prefix_error(error, "strtab_ntags incorrect: "); return FALSE; } g_hash_table_insert(priv->strtab_tags, (gpointer)tmp, GUINT_TO_POINTER(off)); @@ -811,7 +880,9 @@ /* proxy */ if (profile_flags & XB_SILO_PROFILE_FLAG_OPTIMIZER) { - xb_machine_set_debug_flags(priv->machine, XB_MACHINE_DEBUG_FLAG_SHOW_OPTIMIZER); + xb_machine_set_debug_flags(priv->machine, + XB_MACHINE_DEBUG_FLAG_SHOW_OPTIMIZER | + XB_MACHINE_DEBUG_FLAG_SHOW_SLOW_PATH); } } @@ -1177,6 +1248,7 @@ { XbOpcode *op1; XbOpcode *op2; + XbOpcode *tail = xb_stack_peek_tail(opcodes); if (!_xb_stack_push_two(opcodes, &op1, &op2, error)) return FALSE; @@ -1184,6 +1256,12 @@ xb_machine_opcode_func_init(self, op1, "position"); xb_machine_opcode_func_init(self, op2, "eq"); + /* always exists, but maybe a @level would be cleaner */ + if (tail != NULL) { + xb_opcode_set_level(op1, _xb_opcode_get_level(tail)); + xb_opcode_set_level(op2, _xb_opcode_get_level(tail)); + } + return TRUE; } @@ -1196,6 +1274,7 @@ { XbOpcode *op1; XbOpcode *op2; + XbOpcode *tail = xb_stack_peek_tail(opcodes); if (!_xb_stack_push_two(opcodes, &op1, &op2, error)) return FALSE; @@ -1203,6 +1282,12 @@ xb_opcode_text_init_static(op1, NULL); xb_machine_opcode_func_init(self, op2, "ne"); + /* always exists, but maybe a @level would be cleaner */ + if (tail != NULL) { + xb_opcode_set_level(op1, _xb_opcode_get_level(tail)); + xb_opcode_set_level(op2, _xb_opcode_get_level(tail)); + } + return TRUE; } @@ -1259,6 +1344,7 @@ XbSiloNodeAttr *a; XbSilo *silo = XB_SILO(user_data); XbSiloQueryData *query_data = (XbSiloQueryData *)exec_data; + const gchar *attr_value; g_auto(XbOpcode) op = XB_OPCODE_INIT(); /* optimize pass */ @@ -1286,11 +1372,10 @@ } if (!xb_machine_stack_push(self, stack, &op2, error)) return FALSE; - xb_opcode_init(op2, - XB_OPCODE_KIND_INDEXED_TEXT, - xb_silo_from_strtab(silo, a->attr_value), - a->attr_value, - NULL); + attr_value = xb_silo_from_strtab(silo, a->attr_value, error); + if (attr_value == NULL) + return FALSE; + xb_opcode_init(op2, XB_OPCODE_KIND_INDEXED_TEXT, attr_value, a->attr_value, NULL); return TRUE; } @@ -1337,6 +1422,7 @@ XbSilo *silo = XB_SILO(user_data); XbSiloQueryData *query_data = (XbSiloQueryData *)exec_data; XbOpcode *op; + const gchar *text; guint8 token_count; /* optimize pass */ @@ -1348,11 +1434,18 @@ return FALSE; } + if (xb_silo_node_get_text_idx(query_data->sn) != XB_SILO_UNSET) { + text = xb_silo_from_strtab(silo, xb_silo_node_get_text_idx(query_data->sn), error); + if (text == NULL) + return FALSE; + } else { + text = ""; + } if (!xb_machine_stack_push(self, stack, &op, error)) return FALSE; xb_opcode_init(op, XB_OPCODE_KIND_INDEXED_TEXT, - xb_silo_get_node_text(silo, query_data->sn), + text, xb_silo_node_get_text_idx(query_data->sn), NULL); @@ -1364,7 +1457,10 @@ token_count = xb_silo_node_get_token_count(query_data->sn); for (guint i = 0; i < token_count; i++) { guint32 stridx = xb_silo_node_get_token_idx(query_data->sn, i); - xb_opcode_append_token(op, xb_silo_from_strtab(silo, stridx)); + const gchar *token = xb_silo_from_strtab(silo, stridx, error); + if (token == NULL) + return FALSE; + xb_opcode_append_token(op, token); } return TRUE; @@ -1380,6 +1476,7 @@ { XbSilo *silo = XB_SILO(user_data); XbSiloQueryData *query_data = (XbSiloQueryData *)exec_data; + const gchar *tail; XbOpcode *op; /* optimize pass */ @@ -1391,11 +1488,18 @@ return FALSE; } + if (xb_silo_node_get_tail_idx(query_data->sn) != XB_SILO_UNSET) { + tail = xb_silo_from_strtab(silo, xb_silo_node_get_tail_idx(query_data->sn), error); + if (tail == NULL) + return FALSE; + } else { + tail = ""; + } if (!xb_machine_stack_push(self, stack, &op, error)) return FALSE; xb_opcode_init(op, XB_OPCODE_KIND_INDEXED_TEXT, - xb_silo_get_node_tail(silo, query_data->sn), + tail, xb_silo_node_get_tail_idx(query_data->sn), NULL); return TRUE; @@ -1501,6 +1605,16 @@ if (!xb_machine_stack_pop_two(self, stack, &op1, &op2, error)) return FALSE; + /* this cannot be optimized away when constructing the query */ + if (!_xb_opcode_has_flag(&op1, XB_OPCODE_FLAG_TOKENIZED) && + _xb_opcode_get_kind(&op1) == XB_OPCODE_KIND_BOUND_TEXT) { + xb_machine_opcode_tokenize(self, &op1); + } + if (!_xb_opcode_has_flag(&op2, XB_OPCODE_FLAG_TOKENIZED) && + _xb_opcode_get_kind(&op2) == XB_OPCODE_KIND_BOUND_TEXT) { + xb_machine_opcode_tokenize(self, &op2); + } + /* TOKN:TOKN */ if (xb_opcode_has_flag(&op1, XB_OPCODE_FLAG_TOKENIZED) && xb_opcode_has_flag(&op2, XB_OPCODE_FLAG_TOKENIZED)) { @@ -1815,7 +1929,6 @@ if (result != NULL) { g_object_ref(result); - g_debug("Found cached query ‘%s’ (%p) in silo %p", xpath, result, self); } else { g_autoptr(XbQuery) query = NULL; @@ -1824,7 +1937,6 @@ result = g_hash_table_lookup(priv->query_cache, xpath); if (result != NULL) { g_object_ref(result); - g_debug("Found cached query ‘%s’ (%p) in silo %p", xpath, result, self); } else { g_autoptr(GError) error_local = NULL; diff -Nru libxmlb-0.3.10/src/xb-silo.h libxmlb-0.3.22/src/xb-silo.h --- libxmlb-0.3.10/src/xb-silo.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-silo.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once @@ -68,46 +68,49 @@ XbSilo * xb_silo_new(void); XbSilo * -xb_silo_new_from_xml(const gchar *xml, GError **error); +xb_silo_new_from_xml(const gchar *xml, GError **error) G_GNUC_NON_NULL(1); GBytes * -xb_silo_get_bytes(XbSilo *self); +xb_silo_get_bytes(XbSilo *self) G_GNUC_NON_NULL(1); gboolean -xb_silo_load_from_bytes(XbSilo *self, GBytes *blob, XbSiloLoadFlags flags, GError **error); +xb_silo_load_from_bytes(XbSilo *self, GBytes *blob, XbSiloLoadFlags flags, GError **error) + G_GNUC_NON_NULL(1, 2); gboolean xb_silo_load_from_file(XbSilo *self, GFile *file, XbSiloLoadFlags flags, GCancellable *cancellable, - GError **error); + GError **error) G_GNUC_NON_NULL(1, 2); gboolean -xb_silo_save_to_file(XbSilo *self, GFile *file, GCancellable *cancellable, GError **error); +xb_silo_save_to_file(XbSilo *self, GFile *file, GCancellable *cancellable, GError **error) + G_GNUC_NON_NULL(1, 2); gchar * -xb_silo_to_string(XbSilo *self, GError **error); +xb_silo_to_string(XbSilo *self, GError **error) G_GNUC_NON_NULL(1); guint -xb_silo_get_size(XbSilo *self); +xb_silo_get_size(XbSilo *self) G_GNUC_NON_NULL(1); const gchar * -xb_silo_get_guid(XbSilo *self); +xb_silo_get_guid(XbSilo *self) G_GNUC_NON_NULL(1); XbNode * -xb_silo_get_root(XbSilo *self); +xb_silo_get_root(XbSilo *self) G_GNUC_NON_NULL(1); void -xb_silo_invalidate(XbSilo *self); +xb_silo_invalidate(XbSilo *self) G_GNUC_NON_NULL(1); gboolean -xb_silo_is_valid(XbSilo *self); +xb_silo_is_valid(XbSilo *self) G_GNUC_NON_NULL(1); gboolean -xb_silo_watch_file(XbSilo *self, GFile *file, GCancellable *cancellable, GError **error); +xb_silo_watch_file(XbSilo *self, GFile *file, GCancellable *cancellable, GError **error) + G_GNUC_NON_NULL(1, 2); void -xb_silo_set_profile_flags(XbSilo *self, XbSiloProfileFlags profile_flags); +xb_silo_set_profile_flags(XbSilo *self, XbSiloProfileFlags profile_flags) G_GNUC_NON_NULL(1); const gchar * -xb_silo_get_profile_string(XbSilo *self); +xb_silo_get_profile_string(XbSilo *self) G_GNUC_NON_NULL(1); gboolean -xb_silo_get_enable_node_cache(XbSilo *self); +xb_silo_get_enable_node_cache(XbSilo *self) G_GNUC_NON_NULL(1); void -xb_silo_set_enable_node_cache(XbSilo *self, gboolean enable_node_cache); +xb_silo_set_enable_node_cache(XbSilo *self, gboolean enable_node_cache) G_GNUC_NON_NULL(1); #include "xb-query.h" XbQuery * -xb_silo_lookup_query(XbSilo *self, const gchar *xpath); +xb_silo_lookup_query(XbSilo *self, const gchar *xpath) G_GNUC_NON_NULL(1, 2); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-stack-private.h libxmlb-0.3.22/src/xb-stack-private.h --- libxmlb-0.3.10/src/xb-stack-private.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-stack-private.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once @@ -56,23 +56,24 @@ XbStack * xb_stack_new(guint max_size); void -xb_stack_unref(XbStack *self); +xb_stack_unref(XbStack *self) G_GNUC_NON_NULL(1); XbStack * -xb_stack_ref(XbStack *self); +xb_stack_ref(XbStack *self) G_GNUC_NON_NULL(1); guint -xb_stack_get_size(XbStack *self); +xb_stack_get_size(XbStack *self) G_GNUC_NON_NULL(1); guint -xb_stack_get_max_size(XbStack *self); +xb_stack_get_max_size(XbStack *self) G_GNUC_NON_NULL(1); gboolean -xb_stack_pop_two(XbStack *self, XbOpcode *opcode1_out, XbOpcode *opcode2_out, GError **error); +xb_stack_pop_two(XbStack *self, XbOpcode *opcode1_out, XbOpcode *opcode2_out, GError **error) + G_GNUC_NON_NULL(1); gboolean -xb_stack_push_bool(XbStack *self, gboolean val, GError **error); +xb_stack_push_bool(XbStack *self, gboolean val, GError **error) G_GNUC_NON_NULL(1); XbOpcode * -xb_stack_peek(XbStack *self, guint idx); +xb_stack_peek(XbStack *self, guint idx) G_GNUC_NON_NULL(1); XbOpcode * -xb_stack_peek_head(XbStack *self); +xb_stack_peek_head(XbStack *self) G_GNUC_NON_NULL(1); XbOpcode * -xb_stack_peek_tail(XbStack *self); +xb_stack_peek_tail(XbStack *self) G_GNUC_NON_NULL(1); G_DEFINE_AUTOPTR_CLEANUP_FUNC(XbStack, xb_stack_unref) diff -Nru libxmlb-0.3.10/src/xb-stack.c libxmlb-0.3.22/src/xb-stack.c --- libxmlb-0.3.10/src/xb-stack.c 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-stack.c 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #define G_LOG_DOMAIN "XbMachine" @@ -26,7 +26,7 @@ xb_stack_unref(XbStack *self) { g_assert(self->ref > 0); - if (--self->ref > 0) + if (G_UNLIKELY(--self->ref > 0)) return; for (guint i = 0; i < self->pos; i++) xb_opcode_clear(&self->opcodes[i]); @@ -66,7 +66,7 @@ gboolean xb_stack_pop(XbStack *self, XbOpcode *opcode_out, GError **error) { - if (self->pos == 0) { + if (G_UNLIKELY(self->pos == 0)) { g_set_error(error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "stack is empty"); return FALSE; } @@ -82,7 +82,7 @@ gboolean xb_stack_pop_two(XbStack *self, XbOpcode *opcode1_out, XbOpcode *opcode2_out, GError **error) { - if (self->pos < 2) { + if (G_UNLIKELY(self->pos < 2)) { g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, @@ -111,7 +111,7 @@ XbOpcode * xb_stack_peek(XbStack *self, guint idx) { - if (idx >= self->pos) + if (G_UNLIKELY(idx >= self->pos)) return NULL; return &self->opcodes[idx]; } @@ -163,7 +163,7 @@ gboolean xb_stack_push(XbStack *self, XbOpcode **opcode_out, GError **error) { - if (self->pos >= self->max_size) { + if (G_UNLIKELY(self->pos >= self->max_size)) { *opcode_out = NULL; g_set_error(error, G_IO_ERROR, diff -Nru libxmlb-0.3.10/src/xb-stack.h libxmlb-0.3.22/src/xb-stack.h --- libxmlb-0.3.10/src/xb-stack.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-stack.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once @@ -17,10 +17,10 @@ GType xb_stack_get_type(void); gchar * -xb_stack_to_string(XbStack *self); +xb_stack_to_string(XbStack *self) G_GNUC_NON_NULL(1); gboolean -xb_stack_pop(XbStack *self, XbOpcode *opcode_out, GError **error); +xb_stack_pop(XbStack *self, XbOpcode *opcode_out, GError **error) G_GNUC_NON_NULL(1); gboolean -xb_stack_push(XbStack *self, XbOpcode **opcode_out, GError **error); +xb_stack_push(XbStack *self, XbOpcode **opcode_out, GError **error) G_GNUC_NON_NULL(1, 2); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-string-private.h libxmlb-0.3.22/src/xb-string-private.h --- libxmlb-0.3.10/src/xb-string-private.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-string-private.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once @@ -13,7 +13,7 @@ G_BEGIN_DECLS guint -xb_string_replace(GString *str, const gchar *search, const gchar *replace); +xb_string_replace(GString *str, const gchar *search, const gchar *replace) G_GNUC_NON_NULL(1); gboolean xb_string_contains(const gchar *text, const gchar *search); gboolean @@ -36,8 +36,8 @@ } XbGuid; gchar * -xb_guid_to_string(XbGuid *guid); +xb_guid_to_string(XbGuid *guid) G_GNUC_NON_NULL(1); void -xb_guid_compute_for_data(XbGuid *out, const guint8 *buf, gsize bufsz); +xb_guid_compute_for_data(XbGuid *out, const guint8 *buf, gsize bufsz) G_GNUC_NON_NULL(1); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-string.c libxmlb-0.3.22/src/xb-string.c --- libxmlb-0.3.10/src/xb-string.c 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-string.c 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #define G_LOG_DOMAIN "XbSilo" diff -Nru libxmlb-0.3.10/src/xb-string.h libxmlb-0.3.22/src/xb-string.h --- libxmlb-0.3.10/src/xb-string.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-string.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,18 +1,19 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include +#include "xb-compile.h" G_BEGIN_DECLS void -xb_string_append_union(GString *xpath, const gchar *fmt, ...) G_GNUC_PRINTF(2, 3); +xb_string_append_union(GString *xpath, const gchar *fmt, ...) G_GNUC_PRINTF(2, 3) + G_GNUC_NON_NULL(1); gchar * -xb_string_escape(const gchar *str); +xb_string_escape(const gchar *str) G_GNUC_NON_NULL(1); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-tool.c libxmlb-0.3.22/src/xb-tool.c --- libxmlb-0.3.10/src/xb-tool.c 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-tool.c 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "config.h" diff -Nru libxmlb-0.3.10/src/xb-value-bindings-private.h libxmlb-0.3.22/src/xb-value-bindings-private.h --- libxmlb-0.3.10/src/xb-value-bindings-private.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-value-bindings-private.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,12 +1,16 @@ /* - * Copyright (C) 2022 Richard Hughes + * Copyright 2022 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include +#include "xb-silo.h" +#include "xb-value-bindings.h" gchar * -xb_value_bindings_to_string(XbValueBindings *self); +xb_value_bindings_to_string(XbValueBindings *self) G_GNUC_NON_NULL(1); +gboolean +xb_value_bindings_indexed_text_lookup(XbValueBindings *self, XbSilo *silo, GError **error) + G_GNUC_NON_NULL(1, 2); diff -Nru libxmlb-0.3.10/src/xb-value-bindings.c libxmlb-0.3.22/src/xb-value-bindings.c --- libxmlb-0.3.10/src/xb-value-bindings.c 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-value-bindings.c 2025-03-12 09:35:38.000000000 +0000 @@ -1,46 +1,44 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * vi:set noexpandtab tabstop=8 shiftwidth=8: * - * Copyright (C) 2020 Endless OS Foundation LLC + * Copyright 2020 Endless OS Foundation LLC * * Author: Philip Withnall * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #define G_LOG_DOMAIN "XbValueBindings" -#include "xb-value-bindings.h" - #include "config.h" #include #include "xb-opcode-private.h" +#include "xb-silo-private.h" #include "xb-value-bindings-private.h" typedef struct { - enum { - KIND_NONE, - KIND_TEXT, - KIND_INTEGER, - } kind; - union { - gchar *text; - guint32 integer; - }; + guint8 kind; /* XbBoundValueKind */ + guint32 val; + gpointer ptr; GDestroyNotify destroy_func; -} BoundValue; +} XbBoundValue; + +typedef enum { + XB_BOUND_VALUE_KIND_NONE, + XB_BOUND_VALUE_KIND_TEXT, + XB_BOUND_VALUE_KIND_INTEGER, + XB_BOUND_VALUE_KIND_INDEXED_TEXT, +} XbBoundValueKind; typedef struct { /* Currently limited to 4 values since that’s all that any client * uses. This could be expanded to dynamically allow more in future. */ - BoundValue values[4]; + XbBoundValue values[4]; gpointer dummy[3]; } RealValueBindings; -G_STATIC_ASSERT(sizeof(XbValueBindings) == sizeof(RealValueBindings)); - G_DEFINE_BOXED_TYPE(XbValueBindings, xb_value_bindings, xb_value_bindings_copy, @@ -64,7 +62,7 @@ RealValueBindings *_self = (RealValueBindings *)self; for (gsize i = 0; i < G_N_ELEMENTS(_self->values); i++) - _self->values[i].kind = KIND_NONE; + _self->values[i].kind = XB_BOUND_VALUE_KIND_NONE; } static void @@ -74,10 +72,10 @@ g_return_if_fail(idx < G_N_ELEMENTS(_self->values)); - if (_self->values[idx].kind == KIND_TEXT && _self->values[idx].destroy_func) - _self->values[idx].destroy_func(_self->values[idx].text); - _self->values[idx].kind = KIND_NONE; - _self->values[idx].text = NULL; + if (_self->values[idx].ptr != NULL && _self->values[idx].destroy_func) + _self->values[idx].destroy_func(_self->values[idx].ptr); + _self->values[idx].kind = XB_BOUND_VALUE_KIND_NONE; + _self->values[idx].ptr = NULL; _self->values[idx].destroy_func = NULL; } @@ -109,15 +107,21 @@ g_autoptr(GString) str = g_string_new(""); for (guint i = 0; i < G_N_ELEMENTS(_self->values); i++) { - BoundValue *value = &_self->values[i]; - if (value->kind == KIND_NONE) + XbBoundValue *value = &_self->values[i]; + if (value->kind == XB_BOUND_VALUE_KIND_NONE) continue; if (str->len > 0) g_string_append(str, ", "); - if (value->kind == KIND_INTEGER) - g_string_append_printf(str, "?%u → %u", i, value->integer); - else if (value->kind == KIND_TEXT) - g_string_append_printf(str, "?%u → %s", i, value->text); + if (value->kind == XB_BOUND_VALUE_KIND_INTEGER) + g_string_append_printf(str, "?%u → %u", i, value->val); + else if (value->kind == XB_BOUND_VALUE_KIND_TEXT && value->val > 0) + g_string_append_printf(str, + "?%u → %s [%u]", + i, + (const gchar *)value->ptr, + value->val); + else if (value->kind == XB_BOUND_VALUE_KIND_TEXT) + g_string_append_printf(str, "?%u → %s", i, (const gchar *)value->ptr); } return g_string_free(g_steal_pointer(&str), FALSE); } @@ -184,7 +188,8 @@ { RealValueBindings *_self = (RealValueBindings *)self; - return (idx < G_N_ELEMENTS(_self->values) && _self->values[idx].kind != KIND_NONE); + return (idx < G_N_ELEMENTS(_self->values) && + _self->values[idx].kind != XB_BOUND_VALUE_KIND_NONE); } /** @@ -220,8 +225,8 @@ xb_value_bindings_clear_index(self, idx); - _self->values[idx].kind = KIND_TEXT; - _self->values[idx].text = (gchar *)str; + _self->values[idx].kind = XB_BOUND_VALUE_KIND_TEXT; + _self->values[idx].ptr = (gpointer)str; _self->values[idx].destroy_func = destroy_func; } @@ -250,8 +255,8 @@ xb_value_bindings_clear_index(self, idx); - _self->values[idx].kind = KIND_INTEGER; - _self->values[idx].integer = val; + _self->values[idx].kind = XB_BOUND_VALUE_KIND_INTEGER; + _self->values[idx].val = val; _self->values[idx].destroy_func = NULL; } @@ -281,21 +286,28 @@ return FALSE; switch (_self->values[idx].kind) { - case KIND_TEXT: + case XB_BOUND_VALUE_KIND_TEXT: xb_opcode_init(opcode_out, XB_OPCODE_KIND_BOUND_TEXT, - _self->values[idx].text, + _self->values[idx].ptr, 0, NULL); break; - case KIND_INTEGER: + case XB_BOUND_VALUE_KIND_INTEGER: xb_opcode_init(opcode_out, XB_OPCODE_KIND_BOUND_INTEGER, NULL, - _self->values[idx].integer, + _self->values[idx].val, + NULL); + break; + case XB_BOUND_VALUE_KIND_INDEXED_TEXT: + xb_opcode_init(opcode_out, + XB_OPCODE_KIND_BOUND_INDEXED_TEXT, + _self->values[idx].ptr, + _self->values[idx].val, NULL); break; - case KIND_NONE: + case XB_BOUND_VALUE_KIND_NONE: default: g_assert_not_reached(); } @@ -326,21 +338,51 @@ guint dest_idx) { RealValueBindings *_self = (RealValueBindings *)self; + RealValueBindings *_dest = (RealValueBindings *)dest; if (!xb_value_bindings_is_bound(self, idx)) return FALSE; switch (_self->values[idx].kind) { - case KIND_TEXT: - xb_value_bindings_bind_str(dest, dest_idx, _self->values[idx].text, NULL); + case XB_BOUND_VALUE_KIND_TEXT: + xb_value_bindings_bind_str(dest, dest_idx, _self->values[idx].ptr, NULL); break; - case KIND_INTEGER: - xb_value_bindings_bind_val(dest, dest_idx, _self->values[idx].integer); + case XB_BOUND_VALUE_KIND_INTEGER: + xb_value_bindings_bind_val(dest, dest_idx, _self->values[idx].val); break; - case KIND_NONE: + case XB_BOUND_VALUE_KIND_INDEXED_TEXT: + xb_value_bindings_bind_str(dest, dest_idx, _self->values[idx].ptr, NULL); + _dest->values[idx].kind = XB_BOUND_VALUE_KIND_INDEXED_TEXT; + _dest->values[idx].val = _self->values[idx].val; + break; + case XB_BOUND_VALUE_KIND_NONE: default: g_assert_not_reached(); } return TRUE; } + +/* private */ +gboolean +xb_value_bindings_indexed_text_lookup(XbValueBindings *self, XbSilo *silo, GError **error) +{ + RealValueBindings *_self = (RealValueBindings *)self; + for (guint i = 0; i < G_N_ELEMENTS(_self->values); i++) { + XbBoundValue *value = &_self->values[i]; + if (value->kind == XB_BOUND_VALUE_KIND_TEXT) { + guint32 val = xb_silo_strtab_index_lookup(silo, (const gchar *)value->ptr); + if (val == XB_SILO_UNSET) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + "indexed string '%s' was unfound", + (const gchar *)value->ptr); + return FALSE; + } + value->kind = XB_BOUND_VALUE_KIND_INDEXED_TEXT; + value->val = val; + } + } + return TRUE; +} diff -Nru libxmlb-0.3.10/src/xb-value-bindings.h libxmlb-0.3.22/src/xb-value-bindings.h --- libxmlb-0.3.10/src/xb-value-bindings.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-value-bindings.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,11 +1,11 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * vi:set noexpandtab tabstop=8 shiftwidth=8: * - * Copyright (C) 2020 Endless OS Foundation LLC + * Copyright 2020 Endless OS Foundation LLC * * Author: Philip Withnall * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once @@ -25,15 +25,19 @@ */ typedef struct { /*< private >*/ - gint dummy0; - gpointer dummy1[2]; - gint dummy2; - gpointer dummy3[2]; - gint dummy4; + guint8 dummy0; + guint32 dummy1; + gpointer dummy2[2]; + guint8 dummy3; + guint32 dummy4; gpointer dummy5[2]; - gint dummy6; - gpointer dummy7[2]; - gpointer dummy8[3]; + guint8 dummy6; + guint32 dummy7; + gpointer dummy8[2]; + guint8 dummy9; + guint32 dummy10; + gpointer dummy11[2]; + gpointer dummy12[3]; } XbValueBindings; GType @@ -56,40 +60,44 @@ */ #define XB_VALUE_BINDINGS_INIT() \ { \ - 0, {NULL, NULL}, 0, {NULL, NULL}, 0, {NULL, NULL}, 0, {NULL, NULL}, { NULL, } \ + 0, 0, {NULL, NULL}, 0, 0, {NULL, NULL}, 0, 0, {NULL, NULL}, 0, 0, {NULL, NULL}, \ + { \ + NULL, \ + } \ } void -xb_value_bindings_init(XbValueBindings *self); +xb_value_bindings_init(XbValueBindings *self) G_GNUC_NON_NULL(1); void -xb_value_bindings_clear(XbValueBindings *self); +xb_value_bindings_clear(XbValueBindings *self) G_GNUC_NON_NULL(1); G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(XbValueBindings, xb_value_bindings_clear) XbValueBindings * -xb_value_bindings_copy(XbValueBindings *self); +xb_value_bindings_copy(XbValueBindings *self) G_GNUC_NON_NULL(1); void -xb_value_bindings_free(XbValueBindings *self); +xb_value_bindings_free(XbValueBindings *self) G_GNUC_NON_NULL(1); G_DEFINE_AUTOPTR_CLEANUP_FUNC(XbValueBindings, xb_value_bindings_free) gboolean -xb_value_bindings_is_bound(XbValueBindings *self, guint idx); +xb_value_bindings_is_bound(XbValueBindings *self, guint idx) G_GNUC_NON_NULL(1); void xb_value_bindings_bind_str(XbValueBindings *self, guint idx, const gchar *str, - GDestroyNotify destroy_func); + GDestroyNotify destroy_func) G_GNUC_NON_NULL(1); void -xb_value_bindings_bind_val(XbValueBindings *self, guint idx, guint32 val); +xb_value_bindings_bind_val(XbValueBindings *self, guint idx, guint32 val) G_GNUC_NON_NULL(1); gboolean -xb_value_bindings_lookup_opcode(XbValueBindings *self, guint idx, XbOpcode *opcode_out); +xb_value_bindings_lookup_opcode(XbValueBindings *self, guint idx, XbOpcode *opcode_out) + G_GNUC_NON_NULL(1, 3); gboolean xb_value_bindings_copy_binding(XbValueBindings *self, guint idx, XbValueBindings *dest, - guint dest_idx); + guint dest_idx) G_GNUC_NON_NULL(1, 3); G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-version.c libxmlb-0.3.22/src/xb-version.c --- libxmlb-0.3.10/src/xb-version.c 1970-01-01 00:00:00.000000000 +0000 +++ libxmlb-0.3.22/src/xb-version.c 2025-03-12 09:35:38.000000000 +0000 @@ -0,0 +1,25 @@ +/* + * Copyright 2024 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#include "config.h" + +#include "xb-version.h" + +/** + * xb_version_string: + * + * Gets the XMLb installed runtime version. + * + * Returns: a version number, e.g. "0.3.19" + * + * Since: 0.3.19 + **/ +const gchar * +xb_version_string(void) +{ + return G_STRINGIFY(XMLB_MAJOR_VERSION) "." G_STRINGIFY(XMLB_MINOR_VERSION) "." G_STRINGIFY( + XMLB_MICRO_VERSION); +} diff -Nru libxmlb-0.3.10/src/xb-version.h.in libxmlb-0.3.22/src/xb-version.h.in --- libxmlb-0.3.10/src/xb-version.h.in 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xb-version.h.in 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2015 Richard Hughes + * Copyright 2015 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ /** * SECTION:xb-version @@ -11,12 +11,9 @@ * depending on the version of libxmlb installed. */ -#if !defined (__LIBXMLB_H_INSIDE__) && !defined (LIBXMLB_COMPILATION) -#error "Only can be included directly." -#endif +#pragma once -#ifndef __LIBXMLB_VERSION_H -#define __LIBXMLB_VERSION_H +#include /** * XMLB_MAJOR_VERSION: @@ -60,4 +57,8 @@ (XMLB_MAJOR_VERSION == (major) && XMLB_MINOR_VERSION == (minor) && \ XMLB_MICRO_VERSION >= (micro))) -#endif /* __LIBXMLB_VERSION_H */ +G_BEGIN_DECLS + +const gchar *xb_version_string (void); + +G_END_DECLS diff -Nru libxmlb-0.3.10/src/xb-zstd-decompressor.c libxmlb-0.3.22/src/xb-zstd-decompressor.c --- libxmlb-0.3.10/src/xb-zstd-decompressor.c 1970-01-01 00:00:00.000000000 +0000 +++ libxmlb-0.3.22/src/xb-zstd-decompressor.c 2025-03-12 09:35:38.000000000 +0000 @@ -0,0 +1,113 @@ +/* + * Copyright 2022 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#include "config.h" + +#include +#include + +#include "xb-zstd-decompressor.h" + +static void +xb_zstd_decompressor_iface_init(GConverterIface *iface); + +struct _XbZstdDecompressor { + GObject parent_instance; + ZSTD_DStream *zstdstream; +}; + +G_DEFINE_TYPE_WITH_CODE(XbZstdDecompressor, + xb_zstd_decompressor, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE(G_TYPE_CONVERTER, xb_zstd_decompressor_iface_init)) + +static void +xb_zstd_decompressor_finalize(GObject *object) +{ + XbZstdDecompressor *self = XB_ZSTD_DECOMPRESSOR(object); + ZSTD_freeDStream(self->zstdstream); + G_OBJECT_CLASS(xb_zstd_decompressor_parent_class)->finalize(object); +} + +static void +xb_zstd_decompressor_init(XbZstdDecompressor *self) +{ +} + +static void +xb_zstd_decompressor_constructed(GObject *object) +{ + XbZstdDecompressor *self = XB_ZSTD_DECOMPRESSOR(object); + self->zstdstream = ZSTD_createDStream(); +} + +static void +xb_zstd_decompressor_class_init(XbZstdDecompressorClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + object_class->finalize = xb_zstd_decompressor_finalize; + object_class->constructed = xb_zstd_decompressor_constructed; +} + +XbZstdDecompressor * +xb_zstd_decompressor_new(void) +{ + return g_object_new(XB_TYPE_ZSTD_DECOMPRESSOR, NULL); +} + +static void +xb_zstd_decompressor_reset(GConverter *converter) +{ + XbZstdDecompressor *self = XB_ZSTD_DECOMPRESSOR(converter); + ZSTD_initDStream(self->zstdstream); +} + +static GConverterResult +xb_zstd_decompressor_convert(GConverter *converter, + const void *inbuf, + gsize inbuf_size, + void *outbuf, + gsize outbuf_size, + GConverterFlags flags, + gsize *bytes_read, + gsize *bytes_written, + GError **error) +{ + XbZstdDecompressor *self = XB_ZSTD_DECOMPRESSOR(converter); + ZSTD_outBuffer output = { + .dst = outbuf, + .size = outbuf_size, + .pos = 0, + }; + ZSTD_inBuffer input = { + .src = inbuf, + .size = inbuf_size, + .pos = 0, + }; + size_t res; + + res = ZSTD_decompressStream(self->zstdstream, &output, &input); + if (ZSTD_isError(res)) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "cannot decompress data: %s", + ZSTD_getErrorName(res)); + return G_CONVERTER_ERROR; + } + *bytes_read = input.pos; + *bytes_written = output.pos; + + /* success */ + return res == 0 ? G_CONVERTER_FINISHED : G_CONVERTER_CONVERTED; +} + +static void +xb_zstd_decompressor_iface_init(GConverterIface *iface) +{ + iface->convert = xb_zstd_decompressor_convert; + iface->reset = xb_zstd_decompressor_reset; +} diff -Nru libxmlb-0.3.10/src/xb-zstd-decompressor.h libxmlb-0.3.22/src/xb-zstd-decompressor.h --- libxmlb-0.3.10/src/xb-zstd-decompressor.h 1970-01-01 00:00:00.000000000 +0000 +++ libxmlb-0.3.22/src/xb-zstd-decompressor.h 2025-03-12 09:35:38.000000000 +0000 @@ -0,0 +1,19 @@ +/* + * Copyright 2022 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define XB_TYPE_ZSTD_DECOMPRESSOR (xb_zstd_decompressor_get_type()) +G_DECLARE_FINAL_TYPE(XbZstdDecompressor, xb_zstd_decompressor, XB, ZSTD_DECOMPRESSOR, GObject) + +XbZstdDecompressor * +xb_zstd_decompressor_new(void); + +G_END_DECLS diff -Nru libxmlb-0.3.10/src/xmlb.h libxmlb-0.3.22/src/xmlb.h --- libxmlb-0.3.10/src/xmlb.h 2022-09-11 10:09:18.000000000 +0000 +++ libxmlb-0.3.22/src/xmlb.h 2025-03-12 09:35:38.000000000 +0000 @@ -1,7 +1,7 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright 2018 Richard Hughes * - * SPDX-License-Identifier: LGPL-2.1+ + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once