From 68b19e686e7a1da2dd94a3c6b8825f85020fe20d Mon Sep 17 00:00:00 2001 From: Nastaliss Date: Tue, 6 Oct 2026 01:56:57 +0200 Subject: [PATCH 1/4] Publish Docker, not OCI, mediatypes so podman honours HEALTHCHECK (cherry picked from commit b179b6a49285d431ebba83f5d209bbcb77ceb844) --- .github/workflows/docker.yml | 107 ++++++++++++++++++++++++++++++++++- 1 file changed, 106 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 46cac9d2..16b539e5 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -6,6 +6,8 @@ # binaries natively on amd64 (via `cross`, NOT under QEMU) and `publish` # assembles the multi-arch image around them with `COPY` — compiling the # Rust+ring tree emulated for arm64 is what used to make publishing slow. +# `publish` then re-checks the pushed tag, because the image must carry Docker +# (not OCI) mediatypes for podman to honour its HEALTHCHECK; see that step. # Pull with: # docker run -d -p 3310:3310 -v exav-db:/var/lib/exav ghcr.io/sylvinus/exav name: docker @@ -125,9 +127,112 @@ jobs: with: context: . platforms: linux/amd64,linux/arm64 - push: true # Take bins/exav-$TARGETARCH from the `binaries` job instead of # compiling in-image (Dockerfile documents both branches). build-args: BIN_SOURCE=prebuilt tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} + # Publish Docker manifest-list/schema2 mediatypes rather than OCI + # ones, so that podman honours the image's HEALTHCHECK. + # + # `Healthcheck` is a Docker config extension with no equivalent in + # the OCI image spec. Nothing strips it: flipping this exporter + # option leaves the config blob byte-identical (same sha256), and + # only the declared mediatype changes. But podman reads the field + # back solely from a schema2 config — containers/common fills + # `HealthCheck` in the `DockerV2Schema2MediaType` branch of + # libimage/inspect.go and in no other branch — so under OCI + # mediatypes it reports "has no defined healthcheck" however healthy + # the daemon actually is. That leaves a rootless podman deployment + # with no readiness signal at all: the image is distroless, so a + # compose-level `test:` has no shell to run in either. Docker reads + # the field from both configs, so this is a no-op for `docker run`. + # + # `provenance: false` is load-bearing, not tidying: attestations can + # only be referenced from an OCI index, so buildx's default + # provenance attestation would force OCI mediatypes straight back. + # Attaching SLSA provenance as a separate referrer instead (e.g. + # actions/attest-build-provenance with push-to-registry) leaves the + # image's own mediatype alone. + # + # `push` moves into `outputs` so there is a single image exporter + # making a single mediatype decision. + provenance: false + outputs: type=image,oci-mediatypes=false,push=true + + # The `build-test` job above smoke-tests a locally `load`ed image, which + # cannot catch a *push-time* mediatype change — the exporter is what + # differs. These two steps therefore run against the pushed tag. + - name: Assert the published manifest is a Docker manifest list + env: + # Via env: rather than inlined into `run:`, so a tag reaches bash as + # data and not as code. + TAGS: ${{ steps.meta.outputs.tags }} + EXPECTED: application/vnd.docker.distribution.manifest.list.v2+json + run: | + set -euo pipefail + # Every tag in the set points at the same index, so one is enough. + TAG=$(printf '%s\n' "$TAGS" | head -1) + docker buildx imagetools inspect "$TAG" --raw > "$RUNNER_TEMP/manifest.json" + GOT=$(jq -r '.mediaType' "$RUNNER_TEMP/manifest.json") + echo "$TAG -> $GOT" + if [ "$GOT" != "$EXPECTED" ]; then + echo "::error::published $GOT, expected $EXPECTED -- podman will ignore the image HEALTHCHECK" + exit 1 + fi + + # The assertion above pins the wire format; this one tests the consumer + # that the format exists for. podman is preinstalled on ubuntu-latest. + - name: Verify podman sees the HEALTHCHECK on the published image + env: + TAGS: ${{ steps.meta.outputs.tags }} + REGISTRY_USER: ${{ github.actor }} + REGISTRY_PASSWORD: ${{ secrets.GITHUB_TOKEN }} + run: | + set -euo pipefail + TAG=$(printf '%s\n' "$TAGS" | head -1) + podman --version + # Log in rather than relying on an anonymous pull: a GHCR package + # starts out private, so the very first publish of a fork would + # otherwise fail here for the wrong reason. + podman login ghcr.io -u "$REGISTRY_USER" --password-stdin <<<"$REGISTRY_PASSWORD" + podman pull -q "$TAG" + + # This coming back empty *is* the regression being guarded against: + # podman populates it only from a Docker schema2 config. + IMAGE_HC=$(podman image inspect \ + --format '{{if .HealthCheck}}{{.HealthCheck.Test}}{{end}}' "$TAG") + echo "image healthcheck: ${IMAGE_HC:-}" + if [ -z "$IMAGE_HC" ]; then + echo "::error::podman reports no healthcheck on $TAG" + exit 1 + fi + + # Same env as the `build-test` smoke test: no mirror configured, so + # opt into the built-in EICAR-only baseline and skip the wait for a + # sidecar that is not coming. + podman run -d --name exav-podman \ + -e EXAV_STARTUP_WAIT_SECS=0 -e EXAV_ALLOW_NO_DB=1 "$TAG" + CONTAINER_HC=$(podman inspect \ + --format '{{if .Config.Healthcheck}}{{.Config.Healthcheck.Test}}{{end}}' exav-podman) + echo "container healthcheck: ${CONTAINER_HC:-}" + if [ -z "$CONTAINER_HC" ]; then + echo "::error::healthcheck did not reach the container config" + podman rm -f exav-podman + exit 1 + fi + + # `/exav --ping` answers only once the database is loaded, so poll + # instead of asserting on the first probe. + for _ in $(seq 60); do + if podman healthcheck run exav-podman; then + echo "podman reports: $(podman inspect --format '{{.State.Health.Status}}' exav-podman)" + podman rm -f exav-podman + exit 0 + fi + sleep 1 + done + echo "::error::podman healthcheck never passed" + podman logs exav-podman + podman rm -f exav-podman + exit 1 From 503ec3b3fec280f9067077d2ea6754b30e8df12f Mon Sep 17 00:00:00 2001 From: Sylvain Zimmer Date: Sun, 11 Oct 2026 23:27:19 +0200 Subject: [PATCH 2/4] Release 0.0.2: streaming scans, render and viewer crates, fuzzing - Streaming scan core: every object goes through one scan whatever its size, large objects read through a bounded block cache, with the engine, unpacking and spill paths reworked around it. - New crates: exav-imagehash (perceptual image hashes), exav-render (DWG, DXF, IFC, STL, image decoders) and @exav/viewer, the browser viewer with its sandboxed frame and e2e suite. - Arithmetic and overflow audit across the extractors, the signature engine and the emulator, with a regression test for each fix. - Fuzzing: 26 targets (YARA, PCRE, clamd, ICAP, volumes, seekable readers, database and signature loaders, authenticode), signature files and synthesized seeds, dictionaries, a nightly campaign and a corpus cache in CI. Bugs it found are fixed and logged in docs/FUZZING.md. - Release prep: changelog cut, release gate and CI fixes. --- .github/workflows/ci.yml | 92 +- .github/workflows/docker.yml | 28 +- .github/workflows/fuzz-nightly.yml | 58 + .github/workflows/release.yml | 43 +- .github/workflows/www.yml | 37 +- .gitignore | 4 +- .oss-scanner/Dockerfile | 44 + .oss-scanner/Dockerfile.dockerignore | 10 + .oss-scanner/threat_model.md | 111 + CHANGELOG.md | 931 +- CONTRIBUTING.md | 56 +- Cargo.lock | 1179 +- Cargo.toml | 29 +- Dockerfile | 50 +- Makefile | 96 +- NOTICE | 438 +- README.md | 88 +- SECURITY.md | 97 +- crates/exav-core/Cargo.toml | 127 +- crates/exav-core/NOTICE | 509 +- crates/exav-core/README.md | 4 +- crates/exav-core/examples/bc_scan.rs | 6 +- crates/exav-core/examples/diag.rs | 30 + crates/exav-core/examples/dump_bc.rs | 1 + crates/exav-core/examples/skipcensus.rs | 2 +- crates/exav-core/examples/sweepbench.rs | 64 + crates/exav-core/examples/triage_bc.rs | 1 + crates/exav-core/src/authenticode/mod.rs | 117 +- crates/exav-core/src/bin/exav-wasm.rs | 84 +- crates/exav-core/src/byte_source.rs | 4 + crates/exav-core/src/bytecode/exec.rs | 854 +- crates/exav-core/src/bytecode/instr.rs | 2 +- crates/exav-core/src/bytecode/runtime.rs | 343 +- crates/exav-core/src/bytes.rs | 24 + crates/exav-core/src/cvd.rs | 2 +- crates/exav-core/src/database.rs | 689 +- crates/exav-core/src/dlp.rs | 68 +- crates/exav-core/src/engine/logic.rs | 176 +- crates/exav-core/src/engine/mod.rs | 4822 ++++-- crates/exav-core/src/engine/parse.rs | 174 +- crates/exav-core/src/engine/pcre.rs | 1789 +++ crates/exav-core/src/engine/pins.rs | 279 + crates/exav-core/src/fancy_regex/LICENSE | 21 + crates/exav-core/src/fancy_regex/README.md | 84 + crates/exav-core/src/fancy_regex/analyze.rs | 2426 ++++ crates/exav-core/src/fancy_regex/bytes/mod.rs | 63 + crates/exav-core/src/fancy_regex/compile.rs | 2367 +++ crates/exav-core/src/fancy_regex/error.rs | 216 + crates/exav-core/src/fancy_regex/expand.rs | 273 + crates/exav-core/src/fancy_regex/input.rs | 355 + crates/exav-core/src/fancy_regex/mod.rs | 3387 +++++ crates/exav-core/src/fancy_regex/optimize.rs | 1006 ++ crates/exav-core/src/fancy_regex/parse.rs | 4473 ++++++ .../exav-core/src/fancy_regex/parse_flags.rs | 18 + crates/exav-core/src/fancy_regex/regexset.rs | 1018 ++ crates/exav-core/src/fancy_regex/replacer.rs | 162 + crates/exav-core/src/fancy_regex/seek.rs | 724 + crates/exav-core/src/fancy_regex/to_hir.rs | 320 + crates/exav-core/src/fancy_regex/vm.rs | 1862 +++ crates/exav-core/src/filetype.rs | 142 +- crates/exav-core/src/fuzzy.rs | 29 +- crates/exav-core/src/fuzzy_img.rs | 168 - crates/exav-core/src/grams/mod.rs | 976 ++ crates/exav-core/src/grams/rarity.rs | 210 + crates/exav-core/src/grams/sweep.rs | 219 + crates/exav-core/src/hashes.rs | 415 +- crates/exav-core/src/icon.rs | 84 +- crates/exav-core/src/jsnorm.rs | 1001 +- crates/exav-core/src/lib.rs | 5272 ++++--- crates/exav-core/src/loader.rs | 420 +- crates/exav-core/src/ml.rs | 2 +- crates/exav-core/src/normalize.rs | 325 +- crates/exav-core/src/patterns.rs | 261 +- crates/exav-core/src/pe.rs | 1163 +- crates/exav-core/src/phishing.rs | 164 +- crates/exav-core/src/profile.rs | 82 +- crates/exav-core/src/source.rs | 160 +- crates/exav-core/src/spill.rs | 179 + crates/exav-core/src/stream_regex.rs | 369 + crates/exav-core/src/yara/atoms.rs | 409 +- crates/exav-core/src/yara/compiler.rs | 2 + crates/exav-core/src/yara/ir.rs | 11 +- crates/exav-core/src/yara/matcher.rs | 543 +- crates/exav-core/src/yara/mod.rs | 170 +- crates/exav-core/src/yara/modules/dotnet.rs | 35 +- crates/exav-core/src/yara/modules/elf.rs | 10 +- crates/exav-core/src/yara/modules/hash.rs | 71 +- crates/exav-core/src/yara/modules/math.rs | 269 +- crates/exav-core/src/yara/modules/mod.rs | 37 +- crates/exav-core/src/yara/scanner.rs | 412 +- crates/exav-core/tests/fixtures/pe/icon32.exe | Bin 0 -> 5632 bytes .../tests/fixtures/pe/make_icon_pe.py | 63 + .../exav-core/tests/suites/allmatch_parity.rs | 17 +- crates/exav-core/tests/suites/authenticode.rs | 26 + crates/exav-core/tests/suites/base64_scan.rs | 31 + .../tests/suites/broken_executable.rs | 766 + .../exav-core/tests/suites/bytecode_gating.rs | 128 +- .../tests/suites/checksum_mismatch.rs | 305 + .../tests/suites/cut_short_members.rs | 490 + .../exav-core/tests/suites/embedded_carve.rs | 127 + .../tests/suites/encrypted_archives.rs | 30 + .../tests/suites/fuzzy_img_formats.rs | 97 + .../tests/suites/heuristic_alerts.rs | 157 + .../exav-core/tests/suites/heuristic_names.rs | 119 +- .../exav-core/tests/suites/limits_alerts.rs | 77 + crates/exav-core/tests/suites/mod.rs | 15 + crates/exav-core/tests/suites/one_scan.rs | 94 + .../tests/suites/oversize_container.rs | 147 +- crates/exav-core/tests/suites/salvage.rs | 360 +- crates/exav-core/tests/suites/sevenz_ppmd.rs | 89 + crates/exav-core/tests/suites/size_caps.rs | 236 + crates/exav-core/tests/suites/target_text.rs | 77 + .../suites/untyped_container_dispatch.rs | 260 + crates/exav-core/tests/suites/yara_dotnet.rs | 41 + .../exav-core/tests/suites/zip_dual_index.rs | 211 +- crates/exav-core/tests/suites/zip_ppmd.rs | 90 + .../exav-core/tests/yara_coverage_difftest.rs | 26 +- crates/exav-core/tests/yara_difftest.rs | 27 +- crates/exav-core/tests/yara_elf_module.rs | 38 + crates/exav-grep/Cargo.toml | 2 +- crates/exav-grep/NOTICE | 486 +- crates/exav-grep/README.md | 14 +- crates/exav-grep/src/lib.rs | 103 +- crates/exav-grep/src/main.rs | 2 +- crates/exav-imagehash/Cargo.toml | 66 + crates/exav-imagehash/LICENSE | 21 + crates/exav-imagehash/NOTICE | 43 + crates/exav-imagehash/README.md | 77 + crates/exav-imagehash/src/LICENSE-pillow | 30 + crates/exav-imagehash/src/LICENSE-rustdct | 19 + crates/exav-imagehash/src/dct.rs | 677 + crates/exav-imagehash/src/lib.rs | 698 + crates/exav-imagehash/src/main.rs | 263 + crates/exav-imagehash/src/pillow.rs | 319 + crates/exav-imagehash/src/tests.rs | 330 + .../tests/fixtures/decoder_sensitive.jpg | Bin 0 -> 2543 bytes .../tests/fixtures/expected.txt | 34 + .../exav-imagehash/tests/fixtures/generate.py | 71 + .../tests/fixtures/img/bilevel.bmp | Bin 0 -> 1038 bytes .../tests/fixtures/img/bilevel.pbm | Bin 0 -> 802 bytes .../tests/fixtures/img/bilevel.png | Bin 0 -> 922 bytes .../exav-imagehash/tests/fixtures/img/bmp.ico | Bin 0 -> 4158 bytes .../tests/fixtures/img/cmyk.tif | Bin 0 -> 23810 bytes .../tests/fixtures/img/deflate.tif | Bin 0 -> 17436 bytes .../exav-imagehash/tests/fixtures/img/i16.png | Bin 0 -> 3375 bytes .../exav-imagehash/tests/fixtures/img/l.jpg | Bin 0 -> 1521 bytes .../exav-imagehash/tests/fixtures/img/l.pgm | Bin 0 -> 5930 bytes .../exav-imagehash/tests/fixtures/img/l.png | Bin 0 -> 2978 bytes .../exav-imagehash/tests/fixtures/img/l.tif | Bin 0 -> 6039 bytes .../exav-imagehash/tests/fixtures/img/la.png | Bin 0 -> 3375 bytes .../tests/fixtures/img/lossless.webp | Bin 0 -> 4678 bytes .../tests/fixtures/img/lossy.webp | Bin 0 -> 990 bytes .../exav-imagehash/tests/fixtures/img/lzw.tif | Bin 0 -> 23266 bytes .../exav-imagehash/tests/fixtures/img/p.bmp | Bin 0 -> 7178 bytes .../exav-imagehash/tests/fixtures/img/p.png | Bin 0 -> 2564 bytes .../tests/fixtures/img/p_trns.png | Bin 0 -> 1631 bytes .../exav-imagehash/tests/fixtures/img/rgb.bmp | Bin 0 -> 17866 bytes .../exav-imagehash/tests/fixtures/img/rgb.gif | Bin 0 -> 5230 bytes .../exav-imagehash/tests/fixtures/img/rgb.jpg | Bin 0 -> 2377 bytes .../exav-imagehash/tests/fixtures/img/rgb.png | Bin 0 -> 9146 bytes .../exav-imagehash/tests/fixtures/img/rgb.ppm | Bin 0 -> 17764 bytes .../exav-imagehash/tests/fixtures/img/rgb.qoi | Bin 0 -> 22687 bytes .../exav-imagehash/tests/fixtures/img/rgb.tif | Bin 0 -> 17891 bytes .../tests/fixtures/img/rgb16.ppm | Bin 0 -> 35517 bytes .../tests/fixtures/img/rgba.bmp | Bin 0 -> 23722 bytes .../tests/fixtures/img/rgba.ico | Bin 0 -> 4895 bytes .../tests/fixtures/img/rgba.png | Bin 0 -> 9863 bytes .../tests/fixtures/img/rgba.qoi | Bin 0 -> 29607 bytes .../tests/fixtures/img/rgba.webp | Bin 0 -> 5060 bytes .../tests/fixtures/img/trns.gif | Bin 0 -> 2363 bytes crates/exav-imagehash/tests/memory.rs | 53 + crates/exav-imagehash/tests/reference.rs | 46 + crates/exav-pe-emu/Cargo.toml | 7 +- crates/exav-pe-emu/NOTICE | 486 +- crates/exav-pe-emu/src/cpu.rs | 92 +- crates/exav-pe-emu/src/main.rs | 7 +- crates/exav-pe-emu/src/mem.rs | 27 +- crates/exav-pe-emu/src/run.rs | 81 +- crates/exav-pe-emu/src/win.rs | 313 +- crates/exav-render/Cargo.toml | 153 + crates/exav-render/LICENSE | 21 + crates/exav-render/README.md | 57 + crates/exav-render/build.rs | 50 + crates/exav-render/examples/cad_dump.rs | 48 + crates/exav-render/examples/ifc_stats.rs | 125 + crates/exav-render/examples/scene_stats.rs | 425 + crates/exav-render/fonts/LICENSE-CC0-1.0.txt | 121 + crates/exav-render/fonts/newstroke.bene | 12076 ++++++++++++++++ crates/exav-render/scripts/font-tables.py | 200 + .../exav-render/src/formats/cad/dwg/blocks.rs | 571 + .../src/formats/cad/dwg/entities.rs | 1995 +++ .../exav-render/src/formats/cad/dwg/header.rs | 457 + crates/exav-render/src/formats/cad/dwg/mod.rs | 297 + .../src/formats/cad/dwg/objects.rs | 590 + .../exav-render/src/formats/cad/dwg/tables.rs | 613 + .../exav-render/src/formats/cad/dxf/build.rs | 339 + .../src/formats/cad/dxf/entities.rs | 1634 +++ .../exav-render/src/formats/cad/dxf/header.rs | 112 + crates/exav-render/src/formats/cad/dxf/mod.rs | 484 + .../src/formats/cad/dxf/objects.rs | 264 + .../exav-render/src/formats/cad/dxf/tables.rs | 291 + .../exav-render/src/formats/cad/dxf/tests.rs | 246 + crates/exav-render/src/formats/cad/json.rs | 1283 ++ crates/exav-render/src/formats/cad/mod.rs | 112 + crates/exav-render/src/formats/cad/model.rs | 475 + .../src/formats/cad/model/entity.rs | 1450 ++ .../src/formats/cad/model/objects.rs | 282 + .../src/formats/cad/model/proxy.rs | 215 + .../src/formats/cad/model/tables.rs | 245 + crates/exav-render/src/formats/cad/preview.rs | 126 + crates/exav-render/src/formats/cad/proxy.rs | 580 + crates/exav-render/src/formats/dwg/DESIGN.md | 244 + crates/exav-render/src/formats/dwg/clip.rs | 440 + crates/exav-render/src/formats/dwg/curves.rs | 827 ++ crates/exav-render/src/formats/dwg/fill.rs | 554 + crates/exav-render/src/formats/dwg/font.rs | 718 + .../exav-render/src/formats/dwg/gradient.rs | 430 + crates/exav-render/src/formats/dwg/hatch.rs | 759 + .../exav-render/src/formats/dwg/linetype.rs | 582 + crates/exav-render/src/formats/dwg/metrics.rs | 584 + crates/exav-render/src/formats/dwg/mod.rs | 384 + crates/exav-render/src/formats/dwg/palette.rs | 639 + crates/exav-render/src/formats/dwg/proxy.rs | 635 + crates/exav-render/src/formats/dwg/scene.rs | 960 ++ .../src/formats/dwg/stroke_font/binary.rs | 305 + .../src/formats/dwg/stroke_font/fontobene.rs | 516 + .../src/formats/dwg/stroke_font/mod.rs | 492 + .../exav-render/src/formats/dwg/tessellate.rs | 3034 ++++ crates/exav-render/src/formats/dwg/text.rs | 1097 ++ crates/exav-render/src/formats/dwg/tiles.rs | 366 + crates/exav-render/src/formats/ifc/csg.rs | 440 + crates/exav-render/src/formats/ifc/curves.rs | 493 + crates/exav-render/src/formats/ifc/items.rs | 594 + crates/exav-render/src/formats/ifc/math.rs | 159 + crates/exav-render/src/formats/ifc/mod.rs | 884 ++ .../exav-render/src/formats/ifc/profiles.rs | 581 + crates/exav-render/src/formats/ifc/solids.rs | 1075 ++ crates/exav-render/src/formats/ifc/step.rs | 900 ++ .../src/formats/ifc/triangulate.rs | 440 + crates/exav-render/src/formats/image.rs | 431 + crates/exav-render/src/formats/image/jbig2.rs | 72 + crates/exav-render/src/formats/image/jp2.rs | 48 + crates/exav-render/src/formats/image/tests.rs | 327 + crates/exav-render/src/formats/mesh.rs | 509 + crates/exav-render/src/formats/mod.rs | 16 + .../src/formats/pdf_image/ccitt.rs | 144 + .../src/formats/pdf_image/jbig2.rs | 223 + .../exav-render/src/formats/pdf_image/jpx.rs | 715 + .../exav-render/src/formats/pdf_image/mod.rs | 54 + crates/exav-render/src/formats/stl.rs | 273 + .../src/image_codecs/LICENSE-image | 25 + crates/exav-render/src/image_codecs/README.md | 58 + crates/exav-render/src/image_codecs/jpeg.rs | 144 + crates/exav-render/src/image_codecs/mod.rs | 22 + .../exav-render/src/image_codecs/tiff/LICENSE | 21 + .../src/image_codecs/tiff/bytecast.rs | 35 + .../src/image_codecs/tiff/decoder/cycles.rs | 169 + .../src/image_codecs/tiff/decoder/ifd.rs | 715 + .../src/image_codecs/tiff/decoder/image.rs | 749 + .../src/image_codecs/tiff/decoder/mod.rs | 1579 ++ .../src/image_codecs/tiff/decoder/stream.rs | 402 + .../image_codecs/tiff/decoder/tag_reader.rs | 57 + .../src/image_codecs/tiff/directory.rs | 166 + .../src/image_codecs/tiff/error.rs | 226 + .../exav-render/src/image_codecs/tiff/mod.rs | 63 + .../exav-render/src/image_codecs/tiff/tags.rs | 273 + .../src/image_codecs/tiff_image.rs | 352 + crates/exav-render/src/lib.rs | 44 + .../exav-render/tests/cad_common/compare.rs | 909 ++ crates/exav-render/tests/cad_common/mod.rs | 110 + crates/exav-render/tests/cad_dwg.rs | 493 + crates/exav-render/tests/cad_dwg_oracle.rs | 1173 ++ crates/exav-render/tests/cad_fixtures.rs | 232 + crates/exav-render/tests/cad_oracle.rs | 545 + .../tests/cad_oracle/ezdxf_dump.py | 1267 ++ crates/exav-render/tests/cad_proxy.rs | 367 + crates/exav-render/tests/cad_robust.rs | 233 + crates/exav-render/tests/dwg.rs | 526 + .../tests/fixtures/cad/ascii/R12/all.dxf.gz | Bin 0 -> 14915 bytes .../fixtures/cad/ascii/R12/cp1251.dxf.gz | Bin 0 -> 1596 bytes .../tests/fixtures/cad/ascii/R2000/all.dxf.gz | Bin 0 -> 21043 bytes .../fixtures/cad/ascii/R2000/cp1251.dxf.gz | Bin 0 -> 8580 bytes .../tests/fixtures/cad/ascii/R2004/all.dxf.gz | Bin 0 -> 21374 bytes .../fixtures/cad/ascii/R2004/cp1251.dxf.gz | Bin 0 -> 8965 bytes .../tests/fixtures/cad/ascii/R2007/all.dxf.gz | Bin 0 -> 21228 bytes .../fixtures/cad/ascii/R2007/cp1251.dxf.gz | Bin 0 -> 9102 bytes .../tests/fixtures/cad/ascii/R2010/all.dxf.gz | Bin 0 -> 20687 bytes .../fixtures/cad/ascii/R2010/cp1251.dxf.gz | Bin 0 -> 8191 bytes .../tests/fixtures/cad/ascii/R2013/all.dxf.gz | Bin 0 -> 19514 bytes .../fixtures/cad/ascii/R2013/cp1251.dxf.gz | Bin 0 -> 7005 bytes .../tests/fixtures/cad/ascii/R2018/all.dxf.gz | Bin 0 -> 19443 bytes .../fixtures/cad/ascii/R2018/cp1251.dxf.gz | Bin 0 -> 6913 bytes .../tests/fixtures/cad/binary/R12/all.dxf.gz | Bin 0 -> 14241 bytes .../fixtures/cad/binary/R12/cp1251.dxf.gz | Bin 0 -> 1521 bytes .../fixtures/cad/binary/R2000/all.dxf.gz | Bin 0 -> 19477 bytes .../fixtures/cad/binary/R2000/cp1251.dxf.gz | Bin 0 -> 7688 bytes .../fixtures/cad/binary/R2004/all.dxf.gz | Bin 0 -> 19797 bytes .../fixtures/cad/binary/R2004/cp1251.dxf.gz | Bin 0 -> 8039 bytes .../fixtures/cad/binary/R2007/all.dxf.gz | Bin 0 -> 19676 bytes .../fixtures/cad/binary/R2007/cp1251.dxf.gz | Bin 0 -> 8150 bytes .../fixtures/cad/binary/R2010/all.dxf.gz | Bin 0 -> 19180 bytes .../fixtures/cad/binary/R2010/cp1251.dxf.gz | Bin 0 -> 7553 bytes .../fixtures/cad/binary/R2013/all.dxf.gz | Bin 0 -> 18026 bytes .../fixtures/cad/binary/R2013/cp1251.dxf.gz | Bin 0 -> 6385 bytes .../fixtures/cad/binary/R2018/all.dxf.gz | Bin 0 -> 17971 bytes .../fixtures/cad/binary/R2018/cp1251.dxf.gz | Bin 0 -> 6310 bytes .../tests/fixtures/cad/dwg/R13/all.dwg.gz | Bin 0 -> 28410 bytes .../tests/fixtures/cad/dwg/R13/c7.dwg.gz | Bin 0 -> 11365 bytes .../tests/fixtures/cad/dwg/R13/cp1251.dwg.gz | Bin 0 -> 9533 bytes .../fixtures/cad/dwg/R13/dwgcases.dwg.gz | Bin 0 -> 9786 bytes .../fixtures/cad/dwg/R13/entities.dwg.gz | Bin 0 -> 17561 bytes .../tests/fixtures/cad/dwg/R13/objects.dwg.gz | Bin 0 -> 15806 bytes .../tests/fixtures/cad/dwg/R14/all.dwg.gz | Bin 0 -> 26281 bytes .../tests/fixtures/cad/dwg/R14/c7.dwg.gz | Bin 0 -> 10991 bytes .../tests/fixtures/cad/dwg/R14/cp1251.dwg.gz | Bin 0 -> 9647 bytes .../fixtures/cad/dwg/R14/dwgcases.dwg.gz | Bin 0 -> 9916 bytes .../fixtures/cad/dwg/R14/entities.dwg.gz | Bin 0 -> 17468 bytes .../tests/fixtures/cad/dwg/R14/objects.dwg.gz | Bin 0 -> 15763 bytes .../tests/fixtures/cad/dwg/R2000/all.dwg.gz | Bin 0 -> 24190 bytes .../tests/fixtures/cad/dwg/R2000/c7.dwg.gz | Bin 0 -> 10964 bytes .../fixtures/cad/dwg/R2000/cp1251.dwg.gz | Bin 0 -> 9743 bytes .../fixtures/cad/dwg/R2000/dwgcases.dwg.gz | Bin 0 -> 10066 bytes .../fixtures/cad/dwg/R2000/entities.dwg.gz | Bin 0 -> 15691 bytes .../fixtures/cad/dwg/R2000/objects.dwg.gz | Bin 0 -> 13901 bytes .../tests/fixtures/cad/dwg/R2004/all.dwg.gz | Bin 0 -> 27532 bytes .../tests/fixtures/cad/dwg/R2004/c7.dwg.gz | Bin 0 -> 13146 bytes .../fixtures/cad/dwg/R2004/cp1251.dwg.gz | Bin 0 -> 11856 bytes .../fixtures/cad/dwg/R2004/dwgcases.dwg.gz | Bin 0 -> 11855 bytes .../fixtures/cad/dwg/R2004/entities.dwg.gz | Bin 0 -> 18081 bytes .../fixtures/cad/dwg/R2004/objects.dwg.gz | Bin 0 -> 16244 bytes .../tests/fixtures/cad/dwg/R2007/all.dwg.gz | Bin 0 -> 34167 bytes .../tests/fixtures/cad/dwg/R2007/c7.dwg.gz | Bin 0 -> 18763 bytes .../fixtures/cad/dwg/R2007/cp1251.dwg.gz | Bin 0 -> 17417 bytes .../fixtures/cad/dwg/R2007/dwgcases.dwg.gz | Bin 0 -> 17681 bytes .../fixtures/cad/dwg/R2007/entities.dwg.gz | Bin 0 -> 24734 bytes .../fixtures/cad/dwg/R2007/objects.dwg.gz | Bin 0 -> 21664 bytes .../tests/fixtures/cad/dwg/R2010/all.dwg.gz | Bin 0 -> 27194 bytes .../tests/fixtures/cad/dwg/R2010/c7.dwg.gz | Bin 0 -> 12603 bytes .../fixtures/cad/dwg/R2010/cp1251.dwg.gz | Bin 0 -> 11320 bytes .../fixtures/cad/dwg/R2010/dwgcases.dwg.gz | Bin 0 -> 11558 bytes .../fixtures/cad/dwg/R2010/entities.dwg.gz | Bin 0 -> 17743 bytes .../fixtures/cad/dwg/R2010/objects.dwg.gz | Bin 0 -> 15969 bytes .../tests/fixtures/cad/dwg/R2013/all.dwg.gz | Bin 0 -> 24997 bytes .../tests/fixtures/cad/dwg/R2013/c7.dwg.gz | Bin 0 -> 10295 bytes .../fixtures/cad/dwg/R2013/cp1251.dwg.gz | Bin 0 -> 9353 bytes .../fixtures/cad/dwg/R2013/dwgcases.dwg.gz | Bin 0 -> 9510 bytes .../fixtures/cad/dwg/R2013/entities.dwg.gz | Bin 0 -> 15937 bytes .../fixtures/cad/dwg/R2013/objects.dwg.gz | Bin 0 -> 13861 bytes .../tests/fixtures/cad/dwg/R2018/all.dwg.gz | Bin 0 -> 25006 bytes .../tests/fixtures/cad/dwg/R2018/c7.dwg.gz | Bin 0 -> 10108 bytes .../fixtures/cad/dwg/R2018/cp1251.dwg.gz | Bin 0 -> 9164 bytes .../fixtures/cad/dwg/R2018/dwgcases.dwg.gz | Bin 0 -> 9308 bytes .../fixtures/cad/dwg/R2018/entities.dwg.gz | Bin 0 -> 15102 bytes .../fixtures/cad/dwg/R2018/objects.dwg.gz | Bin 0 -> 13657 bytes .../tests/fixtures/cad/expected.json | 1518 ++ crates/exav-render/tests/fixtures/cad/make.py | 961 ++ .../fixtures/cad/proxy/dwg/R13/proxy.dwg.gz | Bin 0 -> 15795 bytes .../fixtures/cad/proxy/dwg/R14/proxy.dwg.gz | Bin 0 -> 15774 bytes .../fixtures/cad/proxy/dwg/R2000/proxy.dwg.gz | Bin 0 -> 14147 bytes .../fixtures/cad/proxy/dwg/R2004/proxy.dwg.gz | Bin 0 -> 16434 bytes .../fixtures/cad/proxy/dwg/R2007/proxy.dwg.gz | Bin 0 -> 23203 bytes .../fixtures/cad/proxy/dwg/R2010/proxy.dwg.gz | Bin 0 -> 16327 bytes .../fixtures/cad/proxy/dwg/R2013/proxy.dwg.gz | Bin 0 -> 14513 bytes .../fixtures/cad/proxy/dwg/R2018/proxy.dwg.gz | Bin 0 -> 14307 bytes .../tests/fixtures/cad/proxy/make.py | 463 + .../tests/fixtures/cad/proxy/r12/proxy.dxf.gz | Bin 0 -> 6053 bytes .../tests/fixtures/cad/proxy/r13/proxy.dxf.gz | Bin 0 -> 8162 bytes .../tests/fixtures/cad/proxy/src/proxy.dxf.gz | Bin 0 -> 7172 bytes .../tests/fixtures/cad/src/all-binary.dxf.gz | Bin 0 -> 12236 bytes .../tests/fixtures/cad/src/all.dxf.gz | Bin 0 -> 12238 bytes .../tests/fixtures/cad/src/c7.dxf.gz | Bin 0 -> 5000 bytes .../tests/fixtures/cad/src/cp1251.dxf.gz | Bin 0 -> 3581 bytes .../tests/fixtures/cad/src/dwgcases.dxf.gz | Bin 0 -> 4054 bytes .../tests/fixtures/cad/src/entities.dxf.gz | Bin 0 -> 8426 bytes .../tests/fixtures/cad/src/gradient.dxf.gz | Bin 0 -> 4038 bytes .../tests/fixtures/cad/src/objects.dxf.gz | Bin 0 -> 7802 bytes .../tests/fixtures/dwg/attribs-R2000.dwg.gz | Bin 0 -> 9964 bytes .../tests/fixtures/dwg/attribs.dwg.gz | Bin 0 -> 9216 bytes .../tests/fixtures/dwg/attribs.dxf.gz | Bin 0 -> 4026 bytes .../tests/fixtures/dwg/hatch7.dwg.gz | Bin 0 -> 9011 bytes .../tests/fixtures/dwg/hatch7.dxf.gz | Bin 0 -> 3937 bytes .../tests/fixtures/dwg/hostile.dxf.gz | Bin 0 -> 3998 bytes .../tests/fixtures/dwg/layouts.dwg.gz | Bin 0 -> 9429 bytes .../tests/fixtures/dwg/layouts.dxf.gz | Bin 0 -> 4217 bytes .../tests/fixtures/dwg/leader.dxf.gz | Bin 0 -> 3846 bytes .../tests/fixtures/dwg/lines200.dxf.gz | Bin 0 -> 5714 bytes crates/exav-render/tests/fixtures/dwg/make.py | 178 + .../tests/fixtures/dwg/plan-R2000.dwg.gz | Bin 0 -> 9971 bytes .../tests/fixtures/dwg/plan.dwg.gz | Bin 0 -> 9127 bytes .../tests/fixtures/dwg/plan.dxf.gz | Bin 0 -> 3963 bytes .../fixtures/fuzz/arc-end-angle-1e99.dwg | Bin 0 -> 21811 bytes .../fixtures/fuzz/frozen-layer-count.dwg | Bin 0 -> 21811 bytes .../tests/fixtures/fuzz/graphic-size-2gb.dwg | Bin 0 -> 21811 bytes .../tests/fixtures/fuzz/handle-seed-max.dwg | Bin 0 -> 21811 bytes .../fixtures/fuzz/modular-short-shift.dwg | Bin 0 -> 21811 bytes .../tests/fixtures/ifc/booleans.ifc | 127 + .../tests/fixtures/ifc/damaged.ifc | 82 + .../tests/fixtures/ifc/expected.json | 757 + .../tests/fixtures/ifc/ifc2x3_feet.ifc | 55 + crates/exav-render/tests/fixtures/ifc/make.py | 516 + .../tests/fixtures/ifc/mapped_units.ifc | 154 + .../tests/fixtures/ifc/profiles.ifc | 281 + .../exav-render/tests/fixtures/ifc/solids.ifc | 208 + .../tests/fixtures/ifc/tessellated.ifc | 216 + .../tests/fixtures/images/bilevel.g3-1d | Bin 0 -> 305 bytes .../tests/fixtures/images/bilevel.g3-2d | Bin 0 -> 282 bytes .../tests/fixtures/images/bilevel.g3-fill | Bin 0 -> 317 bytes .../tests/fixtures/images/bilevel.g4 | Bin 0 -> 190 bytes .../tests/fixtures/images/bilevel.png | Bin 0 -> 285 bytes .../tests/fixtures/images/bilevel.rle | Bin 0 -> 264 bytes .../tests/fixtures/images/generic-random.jb2 | Bin 0 -> 246 bytes .../tests/fixtures/images/generic.jb2 | Bin 0 -> 246 bytes .../fixtures/images/grey-subsampled-tiles.j2k | Bin 0 -> 908 bytes .../tests/fixtures/images/grey.j2k | Bin 0 -> 486 bytes .../tests/fixtures/images/grey.png | Bin 0 -> 195 bytes .../fixtures/images/jbig2_region_bomb.seg | Bin 0 -> 227 bytes .../exav-render/tests/fixtures/images/make.py | 146 + .../tests/fixtures/images/rgb-offset.j2k | Bin 0 -> 1693 bytes .../exav-render/tests/fixtures/images/rgb.j2k | Bin 0 -> 1683 bytes .../exav-render/tests/fixtures/images/rgb.jp2 | Bin 0 -> 1768 bytes .../exav-render/tests/fixtures/images/rgb.png | Bin 0 -> 354 bytes .../fixtures/images/rgb38-narrow-tile.j2k | Bin 0 -> 1757 bytes .../tests/fixtures/images/rgb38-tiles-r1.png | Bin 0 -> 610 bytes .../tests/fixtures/images/rgb38-tiles.j2k | Bin 0 -> 2277 bytes .../tests/fixtures/images/rgb38.png | Bin 0 -> 359 bytes .../tests/fixtures/images/rgba.jp2 | Bin 0 -> 1057 bytes .../tests/fixtures/images/rgba.png | Bin 0 -> 260 bytes .../tests/fixtures/images/symbol.jb2 | Bin 0 -> 243 bytes crates/exav-render/tests/fixtures/stl/box.stl | Bin 0 -> 684 bytes .../tests/fixtures/stl/box_ascii.stl | 86 + .../tests/fixtures/stl/expected.json | 104 + .../tests/fixtures/stl/huge_count.stl | Bin 0 -> 134 bytes .../exav-render/tests/fixtures/stl/magics.stl | Bin 0 -> 684 bytes crates/exav-render/tests/fixtures/stl/make.py | 81 + .../tests/fixtures/stl/solid_header.stl | Bin 0 -> 684 bytes .../tests/fixtures/stl/truncated.stl | Bin 0 -> 334 bytes .../exav-render/tests/fixtures/stl/viscam.stl | Bin 0 -> 684 bytes .../tests/fixtures/viewer/house.ifc | 96 + .../tests/fixtures/viewer/house.stl | 212 + crates/exav-render/tests/ifc.rs | 336 + crates/exav-render/tests/ifc_oracle.rs | 266 + .../tests/ifc_oracle/webifc_stats.mjs | 66 + crates/exav-render/tests/jpeg2000_jbig2.rs | 619 + crates/exav-render/tests/stl.rs | 109 + crates/exav-unpack-wasm/Cargo.lock | 422 +- crates/exav-unpack-wasm/Cargo.toml | 6 +- crates/exav-unpack-wasm/NOTICE | 900 +- crates/exav-unpack-wasm/README.md | 12 +- crates/exav-unpack-wasm/js/index.d.ts | 9 +- crates/exav-unpack-wasm/js/index.js | 28 +- crates/exav-unpack-wasm/js/worker.js | 5 +- crates/exav-unpack-wasm/package.json | 4 +- crates/exav-unpack-wasm/src/lib.rs | 327 +- crates/exav-unpack-wasm/src/source.rs | 32 +- crates/exav-unpack/Cargo.toml | 151 +- crates/exav-unpack/MEMORY.md | 344 +- crates/exav-unpack/NOTICE | 776 +- crates/exav-unpack/README.md | 41 +- crates/exav-unpack/examples/dump_members.rs | 25 +- crates/exav-unpack/examples/rar3_check.rs | 8 +- crates/exav-unpack/examples/rar5_check.rs | 8 +- crates/exav-unpack/src/bytes.rs | 55 + crates/exav-unpack/src/formats/aimodel.rs | 45 +- crates/exav-unpack/src/formats/alz.rs | 64 +- crates/exav-unpack/src/formats/ar.rs | 70 +- crates/exav-unpack/src/formats/arc.rs | 67 +- .../src/formats/arj_parse/arj_archive.rs | 42 +- crates/exav-unpack/src/formats/autoit.rs | 662 +- crates/exav-unpack/src/formats/autoit_data.rs | 90 + crates/exav-unpack/src/formats/azo.rs | 13 +- crates/exav-unpack/src/formats/bzip2.rs | 160 +- .../src/formats/bzip2_rs/bitreader.rs | 163 + .../src/formats/bzip2_rs/block/bwt.rs | 17 + .../src/formats/bzip2_rs/block/error.rs | 66 + .../src/formats/bzip2_rs/block/mod.rs | 475 + .../exav-unpack/src/formats/bzip2_rs/crc.rs | 46 + .../src/formats/bzip2_rs/decoder/error.rs | 57 + .../src/formats/bzip2_rs/decoder/mod.rs | 200 + .../src/formats/bzip2_rs/decoder/reader.rs | 92 + .../src/formats/bzip2_rs/header/error.rs | 34 + .../src/formats/bzip2_rs/header/mod.rs | 68 + .../src/formats/bzip2_rs/huffman.rs | 167 + .../exav-unpack/src/formats/bzip2_rs/mod.rs | 30 + .../src/formats/bzip2_rs/move_to_front.rs | 65 + crates/exav-unpack/src/formats/cab.rs | 156 +- .../src/formats/cab_parse/cabinet.rs | 97 +- .../src/formats/cab_parse/folder.rs | 69 +- crates/exav-unpack/src/formats/chm.rs | 212 +- crates/exav-unpack/src/formats/codepage.rs | 275 + crates/exav-unpack/src/formats/cpio.rs | 222 +- crates/exav-unpack/src/formats/dmg.rs | 624 +- crates/exav-unpack/src/formats/dwg/bits.rs | 511 + crates/exav-unpack/src/formats/dwg/extract.rs | 403 + crates/exav-unpack/src/formats/dwg/file.rs | 986 ++ crates/exav-unpack/src/formats/dwg/mod.rs | 321 + crates/exav-unpack/src/formats/dwg/object.rs | 581 + crates/exav-unpack/src/formats/dwg/r2004.rs | 659 + crates/exav-unpack/src/formats/dwg/r2007.rs | 1040 ++ crates/exav-unpack/src/formats/dxf/extract.rs | 225 + crates/exav-unpack/src/formats/dxf/mod.rs | 99 + crates/exav-unpack/src/formats/dxf/pairs.rs | 579 + crates/exav-unpack/src/formats/dxf/parts.rs | 137 + crates/exav-unpack/src/formats/dxf/records.rs | 98 + crates/exav-unpack/src/formats/egg.rs | 181 +- crates/exav-unpack/src/formats/ext.rs | 8 +- crates/exav-unpack/src/formats/fat.rs | 8 +- crates/exav-unpack/src/formats/gzip.rs | 42 +- crates/exav-unpack/src/formats/hwp3.rs | 51 +- crates/exav-unpack/src/formats/inno.rs | 6 +- crates/exav-unpack/src/formats/ishield_z.rs | 34 +- crates/exav-unpack/src/formats/iso.rs | 257 +- crates/exav-unpack/src/formats/javaclass.rs | 6 +- crates/exav-unpack/src/formats/lha.rs | 77 +- crates/exav-unpack/src/formats/lnk.rs | 20 +- crates/exav-unpack/src/formats/lz4.rs | 351 +- crates/exav-unpack/src/formats/lzip.rs | 210 +- crates/exav-unpack/src/formats/lzma.rs | 172 + crates/exav-unpack/src/formats/lzw.rs | 371 +- crates/exav-unpack/src/formats/machofat.rs | 87 +- crates/exav-unpack/src/formats/mediacheck.rs | 148 +- crates/exav-unpack/src/formats/mod.rs | 117 +- crates/exav-unpack/src/formats/nsis.rs | 206 +- crates/exav-unpack/src/formats/ntfs.rs | 356 +- crates/exav-unpack/src/formats/ole.rs | 389 +- crates/exav-unpack/src/formats/ole_crypto.rs | 173 +- crates/exav-unpack/src/formats/onenote.rs | 108 +- crates/exav-unpack/src/formats/partition.rs | 431 +- crates/exav-unpack/src/formats/pdf.rs | 379 +- .../src/formats/pdf_parse/crypt.rs | 236 +- .../exav-unpack/src/formats/pdf_parse/lex.rs | 66 +- .../src/formats/pdf_parse/parse.rs | 9 +- crates/exav-unpack/src/formats/pepack.rs | 57 +- .../exav-unpack/src/formats/ppmd7/common.rs | 66 + crates/exav-unpack/src/formats/ppmd7/mod.rs | 74 +- crates/exav-unpack/src/formats/ppmd7/model.rs | 669 +- .../exav-unpack/src/formats/ppmd7/rangedec.rs | 58 +- .../src/formats/ppmd7/tagged_offset.rs | 10 +- crates/exav-unpack/src/formats/ppmd8/mod.rs | 537 + crates/exav-unpack/src/formats/ppmd8/model.rs | 1826 +++ crates/exav-unpack/src/formats/pyc.rs | 40 +- crates/exav-unpack/src/formats/qcow2.rs | 72 +- crates/exav-unpack/src/formats/rar.rs | 1401 +- crates/exav-unpack/src/formats/rar3_crypt.rs | 131 + crates/exav-unpack/src/formats/rar3_unpack.rs | 152 +- crates/exav-unpack/src/formats/rar5_crypt.rs | 243 + crates/exav-unpack/src/formats/rar5_unpack.rs | 142 +- crates/exav-unpack/src/formats/reported.rs | 11 +- crates/exav-unpack/src/formats/rtf.rs | 10 +- crates/exav-unpack/src/formats/screnc.rs | 18 +- crates/exav-unpack/src/formats/sevenz/aes.rs | 14 +- crates/exav-unpack/src/formats/sevenz/bcj2.rs | 4 +- .../exav-unpack/src/formats/sevenz/decode.rs | 482 +- .../exav-unpack/src/formats/sevenz/entry.rs | 684 +- .../exav-unpack/src/formats/sevenz/header.rs | 126 +- crates/exav-unpack/src/formats/sevenz/mod.rs | 106 +- crates/exav-unpack/src/formats/sfx.rs | 302 +- crates/exav-unpack/src/formats/sniff.rs | 23 +- crates/exav-unpack/src/formats/swf.rs | 189 +- crates/exav-unpack/src/formats/szdd.rs | 184 +- crates/exav-unpack/src/formats/tar.rs | 100 +- crates/exav-unpack/src/formats/tnef.rs | 110 +- crates/exav-unpack/src/formats/udf.rs | 1046 +- crates/exav-unpack/src/formats/udif.rs | 461 +- crates/exav-unpack/src/formats/upx.rs | 338 +- crates/exav-unpack/src/formats/uuencode.rs | 138 +- crates/exav-unpack/src/formats/vba.rs | 61 +- crates/exav-unpack/src/formats/vhd.rs | 28 +- crates/exav-unpack/src/formats/vhdx.rs | 65 +- crates/exav-unpack/src/formats/vmdk.rs | 103 +- crates/exav-unpack/src/formats/wim/lzx.rs | 18 +- crates/exav-unpack/src/formats/wim/mod.rs | 117 +- crates/exav-unpack/src/formats/xar.rs | 37 +- crates/exav-unpack/src/formats/xlm.rs | 10 +- crates/exav-unpack/src/formats/xz.rs | 193 +- crates/exav-unpack/src/formats/zip.rs | 1773 ++- crates/exav-unpack/src/formats/zip_crypto.rs | 15 +- crates/exav-unpack/src/formats/zoo.rs | 76 +- crates/exav-unpack/src/formats/zoo_parse.rs | 10 +- crates/exav-unpack/src/formats/zstd.rs | 169 +- crates/exav-unpack/src/inflate.rs | 421 + crates/exav-unpack/src/lib.rs | 2691 ++-- crates/exav-unpack/src/main.rs | 1613 ++- crates/exav-unpack/src/profile.rs | 85 + crates/exav-unpack/src/source.rs | 739 + crates/exav-unpack/src/span.rs | 398 + crates/exav-unpack/src/stream.rs | 1785 +-- crates/exav-unpack/src/volume.rs | 55 +- crates/exav-unpack/tests/cli.rs | 726 +- .../tests/fixtures/7z/aes_solid_many.7z | Bin 0 -> 1184 bytes .../exav-unpack/tests/fixtures/7z/bcj_lzma.7z | Bin 0 -> 292 bytes .../tests/fixtures/7z/delta_lzma.7z | Bin 0 -> 378 bytes .../tests/fixtures/7z/ppmd_plain_header.7z | Bin 0 -> 275 bytes crates/exav-unpack/tests/fixtures/README.md | 30 + .../tests/fixtures/checksum/clean.arc | Bin 0 -> 1414 bytes .../tests/fixtures/checksum/clean.bz2 | Bin 0 -> 35094 bytes .../tests/fixtures/checksum/clean.lz | Bin 0 -> 6865 bytes .../tests/fixtures/checksum/clean.wim | Bin 0 -> 1708 bytes .../tests/fixtures/checksum/eicar.arc.xor | Bin 0 -> 1477 bytes .../tests/fixtures/checksum/eicar.wim.xor | Bin 0 -> 1708 bytes .../tests/fixtures/checksum/make.py | 107 + .../fixtures/checksum/two_blocks.bz2.xor | Bin 0 -> 35096 bytes .../fixtures/checksum/two_members.lz.xor | Bin 0 -> 13897 bytes .../exav-unpack/tests/fixtures/chm/README.md | 12 +- .../tests/fixtures/chm/multi-frame-lzx.chm | Bin 0 -> 19036 bytes .../tests/fixtures/cut_lzip.lz.xor | Bin 0 -> 7773 bytes .../fixtures/cut_short/7z_bcj2.7z.gz.xor | Bin 0 -> 31352 bytes .../fixtures/cut_short/7z_deflate.7z.gz.xor | Bin 0 -> 30640 bytes .../fixtures/cut_short/7z_lzma.7z.gz.xor | Bin 0 -> 31282 bytes .../fixtures/cut_short/7z_lzma2.7z.gz.xor | Bin 0 -> 31289 bytes .../fixtures/cut_short/disk.qcow2.gz.xor | Bin 0 -> 30947 bytes .../tests/fixtures/cut_short/disk.vmdk.gz.xor | Bin 0 -> 31446 bytes .../tests/fixtures/cut_short/make.py | 109 + .../tests/fixtures/cut_short/make_udif.py | 152 + .../cut_short/nsis_solid_lzma.exe.gz.xor | Bin 0 -> 72911 bytes .../fixtures/cut_short/nsis_zlib.exe.gz.xor | Bin 0 -> 73037 bytes .../fixtures/cut_short/swf_cws.swf.gz.xor | Bin 0 -> 30554 bytes .../fixtures/cut_short/swf_zws.swf.gz.xor | Bin 0 -> 31113 bytes .../fixtures/cut_short/udif_bzip2.dmg.gz.xor | Bin 0 -> 51120 bytes .../cut_short/udif_bzip2_first.dmg.gz.xor | Bin 0 -> 68597 bytes .../fixtures/cut_short/udif_xz.dmg.gz.xor | Bin 0 -> 66573 bytes .../cut_short/udif_xz_first.dmg.gz.xor | Bin 0 -> 75218 bytes .../fixtures/cut_short/udif_zlib.dmg.gz.xor | Bin 0 -> 78323 bytes .../fixtures/cut_short/upx_lzma.elf.gz.xor | Bin 0 -> 53392 bytes .../exav-unpack/tests/fixtures/dwg/R13.dwg.gz | Bin 0 -> 9533 bytes .../exav-unpack/tests/fixtures/dwg/R14.dwg.gz | Bin 0 -> 9647 bytes .../tests/fixtures/dwg/R2000.dwg.gz | Bin 0 -> 9743 bytes .../tests/fixtures/dwg/R2004.dwg.gz | Bin 0 -> 11856 bytes .../tests/fixtures/dwg/R2007.dwg.gz | Bin 0 -> 17417 bytes .../tests/fixtures/dwg/R2010.dwg.gz | Bin 0 -> 11320 bytes .../tests/fixtures/dwg/R2013.dwg.gz | Bin 0 -> 9353 bytes .../tests/fixtures/dwg/R2018.dwg.gz | Bin 0 -> 9164 bytes .../fixtures/dwg/c4/macros/R13.dwg.gz.xor | Bin 0 -> 10001 bytes .../fixtures/dwg/c4/macros/R14.dwg.gz.xor | Bin 0 -> 10130 bytes .../fixtures/dwg/c4/macros/R2000.dwg.gz.xor | Bin 0 -> 10279 bytes .../fixtures/dwg/c4/macros/R2004.dwg.gz.xor | Bin 0 -> 12407 bytes .../fixtures/dwg/c4/macros/R2007.dwg.gz.xor | Bin 0 -> 17415 bytes .../fixtures/dwg/c4/macros/R2010.dwg.gz.xor | Bin 0 -> 11730 bytes .../fixtures/dwg/c4/macros/R2013.dwg.gz.xor | Bin 0 -> 9692 bytes .../fixtures/dwg/c4/macros/R2018.dwg.gz.xor | Bin 0 -> 9490 bytes .../exav-unpack/tests/fixtures/dwg/c4/make.py | 290 + .../fixtures/dwg/c4/packager/R13.dwg.gz.xor | Bin 0 -> 9918 bytes .../fixtures/dwg/c4/packager/R14.dwg.gz.xor | Bin 0 -> 10056 bytes .../fixtures/dwg/c4/packager/R2000.dwg.gz.xor | Bin 0 -> 10208 bytes .../fixtures/dwg/c4/packager/R2004.dwg.gz.xor | Bin 0 -> 12435 bytes .../fixtures/dwg/c4/packager/R2007.dwg.gz.xor | Bin 0 -> 17174 bytes .../fixtures/dwg/c4/packager/R2010.dwg.gz.xor | Bin 0 -> 11614 bytes .../fixtures/dwg/c4/packager/R2013.dwg.gz.xor | Bin 0 -> 9606 bytes .../fixtures/dwg/c4/packager/R2018.dwg.gz.xor | Bin 0 -> 9401 bytes .../tests/fixtures/dwg/ole/R13.dwg.gz.xor | Bin 0 -> 9786 bytes .../tests/fixtures/dwg/ole/R14.dwg.gz.xor | Bin 0 -> 9923 bytes .../tests/fixtures/dwg/ole/R2000.dwg.gz.xor | Bin 0 -> 10058 bytes .../tests/fixtures/dwg/ole/R2004.dwg.gz.xor | Bin 0 -> 12244 bytes .../tests/fixtures/dwg/ole/R2007.dwg.gz.xor | Bin 0 -> 17441 bytes .../tests/fixtures/dwg/ole/R2010.dwg.gz.xor | Bin 0 -> 11470 bytes .../tests/fixtures/dwg/ole/R2013.dwg.gz.xor | Bin 0 -> 9458 bytes .../tests/fixtures/dwg/ole/R2018.dwg.gz.xor | Bin 0 -> 9253 bytes .../tests/fixtures/dwg/ole/make.py | 78 + .../tests/fixtures/dwg/pre-r13/R12.dwg.gz | Bin 0 -> 1143 bytes .../tests/fixtures/dwg/pre-r13/make.py | 49 + .../tests/fixtures/dwg/preview/DIB.hex | 1 + .../tests/fixtures/dwg/preview/R13.dwg.gz | Bin 0 -> 9506 bytes .../tests/fixtures/dwg/preview/R14.dwg.gz | Bin 0 -> 9628 bytes .../tests/fixtures/dwg/preview/R2000.dwg.gz | Bin 0 -> 9787 bytes .../tests/fixtures/dwg/preview/R2004.dwg.gz | Bin 0 -> 11880 bytes .../tests/fixtures/dwg/preview/R2007.dwg.gz | Bin 0 -> 17124 bytes .../tests/fixtures/dwg/preview/R2010.dwg.gz | Bin 0 -> 11128 bytes .../tests/fixtures/dwg/preview/R2013.dwg.gz | Bin 0 -> 9163 bytes .../tests/fixtures/dwg/preview/R2018.dwg.gz | Bin 0 -> 8957 bytes .../tests/fixtures/dwg/preview/make.py | 85 + .../tests/fixtures/dxf/ascii-R12.dxf.gz | Bin 0 -> 14915 bytes .../tests/fixtures/dxf/ascii-R2018.dxf.gz | Bin 0 -> 19443 bytes .../tests/fixtures/dxf/binary-R12.dxf.gz | Bin 0 -> 14241 bytes .../tests/fixtures/dxf/binary-R2018.dxf.gz | Bin 0 -> 17971 bytes .../exav-unpack/tests/fixtures/lnk/README.md | 4 +- .../tests/fixtures/lzw_full/fulltable.b16.Z | Bin 0 -> 123819 bytes .../exav-unpack/tests/fixtures/nsis/README.md | 5 +- .../tests/fixtures/ntfs/attribute_list.img.gz | Bin 0 -> 673846 bytes .../tests/fixtures/onenote/README.md | 4 +- .../fixtures/pdf/eicar_qpdf_aesv2_r4.pdf.xor | Bin 0 -> 999 bytes .../fixtures/pdf/eicar_qpdf_aesv3_r6.pdf.xor | Bin 0 -> 1314 bytes .../fixtures/pdf/eicar_rc4_r2_gen1.pdf.xor | Bin 0 -> 888 bytes .../tests/fixtures/pdf/empty_aesv2_r4.pdf.xor | 7 + .../fixtures/pdf/qpdf_actions_aes128.pdf | Bin 0 -> 1112 bytes .../fixtures/pdf/qpdf_actions_aes256.pdf | Bin 0 -> 1427 bytes .../cutoff_random_24576_o16_m32768.ppmd8 | Bin 0 -> 25208 bytes .../ppmd8/cutoff_random_24576_o6_m16384.ppmd8 | Bin 0 -> 25058 bytes .../ppmd8/cutoff_skewed_65536_o2_m16384.ppmd8 | Bin 0 -> 37436 bytes .../ppmd8/cutoff_skewed_65536_o4_m32768.ppmd8 | Bin 0 -> 36325 bytes .../ppmd8/cutoff_text_131072_o16_m65536.ppmd8 | Bin 0 -> 18957 bytes .../ppmd8/cutoff_text_400000_o8_m262144.ppmd8 | Bin 0 -> 53788 bytes .../ppmd8/cutoff_text_65536_o2_m8192.ppmd8 | Bin 0 -> 9378 bytes .../ppmd8/cutoff_text_65536_o6_m16384.ppmd8 | Bin 0 -> 9894 bytes .../tests/fixtures/rar4/enc_data.rar | Bin 0 -> 11801 bytes .../tests/fixtures/rar4/enc_headers.rar | Bin 0 -> 11852 bytes .../fixtures/rar4/enc_headers_unknown.rar | Bin 0 -> 164 bytes .../tests/fixtures/rar4/solid_empty.rar | Bin 0 -> 11826 bytes .../tests/fixtures/rar4/solid_ppmd.rar | Bin 0 -> 21141 bytes .../tests/fixtures/rar4/solid_x86.rar | Bin 0 -> 4495 bytes .../tests/fixtures/rar4/two_windows.rar | Bin 0 -> 66307 bytes .../tests/fixtures/rar4/x86_second.rar | Bin 0 -> 54301 bytes .../tests/fixtures/rar5/enc_data.rar | Bin 0 -> 290 bytes .../tests/fixtures/rar5/enc_headers.rar | Bin 0 -> 414 bytes .../fixtures/rar5/enc_headers_unknown.rar | Bin 0 -> 270 bytes .../fixtures/rar5/enc_stored_unknown.rar | Bin 0 -> 2249 bytes .../tests/fixtures/rar5/hardlink.rar | Bin 0 -> 174 bytes .../tests/fixtures/rar_solid/solid_x86.rar | Bin 0 -> 42802 bytes .../tests/fixtures/rar_solid/two_windows.rar | Bin 0 -> 135750 bytes .../tests/fixtures/rar_volumes/set4.r00 | Bin 0 -> 8192 bytes .../tests/fixtures/rar_volumes/set4.r01 | Bin 0 -> 6508 bytes .../tests/fixtures/rar_volumes/set4.rar | Bin 0 -> 8192 bytes .../tests/fixtures/rar_volumes/set5.part1.rar | Bin 0 -> 8192 bytes .../tests/fixtures/rar_volumes/set5.part2.rar | Bin 0 -> 8192 bytes .../tests/fixtures/rar_volumes/set5.part3.rar | Bin 0 -> 6702 bytes .../tests/fixtures/udf/make_metadata_iso.py | 224 + .../tests/fixtures/udf/metadata.iso.gz.xor | Bin 0 -> 3006 bytes .../zip/7z_bzip2_large_then_small.zip | Bin 0 -> 3348 bytes .../zip/7z_deflate64_large_then_small.zip | Bin 0 -> 3930 bytes .../fixtures/zip/7z_lzma_large_then_small.zip | Bin 0 -> 2982 bytes .../fixtures/zip/7z_ppmd_large_then_small.zip | Bin 0 -> 3422 bytes .../fixtures/zip/bzip2_large_then_small.zip | Bin 0 -> 20699 bytes .../tests/fixtures/zip/cut_bzip2.zip.xor | Bin 0 -> 26263 bytes .../tests/fixtures/zip/cut_deflate.zip.xor | Bin 0 -> 8562 bytes .../tests/fixtures/zip/cut_deflate64.zip.xor | Bin 0 -> 8562 bytes .../tests/fixtures/zip/cut_lzma.zip.xor | Bin 0 -> 7878 bytes .../tests/fixtures/zip/cut_ppmd.zip.xor | Bin 0 -> 5870 bytes .../tests/fixtures/zip/cut_stored.zip.xor | 8 + .../tests/fixtures/zip/cut_xz.zip.xor | Bin 0 -> 7922 bytes .../tests/fixtures/zip/cut_zstd.zip.xor | Bin 0 -> 43025 bytes .../tests/fixtures/zip/dd_7zip_bzip2.zip | Bin 0 -> 387 bytes .../tests/fixtures/zip/dd_7zip_deflate.zip | Bin 0 -> 348 bytes .../tests/fixtures/zip/dd_7zip_deflate64.zip | Bin 0 -> 348 bytes .../tests/fixtures/zip/dd_7zip_lzma.zip | Bin 0 -> 336 bytes .../tests/fixtures/zip/dd_7zip_ppmd.zip | Bin 0 -> 322 bytes .../tests/fixtures/zip/dd_7zip_xz.zip | Bin 0 -> 384 bytes .../fixtures/zip/dd_python_lzma_zip64.zip | Bin 0 -> 329 bytes .../tests/fixtures/zip/dd_python_stored.zip | Bin 0 -> 2281 bytes .../fixtures/zip/dd_python_stored_zip64.zip | Bin 0 -> 2309 bytes .../tests/fixtures/zip/legacy_implode.zip | Bin 0 -> 800 bytes .../tests/fixtures/zip/legacy_reduce.zip | Bin 0 -> 1058 bytes .../tests/fixtures/zip/legacy_shrink.zip | Bin 0 -> 825 bytes .../tests/fixtures/zip/ppmd_7zip.zip | Bin 0 -> 667 bytes .../tests/fixtures/zip/zip64_python_lzma.zip | Bin 0 -> 305 bytes crates/exav-unpack/tests/suites/alz.rs | 13 +- crates/exav-unpack/tests/suites/arc.rs | 49 +- .../tests/suites/arj_never_silent.rs | 3 +- .../exav-unpack/tests/suites/broken_media.rs | 138 +- .../exav-unpack/tests/suites/bzip2_blocks.rs | 40 + crates/exav-unpack/tests/suites/chm.rs | 72 +- .../tests/suites/cpio_never_silent.rs | 3 +- .../tests/suites/decrypt_disabled.rs | 2 +- .../tests/suites/disabled_formats.rs | 2 +- crates/exav-unpack/tests/suites/diskimage.rs | 26 +- crates/exav-unpack/tests/suites/dmg.rs | 91 + crates/exav-unpack/tests/suites/dwg.rs | 557 + crates/exav-unpack/tests/suites/dxf.rs | 191 + crates/exav-unpack/tests/suites/egg.rs | 38 +- .../tests/suites/entry_accounting.rs | 2 +- crates/exav-unpack/tests/suites/ext.rs | 3 +- crates/exav-unpack/tests/suites/extreme.rs | 377 + crates/exav-unpack/tests/suites/fat.rs | 3 +- crates/exav-unpack/tests/suites/hwp3.rs | 5 +- crates/exav-unpack/tests/suites/ishield_z.rs | 38 +- .../tests/suites/iso_never_silent.rs | 61 +- .../tests/suites/lha_header_bounds.rs | 2 +- crates/exav-unpack/tests/suites/lz4.rs | 3 +- crates/exav-unpack/tests/suites/lzw.rs | 50 +- crates/exav-unpack/tests/suites/mod.rs | 72 + crates/exav-unpack/tests/suites/nsis.rs | 38 +- crates/exav-unpack/tests/suites/ntfs.rs | 116 +- .../exav-unpack/tests/suites/ole_lenient.rs | 145 + crates/exav-unpack/tests/suites/onenote.rs | 38 +- .../tests/suites/panic_containment.rs | 36 +- .../tests/suites/partition_never_silent.rs | 3 +- .../tests/suites/pdf_empty_password.rs | 57 + crates/exav-unpack/tests/suites/pdf_parse.rs | 2 +- .../exav-unpack/tests/suites/pe_emulation.rs | 34 +- .../tests/suites/pe_emulation_corpus.rs | 2 +- .../tests/suites/pe_emulation_techniques.rs | 2 +- .../tests/suites/ppt_embedded_storage.rs | 35 +- crates/exav-unpack/tests/suites/protectors.rs | 2 +- .../exav-unpack/tests/suites/rar4_compat.rs | 183 + .../tests/suites/rar5_encryption.rs | 125 + crates/exav-unpack/tests/suites/rar_solid.rs | 428 +- .../exav-unpack/tests/suites/sevenz_bcj2.rs | 3 +- .../exav-unpack/tests/suites/sevenz_ppmd.rs | 139 + .../exav-unpack/tests/suites/silent_skips.rs | 88 +- .../tests/suites/stream_read_errors.rs | 204 + crates/exav-unpack/tests/suites/udf.rs | 84 +- .../exav-unpack/tests/suites/upx_rebuild.rs | 15 +- .../tests/suites/vba_module_source.rs | 71 + crates/exav-unpack/tests/suites/vhd.rs | 7 +- crates/exav-unpack/tests/suites/wim.rs | 85 +- .../exav-unpack/tests/suites/zip_appended.rs | 98 + crates/exav-unpack/tests/suites/zip_codecs.rs | 990 +- .../exav-unpack/tests/suites/zip_deflate64.rs | 2 +- .../tests/suites/zip_disguised_members.rs | 171 +- crates/exav-unpack/tests/suites/zoo.rs | 38 +- crates/exav-update/Cargo.toml | 14 +- crates/exav-update/NOTICE | 486 +- crates/exav-update/README.md | 5 +- crates/exav-update/src/lib.rs | 180 +- crates/exav-update/tests/http_fetch.rs | 23 +- crates/exav-viewer/.gitignore | 8 + crates/exav-viewer/Cargo.lock | 523 + crates/exav-viewer/Cargo.toml | 46 + crates/exav-viewer/LICENSE | 21 + crates/exav-viewer/LICENSES/Apache-2.0.txt | 201 + crates/exav-viewer/LICENSES/CC0-1.0.txt | 121 + crates/exav-viewer/NOTICE | 167 + crates/exav-viewer/README.md | 164 + .../assets/fonts/Arimo-Italic-wght.woff2 | Bin 0 -> 255940 bytes .../exav-viewer/assets/fonts/Arimo-wght.woff2 | Bin 0 -> 222428 bytes .../assets/fonts/Cousine-Bold.woff2 | Bin 0 -> 111392 bytes .../assets/fonts/Cousine-BoldItalic.woff2 | Bin 0 -> 120548 bytes .../assets/fonts/Cousine-Italic.woff2 | Bin 0 -> 118936 bytes .../assets/fonts/Cousine-Regular.woff2 | Bin 0 -> 109872 bytes crates/exav-viewer/assets/fonts/NOTICE.md | 18 + crates/exav-viewer/assets/fonts/OFL-1.1.txt | 93 + crates/exav-viewer/assets/fonts/OFL-arimo.txt | 93 + .../exav-viewer/assets/fonts/Tinos-Bold.woff2 | Bin 0 -> 201408 bytes .../assets/fonts/Tinos-BoldItalic.woff2 | Bin 0 -> 206440 bytes .../assets/fonts/Tinos-Italic.woff2 | Bin 0 -> 205572 bytes .../assets/fonts/Tinos-Regular.woff2 | Bin 0 -> 181672 bytes crates/exav-viewer/assets/pdfjs/absent.wasm | 0 crates/exav-viewer/demo/index.html | 19 + crates/exav-viewer/demo/src/App.tsx | 251 + crates/exav-viewer/demo/src/demo.css | 236 + crates/exav-viewer/demo/src/main.tsx | 12 + crates/exav-viewer/demo/src/showcase.ts | 31 + crates/exav-viewer/demo/tsconfig.json | 15 + crates/exav-viewer/demo/vite.config.ts | 177 + crates/exav-viewer/e2e/csp.ts | 31 + crates/exav-viewer/e2e/delivery-setup.ts | 145 + crates/exav-viewer/e2e/delivery.spec.ts | 308 + crates/exav-viewer/e2e/demo.spec.ts | 831 ++ crates/exav-viewer/e2e/fixtures/make-plan.py | 99 + .../exav-viewer/e2e/fixtures/make-samples.mjs | 445 + .../e2e/fixtures/pdf-images/cases.json | 206 + .../e2e/fixtures/pdf-images/ccitt-g3-1d.pdf | Bin 0 -> 1559 bytes .../e2e/fixtures/pdf-images/ccitt-g3-2d.pdf | Bin 0 -> 1529 bytes .../e2e/fixtures/pdf-images/ccitt-g3-fill.pdf | Bin 0 -> 1587 bytes .../fixtures/pdf-images/ccitt-g4-blackis1.pdf | Bin 0 -> 1359 bytes .../e2e/fixtures/pdf-images/ccitt-g4.pdf | Bin 0 -> 1360 bytes .../e2e/fixtures/pdf-images/ccitt-rle.pdf | Bin 0 -> 1484 bytes .../e2e/fixtures/pdf-images/cmyk.jp2 | Bin 0 -> 6747 bytes .../e2e/fixtures/pdf-images/g3-1d.ccitt | Bin 0 -> 769 bytes .../e2e/fixtures/pdf-images/g3-2d.ccitt | Bin 0 -> 739 bytes .../e2e/fixtures/pdf-images/g3-fill.ccitt | Bin 0 -> 798 bytes .../e2e/fixtures/pdf-images/g4.ccitt | Bin 0 -> 568 bytes .../e2e/fixtures/pdf-images/generic.jbig2 | Bin 0 -> 357 bytes .../e2e/fixtures/pdf-images/grey.j2k | Bin 0 -> 735 bytes .../e2e/fixtures/pdf-images/grey.jp2 | Bin 0 -> 820 bytes .../e2e/fixtures/pdf-images/grey4.j2k | Bin 0 -> 467 bytes .../e2e/fixtures/pdf-images/greya.jp2 | Bin 0 -> 1432 bytes .../e2e/fixtures/pdf-images/icc.pdf | Bin 0 -> 5350 bytes .../e2e/fixtures/pdf-images/jbig2-generic.pdf | Bin 0 -> 1041 bytes .../e2e/fixtures/pdf-images/jbig2-symbol.pdf | Bin 0 -> 1125 bytes .../e2e/fixtures/pdf-images/jbig2-tpgd.pdf | Bin 0 -> 1046 bytes .../pdf-images/jpx-cmyk-devicecmyk.pdf | Bin 0 -> 7430 bytes .../e2e/fixtures/pdf-images/jpx-cmyk.pdf | Bin 0 -> 7406 bytes .../pdf-images/jpx-grey-devicegray.pdf | Bin 0 -> 1417 bytes .../e2e/fixtures/pdf-images/jpx-grey.pdf | Bin 0 -> 1478 bytes .../e2e/fixtures/pdf-images/jpx-grey4.pdf | Bin 0 -> 1148 bytes .../pdf-images/jpx-greya-smaskindata.pdf | Bin 0 -> 2106 bytes .../e2e/fixtures/pdf-images/jpx-indexed.pdf | Bin 0 -> 3858 bytes .../e2e/fixtures/pdf-images/jpx-lossy.pdf | Bin 0 -> 1592 bytes .../e2e/fixtures/pdf-images/jpx-palette.pdf | Bin 0 -> 2281 bytes .../fixtures/pdf-images/jpx-rgb-devicergb.pdf | Bin 0 -> 2839 bytes .../e2e/fixtures/pdf-images/jpx-rgb.pdf | Bin 0 -> 2816 bytes .../pdf-images/jpx-rgba-smaskindata.pdf | Bin 0 -> 3423 bytes .../e2e/fixtures/pdf-images/jpx-sycc.pdf | Bin 0 -> 2644 bytes .../e2e/fixtures/pdf-images/lossy.jp2 | Bin 0 -> 934 bytes .../e2e/fixtures/pdf-images/make.py | 285 + .../e2e/fixtures/pdf-images/palette.jp2 | Bin 0 -> 1622 bytes .../e2e/fixtures/pdf-images/rgb.jp2 | Bin 0 -> 2157 bytes .../e2e/fixtures/pdf-images/rgba.jp2 | Bin 0 -> 2749 bytes .../e2e/fixtures/pdf-images/rle.ccitt | Bin 0 -> 694 bytes .../e2e/fixtures/pdf-images/sycc.jp2 | Bin 0 -> 1985 bytes .../fixtures/pdf-images/symbol-globals.jbig2 | Bin 0 -> 206 bytes .../e2e/fixtures/pdf-images/symbol.jbig2 | Bin 0 -> 124 bytes .../e2e/fixtures/pdf-images/tpgd.jbig2 | Bin 0 -> 362 bytes crates/exav-viewer/e2e/fixtures/plan.dwg | Bin 0 -> 12793 bytes crates/exav-viewer/e2e/fixtures/plan.dxf | 3942 +++++ crates/exav-viewer/e2e/fonts.conf | 14 + crates/exav-viewer/e2e/frame.spec.ts | 303 + crates/exav-viewer/e2e/lifetime.spec.ts | 74 + crates/exav-viewer/e2e/model.spec.ts | 51 + crates/exav-viewer/e2e/pdf-decoders.spec.ts | 135 + crates/exav-viewer/e2e/pinch.spec.ts | 134 + crates/exav-viewer/e2e/pixels.ts | 104 + crates/exav-viewer/e2e/samples.ts | 22 + crates/exav-viewer/e2e/selection.spec.ts | 129 + crates/exav-viewer/e2e/tsconfig.json | 10 + crates/exav-viewer/e2e/webpack.spec.ts | 138 + crates/exav-viewer/e2e/zip.ts | 76 + crates/exav-viewer/package-lock.json | 3509 +++++ crates/exav-viewer/package.json | 162 + crates/exav-viewer/playwright.config.ts | 51 + crates/exav-viewer/scripts/build-frame.mjs | 176 + .../scripts/build-pdf-decoders.mjs | 54 + crates/exav-viewer/scripts/build-wasm.sh | 77 + crates/exav-viewer/scripts/build.mjs | 35 + .../scripts/check-bundle-sinks.mjs | 101 + .../scripts/check-bundle-sinks.test.mjs | 65 + crates/exav-viewer/scripts/check-package.mjs | 80 + crates/exav-viewer/scripts/check-sinks.mjs | 197 + .../exav-viewer/scripts/check-sinks.test.mjs | 81 + .../scripts/check-wasm-imports.mjs | 211 + .../scripts/check-wasm-imports.test.mjs | 127 + .../scripts/pdf-decoder.template.js | 99 + crates/exav-viewer/scripts/sync-samples.mjs | 50 + crates/exav-viewer/src/lib.rs | 562 + crates/exav-viewer/ts/all.ts | 43 + crates/exav-viewer/ts/archive/index.ts | 27 + crates/exav-viewer/ts/archive/names.test.ts | 34 + crates/exav-viewer/ts/archive/names.ts | 45 + .../exav-viewer/ts/archive/ranged-protocol.ts | 22 + crates/exav-viewer/ts/archive/ranged.ts | 83 + .../exav-viewer/ts/archive/ranges.worker.ts | 319 + crates/exav-viewer/ts/archive/renderer.ts | 163 + crates/exav-viewer/ts/cad/cad.worker.ts | 100 + crates/exav-viewer/ts/cad/index.ts | 12 + crates/exav-viewer/ts/cad/layer-tree.test.ts | 179 + crates/exav-viewer/ts/cad/layer-tree.ts | 176 + crates/exav-viewer/ts/cad/plugin.ts | 64 + .../ts/cad/renderer/camera.test.ts | 133 + crates/exav-viewer/ts/cad/renderer/camera.ts | 56 + .../exav-viewer/ts/cad/renderer/fonts.test.ts | 112 + crates/exav-viewer/ts/cad/renderer/fonts.ts | 186 + .../ts/cad/renderer/glyph-atlas.ts | 366 + .../exav-viewer/ts/cad/renderer/renderer.ts | 693 + crates/exav-viewer/ts/cad/renderer/shaders.ts | 294 + .../ts/cad/renderer/text-layout.test.ts | 106 + .../ts/cad/renderer/text-layout.ts | 247 + .../ts/cad/renderer/text-resolution.test.ts | 255 + .../ts/cad/renderer/text-resolution.ts | 147 + .../exav-viewer/ts/cad/renderer/tiles.test.ts | 202 + crates/exav-viewer/ts/cad/renderer/tiles.ts | 147 + crates/exav-viewer/ts/cad/types.ts | 112 + crates/exav-viewer/ts/cad/view.ts | 408 + crates/exav-viewer/ts/core/assets.ts | 37 + crates/exav-viewer/ts/core/detect.test.ts | 235 + crates/exav-viewer/ts/core/detect.ts | 78 + crates/exav-viewer/ts/core/formats.ts | 232 + crates/exav-viewer/ts/core/index.ts | 12 + crates/exav-viewer/ts/core/source.ts | 155 + crates/exav-viewer/ts/core/store.test.ts | 27 + crates/exav-viewer/ts/core/store.ts | 49 + crates/exav-viewer/ts/core/types.ts | 510 + crates/exav-viewer/ts/core/viewer.test.ts | 415 + crates/exav-viewer/ts/core/viewer.ts | 248 + .../exav-viewer/ts/core/worker-host.test.ts | 74 + crates/exav-viewer/ts/core/worker-host.ts | 104 + crates/exav-viewer/ts/frame/app/frame.css | 13 + crates/exav-viewer/ts/frame/app/main.ts | 306 + .../exav-viewer/ts/frame/app/ranges.test.ts | 82 + crates/exav-viewer/ts/frame/app/ranges.ts | 87 + .../exav-viewer/ts/frame/app/workers.test.ts | 71 + crates/exav-viewer/ts/frame/app/workers.ts | 135 + crates/exav-viewer/ts/frame/delivery.test.ts | 168 + crates/exav-viewer/ts/frame/delivery.ts | 280 + crates/exav-viewer/ts/frame/host.test.ts | 485 + crates/exav-viewer/ts/frame/index.ts | 507 + crates/exav-viewer/ts/frame/policy.test.ts | 87 + crates/exav-viewer/ts/frame/policy.ts | 171 + crates/exav-viewer/ts/frame/protocol.test.ts | 180 + crates/exav-viewer/ts/frame/protocol.ts | 510 + crates/exav-viewer/ts/ifc/index.ts | 39 + crates/exav-viewer/ts/ifc/renderer.ts | 351 + crates/exav-viewer/ts/image/decode.ts | 45 + crates/exav-viewer/ts/image/decode.worker.ts | 22 + crates/exav-viewer/ts/image/index.ts | 71 + crates/exav-viewer/ts/image/renderer.test.ts | 138 + crates/exav-viewer/ts/image/renderer.ts | 120 + crates/exav-viewer/ts/image/surface.test.ts | 125 + crates/exav-viewer/ts/image/surface.ts | 435 + crates/exav-viewer/ts/media/index.ts | 42 + crates/exav-viewer/ts/model/engine.test.ts | 60 + crates/exav-viewer/ts/model/engine.ts | 79 + crates/exav-viewer/ts/model/framing.test.ts | 89 + crates/exav-viewer/ts/model/framing.ts | 86 + crates/exav-viewer/ts/model/index.ts | 32 + crates/exav-viewer/ts/model/model.worker.ts | 32 + crates/exav-viewer/ts/model/stl.ts | 190 + .../exav-viewer/ts/office/delimited.test.ts | 139 + crates/exav-viewer/ts/office/delimited.ts | 132 + crates/exav-viewer/ts/office/index.ts | 37 + crates/exav-viewer/ts/office/renderer.ts | 151 + .../exav-viewer/ts/office/selection.test.ts | 165 + crates/exav-viewer/ts/office/selection.ts | 90 + crates/exav-viewer/ts/office/zip-tail.test.ts | 69 + crates/exav-viewer/ts/office/zip-tail.ts | 27 + crates/exav-viewer/ts/pdf/assets.ts | 25 + crates/exav-viewer/ts/pdf/decoders.test.ts | 194 + crates/exav-viewer/ts/pdf/engine.ts | 520 + crates/exav-viewer/ts/pdf/index.ts | 69 + crates/exav-viewer/ts/pdf/links.test.ts | 111 + crates/exav-viewer/ts/pdf/options.test.ts | 14 + crates/exav-viewer/ts/pdf/pdfjs-worker.d.ts | 2 + crates/exav-viewer/ts/pdf/pdfjs.worker.ts | 4 + crates/exav-viewer/ts/pdf/rasterizer.ts | 242 + .../exav-viewer/ts/pdf/rasterizer.worker.ts | 185 + crates/exav-viewer/ts/pdf/reader.test.ts | 201 + crates/exav-viewer/ts/pdf/reader.ts | 663 + crates/exav-viewer/ts/pdf/renderer.ts | 79 + .../exav-viewer/ts/react/ViewerBody.test.tsx | 379 + crates/exav-viewer/ts/react/ViewerBody.tsx | 135 + .../ts/react/ViewerDialog.test.tsx | 105 + crates/exav-viewer/ts/react/ViewerDialog.tsx | 172 + crates/exav-viewer/ts/react/context.tsx | 61 + crates/exav-viewer/ts/react/hooks.ts | 72 + crates/exav-viewer/ts/react/icons.tsx | 98 + crates/exav-viewer/ts/react/index.ts | 41 + crates/exav-viewer/ts/react/messages.ts | 171 + crates/exav-viewer/ts/react/overlay.tsx | 33 + crates/exav-viewer/ts/react/parts.tsx | 510 + crates/exav-viewer/ts/react/sandbox.tsx | 54 + crates/exav-viewer/ts/react/styles.css | 911 ++ crates/exav-viewer/ts/test/blob.ts | 10 + crates/exav-viewer/ts/vite/assets.test.ts | 119 + crates/exav-viewer/ts/vite/assets.ts | 147 + crates/exav-viewer/ts/vite/cli.ts | 72 + crates/exav-viewer/ts/vite/index.ts | 141 + crates/exav-viewer/tsconfig.build.json | 4 + crates/exav-viewer/tsconfig.json | 23 + crates/exav-viewer/vitest.config.ts | 8 + crates/exav-x86/NOTICE | 508 +- crates/exav-x86/README.md | 10 +- crates/exav-x86/src/lib.rs | 187 +- crates/exav-x86/tests/differential.rs | 52 + crates/exav/Cargo.toml | 65 +- crates/exav/NOTICE | 486 +- crates/exav/README.md | 9 +- crates/exav/src/daemon.rs | 1891 ++- crates/exav/src/endpoint.rs | 10 +- crates/exav/src/fuzzing.rs | 48 + crates/exav/src/icap/chunked.rs | 8 + crates/exav/src/icap/config.rs | 16 +- crates/exav/src/icap/mod.rs | 124 +- crates/exav/src/icap/response.rs | 76 +- crates/exav/src/icap/server.rs | 267 +- crates/exav/src/main.rs | 1520 +- crates/exav/src/metrics.rs | 10 +- crates/exav/src/perf.rs | 8 +- crates/exav/src/policy.rs | 42 +- crates/exav/src/signatures.rs | 123 +- crates/exav/src/spill.rs | 65 +- crates/exav/tests/daemon_client.rs | 405 +- crates/exav/tests/detect.rs | 34 + crates/exav/tests/docs_match_cli.rs | 138 +- crates/exav/tests/icap_server.rs | 90 +- crates/exav/tests/json_output.rs | 142 +- crates/exav/tests/listeners.rs | 666 +- crates/exav/tests/multi_volume.rs | 19 +- crates/exav/tests/one_scan.rs | 306 + crates/exav/tests/packaging.rs | 175 + crates/exav/tests/self_scan.rs | 3 +- crates/exav/tests/value_vocabulary.rs | 91 +- crates/exav/tests/walk_errors.rs | 79 +- deny.toml | 5 - docker-compose.yml | 30 +- docs/BACKLOG.md | 182 + docs/BYTECODE.md | 219 +- docs/COMPARISON_NOTES.md | 106 + docs/DATABASE.md | 116 +- docs/DIFF_TESTING.md | 82 +- docs/FUZZING.md | 233 +- docs/GAPS.md | 2 +- docs/PARTIAL.md | 107 +- docs/QUIRKS.md | 57 +- docs/STREAMING_FORMATS.md | 30 + docs/VERDICT_PROTOCOL_PLAN.md | 567 - docs/WASM.md | 112 +- docs/YARA.md | 132 +- fuzz/Cargo.lock | 1101 +- fuzz/Cargo.toml | 178 +- fuzz/db.rs | 72 + fuzz/db/README.md | 16 + fuzz/db/fuzz.cbc | 11 + fuzz/db/fuzz.cdb | 4 + fuzz/db/fuzz.crb | 2 + fuzz/db/fuzz.db | 3 + fuzz/db/fuzz.fdb | 2 + fuzz/db/fuzz.fp | 1 + fuzz/db/fuzz.ftm | 4 + fuzz/db/fuzz.hdb | 3 + fuzz/db/fuzz.hsb | 3 + fuzz/db/fuzz.ign2 | 3 + fuzz/db/fuzz.imp | 2 + fuzz/db/fuzz.ldb | 23 + fuzz/db/fuzz.mdb | 2 + fuzz/db/fuzz.ndb | 27 + fuzz/db/fuzz.pdb | 4 + fuzz/db/fuzz.pwdb | 2 + fuzz/db/fuzz.wdb | 3 + fuzz/db/fuzz.yar | 98 + fuzz/dicts/clamd.dict | 26 + fuzz/dicts/icap.dict | 30 + fuzz/dicts/pcre.dict | 65 + fuzz/dicts/signatures.dict | 51 + fuzz/dicts/yara.dict | 64 + fuzz/exav-cli/Cargo.toml | 40 + fuzz/fuzz_targets/analyze.rs | 35 +- fuzz/fuzz_targets/authenticode.rs | 43 + fuzz/fuzz_targets/cad_dwg.rs | 28 + fuzz/fuzz_targets/cad_dxf.rs | 24 + fuzz/fuzz_targets/clamd.rs | 213 + fuzz/fuzz_targets/cvd.rs | 29 +- fuzz/fuzz_targets/database.rs | 30 + fuzz/fuzz_targets/drawing.rs | 19 + fuzz/fuzz_targets/full_pipeline.rs | 249 +- fuzz/fuzz_targets/icap.rs | 249 + fuzz/fuzz_targets/ifc.rs | 17 + fuzz/fuzz_targets/imagehash.rs | 58 + fuzz/fuzz_targets/ndb_compile.rs | 2 +- fuzz/fuzz_targets/pcre.rs | 50 + fuzz/fuzz_targets/pe_emulator.rs | 9 +- fuzz/fuzz_targets/seekable.rs | 99 + fuzz/fuzz_targets/sigs.rs | 8 +- fuzz/fuzz_targets/unpack.rs | 71 +- fuzz/fuzz_targets/volumes.rs | 107 + fuzz/fuzz_targets/yara.rs | 59 + fuzz/options.rs | 71 + fuzz/seeds/imagehash/dxt1.dds | Bin 0 -> 136 bytes fuzz/seeds/imagehash/rgb.hdr | Bin 0 -> 109 bytes fuzz/seeds/imagehash/rgba.ff | Bin 0 -> 144 bytes fuzz/seeds/pcre/patterns.txt | 32 + fuzz/seeds/yara/modules.yar | 15 + fuzz/seeds/yara/small.yar | 10 + fuzz/support/Cargo.toml | 8 + fuzz/support/src/extreme.rs | 107 + fuzz/support/src/frame.rs | 124 + fuzz/support/src/lib.rs | 5 + packaging/exav-clamd.service | 72 - packaging/exav.service | 76 + scripts/check-features.sh | 40 + scripts/check-links.mjs | 103 + scripts/clamav-reach.sh | 2 +- scripts/difftest.sh | 104 +- scripts/format-chain-fuzz.py | 11 +- scripts/fuzz-campaign.sh | 34 +- scripts/fuzz-seeds-synth.py | 196 + scripts/fuzz-seeds.sh | 265 + scripts/release.sh | 18 +- scripts/test-viewer.sh | 95 + scripts/test-wasm.sh | 9 + scripts/test-www.sh | 10 +- scripts/wasm-format-sizes.sh | 9 +- www/astro.config.mjs | 292 +- www/package-lock.json | 18 +- www/package.json | 5 +- www/src/components/Header.astro | 92 + www/src/components/SectionsMenu.astro | 68 + www/src/components/Sidebar.astro | 18 + www/src/components/ThemeProvider.astro | 4 + www/src/components/ThemeSelect.astro | 3 + www/src/components/TopicList.astro | 68 + www/src/components/TopicNav.astro | 60 + www/src/content/docs/concepts/architecture.md | 211 - .../docs/concepts/archive-extraction.md | 318 - .../content/docs/concepts/bytecode-sandbox.md | 93 - .../docs/concepts/design-principles.md | 145 - .../docs/concepts/differential-testing.md | 104 - www/src/content/docs/concepts/pe-emulation.md | 163 - www/src/content/docs/concepts/quirks.md | 869 -- .../content/docs/concepts/streaming-memory.md | 89 - .../docs/getting-started/installation.mdx | 123 - .../docs/getting-started/introduction.md | 96 - .../docs/getting-started/quick-start.mdx | 137 - www/src/content/docs/guides/daemon.mdx | 248 - www/src/content/docs/guides/docker.mdx | 228 - www/src/content/docs/guides/icap.mdx | 417 - www/src/content/docs/guides/library-usage.md | 138 - .../docs/guides/migrating-from-clamav.mdx | 288 - .../content/docs/guides/prebuilt-database.mdx | 145 - www/src/content/docs/guides/scanning.mdx | 196 - www/src/content/docs/guides/signatures.mdx | 140 - .../content/docs/guides/troubleshooting.md | 90 - www/src/content/docs/guides/wasm-sandbox.mdx | 118 - www/src/content/docs/guides/yara.mdx | 100 - www/src/content/docs/index.mdx | 112 +- www/src/content/docs/project/architecture.md | 141 + .../docs/project/comparison-with-clamav.md | 756 - www/src/content/docs/project/contributing.md | 192 +- www/src/content/docs/project/dependencies.md | 318 + www/src/content/docs/project/license.md | 51 +- www/src/content/docs/project/roadmap.md | 233 +- www/src/content/docs/project/security.md | 177 +- .../docs/reference/clamav-flag-matrix.md | 486 - www/src/content/docs/reference/cli.md | 562 - .../content/docs/reference/configuration.md | 155 - .../content/docs/reference/dependencies.md | 289 - .../content/docs/reference/feature-flags.md | 146 - www/src/content/docs/reference/formats.md | 364 - www/src/content/docs/reference/limits.md | 125 - www/src/content/docs/reference/verdicts.md | 123 - .../docs/scanner/concepts/bytecode-sandbox.md | 102 + .../scanner/concepts/design-principles.md | 130 + .../scanner/concepts/differential-testing.md | 86 + .../docs/scanner/concepts/how-it-works.md | 282 + .../docs/scanner/concepts/pe-emulation.md | 149 + .../content/docs/scanner/concepts/quirks.md | 462 + .../docs/scanner/concepts/streaming-memory.md | 245 + .../scanner/getting-started/installation.mdx | 145 + .../scanner/getting-started/introduction.mdx | 118 + .../scanner/getting-started/quick-start.mdx | 130 + .../content/docs/scanner/guides/daemon.mdx | 313 + .../content/docs/scanner/guides/docker.mdx | 289 + www/src/content/docs/scanner/guides/icap.mdx | 329 + .../scanner/guides/migrating-from-clamav.mdx | 276 + .../docs/scanner/guides/prebuilt-database.mdx | 150 + .../content/docs/scanner/guides/scanning.mdx | 167 + .../docs/scanner/guides/signatures.mdx | 151 + www/src/content/docs/scanner/guides/sizing.md | 159 + .../docs/scanner/guides/troubleshooting.md | 142 + .../docs/scanner/guides/wasm-sandbox.mdx | 133 + www/src/content/docs/scanner/guides/yara.mdx | 120 + .../scanner/reference/clamav-flag-matrix.md | 451 + www/src/content/docs/scanner/reference/cli.md | 477 + .../reference/comparison-with-clamav.md | 515 + .../docs/scanner/reference/configuration.md | 92 + .../docs/scanner/reference/feature-flags.md | 116 + .../content/docs/scanner/reference/formats.md | 248 + .../content/docs/scanner/reference/limits.md | 185 + .../docs/scanner/reference/verdicts.md | 131 + www/src/content/docs/subprojects/exav-core.md | 260 +- www/src/content/docs/subprojects/exav-grep.md | 86 +- .../docs/subprojects/exav-imagehash.md | 150 + .../content/docs/subprojects/exav-pe-emu.md | 112 +- .../content/docs/subprojects/exav-render.md | 224 + .../content/docs/subprojects/exav-unpack.md | 181 - .../content/docs/subprojects/exav-update.md | 65 +- www/src/content/docs/subprojects/exav-x86.md | 60 +- www/src/content/docs/subprojects/index.md | 56 +- www/src/content/docs/unpack/cli.md | 148 + www/src/content/docs/unpack/formats.md | 300 + www/src/content/docs/unpack/how-it-works.md | 310 + www/src/content/docs/unpack/index.md | 104 + www/src/content/docs/unpack/rust.md | 166 + www/src/content/docs/unpack/wasm.md | 216 + www/src/content/docs/viewer/api.md | 349 + www/src/content/docs/viewer/index.md | 198 + www/src/content/docs/viewer/integration.md | 345 + www/src/content/docs/viewer/react.md | 195 + www/src/content/docs/viewer/security.md | 373 + www/src/styles/custom.css | 17 +- 1246 files changed, 203039 insertions(+), 30973 deletions(-) create mode 100644 .github/workflows/fuzz-nightly.yml create mode 100644 .oss-scanner/Dockerfile create mode 100644 .oss-scanner/Dockerfile.dockerignore create mode 100644 .oss-scanner/threat_model.md create mode 100644 crates/exav-core/examples/sweepbench.rs create mode 100644 crates/exav-core/src/byte_source.rs create mode 100644 crates/exav-core/src/bytes.rs create mode 100644 crates/exav-core/src/engine/pcre.rs create mode 100644 crates/exav-core/src/engine/pins.rs create mode 100644 crates/exav-core/src/fancy_regex/LICENSE create mode 100644 crates/exav-core/src/fancy_regex/README.md create mode 100644 crates/exav-core/src/fancy_regex/analyze.rs create mode 100644 crates/exav-core/src/fancy_regex/bytes/mod.rs create mode 100644 crates/exav-core/src/fancy_regex/compile.rs create mode 100644 crates/exav-core/src/fancy_regex/error.rs create mode 100644 crates/exav-core/src/fancy_regex/expand.rs create mode 100644 crates/exav-core/src/fancy_regex/input.rs create mode 100644 crates/exav-core/src/fancy_regex/mod.rs create mode 100644 crates/exav-core/src/fancy_regex/optimize.rs create mode 100644 crates/exav-core/src/fancy_regex/parse.rs create mode 100644 crates/exav-core/src/fancy_regex/parse_flags.rs create mode 100644 crates/exav-core/src/fancy_regex/regexset.rs create mode 100644 crates/exav-core/src/fancy_regex/replacer.rs create mode 100644 crates/exav-core/src/fancy_regex/seek.rs create mode 100644 crates/exav-core/src/fancy_regex/to_hir.rs create mode 100644 crates/exav-core/src/fancy_regex/vm.rs delete mode 100644 crates/exav-core/src/fuzzy_img.rs create mode 100644 crates/exav-core/src/grams/mod.rs create mode 100644 crates/exav-core/src/grams/rarity.rs create mode 100644 crates/exav-core/src/grams/sweep.rs create mode 100644 crates/exav-core/src/spill.rs create mode 100644 crates/exav-core/src/stream_regex.rs create mode 100644 crates/exav-core/tests/fixtures/pe/icon32.exe create mode 100644 crates/exav-core/tests/fixtures/pe/make_icon_pe.py create mode 100644 crates/exav-core/tests/suites/broken_executable.rs create mode 100644 crates/exav-core/tests/suites/checksum_mismatch.rs create mode 100644 crates/exav-core/tests/suites/cut_short_members.rs create mode 100644 crates/exav-core/tests/suites/fuzzy_img_formats.rs create mode 100644 crates/exav-core/tests/suites/one_scan.rs create mode 100644 crates/exav-core/tests/suites/sevenz_ppmd.rs create mode 100644 crates/exav-core/tests/suites/size_caps.rs create mode 100644 crates/exav-core/tests/suites/target_text.rs create mode 100644 crates/exav-core/tests/suites/zip_ppmd.rs create mode 100644 crates/exav-imagehash/Cargo.toml create mode 100644 crates/exav-imagehash/LICENSE create mode 100644 crates/exav-imagehash/NOTICE create mode 100644 crates/exav-imagehash/README.md create mode 100644 crates/exav-imagehash/src/LICENSE-pillow create mode 100644 crates/exav-imagehash/src/LICENSE-rustdct create mode 100644 crates/exav-imagehash/src/dct.rs create mode 100644 crates/exav-imagehash/src/lib.rs create mode 100644 crates/exav-imagehash/src/main.rs create mode 100644 crates/exav-imagehash/src/pillow.rs create mode 100644 crates/exav-imagehash/src/tests.rs create mode 100644 crates/exav-imagehash/tests/fixtures/decoder_sensitive.jpg create mode 100644 crates/exav-imagehash/tests/fixtures/expected.txt create mode 100644 crates/exav-imagehash/tests/fixtures/generate.py create mode 100644 crates/exav-imagehash/tests/fixtures/img/bilevel.bmp create mode 100644 crates/exav-imagehash/tests/fixtures/img/bilevel.pbm create mode 100644 crates/exav-imagehash/tests/fixtures/img/bilevel.png create mode 100644 crates/exav-imagehash/tests/fixtures/img/bmp.ico create mode 100644 crates/exav-imagehash/tests/fixtures/img/cmyk.tif create mode 100644 crates/exav-imagehash/tests/fixtures/img/deflate.tif create mode 100644 crates/exav-imagehash/tests/fixtures/img/i16.png create mode 100644 crates/exav-imagehash/tests/fixtures/img/l.jpg create mode 100644 crates/exav-imagehash/tests/fixtures/img/l.pgm create mode 100644 crates/exav-imagehash/tests/fixtures/img/l.png create mode 100644 crates/exav-imagehash/tests/fixtures/img/l.tif create mode 100644 crates/exav-imagehash/tests/fixtures/img/la.png create mode 100644 crates/exav-imagehash/tests/fixtures/img/lossless.webp create mode 100644 crates/exav-imagehash/tests/fixtures/img/lossy.webp create mode 100644 crates/exav-imagehash/tests/fixtures/img/lzw.tif create mode 100644 crates/exav-imagehash/tests/fixtures/img/p.bmp create mode 100644 crates/exav-imagehash/tests/fixtures/img/p.png create mode 100644 crates/exav-imagehash/tests/fixtures/img/p_trns.png create mode 100644 crates/exav-imagehash/tests/fixtures/img/rgb.bmp create mode 100644 crates/exav-imagehash/tests/fixtures/img/rgb.gif create mode 100644 crates/exav-imagehash/tests/fixtures/img/rgb.jpg create mode 100644 crates/exav-imagehash/tests/fixtures/img/rgb.png create mode 100644 crates/exav-imagehash/tests/fixtures/img/rgb.ppm create mode 100644 crates/exav-imagehash/tests/fixtures/img/rgb.qoi create mode 100644 crates/exav-imagehash/tests/fixtures/img/rgb.tif create mode 100644 crates/exav-imagehash/tests/fixtures/img/rgb16.ppm create mode 100644 crates/exav-imagehash/tests/fixtures/img/rgba.bmp create mode 100644 crates/exav-imagehash/tests/fixtures/img/rgba.ico create mode 100644 crates/exav-imagehash/tests/fixtures/img/rgba.png create mode 100644 crates/exav-imagehash/tests/fixtures/img/rgba.qoi create mode 100644 crates/exav-imagehash/tests/fixtures/img/rgba.webp create mode 100644 crates/exav-imagehash/tests/fixtures/img/trns.gif create mode 100644 crates/exav-imagehash/tests/memory.rs create mode 100644 crates/exav-imagehash/tests/reference.rs create mode 100644 crates/exav-render/Cargo.toml create mode 100644 crates/exav-render/LICENSE create mode 100644 crates/exav-render/README.md create mode 100644 crates/exav-render/build.rs create mode 100644 crates/exav-render/examples/cad_dump.rs create mode 100644 crates/exav-render/examples/ifc_stats.rs create mode 100644 crates/exav-render/examples/scene_stats.rs create mode 100644 crates/exav-render/fonts/LICENSE-CC0-1.0.txt create mode 100644 crates/exav-render/fonts/newstroke.bene create mode 100644 crates/exav-render/scripts/font-tables.py create mode 100644 crates/exav-render/src/formats/cad/dwg/blocks.rs create mode 100644 crates/exav-render/src/formats/cad/dwg/entities.rs create mode 100644 crates/exav-render/src/formats/cad/dwg/header.rs create mode 100644 crates/exav-render/src/formats/cad/dwg/mod.rs create mode 100644 crates/exav-render/src/formats/cad/dwg/objects.rs create mode 100644 crates/exav-render/src/formats/cad/dwg/tables.rs create mode 100644 crates/exav-render/src/formats/cad/dxf/build.rs create mode 100644 crates/exav-render/src/formats/cad/dxf/entities.rs create mode 100644 crates/exav-render/src/formats/cad/dxf/header.rs create mode 100644 crates/exav-render/src/formats/cad/dxf/mod.rs create mode 100644 crates/exav-render/src/formats/cad/dxf/objects.rs create mode 100644 crates/exav-render/src/formats/cad/dxf/tables.rs create mode 100644 crates/exav-render/src/formats/cad/dxf/tests.rs create mode 100644 crates/exav-render/src/formats/cad/json.rs create mode 100644 crates/exav-render/src/formats/cad/mod.rs create mode 100644 crates/exav-render/src/formats/cad/model.rs create mode 100644 crates/exav-render/src/formats/cad/model/entity.rs create mode 100644 crates/exav-render/src/formats/cad/model/objects.rs create mode 100644 crates/exav-render/src/formats/cad/model/proxy.rs create mode 100644 crates/exav-render/src/formats/cad/model/tables.rs create mode 100644 crates/exav-render/src/formats/cad/preview.rs create mode 100644 crates/exav-render/src/formats/cad/proxy.rs create mode 100644 crates/exav-render/src/formats/dwg/DESIGN.md create mode 100644 crates/exav-render/src/formats/dwg/clip.rs create mode 100644 crates/exav-render/src/formats/dwg/curves.rs create mode 100644 crates/exav-render/src/formats/dwg/fill.rs create mode 100644 crates/exav-render/src/formats/dwg/font.rs create mode 100644 crates/exav-render/src/formats/dwg/gradient.rs create mode 100644 crates/exav-render/src/formats/dwg/hatch.rs create mode 100644 crates/exav-render/src/formats/dwg/linetype.rs create mode 100644 crates/exav-render/src/formats/dwg/metrics.rs create mode 100644 crates/exav-render/src/formats/dwg/mod.rs create mode 100644 crates/exav-render/src/formats/dwg/palette.rs create mode 100644 crates/exav-render/src/formats/dwg/proxy.rs create mode 100644 crates/exav-render/src/formats/dwg/scene.rs create mode 100644 crates/exav-render/src/formats/dwg/stroke_font/binary.rs create mode 100644 crates/exav-render/src/formats/dwg/stroke_font/fontobene.rs create mode 100644 crates/exav-render/src/formats/dwg/stroke_font/mod.rs create mode 100644 crates/exav-render/src/formats/dwg/tessellate.rs create mode 100644 crates/exav-render/src/formats/dwg/text.rs create mode 100644 crates/exav-render/src/formats/dwg/tiles.rs create mode 100644 crates/exav-render/src/formats/ifc/csg.rs create mode 100644 crates/exav-render/src/formats/ifc/curves.rs create mode 100644 crates/exav-render/src/formats/ifc/items.rs create mode 100644 crates/exav-render/src/formats/ifc/math.rs create mode 100644 crates/exav-render/src/formats/ifc/mod.rs create mode 100644 crates/exav-render/src/formats/ifc/profiles.rs create mode 100644 crates/exav-render/src/formats/ifc/solids.rs create mode 100644 crates/exav-render/src/formats/ifc/step.rs create mode 100644 crates/exav-render/src/formats/ifc/triangulate.rs create mode 100644 crates/exav-render/src/formats/image.rs create mode 100644 crates/exav-render/src/formats/image/jbig2.rs create mode 100644 crates/exav-render/src/formats/image/jp2.rs create mode 100644 crates/exav-render/src/formats/image/tests.rs create mode 100644 crates/exav-render/src/formats/mesh.rs create mode 100644 crates/exav-render/src/formats/mod.rs create mode 100644 crates/exav-render/src/formats/pdf_image/ccitt.rs create mode 100644 crates/exav-render/src/formats/pdf_image/jbig2.rs create mode 100644 crates/exav-render/src/formats/pdf_image/jpx.rs create mode 100644 crates/exav-render/src/formats/pdf_image/mod.rs create mode 100644 crates/exav-render/src/formats/stl.rs create mode 100644 crates/exav-render/src/image_codecs/LICENSE-image create mode 100644 crates/exav-render/src/image_codecs/README.md create mode 100644 crates/exav-render/src/image_codecs/jpeg.rs create mode 100644 crates/exav-render/src/image_codecs/mod.rs create mode 100644 crates/exav-render/src/image_codecs/tiff/LICENSE create mode 100644 crates/exav-render/src/image_codecs/tiff/bytecast.rs create mode 100644 crates/exav-render/src/image_codecs/tiff/decoder/cycles.rs create mode 100644 crates/exav-render/src/image_codecs/tiff/decoder/ifd.rs create mode 100644 crates/exav-render/src/image_codecs/tiff/decoder/image.rs create mode 100644 crates/exav-render/src/image_codecs/tiff/decoder/mod.rs create mode 100644 crates/exav-render/src/image_codecs/tiff/decoder/stream.rs create mode 100644 crates/exav-render/src/image_codecs/tiff/decoder/tag_reader.rs create mode 100644 crates/exav-render/src/image_codecs/tiff/directory.rs create mode 100644 crates/exav-render/src/image_codecs/tiff/error.rs create mode 100644 crates/exav-render/src/image_codecs/tiff/mod.rs create mode 100644 crates/exav-render/src/image_codecs/tiff/tags.rs create mode 100644 crates/exav-render/src/image_codecs/tiff_image.rs create mode 100644 crates/exav-render/src/lib.rs create mode 100644 crates/exav-render/tests/cad_common/compare.rs create mode 100644 crates/exav-render/tests/cad_common/mod.rs create mode 100644 crates/exav-render/tests/cad_dwg.rs create mode 100644 crates/exav-render/tests/cad_dwg_oracle.rs create mode 100644 crates/exav-render/tests/cad_fixtures.rs create mode 100644 crates/exav-render/tests/cad_oracle.rs create mode 100644 crates/exav-render/tests/cad_oracle/ezdxf_dump.py create mode 100644 crates/exav-render/tests/cad_proxy.rs create mode 100644 crates/exav-render/tests/cad_robust.rs create mode 100644 crates/exav-render/tests/dwg.rs create mode 100644 crates/exav-render/tests/fixtures/cad/ascii/R12/all.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/ascii/R12/cp1251.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/ascii/R2000/all.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/ascii/R2000/cp1251.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/ascii/R2004/all.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/ascii/R2004/cp1251.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/ascii/R2007/all.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/ascii/R2007/cp1251.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/ascii/R2010/all.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/ascii/R2010/cp1251.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/ascii/R2013/all.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/ascii/R2013/cp1251.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/ascii/R2018/all.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/ascii/R2018/cp1251.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/binary/R12/all.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/binary/R12/cp1251.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/binary/R2000/all.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/binary/R2000/cp1251.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/binary/R2004/all.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/binary/R2004/cp1251.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/binary/R2007/all.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/binary/R2007/cp1251.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/binary/R2010/all.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/binary/R2010/cp1251.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/binary/R2013/all.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/binary/R2013/cp1251.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/binary/R2018/all.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/binary/R2018/cp1251.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R13/all.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R13/c7.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R13/cp1251.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R13/dwgcases.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R13/entities.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R13/objects.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R14/all.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R14/c7.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R14/cp1251.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R14/dwgcases.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R14/entities.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R14/objects.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2000/all.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2000/c7.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2000/cp1251.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2000/dwgcases.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2000/entities.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2000/objects.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2004/all.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2004/c7.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2004/cp1251.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2004/dwgcases.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2004/entities.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2004/objects.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2007/all.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2007/c7.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2007/cp1251.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2007/dwgcases.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2007/entities.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2007/objects.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2010/all.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2010/c7.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2010/cp1251.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2010/dwgcases.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2010/entities.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2010/objects.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2013/all.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2013/c7.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2013/cp1251.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2013/dwgcases.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2013/entities.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2013/objects.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2018/all.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2018/c7.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2018/cp1251.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2018/dwgcases.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2018/entities.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/dwg/R2018/objects.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/expected.json create mode 100644 crates/exav-render/tests/fixtures/cad/make.py create mode 100644 crates/exav-render/tests/fixtures/cad/proxy/dwg/R13/proxy.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/proxy/dwg/R14/proxy.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/proxy/dwg/R2000/proxy.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/proxy/dwg/R2004/proxy.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/proxy/dwg/R2007/proxy.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/proxy/dwg/R2010/proxy.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/proxy/dwg/R2013/proxy.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/proxy/dwg/R2018/proxy.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/cad/proxy/make.py create mode 100644 crates/exav-render/tests/fixtures/cad/proxy/r12/proxy.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/proxy/r13/proxy.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/proxy/src/proxy.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/src/all-binary.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/src/all.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/src/c7.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/src/cp1251.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/src/dwgcases.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/src/entities.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/src/gradient.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/cad/src/objects.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/dwg/attribs-R2000.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/dwg/attribs.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/dwg/attribs.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/dwg/hatch7.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/dwg/hatch7.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/dwg/hostile.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/dwg/layouts.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/dwg/layouts.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/dwg/leader.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/dwg/lines200.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/dwg/make.py create mode 100644 crates/exav-render/tests/fixtures/dwg/plan-R2000.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/dwg/plan.dwg.gz create mode 100644 crates/exav-render/tests/fixtures/dwg/plan.dxf.gz create mode 100644 crates/exav-render/tests/fixtures/fuzz/arc-end-angle-1e99.dwg create mode 100644 crates/exav-render/tests/fixtures/fuzz/frozen-layer-count.dwg create mode 100644 crates/exav-render/tests/fixtures/fuzz/graphic-size-2gb.dwg create mode 100644 crates/exav-render/tests/fixtures/fuzz/handle-seed-max.dwg create mode 100644 crates/exav-render/tests/fixtures/fuzz/modular-short-shift.dwg create mode 100644 crates/exav-render/tests/fixtures/ifc/booleans.ifc create mode 100644 crates/exav-render/tests/fixtures/ifc/damaged.ifc create mode 100644 crates/exav-render/tests/fixtures/ifc/expected.json create mode 100644 crates/exav-render/tests/fixtures/ifc/ifc2x3_feet.ifc create mode 100644 crates/exav-render/tests/fixtures/ifc/make.py create mode 100644 crates/exav-render/tests/fixtures/ifc/mapped_units.ifc create mode 100644 crates/exav-render/tests/fixtures/ifc/profiles.ifc create mode 100644 crates/exav-render/tests/fixtures/ifc/solids.ifc create mode 100644 crates/exav-render/tests/fixtures/ifc/tessellated.ifc create mode 100644 crates/exav-render/tests/fixtures/images/bilevel.g3-1d create mode 100644 crates/exav-render/tests/fixtures/images/bilevel.g3-2d create mode 100644 crates/exav-render/tests/fixtures/images/bilevel.g3-fill create mode 100644 crates/exav-render/tests/fixtures/images/bilevel.g4 create mode 100644 crates/exav-render/tests/fixtures/images/bilevel.png create mode 100644 crates/exav-render/tests/fixtures/images/bilevel.rle create mode 100644 crates/exav-render/tests/fixtures/images/generic-random.jb2 create mode 100644 crates/exav-render/tests/fixtures/images/generic.jb2 create mode 100644 crates/exav-render/tests/fixtures/images/grey-subsampled-tiles.j2k create mode 100644 crates/exav-render/tests/fixtures/images/grey.j2k create mode 100644 crates/exav-render/tests/fixtures/images/grey.png create mode 100644 crates/exav-render/tests/fixtures/images/jbig2_region_bomb.seg create mode 100644 crates/exav-render/tests/fixtures/images/make.py create mode 100644 crates/exav-render/tests/fixtures/images/rgb-offset.j2k create mode 100644 crates/exav-render/tests/fixtures/images/rgb.j2k create mode 100644 crates/exav-render/tests/fixtures/images/rgb.jp2 create mode 100644 crates/exav-render/tests/fixtures/images/rgb.png create mode 100644 crates/exav-render/tests/fixtures/images/rgb38-narrow-tile.j2k create mode 100644 crates/exav-render/tests/fixtures/images/rgb38-tiles-r1.png create mode 100644 crates/exav-render/tests/fixtures/images/rgb38-tiles.j2k create mode 100644 crates/exav-render/tests/fixtures/images/rgb38.png create mode 100644 crates/exav-render/tests/fixtures/images/rgba.jp2 create mode 100644 crates/exav-render/tests/fixtures/images/rgba.png create mode 100644 crates/exav-render/tests/fixtures/images/symbol.jb2 create mode 100644 crates/exav-render/tests/fixtures/stl/box.stl create mode 100644 crates/exav-render/tests/fixtures/stl/box_ascii.stl create mode 100644 crates/exav-render/tests/fixtures/stl/expected.json create mode 100644 crates/exav-render/tests/fixtures/stl/huge_count.stl create mode 100644 crates/exav-render/tests/fixtures/stl/magics.stl create mode 100644 crates/exav-render/tests/fixtures/stl/make.py create mode 100644 crates/exav-render/tests/fixtures/stl/solid_header.stl create mode 100644 crates/exav-render/tests/fixtures/stl/truncated.stl create mode 100644 crates/exav-render/tests/fixtures/stl/viscam.stl create mode 100644 crates/exav-render/tests/fixtures/viewer/house.ifc create mode 100644 crates/exav-render/tests/fixtures/viewer/house.stl create mode 100644 crates/exav-render/tests/ifc.rs create mode 100644 crates/exav-render/tests/ifc_oracle.rs create mode 100644 crates/exav-render/tests/ifc_oracle/webifc_stats.mjs create mode 100644 crates/exav-render/tests/jpeg2000_jbig2.rs create mode 100644 crates/exav-render/tests/stl.rs create mode 100644 crates/exav-unpack/src/bytes.rs create mode 100644 crates/exav-unpack/src/formats/autoit_data.rs create mode 100644 crates/exav-unpack/src/formats/bzip2_rs/bitreader.rs create mode 100644 crates/exav-unpack/src/formats/bzip2_rs/block/bwt.rs create mode 100644 crates/exav-unpack/src/formats/bzip2_rs/block/error.rs create mode 100644 crates/exav-unpack/src/formats/bzip2_rs/block/mod.rs create mode 100644 crates/exav-unpack/src/formats/bzip2_rs/crc.rs create mode 100644 crates/exav-unpack/src/formats/bzip2_rs/decoder/error.rs create mode 100644 crates/exav-unpack/src/formats/bzip2_rs/decoder/mod.rs create mode 100644 crates/exav-unpack/src/formats/bzip2_rs/decoder/reader.rs create mode 100644 crates/exav-unpack/src/formats/bzip2_rs/header/error.rs create mode 100644 crates/exav-unpack/src/formats/bzip2_rs/header/mod.rs create mode 100644 crates/exav-unpack/src/formats/bzip2_rs/huffman.rs create mode 100644 crates/exav-unpack/src/formats/bzip2_rs/mod.rs create mode 100644 crates/exav-unpack/src/formats/bzip2_rs/move_to_front.rs create mode 100644 crates/exav-unpack/src/formats/codepage.rs create mode 100644 crates/exav-unpack/src/formats/dwg/bits.rs create mode 100644 crates/exav-unpack/src/formats/dwg/extract.rs create mode 100644 crates/exav-unpack/src/formats/dwg/file.rs create mode 100644 crates/exav-unpack/src/formats/dwg/mod.rs create mode 100644 crates/exav-unpack/src/formats/dwg/object.rs create mode 100644 crates/exav-unpack/src/formats/dwg/r2004.rs create mode 100644 crates/exav-unpack/src/formats/dwg/r2007.rs create mode 100644 crates/exav-unpack/src/formats/dxf/extract.rs create mode 100644 crates/exav-unpack/src/formats/dxf/mod.rs create mode 100644 crates/exav-unpack/src/formats/dxf/pairs.rs create mode 100644 crates/exav-unpack/src/formats/dxf/parts.rs create mode 100644 crates/exav-unpack/src/formats/dxf/records.rs create mode 100644 crates/exav-unpack/src/formats/lzma.rs create mode 100644 crates/exav-unpack/src/formats/ppmd7/common.rs create mode 100644 crates/exav-unpack/src/formats/ppmd8/mod.rs create mode 100644 crates/exav-unpack/src/formats/ppmd8/model.rs create mode 100644 crates/exav-unpack/src/formats/rar3_crypt.rs create mode 100644 crates/exav-unpack/src/formats/rar5_crypt.rs create mode 100644 crates/exav-unpack/src/inflate.rs create mode 100644 crates/exav-unpack/src/profile.rs create mode 100644 crates/exav-unpack/src/source.rs create mode 100644 crates/exav-unpack/src/span.rs create mode 100644 crates/exav-unpack/tests/fixtures/7z/aes_solid_many.7z create mode 100644 crates/exav-unpack/tests/fixtures/7z/bcj_lzma.7z create mode 100644 crates/exav-unpack/tests/fixtures/7z/delta_lzma.7z create mode 100644 crates/exav-unpack/tests/fixtures/7z/ppmd_plain_header.7z create mode 100644 crates/exav-unpack/tests/fixtures/checksum/clean.arc create mode 100644 crates/exav-unpack/tests/fixtures/checksum/clean.bz2 create mode 100644 crates/exav-unpack/tests/fixtures/checksum/clean.lz create mode 100644 crates/exav-unpack/tests/fixtures/checksum/clean.wim create mode 100644 crates/exav-unpack/tests/fixtures/checksum/eicar.arc.xor create mode 100644 crates/exav-unpack/tests/fixtures/checksum/eicar.wim.xor create mode 100644 crates/exav-unpack/tests/fixtures/checksum/make.py create mode 100644 crates/exav-unpack/tests/fixtures/checksum/two_blocks.bz2.xor create mode 100644 crates/exav-unpack/tests/fixtures/checksum/two_members.lz.xor create mode 100644 crates/exav-unpack/tests/fixtures/chm/multi-frame-lzx.chm create mode 100644 crates/exav-unpack/tests/fixtures/cut_lzip.lz.xor create mode 100644 crates/exav-unpack/tests/fixtures/cut_short/7z_bcj2.7z.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/cut_short/7z_deflate.7z.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/cut_short/7z_lzma.7z.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/cut_short/7z_lzma2.7z.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/cut_short/disk.qcow2.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/cut_short/disk.vmdk.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/cut_short/make.py create mode 100644 crates/exav-unpack/tests/fixtures/cut_short/make_udif.py create mode 100644 crates/exav-unpack/tests/fixtures/cut_short/nsis_solid_lzma.exe.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/cut_short/nsis_zlib.exe.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/cut_short/swf_cws.swf.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/cut_short/swf_zws.swf.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/cut_short/udif_bzip2.dmg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/cut_short/udif_bzip2_first.dmg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/cut_short/udif_xz.dmg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/cut_short/udif_xz_first.dmg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/cut_short/udif_zlib.dmg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/cut_short/upx_lzma.elf.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/dwg/R13.dwg.gz create mode 100644 crates/exav-unpack/tests/fixtures/dwg/R14.dwg.gz create mode 100644 crates/exav-unpack/tests/fixtures/dwg/R2000.dwg.gz create mode 100644 crates/exav-unpack/tests/fixtures/dwg/R2004.dwg.gz create mode 100644 crates/exav-unpack/tests/fixtures/dwg/R2007.dwg.gz create mode 100644 crates/exav-unpack/tests/fixtures/dwg/R2010.dwg.gz create mode 100644 crates/exav-unpack/tests/fixtures/dwg/R2013.dwg.gz create mode 100644 crates/exav-unpack/tests/fixtures/dwg/R2018.dwg.gz create mode 100644 crates/exav-unpack/tests/fixtures/dwg/c4/macros/R13.dwg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/dwg/c4/macros/R14.dwg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/dwg/c4/macros/R2000.dwg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/dwg/c4/macros/R2004.dwg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/dwg/c4/macros/R2007.dwg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/dwg/c4/macros/R2010.dwg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/dwg/c4/macros/R2013.dwg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/dwg/c4/macros/R2018.dwg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/dwg/c4/make.py create mode 100644 crates/exav-unpack/tests/fixtures/dwg/c4/packager/R13.dwg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/dwg/c4/packager/R14.dwg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/dwg/c4/packager/R2000.dwg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/dwg/c4/packager/R2004.dwg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/dwg/c4/packager/R2007.dwg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/dwg/c4/packager/R2010.dwg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/dwg/c4/packager/R2013.dwg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/dwg/c4/packager/R2018.dwg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/dwg/ole/R13.dwg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/dwg/ole/R14.dwg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/dwg/ole/R2000.dwg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/dwg/ole/R2004.dwg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/dwg/ole/R2007.dwg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/dwg/ole/R2010.dwg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/dwg/ole/R2013.dwg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/dwg/ole/R2018.dwg.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/dwg/ole/make.py create mode 100644 crates/exav-unpack/tests/fixtures/dwg/pre-r13/R12.dwg.gz create mode 100644 crates/exav-unpack/tests/fixtures/dwg/pre-r13/make.py create mode 100644 crates/exav-unpack/tests/fixtures/dwg/preview/DIB.hex create mode 100644 crates/exav-unpack/tests/fixtures/dwg/preview/R13.dwg.gz create mode 100644 crates/exav-unpack/tests/fixtures/dwg/preview/R14.dwg.gz create mode 100644 crates/exav-unpack/tests/fixtures/dwg/preview/R2000.dwg.gz create mode 100644 crates/exav-unpack/tests/fixtures/dwg/preview/R2004.dwg.gz create mode 100644 crates/exav-unpack/tests/fixtures/dwg/preview/R2007.dwg.gz create mode 100644 crates/exav-unpack/tests/fixtures/dwg/preview/R2010.dwg.gz create mode 100644 crates/exav-unpack/tests/fixtures/dwg/preview/R2013.dwg.gz create mode 100644 crates/exav-unpack/tests/fixtures/dwg/preview/R2018.dwg.gz create mode 100644 crates/exav-unpack/tests/fixtures/dwg/preview/make.py create mode 100644 crates/exav-unpack/tests/fixtures/dxf/ascii-R12.dxf.gz create mode 100644 crates/exav-unpack/tests/fixtures/dxf/ascii-R2018.dxf.gz create mode 100644 crates/exav-unpack/tests/fixtures/dxf/binary-R12.dxf.gz create mode 100644 crates/exav-unpack/tests/fixtures/dxf/binary-R2018.dxf.gz create mode 100644 crates/exav-unpack/tests/fixtures/lzw_full/fulltable.b16.Z create mode 100644 crates/exav-unpack/tests/fixtures/ntfs/attribute_list.img.gz create mode 100644 crates/exav-unpack/tests/fixtures/pdf/eicar_qpdf_aesv2_r4.pdf.xor create mode 100644 crates/exav-unpack/tests/fixtures/pdf/eicar_qpdf_aesv3_r6.pdf.xor create mode 100644 crates/exav-unpack/tests/fixtures/pdf/eicar_rc4_r2_gen1.pdf.xor create mode 100644 crates/exav-unpack/tests/fixtures/pdf/empty_aesv2_r4.pdf.xor create mode 100644 crates/exav-unpack/tests/fixtures/pdf/qpdf_actions_aes128.pdf create mode 100644 crates/exav-unpack/tests/fixtures/pdf/qpdf_actions_aes256.pdf create mode 100644 crates/exav-unpack/tests/fixtures/ppmd8/cutoff_random_24576_o16_m32768.ppmd8 create mode 100644 crates/exav-unpack/tests/fixtures/ppmd8/cutoff_random_24576_o6_m16384.ppmd8 create mode 100644 crates/exav-unpack/tests/fixtures/ppmd8/cutoff_skewed_65536_o2_m16384.ppmd8 create mode 100644 crates/exav-unpack/tests/fixtures/ppmd8/cutoff_skewed_65536_o4_m32768.ppmd8 create mode 100644 crates/exav-unpack/tests/fixtures/ppmd8/cutoff_text_131072_o16_m65536.ppmd8 create mode 100644 crates/exav-unpack/tests/fixtures/ppmd8/cutoff_text_400000_o8_m262144.ppmd8 create mode 100644 crates/exav-unpack/tests/fixtures/ppmd8/cutoff_text_65536_o2_m8192.ppmd8 create mode 100644 crates/exav-unpack/tests/fixtures/ppmd8/cutoff_text_65536_o6_m16384.ppmd8 create mode 100644 crates/exav-unpack/tests/fixtures/rar4/enc_data.rar create mode 100644 crates/exav-unpack/tests/fixtures/rar4/enc_headers.rar create mode 100644 crates/exav-unpack/tests/fixtures/rar4/enc_headers_unknown.rar create mode 100644 crates/exav-unpack/tests/fixtures/rar4/solid_empty.rar create mode 100644 crates/exav-unpack/tests/fixtures/rar4/solid_ppmd.rar create mode 100644 crates/exav-unpack/tests/fixtures/rar4/solid_x86.rar create mode 100644 crates/exav-unpack/tests/fixtures/rar4/two_windows.rar create mode 100644 crates/exav-unpack/tests/fixtures/rar4/x86_second.rar create mode 100644 crates/exav-unpack/tests/fixtures/rar5/enc_data.rar create mode 100644 crates/exav-unpack/tests/fixtures/rar5/enc_headers.rar create mode 100644 crates/exav-unpack/tests/fixtures/rar5/enc_headers_unknown.rar create mode 100644 crates/exav-unpack/tests/fixtures/rar5/enc_stored_unknown.rar create mode 100644 crates/exav-unpack/tests/fixtures/rar5/hardlink.rar create mode 100644 crates/exav-unpack/tests/fixtures/rar_solid/solid_x86.rar create mode 100644 crates/exav-unpack/tests/fixtures/rar_solid/two_windows.rar create mode 100644 crates/exav-unpack/tests/fixtures/rar_volumes/set4.r00 create mode 100644 crates/exav-unpack/tests/fixtures/rar_volumes/set4.r01 create mode 100644 crates/exav-unpack/tests/fixtures/rar_volumes/set4.rar create mode 100644 crates/exav-unpack/tests/fixtures/rar_volumes/set5.part1.rar create mode 100644 crates/exav-unpack/tests/fixtures/rar_volumes/set5.part2.rar create mode 100644 crates/exav-unpack/tests/fixtures/rar_volumes/set5.part3.rar create mode 100644 crates/exav-unpack/tests/fixtures/udf/make_metadata_iso.py create mode 100644 crates/exav-unpack/tests/fixtures/udf/metadata.iso.gz.xor create mode 100644 crates/exav-unpack/tests/fixtures/zip/7z_bzip2_large_then_small.zip create mode 100644 crates/exav-unpack/tests/fixtures/zip/7z_deflate64_large_then_small.zip create mode 100644 crates/exav-unpack/tests/fixtures/zip/7z_lzma_large_then_small.zip create mode 100644 crates/exav-unpack/tests/fixtures/zip/7z_ppmd_large_then_small.zip create mode 100644 crates/exav-unpack/tests/fixtures/zip/bzip2_large_then_small.zip create mode 100644 crates/exav-unpack/tests/fixtures/zip/cut_bzip2.zip.xor create mode 100644 crates/exav-unpack/tests/fixtures/zip/cut_deflate.zip.xor create mode 100644 crates/exav-unpack/tests/fixtures/zip/cut_deflate64.zip.xor create mode 100644 crates/exav-unpack/tests/fixtures/zip/cut_lzma.zip.xor create mode 100644 crates/exav-unpack/tests/fixtures/zip/cut_ppmd.zip.xor create mode 100644 crates/exav-unpack/tests/fixtures/zip/cut_stored.zip.xor create mode 100644 crates/exav-unpack/tests/fixtures/zip/cut_xz.zip.xor create mode 100644 crates/exav-unpack/tests/fixtures/zip/cut_zstd.zip.xor create mode 100644 crates/exav-unpack/tests/fixtures/zip/dd_7zip_bzip2.zip create mode 100644 crates/exav-unpack/tests/fixtures/zip/dd_7zip_deflate.zip create mode 100644 crates/exav-unpack/tests/fixtures/zip/dd_7zip_deflate64.zip create mode 100644 crates/exav-unpack/tests/fixtures/zip/dd_7zip_lzma.zip create mode 100644 crates/exav-unpack/tests/fixtures/zip/dd_7zip_ppmd.zip create mode 100644 crates/exav-unpack/tests/fixtures/zip/dd_7zip_xz.zip create mode 100644 crates/exav-unpack/tests/fixtures/zip/dd_python_lzma_zip64.zip create mode 100644 crates/exav-unpack/tests/fixtures/zip/dd_python_stored.zip create mode 100644 crates/exav-unpack/tests/fixtures/zip/dd_python_stored_zip64.zip create mode 100644 crates/exav-unpack/tests/fixtures/zip/legacy_implode.zip create mode 100644 crates/exav-unpack/tests/fixtures/zip/legacy_reduce.zip create mode 100644 crates/exav-unpack/tests/fixtures/zip/legacy_shrink.zip create mode 100644 crates/exav-unpack/tests/fixtures/zip/ppmd_7zip.zip create mode 100644 crates/exav-unpack/tests/fixtures/zip/zip64_python_lzma.zip create mode 100644 crates/exav-unpack/tests/suites/bzip2_blocks.rs create mode 100644 crates/exav-unpack/tests/suites/dwg.rs create mode 100644 crates/exav-unpack/tests/suites/dxf.rs create mode 100644 crates/exav-unpack/tests/suites/extreme.rs create mode 100644 crates/exav-unpack/tests/suites/rar4_compat.rs create mode 100644 crates/exav-unpack/tests/suites/rar5_encryption.rs create mode 100644 crates/exav-unpack/tests/suites/sevenz_ppmd.rs create mode 100644 crates/exav-unpack/tests/suites/stream_read_errors.rs create mode 100644 crates/exav-unpack/tests/suites/zip_appended.rs create mode 100644 crates/exav-viewer/.gitignore create mode 100644 crates/exav-viewer/Cargo.lock create mode 100644 crates/exav-viewer/Cargo.toml create mode 100644 crates/exav-viewer/LICENSE create mode 100644 crates/exav-viewer/LICENSES/Apache-2.0.txt create mode 100644 crates/exav-viewer/LICENSES/CC0-1.0.txt create mode 100644 crates/exav-viewer/NOTICE create mode 100644 crates/exav-viewer/README.md create mode 100644 crates/exav-viewer/assets/fonts/Arimo-Italic-wght.woff2 create mode 100644 crates/exav-viewer/assets/fonts/Arimo-wght.woff2 create mode 100644 crates/exav-viewer/assets/fonts/Cousine-Bold.woff2 create mode 100644 crates/exav-viewer/assets/fonts/Cousine-BoldItalic.woff2 create mode 100644 crates/exav-viewer/assets/fonts/Cousine-Italic.woff2 create mode 100644 crates/exav-viewer/assets/fonts/Cousine-Regular.woff2 create mode 100644 crates/exav-viewer/assets/fonts/NOTICE.md create mode 100644 crates/exav-viewer/assets/fonts/OFL-1.1.txt create mode 100644 crates/exav-viewer/assets/fonts/OFL-arimo.txt create mode 100644 crates/exav-viewer/assets/fonts/Tinos-Bold.woff2 create mode 100644 crates/exav-viewer/assets/fonts/Tinos-BoldItalic.woff2 create mode 100644 crates/exav-viewer/assets/fonts/Tinos-Italic.woff2 create mode 100644 crates/exav-viewer/assets/fonts/Tinos-Regular.woff2 create mode 100644 crates/exav-viewer/assets/pdfjs/absent.wasm create mode 100644 crates/exav-viewer/demo/index.html create mode 100644 crates/exav-viewer/demo/src/App.tsx create mode 100644 crates/exav-viewer/demo/src/demo.css create mode 100644 crates/exav-viewer/demo/src/main.tsx create mode 100644 crates/exav-viewer/demo/src/showcase.ts create mode 100644 crates/exav-viewer/demo/tsconfig.json create mode 100644 crates/exav-viewer/demo/vite.config.ts create mode 100644 crates/exav-viewer/e2e/csp.ts create mode 100644 crates/exav-viewer/e2e/delivery-setup.ts create mode 100644 crates/exav-viewer/e2e/delivery.spec.ts create mode 100644 crates/exav-viewer/e2e/demo.spec.ts create mode 100644 crates/exav-viewer/e2e/fixtures/make-plan.py create mode 100644 crates/exav-viewer/e2e/fixtures/make-samples.mjs create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/cases.json create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/ccitt-g3-1d.pdf create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/ccitt-g3-2d.pdf create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/ccitt-g3-fill.pdf create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/ccitt-g4-blackis1.pdf create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/ccitt-g4.pdf create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/ccitt-rle.pdf create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/cmyk.jp2 create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/g3-1d.ccitt create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/g3-2d.ccitt create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/g3-fill.ccitt create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/g4.ccitt create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/generic.jbig2 create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/grey.j2k create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/grey.jp2 create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/grey4.j2k create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/greya.jp2 create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/icc.pdf create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/jbig2-generic.pdf create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/jbig2-symbol.pdf create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/jbig2-tpgd.pdf create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/jpx-cmyk-devicecmyk.pdf create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/jpx-cmyk.pdf create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/jpx-grey-devicegray.pdf create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/jpx-grey.pdf create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/jpx-grey4.pdf create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/jpx-greya-smaskindata.pdf create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/jpx-indexed.pdf create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/jpx-lossy.pdf create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/jpx-palette.pdf create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/jpx-rgb-devicergb.pdf create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/jpx-rgb.pdf create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/jpx-rgba-smaskindata.pdf create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/jpx-sycc.pdf create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/lossy.jp2 create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/make.py create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/palette.jp2 create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/rgb.jp2 create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/rgba.jp2 create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/rle.ccitt create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/sycc.jp2 create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/symbol-globals.jbig2 create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/symbol.jbig2 create mode 100644 crates/exav-viewer/e2e/fixtures/pdf-images/tpgd.jbig2 create mode 100644 crates/exav-viewer/e2e/fixtures/plan.dwg create mode 100644 crates/exav-viewer/e2e/fixtures/plan.dxf create mode 100644 crates/exav-viewer/e2e/fonts.conf create mode 100644 crates/exav-viewer/e2e/frame.spec.ts create mode 100644 crates/exav-viewer/e2e/lifetime.spec.ts create mode 100644 crates/exav-viewer/e2e/model.spec.ts create mode 100644 crates/exav-viewer/e2e/pdf-decoders.spec.ts create mode 100644 crates/exav-viewer/e2e/pinch.spec.ts create mode 100644 crates/exav-viewer/e2e/pixels.ts create mode 100644 crates/exav-viewer/e2e/samples.ts create mode 100644 crates/exav-viewer/e2e/selection.spec.ts create mode 100644 crates/exav-viewer/e2e/tsconfig.json create mode 100644 crates/exav-viewer/e2e/webpack.spec.ts create mode 100644 crates/exav-viewer/e2e/zip.ts create mode 100644 crates/exav-viewer/package-lock.json create mode 100644 crates/exav-viewer/package.json create mode 100644 crates/exav-viewer/playwright.config.ts create mode 100644 crates/exav-viewer/scripts/build-frame.mjs create mode 100644 crates/exav-viewer/scripts/build-pdf-decoders.mjs create mode 100755 crates/exav-viewer/scripts/build-wasm.sh create mode 100644 crates/exav-viewer/scripts/build.mjs create mode 100644 crates/exav-viewer/scripts/check-bundle-sinks.mjs create mode 100644 crates/exav-viewer/scripts/check-bundle-sinks.test.mjs create mode 100644 crates/exav-viewer/scripts/check-package.mjs create mode 100644 crates/exav-viewer/scripts/check-sinks.mjs create mode 100644 crates/exav-viewer/scripts/check-sinks.test.mjs create mode 100644 crates/exav-viewer/scripts/check-wasm-imports.mjs create mode 100644 crates/exav-viewer/scripts/check-wasm-imports.test.mjs create mode 100644 crates/exav-viewer/scripts/pdf-decoder.template.js create mode 100644 crates/exav-viewer/scripts/sync-samples.mjs create mode 100644 crates/exav-viewer/src/lib.rs create mode 100644 crates/exav-viewer/ts/all.ts create mode 100644 crates/exav-viewer/ts/archive/index.ts create mode 100644 crates/exav-viewer/ts/archive/names.test.ts create mode 100644 crates/exav-viewer/ts/archive/names.ts create mode 100644 crates/exav-viewer/ts/archive/ranged-protocol.ts create mode 100644 crates/exav-viewer/ts/archive/ranged.ts create mode 100644 crates/exav-viewer/ts/archive/ranges.worker.ts create mode 100644 crates/exav-viewer/ts/archive/renderer.ts create mode 100644 crates/exav-viewer/ts/cad/cad.worker.ts create mode 100644 crates/exav-viewer/ts/cad/index.ts create mode 100644 crates/exav-viewer/ts/cad/layer-tree.test.ts create mode 100644 crates/exav-viewer/ts/cad/layer-tree.ts create mode 100644 crates/exav-viewer/ts/cad/plugin.ts create mode 100644 crates/exav-viewer/ts/cad/renderer/camera.test.ts create mode 100644 crates/exav-viewer/ts/cad/renderer/camera.ts create mode 100644 crates/exav-viewer/ts/cad/renderer/fonts.test.ts create mode 100644 crates/exav-viewer/ts/cad/renderer/fonts.ts create mode 100644 crates/exav-viewer/ts/cad/renderer/glyph-atlas.ts create mode 100644 crates/exav-viewer/ts/cad/renderer/renderer.ts create mode 100644 crates/exav-viewer/ts/cad/renderer/shaders.ts create mode 100644 crates/exav-viewer/ts/cad/renderer/text-layout.test.ts create mode 100644 crates/exav-viewer/ts/cad/renderer/text-layout.ts create mode 100644 crates/exav-viewer/ts/cad/renderer/text-resolution.test.ts create mode 100644 crates/exav-viewer/ts/cad/renderer/text-resolution.ts create mode 100644 crates/exav-viewer/ts/cad/renderer/tiles.test.ts create mode 100644 crates/exav-viewer/ts/cad/renderer/tiles.ts create mode 100644 crates/exav-viewer/ts/cad/types.ts create mode 100644 crates/exav-viewer/ts/cad/view.ts create mode 100644 crates/exav-viewer/ts/core/assets.ts create mode 100644 crates/exav-viewer/ts/core/detect.test.ts create mode 100644 crates/exav-viewer/ts/core/detect.ts create mode 100644 crates/exav-viewer/ts/core/formats.ts create mode 100644 crates/exav-viewer/ts/core/index.ts create mode 100644 crates/exav-viewer/ts/core/source.ts create mode 100644 crates/exav-viewer/ts/core/store.test.ts create mode 100644 crates/exav-viewer/ts/core/store.ts create mode 100644 crates/exav-viewer/ts/core/types.ts create mode 100644 crates/exav-viewer/ts/core/viewer.test.ts create mode 100644 crates/exav-viewer/ts/core/viewer.ts create mode 100644 crates/exav-viewer/ts/core/worker-host.test.ts create mode 100644 crates/exav-viewer/ts/core/worker-host.ts create mode 100644 crates/exav-viewer/ts/frame/app/frame.css create mode 100644 crates/exav-viewer/ts/frame/app/main.ts create mode 100644 crates/exav-viewer/ts/frame/app/ranges.test.ts create mode 100644 crates/exav-viewer/ts/frame/app/ranges.ts create mode 100644 crates/exav-viewer/ts/frame/app/workers.test.ts create mode 100644 crates/exav-viewer/ts/frame/app/workers.ts create mode 100644 crates/exav-viewer/ts/frame/delivery.test.ts create mode 100644 crates/exav-viewer/ts/frame/delivery.ts create mode 100644 crates/exav-viewer/ts/frame/host.test.ts create mode 100644 crates/exav-viewer/ts/frame/index.ts create mode 100644 crates/exav-viewer/ts/frame/policy.test.ts create mode 100644 crates/exav-viewer/ts/frame/policy.ts create mode 100644 crates/exav-viewer/ts/frame/protocol.test.ts create mode 100644 crates/exav-viewer/ts/frame/protocol.ts create mode 100644 crates/exav-viewer/ts/ifc/index.ts create mode 100644 crates/exav-viewer/ts/ifc/renderer.ts create mode 100644 crates/exav-viewer/ts/image/decode.ts create mode 100644 crates/exav-viewer/ts/image/decode.worker.ts create mode 100644 crates/exav-viewer/ts/image/index.ts create mode 100644 crates/exav-viewer/ts/image/renderer.test.ts create mode 100644 crates/exav-viewer/ts/image/renderer.ts create mode 100644 crates/exav-viewer/ts/image/surface.test.ts create mode 100644 crates/exav-viewer/ts/image/surface.ts create mode 100644 crates/exav-viewer/ts/media/index.ts create mode 100644 crates/exav-viewer/ts/model/engine.test.ts create mode 100644 crates/exav-viewer/ts/model/engine.ts create mode 100644 crates/exav-viewer/ts/model/framing.test.ts create mode 100644 crates/exav-viewer/ts/model/framing.ts create mode 100644 crates/exav-viewer/ts/model/index.ts create mode 100644 crates/exav-viewer/ts/model/model.worker.ts create mode 100644 crates/exav-viewer/ts/model/stl.ts create mode 100644 crates/exav-viewer/ts/office/delimited.test.ts create mode 100644 crates/exav-viewer/ts/office/delimited.ts create mode 100644 crates/exav-viewer/ts/office/index.ts create mode 100644 crates/exav-viewer/ts/office/renderer.ts create mode 100644 crates/exav-viewer/ts/office/selection.test.ts create mode 100644 crates/exav-viewer/ts/office/selection.ts create mode 100644 crates/exav-viewer/ts/office/zip-tail.test.ts create mode 100644 crates/exav-viewer/ts/office/zip-tail.ts create mode 100644 crates/exav-viewer/ts/pdf/assets.ts create mode 100644 crates/exav-viewer/ts/pdf/decoders.test.ts create mode 100644 crates/exav-viewer/ts/pdf/engine.ts create mode 100644 crates/exav-viewer/ts/pdf/index.ts create mode 100644 crates/exav-viewer/ts/pdf/links.test.ts create mode 100644 crates/exav-viewer/ts/pdf/options.test.ts create mode 100644 crates/exav-viewer/ts/pdf/pdfjs-worker.d.ts create mode 100644 crates/exav-viewer/ts/pdf/pdfjs.worker.ts create mode 100644 crates/exav-viewer/ts/pdf/rasterizer.ts create mode 100644 crates/exav-viewer/ts/pdf/rasterizer.worker.ts create mode 100644 crates/exav-viewer/ts/pdf/reader.test.ts create mode 100644 crates/exav-viewer/ts/pdf/reader.ts create mode 100644 crates/exav-viewer/ts/pdf/renderer.ts create mode 100644 crates/exav-viewer/ts/react/ViewerBody.test.tsx create mode 100644 crates/exav-viewer/ts/react/ViewerBody.tsx create mode 100644 crates/exav-viewer/ts/react/ViewerDialog.test.tsx create mode 100644 crates/exav-viewer/ts/react/ViewerDialog.tsx create mode 100644 crates/exav-viewer/ts/react/context.tsx create mode 100644 crates/exav-viewer/ts/react/hooks.ts create mode 100644 crates/exav-viewer/ts/react/icons.tsx create mode 100644 crates/exav-viewer/ts/react/index.ts create mode 100644 crates/exav-viewer/ts/react/messages.ts create mode 100644 crates/exav-viewer/ts/react/overlay.tsx create mode 100644 crates/exav-viewer/ts/react/parts.tsx create mode 100644 crates/exav-viewer/ts/react/sandbox.tsx create mode 100644 crates/exav-viewer/ts/react/styles.css create mode 100644 crates/exav-viewer/ts/test/blob.ts create mode 100644 crates/exav-viewer/ts/vite/assets.test.ts create mode 100644 crates/exav-viewer/ts/vite/assets.ts create mode 100644 crates/exav-viewer/ts/vite/cli.ts create mode 100644 crates/exav-viewer/ts/vite/index.ts create mode 100644 crates/exav-viewer/tsconfig.build.json create mode 100644 crates/exav-viewer/tsconfig.json create mode 100644 crates/exav-viewer/vitest.config.ts create mode 100644 crates/exav/src/fuzzing.rs create mode 100644 crates/exav/tests/detect.rs create mode 100644 crates/exav/tests/one_scan.rs create mode 100644 crates/exav/tests/packaging.rs create mode 100644 docs/BACKLOG.md create mode 100644 docs/COMPARISON_NOTES.md create mode 100644 docs/STREAMING_FORMATS.md delete mode 100644 docs/VERDICT_PROTOCOL_PLAN.md create mode 100644 fuzz/db.rs create mode 100644 fuzz/db/README.md create mode 100644 fuzz/db/fuzz.cbc create mode 100644 fuzz/db/fuzz.cdb create mode 100644 fuzz/db/fuzz.crb create mode 100644 fuzz/db/fuzz.db create mode 100644 fuzz/db/fuzz.fdb create mode 100644 fuzz/db/fuzz.fp create mode 100644 fuzz/db/fuzz.ftm create mode 100644 fuzz/db/fuzz.hdb create mode 100644 fuzz/db/fuzz.hsb create mode 100644 fuzz/db/fuzz.ign2 create mode 100644 fuzz/db/fuzz.imp create mode 100644 fuzz/db/fuzz.ldb create mode 100644 fuzz/db/fuzz.mdb create mode 100644 fuzz/db/fuzz.ndb create mode 100644 fuzz/db/fuzz.pdb create mode 100644 fuzz/db/fuzz.pwdb create mode 100644 fuzz/db/fuzz.wdb create mode 100644 fuzz/db/fuzz.yar create mode 100644 fuzz/dicts/clamd.dict create mode 100644 fuzz/dicts/icap.dict create mode 100644 fuzz/dicts/pcre.dict create mode 100644 fuzz/dicts/signatures.dict create mode 100644 fuzz/dicts/yara.dict create mode 100644 fuzz/exav-cli/Cargo.toml create mode 100644 fuzz/fuzz_targets/authenticode.rs create mode 100644 fuzz/fuzz_targets/cad_dwg.rs create mode 100644 fuzz/fuzz_targets/cad_dxf.rs create mode 100644 fuzz/fuzz_targets/clamd.rs create mode 100644 fuzz/fuzz_targets/database.rs create mode 100644 fuzz/fuzz_targets/drawing.rs create mode 100644 fuzz/fuzz_targets/icap.rs create mode 100644 fuzz/fuzz_targets/ifc.rs create mode 100644 fuzz/fuzz_targets/imagehash.rs create mode 100644 fuzz/fuzz_targets/pcre.rs create mode 100644 fuzz/fuzz_targets/seekable.rs create mode 100644 fuzz/fuzz_targets/volumes.rs create mode 100644 fuzz/fuzz_targets/yara.rs create mode 100644 fuzz/options.rs create mode 100644 fuzz/seeds/imagehash/dxt1.dds create mode 100644 fuzz/seeds/imagehash/rgb.hdr create mode 100644 fuzz/seeds/imagehash/rgba.ff create mode 100644 fuzz/seeds/pcre/patterns.txt create mode 100644 fuzz/seeds/yara/modules.yar create mode 100644 fuzz/seeds/yara/small.yar create mode 100644 fuzz/support/Cargo.toml create mode 100644 fuzz/support/src/extreme.rs create mode 100644 fuzz/support/src/frame.rs create mode 100644 fuzz/support/src/lib.rs delete mode 100644 packaging/exav-clamd.service create mode 100644 packaging/exav.service create mode 100755 scripts/check-features.sh create mode 100644 scripts/check-links.mjs create mode 100644 scripts/fuzz-seeds-synth.py create mode 100755 scripts/fuzz-seeds.sh create mode 100755 scripts/test-viewer.sh create mode 100644 www/src/components/Header.astro create mode 100644 www/src/components/SectionsMenu.astro create mode 100644 www/src/components/Sidebar.astro create mode 100644 www/src/components/ThemeProvider.astro create mode 100644 www/src/components/ThemeSelect.astro create mode 100644 www/src/components/TopicList.astro create mode 100644 www/src/components/TopicNav.astro delete mode 100644 www/src/content/docs/concepts/architecture.md delete mode 100644 www/src/content/docs/concepts/archive-extraction.md delete mode 100644 www/src/content/docs/concepts/bytecode-sandbox.md delete mode 100644 www/src/content/docs/concepts/design-principles.md delete mode 100644 www/src/content/docs/concepts/differential-testing.md delete mode 100644 www/src/content/docs/concepts/pe-emulation.md delete mode 100644 www/src/content/docs/concepts/quirks.md delete mode 100644 www/src/content/docs/concepts/streaming-memory.md delete mode 100644 www/src/content/docs/getting-started/installation.mdx delete mode 100644 www/src/content/docs/getting-started/introduction.md delete mode 100644 www/src/content/docs/getting-started/quick-start.mdx delete mode 100644 www/src/content/docs/guides/daemon.mdx delete mode 100644 www/src/content/docs/guides/docker.mdx delete mode 100644 www/src/content/docs/guides/icap.mdx delete mode 100644 www/src/content/docs/guides/library-usage.md delete mode 100644 www/src/content/docs/guides/migrating-from-clamav.mdx delete mode 100644 www/src/content/docs/guides/prebuilt-database.mdx delete mode 100644 www/src/content/docs/guides/scanning.mdx delete mode 100644 www/src/content/docs/guides/signatures.mdx delete mode 100644 www/src/content/docs/guides/troubleshooting.md delete mode 100644 www/src/content/docs/guides/wasm-sandbox.mdx delete mode 100644 www/src/content/docs/guides/yara.mdx create mode 100644 www/src/content/docs/project/architecture.md delete mode 100644 www/src/content/docs/project/comparison-with-clamav.md create mode 100644 www/src/content/docs/project/dependencies.md delete mode 100644 www/src/content/docs/reference/clamav-flag-matrix.md delete mode 100644 www/src/content/docs/reference/cli.md delete mode 100644 www/src/content/docs/reference/configuration.md delete mode 100644 www/src/content/docs/reference/dependencies.md delete mode 100644 www/src/content/docs/reference/feature-flags.md delete mode 100644 www/src/content/docs/reference/formats.md delete mode 100644 www/src/content/docs/reference/limits.md delete mode 100644 www/src/content/docs/reference/verdicts.md create mode 100644 www/src/content/docs/scanner/concepts/bytecode-sandbox.md create mode 100644 www/src/content/docs/scanner/concepts/design-principles.md create mode 100644 www/src/content/docs/scanner/concepts/differential-testing.md create mode 100644 www/src/content/docs/scanner/concepts/how-it-works.md create mode 100644 www/src/content/docs/scanner/concepts/pe-emulation.md create mode 100644 www/src/content/docs/scanner/concepts/quirks.md create mode 100644 www/src/content/docs/scanner/concepts/streaming-memory.md create mode 100644 www/src/content/docs/scanner/getting-started/installation.mdx create mode 100644 www/src/content/docs/scanner/getting-started/introduction.mdx create mode 100644 www/src/content/docs/scanner/getting-started/quick-start.mdx create mode 100644 www/src/content/docs/scanner/guides/daemon.mdx create mode 100644 www/src/content/docs/scanner/guides/docker.mdx create mode 100644 www/src/content/docs/scanner/guides/icap.mdx create mode 100644 www/src/content/docs/scanner/guides/migrating-from-clamav.mdx create mode 100644 www/src/content/docs/scanner/guides/prebuilt-database.mdx create mode 100644 www/src/content/docs/scanner/guides/scanning.mdx create mode 100644 www/src/content/docs/scanner/guides/signatures.mdx create mode 100644 www/src/content/docs/scanner/guides/sizing.md create mode 100644 www/src/content/docs/scanner/guides/troubleshooting.md create mode 100644 www/src/content/docs/scanner/guides/wasm-sandbox.mdx create mode 100644 www/src/content/docs/scanner/guides/yara.mdx create mode 100644 www/src/content/docs/scanner/reference/clamav-flag-matrix.md create mode 100644 www/src/content/docs/scanner/reference/cli.md create mode 100644 www/src/content/docs/scanner/reference/comparison-with-clamav.md create mode 100644 www/src/content/docs/scanner/reference/configuration.md create mode 100644 www/src/content/docs/scanner/reference/feature-flags.md create mode 100644 www/src/content/docs/scanner/reference/formats.md create mode 100644 www/src/content/docs/scanner/reference/limits.md create mode 100644 www/src/content/docs/scanner/reference/verdicts.md create mode 100644 www/src/content/docs/subprojects/exav-imagehash.md create mode 100644 www/src/content/docs/subprojects/exav-render.md delete mode 100644 www/src/content/docs/subprojects/exav-unpack.md create mode 100644 www/src/content/docs/unpack/cli.md create mode 100644 www/src/content/docs/unpack/formats.md create mode 100644 www/src/content/docs/unpack/how-it-works.md create mode 100644 www/src/content/docs/unpack/index.md create mode 100644 www/src/content/docs/unpack/rust.md create mode 100644 www/src/content/docs/unpack/wasm.md create mode 100644 www/src/content/docs/viewer/api.md create mode 100644 www/src/content/docs/viewer/index.md create mode 100644 www/src/content/docs/viewer/integration.md create mode 100644 www/src/content/docs/viewer/react.md create mode 100644 www/src/content/docs/viewer/security.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a4f43908..6666bdf3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,14 +23,15 @@ jobs: # examples and the `bytecode_gating` integration test) is excluded from the # default build, so lint it in a dedicated pass. - run: cargo clippy -p exav-core --all-targets --features unstable-internals -- -D warnings - # The full native test matrix (default + http + checksums + no-decrypt + - # unstable-internals feature passes). Defined once in the Makefile so this - # and a local `make test` can't drift. + - run: cargo clippy -p exav-render --all-targets --features dwg -- -D warnings + - run: cargo clippy -p exav-render --all-targets --no-default-features --features ifc,stl -- -D warnings + # The full native test matrix, every feature pass. Defined once in the + # Makefile so this and a local `make test` can't drift. - run: make test-native - # The promised floor is `rust-version` in Cargo.toml (1.91, imposed by - # yara-x-parser). `make msrv` reads it there and installs that toolchain on - # demand, so a bump flows through with no edit here — and a contributor on + # The promised floor is `rust-version` in Cargo.toml (1.92, imposed by the + # hayro image decoders). `make msrv` reads it there and installs that toolchain on + # demand, so a bump flows through with no edit here, and a contributor on # stable can't land a newer feature without this going red. msrv: runs-on: ubuntu-latest @@ -41,18 +42,23 @@ jobs: - run: make msrv # The yara-x A/B differential harness. Deliberately NOT part of `make test` - # (see the Makefile) — a differential test can go red because the other engine + # (see the Makefile): a differential test can go red because the other engine # changed, so it is not a merge gate. It runs here anyway, unlike the clamav - # harness, only because it is self-contained: no signature database, no second - # engine to install. Its own job so the optional `yara-x` dependency — 83 extra - # crates, 21 of them cranelift/wasmtime — never lands in the `test` job, and so - # it costs no wall clock. + # harness, only because it is self-contained: no signature database, just + # yara-x's `yr` binary. The tests skip when `yr` is missing, so it is installed + # and checked first; without it this job would pass having compared nothing. yara-diff: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 + - name: Install yr (yara-x CLI) + run: | + YR=v1.21.0 + curl -sSL "https://github.com/VirusTotal/yara-x/releases/download/$YR/yara-x-$YR-x86_64-unknown-linux-gnu.tar.gz" | tar xz -C /tmp + echo "/tmp" >> "$GITHUB_PATH" + - run: yr --version - run: make test-yara-diff wasm: @@ -66,7 +72,7 @@ jobs: - name: Install binaryen (wasm-opt) run: sudo apt-get update && sudo apt-get install -y binaryen # The scanning core compiled to WASI, and the archive-extractor WASM - # bindings (excluded from the workspace, built on their own target) — both + # bindings (excluded from the workspace, built on their own target), both # the default (all-formats + decrypt) build and a minimal single-format, # no-decrypt build, so the feature-gated paths can't silently rot. - run: cargo build -p exav-core --features wasi-bin --target wasm32-wasip1 @@ -97,6 +103,23 @@ jobs: with: node-version: 22 - run: make test-js + # @exav/viewer: its wasm modules and its archive plugin's peer + # (exav-unpack-wasm's pkg/, which test-js built with test-only features) + # are rebuilt from source, with the wasm-bindgen-cli its Cargo.toml pins, + # and its demo is driven in Chromium, its sandboxed frame in Chromium, + # Firefox and WebKit. See scripts/test-viewer.sh. + - uses: taiki-e/install-action@v2 + with: + tool: wasm-bindgen@0.2.129 + - run: make test-viewer + # What the browser saw, for the failures that do not happen on a + # developer's machine. + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: viewer-e2e-results + path: crates/exav-viewer/test-results + if-no-files-found: ignore docs: runs-on: ubuntu-latest @@ -137,6 +160,12 @@ jobs: run: | cargo deny --manifest-path crates/exav-unpack-wasm/Cargo.toml \ --config deny.toml check advisories bans sources licenses + # The viewer's wasm modules, also its own workspace. Every feature: the + # DWG module is not a default. + - name: cargo-deny (viewer) + run: | + cargo deny --manifest-path crates/exav-viewer/Cargo.toml --all-features \ + --config deny.toml check advisories bans sources licenses fuzz-smoke: runs-on: ubuntu-latest @@ -144,9 +173,44 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@nightly - uses: Swatinem/rust-cache@v2 + with: + workspaces: | + . -> target + fuzz -> target + # What the targets found interesting last time, so a 60 s run starts + # where the last one stopped. A new key each run, the newest restored. + - uses: actions/cache@v4 + with: + path: fuzz/corpus + key: fuzz-corpus-${{ github.run_id }} + restore-keys: fuzz-corpus- + - name: The fuzz crate's own tests (the mutator and the input framing) + run: cargo test --manifest-path fuzz/Cargo.toml -p exav-fuzz-support - name: cargo-fuzz smoke run run: | cargo install cargo-fuzz --locked - for t in filetype sigs cvd pe unpack analyze bytecode full_pipeline ndb_compile rar3_ppmd; do - cargo +nightly fuzz run "$t" -- -max_total_time=60 -rss_limit_mb=2048 -timeout=10 + # Seeded from the test fixtures where they match a target's input: + # random bytes rarely get past a header. Outside the checkout, as + # the masked fixtures are unmasked. + seeds="$RUNNER_TEMP/fuzz-seeds" + scripts/fuzz-seeds.sh "$seeds" + for t in filetype sigs cvd pe unpack analyze bytecode full_pipeline seekable yara pcre clamd icap volumes authenticode database ndb_compile rar3_ppmd pe_emulator x86_decode parser_recursion imagehash drawing cad_dxf cad_dwg ifc; do + mkdir -p "fuzz/corpus/$t" + extra="" + [ -d "$seeds/$t" ] && extra="$seeds/$t" + # Strings for the targets whose input is text or a protocol. + dict="" + case "$t" in + yara|pcre|icap|clamd) dict="-dict=fuzz/dicts/$t.dict" ;; + full_pipeline|ndb_compile|sigs|cvd) dict="-dict=fuzz/dicts/signatures.dict" ;; + esac + # iced-x86, the oracle x86_decode compares against, builds its + # decoder tables in a `lazy_static` it never frees: the newest + # nightly's LeakSanitizer reports them at exit (552 bytes, whatever + # the input), which is not a leak of exav's. The other targets keep + # the check. + asan="" + [ "$t" = x86_decode ] && asan="detect_leaks=0" + ASAN_OPTIONS="$asan" cargo +nightly fuzz run "$t" "fuzz/corpus/$t" $extra \ + -- $dict -max_total_time=60 -rss_limit_mb=2048 -timeout=10 done diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 16b539e5..0c286a74 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -48,6 +48,12 @@ jobs: exit 1 fi docker logs exav + # The image's HEALTHCHECK is on the container, and its command works. + # Not `docker inspect .State.Health`: the first probe is 30s away. + HC=$(docker inspect --format '{{json .Config.Healthcheck.Test}}' exav) + echo "healthcheck: $HC" + [ "$HC" = '["CMD","/exav","--ping"]' ] + docker exec exav /exav --ping docker rm -f exav # Static musl binaries for the published image, cross-compiled natively on @@ -171,15 +177,19 @@ jobs: EXPECTED: application/vnd.docker.distribution.manifest.list.v2+json run: | set -euo pipefail - # Every tag in the set points at the same index, so one is enough. - TAG=$(printf '%s\n' "$TAGS" | head -1) - docker buildx imagetools inspect "$TAG" --raw > "$RUNNER_TEMP/manifest.json" - GOT=$(jq -r '.mediaType' "$RUNNER_TEMP/manifest.json") - echo "$TAG -> $GOT" - if [ "$GOT" != "$EXPECTED" ]; then - echo "::error::published $GOT, expected $EXPECTED -- podman will ignore the image HEALTHCHECK" - exit 1 - fi + # The tags are already public when this runs: a failure here is an + # alarm to fix and re-publish, not a gate. + bad=0 + while read -r TAG; do + [ -n "$TAG" ] || continue + GOT=$(docker buildx imagetools inspect "$TAG" --raw | jq -r '.mediaType') + echo "$TAG -> $GOT" + if [ "$GOT" != "$EXPECTED" ]; then + echo "::error::$TAG is already published as $GOT, expected $EXPECTED -- podman will ignore the image HEALTHCHECK" + bad=1 + fi + done <<<"$TAGS" + exit "$bad" # The assertion above pins the wire format; this one tests the consumer # that the format exists for. podman is preinstalled on ubuntu-latest. diff --git a/.github/workflows/fuzz-nightly.yml b/.github/workflows/fuzz-nightly.yml new file mode 100644 index 00000000..ff8dd2ac --- /dev/null +++ b/.github/workflows/fuzz-nightly.yml @@ -0,0 +1,58 @@ +name: fuzz-nightly + +# A longer run of every fuzz target than the 60 seconds a push gets, in fork +# mode so that one run yields every distinct crash and not the first +# (scripts/fuzz-campaign.sh). What it finds is uploaded, never committed: +# triage is docs/FUZZING.md's. +on: + schedule: + - cron: "17 3 * * *" + workflow_dispatch: + inputs: + total: + description: "Seconds of fuzzing, split across the targets" + default: "10800" + +permissions: + contents: read + +jobs: + campaign: + runs-on: ubuntu-latest + timeout-minutes: 360 + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@nightly + - uses: Swatinem/rust-cache@v2 + with: + workspaces: | + . -> target + fuzz -> target + # The corpora of earlier nights: each one starts where the last stopped. + - uses: actions/cache@v4 + with: + path: tmp/data + key: fuzz-nightly-${{ github.run_id }} + restore-keys: fuzz-nightly- + - name: cargo-fuzz campaign + run: | + cargo install cargo-fuzz --locked + # A hosted runner has the memory the campaign script's defaults + # hold back for a small VM. + CARGO_BUILD_JOBS=2 CODEGEN_UNITS=16 TOTAL="${{ inputs.total || 10800 }}" scripts/fuzz-campaign.sh + - uses: actions/upload-artifact@v4 + if: always() + with: + name: fuzz-artifacts + path: fuzz/artifacts + if-no-files-found: ignore + # Fork mode keeps going after a crash, so the job's status says nothing: + # a crash, a hang or an out-of-memory is a file here (a `slow-unit` is + # only slow). + - name: Fail if the campaign found a crash, a timeout or an OOM + run: | + found="$(find fuzz/artifacts -type f \( -name 'crash-*' -o -name 'timeout-*' -o -name 'oom-*' \) 2>/dev/null)" + if [ -n "$found" ]; then + echo "$found" + exit 1 + fi diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fc19543c..69be328f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,6 +1,9 @@ # Tag-driven binary releases. Push a tag like `v0.1.0` and this cross-compiles -# the `exav` CLI for each target, archives it, and attaches it to the GitHub -# Release for that tag. Static musl Linux builds run on any distro (no glibc). +# the `exav` CLI and the standalone `exav-unpack`, `exav-grep`, `exav-pe-emu` +# and `exav-imagehash` for each target, archives each with LICENSE and NOTICE, and +# attaches them to the +# GitHub Release for that tag. Static musl Linux builds run on any distro (no +# glibc). # The `wasm` job adds the two WebAssembly artifacts: the unpacker npm tarball # (`@exav/unpack-wasm`, standard preset — exactly what `npm publish` ships via # `prepublishOnly`) and the engine as a WASI module (`exav-core --features @@ -58,6 +61,42 @@ jobs: archive: exav-$tag-$target # YARA rule support is on by default; keep it for full parity. # For a smaller binary, add: features: "" / no-default-features. + # The licenses of everything linked go with every binary (NOTICE). + include: LICENSE,NOTICE + token: ${{ secrets.GITHUB_TOKEN }} + checksum: sha256 + # The standalone tools, each in an archive of its own: most people + # want one of them, not the scanner. + - uses: taiki-e/upload-rust-binary-action@v1 + with: + bin: exav-unpack + target: ${{ matrix.target }} + archive: exav-unpack-$tag-$target + include: LICENSE,NOTICE + token: ${{ secrets.GITHUB_TOKEN }} + checksum: sha256 + - uses: taiki-e/upload-rust-binary-action@v1 + with: + bin: exav-grep + target: ${{ matrix.target }} + archive: exav-grep-$tag-$target + include: LICENSE,NOTICE + token: ${{ secrets.GITHUB_TOKEN }} + checksum: sha256 + - uses: taiki-e/upload-rust-binary-action@v1 + with: + bin: exav-pe-emu + target: ${{ matrix.target }} + archive: exav-pe-emu-$tag-$target + include: LICENSE,NOTICE + token: ${{ secrets.GITHUB_TOKEN }} + checksum: sha256 + - uses: taiki-e/upload-rust-binary-action@v1 + with: + bin: exav-imagehash + target: ${{ matrix.target }} + archive: exav-imagehash-$tag-$target + include: LICENSE,NOTICE token: ${{ secrets.GITHUB_TOKEN }} checksum: sha256 diff --git a/.github/workflows/www.yml b/.github/workflows/www.yml index ddf3d572..b72d0546 100644 --- a/.github/workflows/www.yml +++ b/.github/workflows/www.yml @@ -1,8 +1,5 @@ -# Sample workflow for building and deploying an Astro site to GitHub Pages -# -# To get started with Astro see: https://docs.astro.build/en/getting-started/ -# -name: Deploy Astro site to Pages +# Builds the website and the viewer demo, and deploys them to GitHub Pages. +name: Deploy site to Pages on: # Runs on pushes targeting the default branch @@ -52,6 +49,36 @@ jobs: --site "${{ steps.pages.outputs.origin }}" \ --base "${{ steps.pages.outputs.base_path }}" working-directory: ${{ env.BUILD_PATH }} + # The @exav/viewer demo, served at /viewer/demo/: the package and its wasm + # modules built from this commit, the archive engine's pkg/ too. + - uses: dtolnay/rust-toolchain@stable + with: + targets: wasm32-unknown-unknown + - uses: Swatinem/rust-cache@v2 + with: + workspaces: | + crates/exav-viewer + crates/exav-unpack-wasm + - name: Install binaryen (wasm-opt) + run: sudo apt-get update && sudo apt-get install -y binaryen + - uses: taiki-e/install-action@v2 + with: + tool: wasm-bindgen@0.2.129,wasm-pack + - name: Build the viewer demo + run: | + (cd crates/exav-unpack-wasm && wasm-pack build --release --target web) + cd crates/exav-viewer + npm ci + npm run build:wasm + npm run build + # The sidebar's files: github.com/sylvinus/exav-samples, HEAD. + npm run demo:showcase + # DEMO_ORIGIN goes into the sandboxed frame's policy, for Safari. + DEMO_BASE="${{ steps.pages.outputs.base_path }}/viewer/demo/" DEMO_ORIGIN="${{ steps.pages.outputs.origin }}" npm run demo:build + # dist/viewer/ holds the File viewer docs; the demo must not land on them. + test ! -e "$GITHUB_WORKSPACE/${{ env.BUILD_PATH }}/dist/viewer/demo" + cp -R demo/dist "$GITHUB_WORKSPACE/${{ env.BUILD_PATH }}/dist/viewer/demo" + test -f "$GITHUB_WORKSPACE/${{ env.BUILD_PATH }}/dist/viewer/demo/index.html" - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: diff --git a/.gitignore b/.gitignore index ee137e36..cd36514a 100644 --- a/.gitignore +++ b/.gitignore @@ -15,7 +15,9 @@ Cargo.lock.orig # real-malware test samples: kept locally (gitignored) for extra decoder # coverage, NEVER committed — the tests that use them skip when absent, and CI # relies on the synthetic/EICAR fixtures. Provenance (sha256) is in each dir's -# README.md. The synthetic `eicar.lnk` and the READMEs stay committed. +# README.md. Each is kept as `.zip`, AES-256 with the password +# `infected` (crates/exav-unpack/tests/fixtures/README.md). The synthetic +# `eicar.lnk` and the READMEs stay committed. crates/exav-unpack/tests/fixtures/**/real-malware-* /yara-x/ # internal strategy notes — never commit diff --git a/.oss-scanner/Dockerfile b/.oss-scanner/Dockerfile new file mode 100644 index 00000000..420c5858 --- /dev/null +++ b/.oss-scanner/Dockerfile @@ -0,0 +1,44 @@ +# Build environment for Anthropic's OSS Scanner (https://red.anthropic.com/oss-scanner/). +# The checkout is at /src, the build context is the repository, and nothing +# after the build has network access: every dependency is fetched here. +# +# Build it the way the scanner does, from the repository root: +# docker build -f .oss-scanner/Dockerfile -t exav-oss-scanner . +FROM rust:1.92-bookworm + +# Frame pointers and line tables for a debugger, without the full debug info +# that makes the build several times larger. +ENV DEBIAN_FRONTEND=noninteractive \ + CARGO_TERM_COLOR=never \ + CARGO_PROFILE_DEV_DEBUG=line-tables-only \ + RUSTFLAGS="-C force-frame-pointers=yes" + +# gdb and valgrind are for the agent that reproduces a finding; clang is what a +# C dependency's build script may look for. +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates build-essential clang pkg-config git python3 gdb valgrind \ + && rm -rf /var/lib/apt/lists/* + +COPY . /src +WORKDIR /src + +# Every dependency of every crate, test-only ones included, so that nothing +# is fetched after this step. `--locked` uses exactly Cargo.lock. +RUN cargo fetch --locked + +# Every crate of the workspace, in the dev profile (overflow checks on, as in +# the release profile). `exav` is built with the optional network-facing half +# (`SCANURL`, `--sig-sources`), which pulls the TLS stack. +RUN cargo build --workspace --locked \ + && cargo build -p exav --locked --features http + +# The tools, on PATH. They read a file given on the command line; `exav` needs +# a signature database to scan, which `threat_model.md` says how to make. +RUN for t in exav exav-unpack exav-grep exav-imagehash; do \ + ln -s "/src/target/debug/$t" "/usr/local/bin/$t"; \ + done + +# A cheap check that the image works: the unit tests of the extractor. A +# failure is reported and does not fail the image. +RUN (cargo test -p exav-unpack --lib --locked 2>&1 | tail -n 5) \ + || echo "WARNING: the exav-unpack unit tests reported failures" diff --git a/.oss-scanner/Dockerfile.dockerignore b/.oss-scanner/Dockerfile.dockerignore new file mode 100644 index 00000000..7d75e32e --- /dev/null +++ b/.oss-scanner/Dockerfile.dockerignore @@ -0,0 +1,10 @@ +# Used instead of the repository's .dockerignore for this Dockerfile: the +# scanner should see the docs, the fuzz targets and the test corpus, which the +# image of the product leaves out. Only what is built or fetched is left out. +**/target/ +**/node_modules/ +.git/ +.env* +*.exavdb +exav-db/ +tmp/ diff --git a/.oss-scanner/threat_model.md b/.oss-scanner/threat_model.md new file mode 100644 index 00000000..83d03a1c --- /dev/null +++ b/.oss-scanner/threat_model.md @@ -0,0 +1,111 @@ +# Threat model + +exav is a set of memory-safe tools for files the user did not write: a malware +scanner (`exav`, with a clamd-compatible daemon and an ICAP server), a bounded +extractor (`exav-unpack`), a signature-aware grep (`exav-grep`), an image +hasher (`exav-imagehash`), the renderers behind a browser viewer +(`exav-render`, `exav-viewer`) and WebAssembly bindings (`exav-unpack-wasm`). +`SECURITY.md` at the root is the maintainers' own statement of the same model. + +## What this project does and where untrusted input enters + +- **A scanned file is fully hostile.** Every byte of it, at any depth of + nesting: `crates/exav-core` (file typing, PE/ELF/Mach-O parsing, the + bytecode interpreter, the YARA engine, `.ndb`/`.ldb` matching), + `crates/exav-unpack` (about 80 archive, disk image, filesystem, document and + packer decoders), `crates/exav-x86` and `crates/exav-pe-emu` (an x86 + emulator that runs packer stubs), and `crates/exav-render` (PDF, image, DWG, + DXF, IFC, STL decoding for the viewer). +- **Network input**: the daemon's clamd protocol (`crates/exav/src/daemon.rs`), + the ICAP listener (`crates/exav/src/icap/`, which parses straight off the + socket), and with `--features http` the `SCANURL` command and the signature + updater (`crates/exav-update`). +- **Command-line and daemon arguments** reach `exav-imagehash`, `exav-grep` + and the `exav` options; they come from the operator, not from a file. +- **The 32-bit WebAssembly build** (`crates/exav-unpack-wasm`, + `crates/exav-viewer`) has a 32-bit `usize`, no overflow checks and + `panic=abort`. A sum of two header numbers that cannot wrap on a 64-bit host + can wrap there and defeat a bounds check. + +## Components that matter most / least + +Most: the decoders in `crates/exav-unpack/src/formats/`, the PE emulator +(`crates/exav-pe-emu`, `crates/exav-x86`), the bytecode interpreter +(`crates/exav-core/src/bytecode/`), the signature matching engine +(`crates/exav-core/src/engine/`), the daemon and ICAP code, and the code that +decides a result is `OK` rather than `PARTIAL`. + +Least: `www/` (the documentation site), `scripts/`, `packaging/`, `corpus/`, +`tmp/`, the test suites and fixtures, and `crates/exav-viewer`'s JavaScript +beyond the places it hands bytes to the Rust or wasm decoders. + +## How to exercise it + +- Everything is built in `/src/target/debug` and on `PATH`: `exav`, + `exav-unpack`, `exav-grep`, `exav-imagehash`. +- `exav-unpack FILE` extracts any supported container in memory with the + default budgets; this is the shortest path to a decoder. `exav-unpack -l` + lists. It never writes to a path named by the archive. +- `exav` refuses to scan with no signature database. A minimal one for a + test is a `.ndb` file in a directory: `echo 'Test.Sig:0:*:4558415600' > + /tmp/db/t.ndb`, then `exav -d /tmp/db FILE`. A `.cbc` bytecode program or + a YARA rule file in the same directory exercises those engines. +- A decoder panic shows as `decoder panicked` in the output; this is how the + tests recognise one. +- `fuzz/fuzz_targets/` has a `cargo-fuzz` target for each parser and for the + whole pipeline (`full_pipeline`, `unpack`). The image has no nightly + toolchain, so write a proof of concept as an input file for the CLI, or as a + unit test in the crate, rather than as a fuzz target. +- For the 32-bit class, `crates/exav-unpack/tests/suites/extreme.rs` sets + header fields to extreme values; `scripts/test-wasm.sh` runs the unit tests + on `wasm32-wasip1` (it needs `wasmtime`, which the image does not have), so + reason about 32-bit wraps from the code. + +## How you rate severity + +- **Critical**: code execution or memory corruption in the exav process from + scanned bytes (this needs `unsafe`, which is confined to + `crates/exav/src/daemon.rs`, `crates/exav/src/main.rs` and third-party + crates); a file-system write outside what the operator configured (the + extractor decodes in memory and spills only to unnamed temp files, so a + write to a path taken from an archive is a finding); a remote client of the + daemon or ICAP port running code or reading files it should not. +- **High**: a file reported `OK` (clean) that was not fully scanned, or whose + malicious content a signature should have seen: a member skipped, a decoder + that returns a prefix and no error, a limit that is hit and not reported. This + is the worst outcome for a scanner and ranks above a crash. Also a + stack overflow, an allocation that aborts the process, or a loop that does + not end within the configured limits, from one small file in the one-shot + CLI; in the prefork daemon these cost one worker, so rate them medium. +- **Medium**: memory or CPU far beyond the documented budgets (decompressed + bytes, per-member size, compression ratio, file count, recursion depth, + emulation steps) from a file much smaller than the work it causes + (amplification); an integer wrap on the 32-bit wasm build that defeats a + bounds check; a panic that the container boundary does not contain. +- **Low**: a panic that `catch_unwind` contains and reports for that one + container (`decoder panicked`), with no wrong verdict; a wrong or missing + name or size in a listing. + +## Anything to leave alone + +- **A signature database is a trusted input.** A `.cbc`/`.ldb` author running + a long bytecode loop, or a YARA rule that matches slowly, is not a finding; + the instruction cap is a failsafe against exav's own bugs. A parser bug + reachable with a crafted database (a panic or abort on load) is in scope + at low severity only. +- The `testing-faults` feature lets a scanned file ask a decoder to panic or + abort so tests can check the reporting; it is never enabled in a shipped + build. +- A panic that the walk reports as `decoder panicked` with the container then + marked `PARTIAL` is the designed behaviour, not a bug. +- Findings in third-party crates (hayro, zune, image, ruzstd, xz4rust and the + like) are welcome only when exav's use of them is what makes them reachable + or unbounded; report the dependency's own bugs upstream. +- Detection quality (a malware family not detected, a false positive) is not a + security finding. +- `exav-viewer` rendering differences from the original application are not + findings; script execution in the sandboxed frames is, but only when it + crosses the frame boundary. +- Prefer a minimal fix with a test that fails without it: every fixed finding + in this project has one (see `docs/FUZZING.md`). Deduplicate by root cause + in one function, not by file format. diff --git a/CHANGELOG.md b/CHANGELOG.md index 5acd3b79..dcfda3d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,923 @@ Notable changes per release. Dates are release dates; the format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) loosely, and versions follow [semantic versioning](https://semver.org/). +## [Unreleased] + +## [0.0.2] - 2026-10-11 + +### Changed + +- A file larger than `--max-object-bytes` (256 MiB by default) gets the full + scan: wildcard and logical signatures, PCRE, YARA, bytecode, normalised text, + carving, embedded payloads and heuristics, read through an 8 MiB block cache + instead of held in memory. It got a literal-and-hash pass only. So does its + archive's own bytes, and an archive member that large once it is spilled to + disk; with `--spill-dir off` such a member is not scanned, and the file is + `LIMITS-EXCEEDED`. What still needs the object in memory (PE structure: EP and section + offsets, section hashes, imphash, icons, Authenticode, UPX and packer + unpacking; YARA's `pe`, `elf` and `dotnet` modules; containers read whole, + such as RAR, 7z or OLE) makes the file `LIMITS-EXCEEDED` naming the size + limit, unless something is found. +- `--max-object-bytes` no longer decides which signatures run, only what may + be held in memory at once. +- A DMG is walked without decompressing its whole disk, so an image whose disk + is larger than `--max-object-bytes` gives up its files; it was refused as + `LIMITS-EXCEEDED`. Each file is still held whole, under the same limit. A + file the image holds but that cannot be read out of it makes the scan + `UNSCANNABLE` unless something is found; it was skipped. LZ4 and Unix + `compress` (`.Z`) are decoded as they are read, as gzip is, instead of + whole. +- `--all-matches` and `ALLMATCHSCAN` list every detection at any size; past + `--max-object-bytes` they fell back to a single match. Past + `--max-input-bytes` they list what the first bytes hold and report the rest + unscanned, as a single-match scan does; `--all-matches` fell back to a single + match there, without saying the search stopped short, and `ALLMATCHSCAN` + ignored the limit. +- Every environment variable without a flag is named `EXAV_DEBUG_*`: + `EXAV_BC_WARN`, `EXAV_BC_TRACE`, `EXAV_BC_FN` and `EXAV_FORCED` are + `EXAV_DEBUG_BC_WARN`, `EXAV_DEBUG_BC_TRACE`, `EXAV_DEBUG_BC_FN` and + `EXAV_DEBUG_BC_FORCED`; `EXAV_YR_BIN`, `EXAV_YARA_CORPUS` and + `EXAV_YARA_BENCH_RULES` (tests and examples) are `EXAV_DEBUG_YR_BIN`, + `EXAV_DEBUG_YARA_CORPUS` and `EXAV_DEBUG_YARA_BENCH_RULES`. + `EXAV_SPLIT_MATCH`, `EXAV_VERIFY_BUDGET`, `EXAV_SIM_BUDGET` and + `EXAV_YARA_NO_GATE` are gone, along with the backtracking signature verifier + `EXAV_SPLIT_MATCH=0` selected. +- The `exav-unpack` command has `unzip`'s command line, as a subset: every + option it takes means what it means to Info-ZIP `unzip` 6.00 (`-l`, `-t`, + `-p`, `-c`, `-Z1`, `-d`, `-x`, `-o`, `-n`, `-P`, `-j`, `-C`, `-q`, `-D`), an + `unzip` option it does not take is an error, and its exit statuses are + `unzip`'s. `exav-unpack ARCHIVE` extracts; the `list` and `extract` + subcommands are gone (`-l`; `-d DIR`). It extracts every format the library + reads, writes each member as it is decoded rather than holding the archive + and its members in memory, restores ZIP and tar times, permission bits and + symbolic links, never writes through a link, and asks before replacing a + file. A ZIP split by `zip -s` (`.z01`, ..., `.zip`) and a RAR volume set + (`.part1.rar`, ... or `.rar`, `.r00`, ...) are read from any part, and + `--volume` names parts that are elsewhere. +- Releases carry `exav-unpack`, `exav-grep`, `exav-pe-emu` and `exav-imagehash` + archives beside `exav`'s, and every archive carries `LICENSE` and `NOTICE`. +- `--partial-as password-protected=found` reports any encrypted member as + `Heuristics.Encrypted.*`, as ClamAV's `--alert-encrypted` does: one exav + decrypted with a password, and one whose encryption flag is set over plain + content (APK packers set it on every member), included. A detection in the + content still wins. Before, a scan without `--all-matches` reported neither, + and a falsely flagged member was not even `.cdb`-matchable as encrypted. + `PASSWORD-PROTECTED` is still only content exav could not decrypt. For a ZIP + member the alert reads the local header as ClamAV does (bit 0 set, bit 13 + clear), and a `.cdb` encryption field matches either the local header or the + central directory record; both read only the central directory before. +- A YARA pattern keeps at most a million matches, as yara-x does; one with more + makes the scan `LIMITS-EXCEEDED` unless a rule matches. +- exav-core: `ScanOptions::spill` gives a scan somewhere to write what it makes + of an object too large to hold (see the `spill` module); `exav` passes its + `--spill-dir` files and budgets. `analyze_all_seekable` is the all-match scan + over a seekable input. `unpack::source` exposes random access over an object + not held in memory. +- Every object goes through one pipeline, the input and whatever is unpacked, + decoded or carved out of it, at any size and depth: + - An archive's members are scanned before its own bytes at every depth, so a + detection in a member stored in a nested archive names the member; the + nested archive's own bytes were matched first. + - The buffers a bytecode unpacker makes are scanned as objects, carving and + heuristics included, under `--max-unpack-depth` and `--max-matcher-bytes`; + they had a separate path capped at 4 levels and 256 MiB. + - The `.fp`/`.sfp` allowlist applies to every object, decoded payloads and + carved images included. + - YARA's filename externals are set for a top-level archive and under + `--all-matches`, as for any other top-level file. + - The signature engine is the only matcher: the separate literal automaton + for large inputs is gone. The `.exavdb` format is at version 4; rebuild + with `--build-db`. +- exav-unpack: `walk(fmt, source, budget, visit)` is the one walk. A member + comes as `Member::Bytes` or, decoded as it is read, `Member::Stream`; + `Member::into_bytes` reads either whole, and `MemberMeta::size` is the size + the archive declares. `walk`, `detect`, `extract` and the heuristics take a + `ByteSource` (a slice, a `Vec`, or a `source::BlockCache` over a reader). + Removed: `extract_each`, `Sink`, `stream_members`, `StreamVisit`, + `is_streamable`, `BudgetReader`, `Archive`, `MemberInfo`, the `*_source` + variants and `source::Slice`. exav-core: `patterns::PatternSet` and + `LoadError::Patterns` are removed. +- A streamed member is held to the compression-ratio guard, as a member + decoded whole is. +- `ScanOptions::deep_analysis_max` also holds `Limits::max_buffer_bytes` for a + scan, so no object is held in memory past it. +- exav-unpack-wasm: `list()` decodes nothing it can avoid, and reports + `uncompressedSize` as the archive declares it, -1 where it declares none + (it was the decoded size there); + `extract(i)` walks the archive up to member `i`. +- YARA detections are named `YARA.` outside `--clamav-compat`; the + `.UNOFFICIAL` suffix is compat-only, as for every other signature. +- A signature reload lets scans in progress finish: old workers and the old ICAP + child exit once idle instead of being killed. One still busy after + `--max-scan-secs` plus 5 seconds (an open session, a client that never + finishes) is stopped. +- A worker stopped mid-job (shutdown, reload deadline, supervisor gone) answers + the job with `ERROR` instead of closing the connection without a reply. +- `off` and `0` on `--max-object-bytes` and `--max-matcher-bytes` mean no limit, + as their help said; they used to set a limit of zero. +- Every input goes through one scan: a file, stdin, a FIFO given as a path, + `INSTREAM`, `EXINSTREAM`, ICAP and `http(s)://`. In particular: + - Past `--max-input-bytes`, the first bytes get the whole scan. A file got + only literal signatures and hashes there, and stdin and the daemon's stream + verbs no scan at all. + - A stream larger than the spill budgets is scanned as far as it was held and + reported `LIMITS-EXCEEDED`. It was `UNSCANNABLE`, unscanned. + - Both follow `--partial-as` as a file does; under `found` they are + `Heuristics.Limits.Exceeded.MaxFileSize` everywhere. + - A container over `--max-object-bytes` gets the full scan over its own + bytes on every entry point, not only a file path. + - Stdin honours `--all-matches`, `--profile` and `--max-process-bytes`, and + counts in the summary. +- exav-core: `scan_stream` is removed (the one scan is `scan_seekable`, and + `scan_path` hands a file to it); `warm_up` builds the lazily-initialised + structures before a fork. +- A stream that ends before its terminator is answered `ERROR` on `INSTREAM` + and `EXINSTREAM`, whatever `--partial-as` says. `EXINSTREAM` used to answer + `PARTIAL` with a `TRUNCATED` category, and `INSTREAM` `UNSCANNABLE`. +- A compressed stream damaged part way (gzip, ZIP, PDF, embedded PowerPoint + storages) is `UNSCANNABLE` when the part before the damage holds no + detection, wherever it sits; a checksum mismatch after a full decode is not. + Nested in another container it used to be `OK`, and a gzip with only a bad + CRC was `UNSCANNABLE` at the top level. A deflated ZIP member declaring 0 + bytes compressed and uncompressed (Civil 3D writes them) is empty, not + damaged. +- The daemon's signals match clamd's: `SIGUSR2` reloads the signatures and + `SIGHUP` reopens the `--log` file (for logrotate), under the worker pool, the + thread model and ICAP alone. `SIGUSR2` used to kill the process in every + mode, as `SIGHUP` did under the thread model and ICAP alone; under the pool + `SIGHUP` reloaded the signatures. +- `--workers threads` and an ICAP-only listener reload on `SIGUSR2`, `RELOAD` and + a change in the signature directory, as the pool does. +- The systemd unit is `exav.service` (it was `exav-clamd.service`). It reads + `/var/lib/clamav`, reloads with `systemctl reload exav` (`SIGUSR2`), and says + how to stop `clamav-daemon.socket` alongside `clamav-daemon`. +- `--max-extracted-bytes` is removed. What a scan holds is 1 GiB (400M under + `--clamav-compat`), and `--max-process-bytes` lowers it to what fits the + memory a scan gets. The flag, or `EXAV_MAX_EXTRACTED_BYTES`, stops the run with a + message naming the change. It also set the largest object held in memory, so + `--max-extracted-bytes 0` loaded any file whole. +- `--max-process-bytes` also lowers `--max-object-bytes` to a quarter of the + memory a scan gets, and the total held to what leaves room for an image + decoded from the largest object and its grey copy plus a tenth, so a file + past them is `LIMITS-EXCEEDED`; it was `out of memory ERROR`. The default 2G + changes neither the default limits nor `--clamav-compat`'s. +- Matching an object no longer copies it whole. PCRE subsignatures ran over a + Latin-1 string of the object, up to twice its size, and case-insensitive + bodies over a lowercased copy: the first now match the bytes directly, the + second lowercase what they read past 16 MiB. A crafted image no longer takes + more memory than an object may: its decoded pixels are held to + `--max-object-bytes` (past it, and short of the 512 MiB ClamAV decodes, the + scan is `LIMITS-EXCEEDED`), and it is turned grey + without a full-size RGB copy. A decoder panic leaves the image unhashed + rather than stopping its scan. +- `0` and `off`, flag by flag: `--max-members 0`/`off` and + `--max-jobs-per-worker 0`/`off` mean no limit; `--max-unpack-depth` and the + `--dlp-` counts refuse `0` (and depth refuses `off`); `--update-interval-secs + off` fetches at startup only; `--spill-threshold-bytes`, `--icap-idle-secs` + and `--icap-max-header-bytes` (at least `1K`) have no `off`; + `--icap-preview-bytes off` and `--icap-options-ttl-secs off` leave their + header out of the `OPTIONS` answer. +- `--quiet` keeps error lines, and error lines are written to `--log`; the + summary counts `Partial files` apart from `Total errors`. +- A scan that fails behind the ICAP listener is a block, with + `X-Exav-Status: ERROR` and `Heuristics.Exav.ScanError`. +- A bytecode program that runs out of instructions makes the scan + `LIMITS-EXCEEDED` unless something else is found. So does one stopped by an + opcode or host API exav does not model, or by the interpreter's call-depth or + frame-size cap; its result was discarded as though it had found nothing. A + program's own fault (an out-of-bounds access, a division by zero) is still + discarded, as ClamAV discards it. +- Bytecode follows ClamAV 1.4.3 in four more places: + - A program that aborts has its detection discarded; it was reported. + - `malloc` returns NULL from 128 MiB less 8 bytes; it allocated up to + 256 MiB. + - `__clambc_pedata` reads as zeros on a file that is not a PE; reading it + discarded the program's result. On a PE that exav has no header data for + (too large to load, or not parsed), it makes the scan `LIMITS-EXCEEDED` + unless something else is found. + - What a program wrote before its run failed is scanned; it was dropped + with the program's detection. A program that asks `disasm_x86` about bytes + the decoder does not know now stops there, so nothing it writes after that + point is scanned. +- A bytecode program that writes more than 256 MiB into one extracted file + makes the scan `LIMITS-EXCEEDED` unless something else is found; the rest + of its output was dropped silently. +- A bytecode `write` fails with -1 once one extracted file would pass + `--max-object-bytes`, or the run's output would pass what is left of + `--max-matcher-bytes`, as ClamAV's does at its file and scan size limits. + The program carries on and the scan is `LIMITS-EXCEEDED` unless something + else is found; the write used to succeed. +- The `docker-compose.yml` example publishes the clamd port on localhost only. +- `make lint` runs the clippy passes CI runs, and `make test-www` checks that + every internal link and anchor of the documentation site resolves. +- exav.org is organised by product: malware scanning, archive extraction + (with new pages for the `exav-unpack` command and `@exav/unpack-wasm`), the + file viewer, subprojects, and about the project, each listed in the header + of every page and with its own sidebar. The old page URLs redirect to the + new ones. The site is dark only. +- A signature path that loads nothing is an error: one that does not exist, or a + directory holding only a prebuilt `.exavdb` (load that with `-d`). +- `clamscan`'s `--alert-encrypted`, `--alert-encrypted-archive`, + `--alert-encrypted-doc` and `--alert-exceeds-max` are refused with the + `--partial-as` value that replaces them. +- The `exav` crate's `checksums` feature is removed; no flag used it. +- exav-unpack: the bzip2 decoder is vendored from `bzip2-rs` (with the fix + below) instead of depending on it; the internal `bzip2-decoder` feature + groups it. ALZ and EGG decode their bzip2 and LZMA members in a build without + the `bzip2` and `lzip` features. +- A build without the `yara` feature warns when rule files are loaded; they + never match. +- A long run of one byte value costs the signature engine about what its first + few hundred bytes do. The search skips the run's interior, and a signature + anchored inside it is checked once for the whole interior and one position at + a time only near its edges. Where several matches lie inside one run, a + first-match scan may report a different one of them. +- Scanning is faster on ordinary files too: + - The signature engine finds its signatures through one index of their + literal anchors, looked up at each position of the object, instead of + running automatons (four for a PE) over it. An anchor longer than five + bytes is indexed by the seven of its bytes the signatures share least, + looked up at every other position. + Case-insensitive anchors are looked up on the bytes + lowercased as they are read; the object is copied lowercased only when a + case-insensitive signature has to be checked. + - A signature whose offset window is at most 4096 bytes wide, counted from + the start, the end, the entry point or a section, is checked where it can + start, not searched for through the object. + - A PE section's MD5 is computed only when a section-hash signature names + its size. + - The bytecode interpreter lays out a function's values once per run rather + than at every call, and reads and writes them whole. + - Bytecode triggers are matched in the same sweep as every other + signature, not in a second sweep of their own. + - A literal a signature searches for after a gap is looked up in the + blocks of the object its check reaches, each searched once per scan, not + through the whole object the first time it is met. + - Whole-file digests are computed once for the allowlist and the hash + signatures together, and only those some signature of the object's size + can match: most objects need no SHA-1 or SHA-256 at all, and SHA-256 uses + the processor's instructions where it has them. + - The group cost check is skipped until a group passes its cap. +- An object read through the block cache, such as a large file or one fetched + over HTTP, is read far fewer times over: format detection's search, carving + and the digests share one read of it, the signature sweep is a second, + carving confirms an archive by its first bytes, and YARA's prefilter looks + up its atoms in one read and its literal and base64 patterns share another. Over HTTP, a request that + continues the previous one fetches twice as much, up to 8 MiB. +- A prebuilt database loads faster: the signature index, anchor groups, hash + tables and the indexes derived from the signatures are stored as the build + made them and read back with a copy, the file is read once rather than once + to check its digest and again to decode it, and the bodies and logical + signatures decode on threads of their own while the index is read. The file + is smaller, and building it takes less memory. Its trailer is a CRC-32 of the + contents instead of a SHA-256: it is there to catch a torn or damaged file, + which is all the digest was checked for. +- `--build-shard-bytes` is removed: the signature index has no automaton to + split, and builds in far less memory. The flag, or `EXAV_BUILD_SHARD_BYTES`, + stops the run with a message naming the change. exav-core: + `loader::load_with_options_mem` and `Builder::set_max_build_mem` are removed. +- Bytecode triggers are evaluated with the object's container, as every other + logical signature is, so a trigger with a `Container:` condition can fire. + exav-core (`unstable-internals`): `BytecodeRuntime::from_sources` adds the + triggers to the `EngineBuilder` it is given, and `BytecodeRuntime::standalone` + builds a runtime with an engine of its own, for tools. +- A first-match scan meets first the signatures their offsets pin, then the + others in the order the object's bytes hit them, rather than one file-type + automaton after another, so when several match it may report a different + one of them. Carving keeps the first + candidates of each kind by position when more than its cap are found. +- The RustCrypto crates move to their current generation (`digest` 0.11, + `cipher` 0.5: `sha2`, `sha1`, `md-5`, `aes`, `cbc`, `des`, `hmac`, `pbkdf2`). +- Dependencies: `bincode` (unmaintained, RUSTSEC-2025-0141) and `serde` are + gone from `exav-unpack`, the encrypted-DMG header being read field by field; + `tlsh2` 1.x; `ext4-view` 1.0 (panics and infinite loops on corrupt + filesystems fixed upstream); `lzma-rust2` 0.21 (malformed-input fixes + upstream); `ureq` 3 for the `http` features, which drops `url` and the ICU + crates from that build and, as ureq 3 does by default, follows the + `HTTP_PROXY`/`HTTPS_PROXY`/`NO_PROXY` environment. + +### Added + +- AutoCAD DXF drawings, ASCII and binary, R12 to 2018 (feature `dxf`, in + `all-formats`): the object an OLE2FRAME embeds, which the file holds as + hexadecimal, is extracted and scanned (the compound file, then its streams), + as is any other binary chunk that is a whole file of a known kind. An ASCII + DXF keeps its text type; nothing changes under `--clamav-compat`. + `exav_unpack::dxf` exposes the pairs, records and code pages of the format. +- AutoCAD DWG drawings, R13 to 2018 (feature `dwg`, in + `all-formats`): the preview images are extracted and scanned, the bitmap + as a BMP file, and so is the object each OLE2FRAME embeds + (`ole2frame-.ole`, the compound file); a drawing whose objects + cannot be read is reported as not fully examined, and so is a drawing of + a release before R13 (R12, AC1009, and older). Nothing changes under + `--clamav-compat`. `exav_unpack::dwg` + reads the format's bit codes, the sections the file header locates (from + 2004: the encrypted file header, the page and section maps, checksummed + and compressed pages, with what they expand to bounded; 2007's own + Reed-Solomon coded pages, compression and CRCs, a damaged header or map + read from the copies the file keeps), the classes, the + object map and each object's common data and strings, from the ODA + specification. The DXF reader now reads MTEXT columns from the extended data (before 2018) + and the embedded object (2018). +- `exav-imagehash`, a crate and a command of its own: perceptual image hashes + with every step a parameter, and presets equal to `sigtool --fuzzy-img` + (ClamAV's `fuzzy_img` hash, which the scanner now computes through it) and + to Python `imagehash.phash`. No `unsafe` in it, its image decoders or its + DCT (rustdct's, vendored); its checksum and cast dependencies do use some. +- `exav-render`, a new crate of memory-safe decoders that turn a file into + something to draw: raster images into pixels (exav-imagehash now hashes + what it decodes; over 9,751 photos the hashes are unchanged), JPEG 2000, + JBIG2 and fax images (`jp2`, `jbig2`; hayro-jpeg2000 and hayro-jbig2, + `forbid(unsafe_code)`, without their SIMD code) including those of PDFs + (`pdf_image`), DWG (R13 to 2018) and DXF drawings into GPU-ready buffers + (feature `dwg`), and IFC (2X3, 4 and 4X3) and STL models into meshes + (features `ifc`, `stl`). +- `@exav/viewer`, a new npm package: a file viewer for the browser, for PDF, + images (TIFF, BMP and the formats browsers do not draw, through exav-render + in WebAssembly), DWG and DXF, Word, Excel, PowerPoint and CSV, IFC and STL + models, video, audio, and the files inside an archive. Each format's engine + loads on its first file; every asset is served by the host, so it runs under + a strict Content-Security-Policy and offline. A framework-free core, a React + UI, a Vite plugin, a command that copies the engines' assets, and a + sandboxed mode that opens each file in an `", + '', + '', + "", + "", + "", + 'text', + "", + ]) { + expect(allowedHtml(html), html).toBe(false); + } + }); +}); + +describe("a worker's blob", () => { + it("is a classic script that sets the script's URL and imports only it", () => { + const calls: string[] = []; + const self: Record = { importScripts: (u: string) => calls.push(u) }; + vm.runInNewContext(workerBoot("https://frame.test/cad.worker.js"), { self, importScripts: self.importScripts }); + expect(self.EXAV_SCRIPT).toBe("https://frame.test/cad.worker.js"); + expect(calls).toEqual(["https://frame.test/cad.worker.js"]); + }); + + it("quotes the URL as data, whatever it holds", () => { + const url = 'https://frame.test/a.js"); importScripts("https://x.test/evil.js'; // eslint-disable-line + const calls: string[] = []; + const self: Record = {}; + vm.runInNewContext(workerBoot(url), { self, importScripts: (u: string) => calls.push(u) }); + expect(calls).toEqual([url]); + }); + + it("goes through a policy that accepts that URL alone, where Trusted Types exist", () => { + const made: { name: string; accepts: (u: string) => unknown }[] = []; + const trustedTypes = { + createPolicy: (name: string, rules: { createScriptURL: (u: string) => string }) => { + made.push({ name, accepts: (u) => rules.createScriptURL(u) }); + return { createScriptURL: (u: string) => ({ trusted: rules.createScriptURL(u) }) }; + }, + }; + const calls: unknown[] = []; + vm.runInNewContext(workerBoot("https://frame.test/w.js"), { self: { trustedTypes }, importScripts: (u: unknown) => calls.push(u) }); + expect(made.map((p) => p.name)).toEqual(["exav-worker"]); + expect(calls).toEqual([{ trusted: "https://frame.test/w.js" }]); + // A TypeError of the script's own realm. + expect(() => made[0]!.accepts("https://frame.test/other.js")).toThrow("not this worker's script"); + }); +}); diff --git a/crates/exav-viewer/ts/frame/app/workers.ts b/crates/exav-viewer/ts/frame/app/workers.ts new file mode 100644 index 00000000..795dbe54 --- /dev/null +++ b/crates/exav-viewer/ts/frame/app/workers.ts @@ -0,0 +1,135 @@ +/** + * Workers and Trusted Types in the frame. + * + * The frame's origin is opaque: `new Worker(url)` on its own scripts throws, + * and a module worker from a `blob:` URL does not start. A classic worker + * from a `blob:` URL does. So every worker an engine asks for (ours, pdf.js's, + * the Office engine's) is started from a blob made here, + * which holds one `importScripts` of the script the engine named. That script + * must be one of the frame's own: the frame's build puts a classic bundle + * where each module worker was. + * + * Under `require-trusted-types-for 'script'` a worker's URL must come from a + * policy: `exav-worker` accepts only the blobs made here. The `default` + * policy takes what the engines write into `innerHTML` (the Office engine + * clears elements and draws an arrow) when it is + * inert SVG, and refuses the rest. + */ + +type Policy = { createScriptURL(url: string): unknown }; +type Factory = { createPolicy(name: string, rules: Record string | null>): Policy }; + +const tt = (globalThis as { trustedTypes?: Factory }).trustedTypes; + +/** Shapes only: no ``, ``, ``, ``, `