├── src ├── index.js ├── utils.js └── global.d.ts ├── tests ├── fixtures │ ├── simple │ │ ├── simple.txt │ │ ├── simple.txt.gz │ │ ├── simple.txt.stats.json │ │ ├── simple.txt-metadata.json │ │ └── binExpected.html │ ├── readme.md │ ├── svg-7-hex │ │ ├── image.svg.gz │ │ ├── image.svg │ │ ├── image.svg.stats.json │ │ ├── defdb.txt │ │ └── binExpected.html │ ├── svg-2-svgo │ │ ├── image.svg.gz │ │ ├── image.svg │ │ ├── image.svg.stats.json │ │ └── defdb.txt │ ├── svg-1-original │ │ ├── image.svg.gz │ │ ├── image.svg │ │ ├── image.svg.stats.json │ │ └── defdb.txt │ ├── svg-3-viewbox │ │ ├── image.svg.gz │ │ ├── image.svg │ │ ├── image.svg.stats.json │ │ └── defdb.txt │ ├── svg-4-unclosed │ │ ├── image.svg.gz │ │ ├── image.svg │ │ ├── image.svg.stats.json │ │ └── defdb.txt │ ├── svg-6-backrefs │ │ ├── image.svg.gz │ │ ├── image.svg │ │ ├── image.svg.stats.json │ │ └── defdb.txt │ ├── svg-5-lowercase │ │ ├── image.svg.gz │ │ ├── image.svg │ │ ├── image.svg.stats.json │ │ └── defdb.txt │ └── large-file │ │ └── websiteExpected.html ├── jsconfig.json ├── utils │ ├── paths.js │ └── log.js ├── stats.test.js ├── basic-inflate.test.js ├── gzip-inflate.test.js ├── bin.test.js └── website.test.js ├── docs └── sample.png ├── webapp ├── website │ ├── types.d.ts │ ├── compress.js │ └── index.jsx ├── shared │ ├── logger.js │ ├── utils.js │ ├── GZHeatMap.d.ts │ ├── constructBackRefs.js │ ├── computeStats.js │ ├── constructHeatMap.js │ └── GZHeatMap.js └── cli │ ├── index.js │ └── rollup.config.js ├── .vscode └── settings.json ├── jsconfig.json ├── vite.config.js ├── .editorconfig ├── index.html ├── bin ├── template.html └── gz-heatmap.js ├── .github └── workflows │ ├── ci.yml │ └── deploy.yml ├── LICENSE ├── README.md ├── package.json └── .gitignore /src/index.js: -------------------------------------------------------------------------------- 1 | export { gzinflate } from "./inflate.js"; 2 | -------------------------------------------------------------------------------- /tests/fixtures/simple/simple.txt: -------------------------------------------------------------------------------- 1 | ham hamburger ham ha hamburg hamb hamburger -------------------------------------------------------------------------------- /docs/sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewiggins/gz-heatmap/HEAD/docs/sample.png -------------------------------------------------------------------------------- /webapp/website/types.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.svg" { 2 | const url: string; 3 | export default url; 4 | } 5 | -------------------------------------------------------------------------------- /tests/fixtures/readme.md: -------------------------------------------------------------------------------- 1 | SVG examples sourced from: https://github.com/subzey/svg-gz-supplement/tree/master/1-original 2 | -------------------------------------------------------------------------------- /tests/fixtures/simple/simple.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewiggins/gz-heatmap/HEAD/tests/fixtures/simple/simple.txt.gz -------------------------------------------------------------------------------- /tests/fixtures/svg-7-hex/image.svg.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewiggins/gz-heatmap/HEAD/tests/fixtures/svg-7-hex/image.svg.gz -------------------------------------------------------------------------------- /tests/fixtures/svg-2-svgo/image.svg.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewiggins/gz-heatmap/HEAD/tests/fixtures/svg-2-svgo/image.svg.gz -------------------------------------------------------------------------------- /tests/fixtures/svg-1-original/image.svg.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewiggins/gz-heatmap/HEAD/tests/fixtures/svg-1-original/image.svg.gz -------------------------------------------------------------------------------- /tests/fixtures/svg-3-viewbox/image.svg.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewiggins/gz-heatmap/HEAD/tests/fixtures/svg-3-viewbox/image.svg.gz -------------------------------------------------------------------------------- /tests/fixtures/svg-4-unclosed/image.svg.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewiggins/gz-heatmap/HEAD/tests/fixtures/svg-4-unclosed/image.svg.gz -------------------------------------------------------------------------------- /tests/fixtures/svg-6-backrefs/image.svg.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewiggins/gz-heatmap/HEAD/tests/fixtures/svg-6-backrefs/image.svg.gz -------------------------------------------------------------------------------- /tests/fixtures/svg-5-lowercase/image.svg.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewiggins/gz-heatmap/HEAD/tests/fixtures/svg-5-lowercase/image.svg.gz -------------------------------------------------------------------------------- /tests/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../jsconfig.json", 3 | "compilerOptions": { 4 | "target": "es2022", 5 | "module": "es2022" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/svg-7-hex/image.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fixtures/svg-2-svgo/image.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fixtures/svg-3-viewbox/image.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fixtures/svg-4-unclosed/image.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fixtures/svg-5-lowercase/image.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fixtures/svg-6-backrefs/image.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "yaml.schemas": { 3 | "https://json.schemastore.org/github-workflow.json": "file:///Users/andre_wiggins/github/andrewiggins/gz-heatmap/.github/workflows/deploy.yml" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tests/fixtures/svg-1-original/image.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "module": "es2020", 5 | "moduleResolution": "node", 6 | "checkJs": true, 7 | "strict": true, 8 | "jsx": "react-jsx", 9 | "jsxImportSource": "preact" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { preact } from "@preact/preset-vite"; 2 | import { defineConfig } from "vite"; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | base: "/gz-heatmap/", 7 | plugins: [preact()], 8 | build: { 9 | target: "es2022", 10 | modulePreload: { polyfill: false }, 11 | }, 12 | }); 13 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [{*.json,.*rc,*.yml}] 11 | indent_style = space 12 | indent_size = 2 13 | insert_final_newline = false 14 | 15 | [*.md] 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /webapp/shared/logger.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @typedef Logger 3 | * @property {(...args: any) => void} debug 4 | * 5 | * @param {{ debug?: boolean }} options 6 | * @returns {Logger} 7 | */ 8 | export function createLogger(options) { 9 | return { 10 | debug(...args) { 11 | if (options.debug) { 12 | console.log(...args); 13 | } 14 | }, 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /webapp/shared/utils.js: -------------------------------------------------------------------------------- 1 | /** @type {Intl.NumberFormat | undefined} */ 2 | let numberFormatter; 3 | try { 4 | numberFormatter = new Intl.NumberFormat(navigator.language); 5 | } catch (e) { 6 | // Oh well... 7 | } 8 | 9 | /** @type {(n: number) => string} */ 10 | export function formatNum(n) { 11 | return numberFormatter ? numberFormatter.format(n) : n.toString(); 12 | } 13 | -------------------------------------------------------------------------------- /webapp/shared/GZHeatMap.d.ts: -------------------------------------------------------------------------------- 1 | import { JSXInternal } from "preact/src/jsx"; 2 | 3 | class GZHeatMap extends HTMLElement { 4 | gzdata: Metadata | null; 5 | } 6 | 7 | declare module "preact" { 8 | namespace JSX { 9 | interface IntrinsicElements { 10 | "gz-heatmap": JSXInternal.HTMLAttributes & { 11 | gzdata?: Metadata | null; 12 | }; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /webapp/cli/index.js: -------------------------------------------------------------------------------- 1 | import "../shared/GZHeatMap.js"; 2 | 3 | /** 4 | * @param {Metadata} metadata 5 | * @param {HTMLElement} container 6 | */ 7 | export function renderIntoDom(metadata, container) { 8 | const gzheatmap = /** @type {import('../shared/GZHeatMap').GZHeatMap} */ ( 9 | document.createElement("gz-heatmap") 10 | ); 11 | gzheatmap.gzdata = metadata; 12 | 13 | container.textContent = ""; 14 | container.appendChild(gzheatmap); 15 | } 16 | -------------------------------------------------------------------------------- /tests/fixtures/simple/simple.txt.stats.json: -------------------------------------------------------------------------------- 1 | { 2 | "gzipHeader": { 3 | "byteLength": 10 4 | }, 5 | "gzipFooter": { 6 | "byteLength": 8 7 | }, 8 | "metadata": { 9 | "bitsCompressed": 10 10 | }, 11 | "codeLengthTables": { 12 | "bitsCompressed": 0 13 | }, 14 | "literals": { 15 | "count": 13, 16 | "bitsCompressed": 104, 17 | "bytesExpanded": 13 18 | }, 19 | "lz77s": { 20 | "count": 5, 21 | "bitsCompressed": 69, 22 | "bytesExpanded": 30 23 | } 24 | } -------------------------------------------------------------------------------- /tests/fixtures/svg-2-svgo/image.svg.stats.json: -------------------------------------------------------------------------------- 1 | { 2 | "gzipHeader": { 3 | "byteLength": 10 4 | }, 5 | "gzipFooter": { 6 | "byteLength": 8 7 | }, 8 | "metadata": { 9 | "bitsCompressed": 23 10 | }, 11 | "codeLengthTables": { 12 | "bitsCompressed": 277 13 | }, 14 | "literals": { 15 | "count": 92, 16 | "bitsCompressed": 467, 17 | "bytesExpanded": 92 18 | }, 19 | "lz77s": { 20 | "count": 8, 21 | "bitsCompressed": 90, 22 | "bytesExpanded": 43 23 | } 24 | } -------------------------------------------------------------------------------- /tests/fixtures/svg-3-viewbox/image.svg.stats.json: -------------------------------------------------------------------------------- 1 | { 2 | "gzipHeader": { 3 | "byteLength": 10 4 | }, 5 | "gzipFooter": { 6 | "byteLength": 8 7 | }, 8 | "metadata": { 9 | "bitsCompressed": 23 10 | }, 11 | "codeLengthTables": { 12 | "bitsCompressed": 268 13 | }, 14 | "literals": { 15 | "count": 94, 16 | "bitsCompressed": 473, 17 | "bytesExpanded": 94 18 | }, 19 | "lz77s": { 20 | "count": 7, 21 | "bitsCompressed": 78, 22 | "bytesExpanded": 39 23 | } 24 | } -------------------------------------------------------------------------------- /tests/fixtures/svg-7-hex/image.svg.stats.json: -------------------------------------------------------------------------------- 1 | { 2 | "gzipHeader": { 3 | "byteLength": 10 4 | }, 5 | "gzipFooter": { 6 | "byteLength": 8 7 | }, 8 | "metadata": { 9 | "bitsCompressed": 24 10 | }, 11 | "codeLengthTables": { 12 | "bitsCompressed": 267 13 | }, 14 | "literals": { 15 | "count": 93, 16 | "bitsCompressed": 455, 17 | "bytesExpanded": 93 18 | }, 19 | "lz77s": { 20 | "count": 6, 21 | "bitsCompressed": 70, 22 | "bytesExpanded": 41 23 | } 24 | } -------------------------------------------------------------------------------- /tests/fixtures/svg-1-original/image.svg.stats.json: -------------------------------------------------------------------------------- 1 | { 2 | "gzipHeader": { 3 | "byteLength": 10 4 | }, 5 | "gzipFooter": { 6 | "byteLength": 8 7 | }, 8 | "metadata": { 9 | "bitsCompressed": 24 10 | }, 11 | "codeLengthTables": { 12 | "bitsCompressed": 307 13 | }, 14 | "literals": { 15 | "count": 100, 16 | "bitsCompressed": 505, 17 | "bytesExpanded": 100 18 | }, 19 | "lz77s": { 20 | "count": 10, 21 | "bitsCompressed": 117, 22 | "bytesExpanded": 76 23 | } 24 | } -------------------------------------------------------------------------------- /tests/fixtures/svg-4-unclosed/image.svg.stats.json: -------------------------------------------------------------------------------- 1 | { 2 | "gzipHeader": { 3 | "byteLength": 10 4 | }, 5 | "gzipFooter": { 6 | "byteLength": 8 7 | }, 8 | "metadata": { 9 | "bitsCompressed": 23 10 | }, 11 | "codeLengthTables": { 12 | "bitsCompressed": 263 13 | }, 14 | "literals": { 15 | "count": 93, 16 | "bitsCompressed": 463, 17 | "bytesExpanded": 93 18 | }, 19 | "lz77s": { 20 | "count": 7, 21 | "bitsCompressed": 80, 22 | "bytesExpanded": 38 23 | } 24 | } -------------------------------------------------------------------------------- /tests/fixtures/svg-5-lowercase/image.svg.stats.json: -------------------------------------------------------------------------------- 1 | { 2 | "gzipHeader": { 3 | "byteLength": 10 4 | }, 5 | "gzipFooter": { 6 | "byteLength": 8 7 | }, 8 | "metadata": { 9 | "bitsCompressed": 23 10 | }, 11 | "codeLengthTables": { 12 | "bitsCompressed": 256 13 | }, 14 | "literals": { 15 | "count": 93, 16 | "bitsCompressed": 461, 17 | "bytesExpanded": 93 18 | }, 19 | "lz77s": { 20 | "count": 7, 21 | "bitsCompressed": 80, 22 | "bytesExpanded": 38 23 | } 24 | } -------------------------------------------------------------------------------- /tests/fixtures/svg-6-backrefs/image.svg.stats.json: -------------------------------------------------------------------------------- 1 | { 2 | "gzipHeader": { 3 | "byteLength": 10 4 | }, 5 | "gzipFooter": { 6 | "byteLength": 8 7 | }, 8 | "metadata": { 9 | "bitsCompressed": 23 10 | }, 11 | "codeLengthTables": { 12 | "bitsCompressed": 252 13 | }, 14 | "literals": { 15 | "count": 93, 16 | "bitsCompressed": 462, 17 | "bytesExpanded": 93 18 | }, 19 | "lz77s": { 20 | "count": 6, 21 | "bitsCompressed": 70, 22 | "bytesExpanded": 40 23 | } 24 | } -------------------------------------------------------------------------------- /webapp/cli/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { fileURLToPath } from "url"; 2 | import { dirname, join } from "path"; 3 | import { nodeResolve } from "@rollup/plugin-node-resolve"; 4 | 5 | const __dirname = dirname(fileURLToPath(import.meta.url)); 6 | /** @type {(...args: string[]) => string} */ 7 | const p = (...args) => join(__dirname, "..", "..", ...args); 8 | 9 | export default { 10 | input: p("./webapp/cli/index.js"), 11 | output: { 12 | file: p("./bin/gz-heatmap-webapp.js"), 13 | format: "iife", 14 | name: "GZHeatmap", 15 | }, 16 | plugins: [nodeResolve()], 17 | }; 18 | -------------------------------------------------------------------------------- /tests/utils/paths.js: -------------------------------------------------------------------------------- 1 | import { fileURLToPath } from "url"; 2 | import { dirname, join } from "path"; 3 | import { readFile } from "fs/promises"; 4 | 5 | const __dirname = dirname(fileURLToPath(import.meta.url)); 6 | 7 | /** @type {(...args: string[]) => string} */ 8 | export const testPath = (...args) => join(__dirname, "..", ...args); 9 | 10 | /** @type {(...args: string[]) => string} */ 11 | export const fixture = (...args) => testPath("fixtures", ...args); 12 | 13 | /** @type {(path: string) => Promise} */ 14 | export const readFixture = async (path) => 15 | (await readFile(path, "utf8")).replace(/\r\n/g, "\n"); 16 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {LZ77BitInfo} info 3 | * @returns {number} 4 | */ 5 | export function getLZ77TotalBitSize(info) { 6 | let length = info.length; 7 | let dist = info.dist; 8 | 9 | return ( 10 | length.symbol.size + 11 | length.extraBits.size + 12 | dist.symbol.size + 13 | dist.extraBits.size 14 | ); 15 | } 16 | 17 | /** 18 | * @param {HuffmanCodeLengths | RepeatHuffmanCodeLengths} datum 19 | * @returns {number} 20 | */ 21 | export function getCodeLengthSize(datum) { 22 | if (datum.type == "code_length") { 23 | return datum.value.size; 24 | } else { 25 | return datum.symbol.size + datum.repeatCount.size; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | GZ Heatmap 11 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /bin/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | GZ Heatmap 7 | 16 | 17 | 18 |
19 | 20 | 21 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /webapp/website/compress.js: -------------------------------------------------------------------------------- 1 | /// 2 | import * as comlink from "comlink"; 3 | import pako from "pako"; 4 | 5 | /** 6 | * @param {string} url 7 | * @returns {Promise} 8 | */ 9 | function fetchData(url) { 10 | return fetch(url).then((res) => { 11 | if (!res.ok) { 12 | throw new Error(`Response indicated failure: ${res.status}`); 13 | } 14 | return res.arrayBuffer(); 15 | }); 16 | } 17 | 18 | /** 19 | * @typedef CompressionWorker 20 | * @property {(url: string) => Promise} compressURL 21 | * @property {(input: ArrayBuffer) => Promise} compressBuffer 22 | */ 23 | 24 | /** @type {CompressionWorker} */ 25 | const compressWorker = { 26 | async compressURL(url) { 27 | return this.compressBuffer(await fetchData(url)); 28 | }, 29 | async compressBuffer(input) { 30 | return pako.gzip(input, { memLevel: 9 }); 31 | }, 32 | }; 33 | 34 | comlink.expose(compressWorker); 35 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | workflow_dispatch: 5 | workflow_call: 6 | pull_request: 7 | branches: 8 | - "**" 9 | push: 10 | branches: 11 | - main 12 | - restructure 13 | 14 | jobs: 15 | build_test: 16 | name: Build & Test 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v3 20 | - uses: actions/setup-node@v3 21 | with: 22 | node-version-file: package.json 23 | cache: npm 24 | - run: npm ci 25 | - run: npm run build 26 | - run: npm run test 27 | timeout-minutes: 5 28 | - name: Package 29 | run: | 30 | npm pack 31 | mv gz-heatmap-*.tgz gz-heatmap.tgz 32 | - name: Upload npm package 33 | uses: actions/upload-artifact@v3 34 | with: 35 | name: npm-package 36 | path: gz-heatmap.tgz 37 | - name: Upload artifact 38 | uses: actions/upload-pages-artifact@v1 39 | with: 40 | path: dist 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Andre Wiggins 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | # Simple workflow for deploying static content to GitHub Pages 2 | name: Deploy 3 | 4 | on: 5 | # Runs on pushes targeting the default branch 6 | push: 7 | branches: ["main"] 8 | paths: 9 | - "src/**/*" 10 | - "webapp/**/*" 11 | - "index.html" 12 | - "vite.config.js" 13 | 14 | # Allows you to run this workflow manually from the Actions tab 15 | workflow_dispatch: 16 | 17 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 18 | permissions: 19 | contents: read 20 | pages: write 21 | id-token: write 22 | 23 | # Allow one concurrent deployment 24 | concurrency: 25 | group: "pages" 26 | cancel-in-progress: true 27 | 28 | jobs: 29 | build: 30 | uses: ./.github/workflows/ci.yml 31 | 32 | deploy: 33 | needs: build 34 | environment: 35 | name: github-pages 36 | url: ${{ steps.deployment.outputs.page_url }} 37 | runs-on: ubuntu-latest 38 | steps: 39 | - name: Setup Pages 40 | uses: actions/configure-pages@v3 41 | - name: Deploy to GitHub Pages 42 | id: deployment 43 | uses: actions/deploy-pages@v1 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gz-heatmap 2 | 3 | Produce a heatmap of gzip files to better understand how gzip compresses your code. 4 | 5 | ![Screenshot of gz-heatmap](./docs/sample.png) 6 | 7 | ## Usage 8 | 9 | ### Website 10 | 11 | Go to https://andrewiggins.github.io/gz-heatmap/ and enter a URL or upload a file to see how GZip compresses your file. Your file is compressed using the [`pako` library](https://github.com/nodeca/pako) with `memLevel` set to `9` (highest compression). 12 | 13 | ### CLI 14 | 15 | Install this npm package to run `gz-heatmap` on a file. It'll compress the given text file using NodeJS's bundled `zlib` and output a local HTML file to view how gzip compresses your file. 16 | 17 | ### NPM package 18 | 19 | If you'd like to build your UI, you can `import { gzinflate } from "gz-heatmap";` to inflate a gzip file and get back metadata describing how gzip has compressed your file. 20 | 21 | ## Acknowledgements 22 | 23 | - [gzthermal](https://encode.su/threads/1889-gzthermal-pseudo-thermal-view-of-Gzip-Deflate-compression-efficiency) 24 | This repository is basically a JS implementation of wicked-cool gzthermal tool. I wanted to add some nifty interactive features gzthermal so I re-implemented it in JavaScript to add them. 25 | - [gzthermal-web](https://github.com/simonw/gzthermal-web) 26 | How I originally discovered the gzthermal tool. 27 | - [tiny-inflate](https://github.com/foliojs/tiny-inflate) 28 | The core inflate algorithm is based on [a fork](https://github.com/andrewiggins/tiny-inflate/tree/experiments) of the tiny-inflate JS implementation. 29 | - [fflate](https://github.com/101arrowz/fflate/) 30 | Another JS inflate implementation I looked at to understand how GZip works 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gz-heatmap", 3 | "type": "module", 4 | "version": "0.0.1", 5 | "description": "Produce a heatmap of gzip files to better understand how gzip compresses your code", 6 | "main": "src/index.js", 7 | "bin": { 8 | "gz-heatmap": "bin/gz-heatmap.js" 9 | }, 10 | "scripts": { 11 | "build": "npm run build:cli && npm run build:website", 12 | "build:cli": "rollup -c ./webapp/cli/rollup.config.js", 13 | "build:website": "vite build", 14 | "test": "uvu tests", 15 | "start": "vite", 16 | "preview": "vite preview" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/andrewiggins/gz-heatmap.git" 21 | }, 22 | "keywords": [ 23 | "gzip", 24 | "heatmap", 25 | "gzthermal", 26 | "compression", 27 | "visualization" 28 | ], 29 | "author": "Andre Wiggins", 30 | "license": "MIT", 31 | "bugs": { 32 | "url": "https://github.com/andrewiggins/gz-heatmap/issues" 33 | }, 34 | "homepage": "https://github.com/andrewiggins/gz-heatmap#readme", 35 | "files": [ 36 | "src", 37 | "bin" 38 | ], 39 | "dependencies": { 40 | "open": "^8.4.0", 41 | "prettier": "^2.8.3", 42 | "sade": "^1.8.1" 43 | }, 44 | "devDependencies": { 45 | "@preact/preset-vite": "^2.5.0", 46 | "@rollup/plugin-node-resolve": "^15.0.0", 47 | "comlink": "^4.4.1", 48 | "pako": "^2.1.0", 49 | "preact": "^10.11.3", 50 | "puppeteer": "^19.6.3", 51 | "rimraf": "^4.1.2", 52 | "rollup": "^3.14.0", 53 | "strip-ansi": "^7.0.1", 54 | "tree-kill": "^1.2.2", 55 | "uvu": "^0.5.6", 56 | "vite": "^4.1.1" 57 | }, 58 | "volta": { 59 | "node": "18.14.0" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /tests/stats.test.js: -------------------------------------------------------------------------------- 1 | import { gzinflate } from "../src/inflate.js"; 2 | import { readFile, writeFile } from "fs/promises"; 3 | import { test } from "uvu"; 4 | import * as assert from "uvu/assert"; 5 | import { getTotalEncodedBitSize } from "./utils/log.js"; 6 | import { fixture, readFixture } from "./utils/paths.js"; 7 | import { 8 | computeStats, 9 | getBitsCompressed, 10 | getBytesCompressed, 11 | getBytesExpanded, 12 | } from "../webapp/shared/computeStats.js"; 13 | 14 | const testFiles = [ 15 | "simple/simple.txt", 16 | "svg-1-original/image.svg", 17 | "svg-2-svgo/image.svg", 18 | "svg-3-viewbox/image.svg", 19 | "svg-4-unclosed/image.svg", 20 | "svg-5-lowercase/image.svg", 21 | "svg-6-backrefs/image.svg", 22 | "svg-7-hex/image.svg", 23 | ]; 24 | 25 | testFiles.forEach((testFile) => { 26 | test(`should compute stats for ${testFile}`, async () => { 27 | const input = await readFile(fixture(testFile + ".gz")); 28 | const expectedOut = await readFixture(fixture(testFile)); 29 | 30 | const statsFixturePath = fixture(testFile + ".stats.json"); 31 | const expectedStats = await readFixture(statsFixturePath); 32 | 33 | const out = Buffer.alloc(expectedOut.length); 34 | const { metadata } = gzinflate(input, out); 35 | const stats = computeStats(metadata); 36 | 37 | const actualStats = JSON.stringify(stats, null, 2); 38 | await writeFile(statsFixturePath, actualStats, "utf8"); 39 | 40 | assert.is(out.toString("utf8"), expectedOut); 41 | 42 | assert.fixture(actualStats, expectedStats); 43 | assert.is(getBytesExpanded(stats), expectedOut.length); 44 | assert.is(getBitsCompressed(stats), getTotalEncodedBitSize(metadata)); 45 | assert.is(getBytesCompressed(stats), input.byteLength); 46 | }); 47 | }); 48 | 49 | test.run(); 50 | -------------------------------------------------------------------------------- /bin/gz-heatmap.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import * as path from "path"; 4 | import { fileURLToPath, pathToFileURL } from "url"; 5 | import { readFile, writeFile, copyFile, mkdir } from "fs/promises"; 6 | import { gzip } from "zlib"; 7 | import { promisify } from "util"; 8 | import sade from "sade"; 9 | import open from "open"; 10 | import { gzinflate } from "../src/index.js"; 11 | 12 | const __dirname = path.dirname(fileURLToPath(import.meta.url)); 13 | /** @type {(...args: string[]) => string} */ 14 | const p = (...args) => path.join(__dirname, "..", ...args); 15 | const gzipAsync = promisify(gzip); 16 | 17 | /** 18 | * @typedef {{ out: string; open: boolean; }} Options 19 | * @param {string} filePath 20 | * @param {Options} options 21 | */ 22 | async function main(filePath, options) { 23 | /** @type {Buffer} */ 24 | let rawGzip; 25 | if (filePath.endsWith(".gz")) { 26 | rawGzip = await readFile(filePath); 27 | } else { 28 | rawGzip = await gzipAsync(await readFile(filePath)); 29 | } 30 | 31 | const { result, metadata } = gzinflate(rawGzip); 32 | 33 | await mkdir(options.out, { recursive: true }); 34 | 35 | const metadataJSON = JSON.stringify(metadata); 36 | const jsContents = `window.GZHeatmapData = JSON.parse(\`${metadataJSON}\`);`; 37 | await writeFile( 38 | path.join(options.out, "gz-heatmap-data.js"), 39 | jsContents, 40 | "utf8" 41 | ); 42 | 43 | const indexPath = path.join(options.out, "index.html"); 44 | await copyFile(p("bin/template.html"), indexPath); 45 | await copyFile( 46 | p("bin/gz-heatmap-webapp.js"), 47 | path.join(options.out, "gz-heatmap-webapp.js") 48 | ); 49 | 50 | if (options.open) { 51 | await open(pathToFileURL(indexPath).toString()); 52 | console.log(`Done! Opening ${indexPath} in your browser...`); 53 | } else { 54 | console.log(`Done! Open ${indexPath} in your browser.`); 55 | } 56 | } 57 | 58 | sade("gz-heatmap ", true) 59 | .describe( 60 | "Produce a heatmap of gzip files to better understand how gzip compresses your code" 61 | ) 62 | .example("build.js") 63 | .example("build.js -o /tmp/directory") 64 | .option( 65 | "-o --out", 66 | "The directory to output files too", 67 | path.join(process.cwd(), "gz-heatmap") 68 | ) 69 | .option("--open", "Open the resulting webapp in a web browser", false) 70 | .action(main) 71 | .parse(process.argv); 72 | -------------------------------------------------------------------------------- /tests/basic-inflate.test.js: -------------------------------------------------------------------------------- 1 | import { inflate } from "../src/inflate.js"; 2 | import { createDeflateRaw, deflateRaw, constants } from "zlib"; 3 | import { readFileSync } from "fs"; 4 | import { deepStrictEqual, strictEqual } from "assert"; 5 | import { promisify } from "util"; 6 | import { test } from "uvu"; 7 | import { fixture } from "./utils/paths.js"; 8 | 9 | const uncompressed = readFileSync(fixture("lorem/lorem.txt")); 10 | 11 | /** @type {Buffer} */ 12 | let compressed; 13 | /** @type {Buffer} */ 14 | let noCompression; 15 | /** @type {Buffer} */ 16 | let fixed; 17 | 18 | /** 19 | * @param {Buffer} buf 20 | * @param {import('zlib').ZlibOptions} options 21 | * @returns {Promise} 22 | */ 23 | function deflate(buf, options) { 24 | return new Promise((resolve, reject) => { 25 | /** @type {Uint8Array[]} */ 26 | const chunks = []; 27 | createDeflateRaw(options) 28 | .on("data", (chunk) => { 29 | chunks.push(chunk); 30 | }) 31 | .on("error", reject) 32 | .on("end", () => { 33 | resolve(Buffer.concat(chunks)); 34 | }) 35 | .end(buf); 36 | }); 37 | } 38 | 39 | test.before(async () => { 40 | compressed = await promisify(deflateRaw)(uncompressed); 41 | noCompression = await deflate(uncompressed, { 42 | level: constants.Z_NO_COMPRESSION, 43 | }); 44 | fixed = await deflate(uncompressed, { strategy: constants.Z_FIXED }); 45 | }); 46 | 47 | test("should inflate some data", () => { 48 | let out = Buffer.alloc(uncompressed.length); 49 | inflate(compressed, out); 50 | deepStrictEqual(out, uncompressed); 51 | }); 52 | 53 | test("should slice output buffer", () => { 54 | let out = Buffer.alloc(uncompressed.length + 1024); 55 | let { result } = inflate(compressed, out); 56 | deepStrictEqual(result, uncompressed); 57 | strictEqual(result.length, uncompressed.length); 58 | }); 59 | 60 | test("should handle uncompressed blocks", () => { 61 | let out = Buffer.alloc(uncompressed.length); 62 | inflate(noCompression, out); 63 | deepStrictEqual(out, uncompressed); 64 | }); 65 | 66 | test("should handle fixed huffman blocks", () => { 67 | let out = Buffer.alloc(uncompressed.length); 68 | inflate(fixed, out); 69 | deepStrictEqual(out, uncompressed); 70 | }); 71 | 72 | test("should handle typed arrays", () => { 73 | let input = new Uint8Array(compressed); 74 | let out = new Uint8Array(uncompressed.length); 75 | inflate(input, out); 76 | deepStrictEqual(out, new Uint8Array(uncompressed)); 77 | }); 78 | 79 | test.run(); 80 | -------------------------------------------------------------------------------- /src/global.d.ts: -------------------------------------------------------------------------------- 1 | type CodeLengthCategory = 2 | | "run_length_table" 3 | | "lz77_length_table" 4 | | "lz77_dist_table"; 5 | 6 | interface BitsRead { 7 | /** The raw bits read from the stream */ 8 | bits: number; 9 | /** The number of bits read from the stream */ 10 | size: number; 11 | /** 12 | * The decoded value from stream. Could be the value read from a huffman tree, 13 | * the bits plus/minus a constant number, etc. 14 | */ 15 | decoded: number; 16 | } 17 | 18 | interface BasicBitInfo { 19 | type: 20 | | "bfinal" 21 | | "btype" 22 | | "hlit" 23 | | "hdist" 24 | | "hclen" 25 | | "literal" 26 | | "block_end"; 27 | value: BitsRead; 28 | } 29 | 30 | interface LZ77Value { 31 | /** The computed value used in the LZ77 back reference */ 32 | value: number; 33 | /** The symbol that started this LZ77 value */ 34 | symbol: BitsRead; 35 | /** The extra bits associated */ 36 | extraBits: BitsRead; 37 | } 38 | 39 | interface LZ77BitInfo { 40 | type: "lz77"; 41 | chars: number[]; 42 | length: LZ77Value; 43 | dist: LZ77Value; 44 | } 45 | 46 | interface HuffmanCodeLengths { 47 | type: "code_length"; 48 | category: CodeLengthCategory; 49 | /** The decoded code length these bits represent */ 50 | huffmanCodeLength: number; 51 | /** 52 | * The "character" in the relevant alphabet this code length represents. For 53 | * lz77_length_table, this is a value between 0 - 287 (with 0 - 255 54 | * representing literal bytes/characters). 55 | */ 56 | char: number; 57 | /** Huffman encoded code length */ 58 | value: BitsRead; 59 | } 60 | 61 | interface RepeatHuffmanCodeLengths { 62 | type: "repeat_code_length"; 63 | category: CodeLengthCategory; 64 | /** The decoded huffman code length to repeat */ 65 | huffmanCodeLength: number; 66 | /** The characters this repeated huffman code length applies to */ 67 | chars: number[]; 68 | /** The symbol that represents what kind of repeat this is (16, 17, or 18) */ 69 | symbol: BitsRead; 70 | /** The count to repeat this code length */ 71 | repeatCount: BitsRead; 72 | } 73 | 74 | interface GzipHeader { 75 | type: "gzip_header"; 76 | bytes: Uint8Array; 77 | } 78 | 79 | interface GzipFooter { 80 | type: "gzip_footer"; 81 | bytes: Uint8Array; 82 | } 83 | 84 | type BitInfo = 85 | | BasicBitInfo 86 | | LZ77BitInfo 87 | | HuffmanCodeLengths 88 | | RepeatHuffmanCodeLengths 89 | | GzipHeader 90 | | GzipFooter; 91 | 92 | type BitInfoType = BitInfo["type"]; 93 | 94 | type Metadata = BitInfo[]; 95 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # 3 | # Project .gitignore 4 | # 5 | ############################################################ 6 | 7 | # Default output directory 8 | gz-heatmap 9 | 10 | # Build output 11 | bin/gz-heatmap-webapp.js 12 | 13 | 14 | ############################################################ 15 | # 16 | # Node .gitignore 17 | # 18 | ############################################################ 19 | 20 | # Logs 21 | logs 22 | *.log 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | lerna-debug.log* 27 | 28 | # Diagnostic reports (https://nodejs.org/api/report.html) 29 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 30 | 31 | # Runtime data 32 | pids 33 | *.pid 34 | *.seed 35 | *.pid.lock 36 | 37 | # Directory for instrumented libs generated by jscoverage/JSCover 38 | lib-cov 39 | 40 | # Coverage directory used by tools like istanbul 41 | coverage 42 | *.lcov 43 | 44 | # nyc test coverage 45 | .nyc_output 46 | 47 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 48 | .grunt 49 | 50 | # Bower dependency directory (https://bower.io/) 51 | bower_components 52 | 53 | # node-waf configuration 54 | .lock-wscript 55 | 56 | # Compiled binary addons (https://nodejs.org/api/addons.html) 57 | build/Release 58 | 59 | # Dependency directories 60 | node_modules/ 61 | jspm_packages/ 62 | 63 | # TypeScript v1 declaration files 64 | typings/ 65 | 66 | # TypeScript cache 67 | *.tsbuildinfo 68 | 69 | # Optional npm cache directory 70 | .npm 71 | 72 | # Optional eslint cache 73 | .eslintcache 74 | 75 | # Microbundle cache 76 | .rpt2_cache/ 77 | .rts2_cache_cjs/ 78 | .rts2_cache_es/ 79 | .rts2_cache_umd/ 80 | 81 | # Optional REPL history 82 | .node_repl_history 83 | 84 | # Output of 'npm pack' 85 | *.tgz 86 | 87 | # Yarn Integrity file 88 | .yarn-integrity 89 | 90 | # dotenv environment variables file 91 | .env 92 | .env.test 93 | 94 | # parcel-bundler cache (https://parceljs.org/) 95 | .cache 96 | 97 | # Next.js build output 98 | .next 99 | 100 | # Nuxt.js build / generate output 101 | .nuxt 102 | dist 103 | 104 | # Gatsby files 105 | .cache/ 106 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 107 | # https://nextjs.org/blog/next-9-1#public-directory-support 108 | # public 109 | 110 | # vuepress build output 111 | .vuepress/dist 112 | 113 | # Serverless directories 114 | .serverless/ 115 | 116 | # FuseBox cache 117 | .fusebox/ 118 | 119 | # DynamoDB Local files 120 | .dynamodb/ 121 | 122 | # TernJS port file 123 | .tern-port 124 | -------------------------------------------------------------------------------- /webapp/shared/constructBackRefs.js: -------------------------------------------------------------------------------- 1 | import { createLogger } from "./logger"; 2 | 3 | /** 4 | * @param {number} value 5 | * @param {string} [extraClass] 6 | * @returns {HTMLSpanElement} 7 | */ 8 | function createNode(value, extraClass = "") { 9 | const span = document.createElement("span"); 10 | span.textContent = String.fromCharCode(value); 11 | span.className = extraClass; 12 | return span; 13 | } 14 | 15 | const backRefAttr = "data-backref-selector"; 16 | 17 | /** 18 | * @param {Metadata} metadata 19 | * @param {Element} root 20 | */ 21 | export function constructBackRefs(metadata, root, options = {}) { 22 | const logger = createLogger(options); 23 | 24 | const container = document.createElement("pre"); 25 | const style = document.createElement("style"); 26 | root.appendChild(style); 27 | root.appendChild(container); 28 | 29 | container.classList.add("backrefs"); 30 | container.addEventListener("mouseover", (e) => { 31 | const target = /** @type {Element} */ (e.target); 32 | let lz77Container; 33 | if (target.classList.contains("lz77")) { 34 | lz77Container = target; 35 | } else { 36 | let parent = target.parentElement; 37 | if (parent && parent.classList.contains("lz77")) { 38 | lz77Container = parent; 39 | } 40 | } 41 | 42 | let cssText = ""; 43 | if (lz77Container) { 44 | let selector = lz77Container.getAttribute(backRefAttr); 45 | cssText = `${selector} { 46 | /* transform: scale(1.1); */ 47 | transform: translateY(-5px); 48 | /* box-shadow: 0px 10px 20px 2px rgb(255 255 255 / 25%); */ 49 | filter: drop-shadow(5px 5px 5px rgba(0,0,0,0.3)); 50 | background-color: #4ab03d !important; 51 | }`; 52 | 53 | lz77Container.classList.add("selected"); 54 | lz77Container.addEventListener( 55 | "mouseleave", 56 | (e) => { 57 | let target = /** @type {Element} */ (e.target); 58 | target.classList.remove("selected"); 59 | }, 60 | { once: true } 61 | ); 62 | } 63 | 64 | logger.debug("settings styles", cssText); 65 | style.textContent = cssText; 66 | }); 67 | 68 | container.addEventListener("mouseleave", () => { 69 | logger.debug("clearing styles"); 70 | style.textContent = ""; 71 | }); 72 | 73 | let pos = 0; 74 | for (let datum of metadata) { 75 | if (datum.type == "literal") { 76 | let className = `literal pos-${pos++}`; 77 | let node = createNode(datum.value.decoded, className); 78 | container.appendChild(node); 79 | } else if (datum.type == "lz77") { 80 | let literalStart = pos - datum.dist.value; 81 | let backRefLiteralSelector = `.pos-${literalStart}`; 82 | for (let i = 1; i < datum.length.value; i++) { 83 | backRefLiteralSelector += `, .pos-${literalStart + i}`; 84 | } 85 | 86 | const lz77Wrapper = document.createElement("span"); 87 | lz77Wrapper.className = "lz77"; 88 | lz77Wrapper.setAttribute(backRefAttr, backRefLiteralSelector); 89 | 90 | for (let char of datum.chars) { 91 | let node = createNode(char, `pos-${pos++}`); 92 | lz77Wrapper.appendChild(node); 93 | } 94 | 95 | container.appendChild(lz77Wrapper); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /tests/gzip-inflate.test.js: -------------------------------------------------------------------------------- 1 | import { gzinflate } from "../src/inflate.js"; 2 | import { dirname, join } from "path"; 3 | import { existsSync } from "fs"; 4 | import { readFile, writeFile } from "fs/promises"; 5 | import { test } from "uvu"; 6 | import * as assert from "uvu/assert"; 7 | import { 8 | formatMetadata, 9 | getTotalEncodedBitSize, 10 | logMetadata, 11 | reconstructBinary, 12 | } from "./utils/log.js"; 13 | import { fixture, readFixture } from "./utils/paths.js"; 14 | 15 | const testFiles = [ 16 | "simple/simple.txt", 17 | "svg-1-original/image.svg", 18 | "svg-2-svgo/image.svg", 19 | "svg-3-viewbox/image.svg", 20 | "svg-4-unclosed/image.svg", 21 | "svg-5-lowercase/image.svg", 22 | "svg-6-backrefs/image.svg", 23 | "svg-7-hex/image.svg", 24 | ]; 25 | 26 | testFiles.forEach((testFile) => { 27 | test(`should inflate ${testFile}`, async () => { 28 | let input = await readFile(fixture(testFile + ".gz")); 29 | let expectedOut = await readFixture(fixture(testFile)); 30 | 31 | let metadataPath = join(dirname(fixture(testFile)), "defdb.txt"); 32 | let expectedMeta = null; 33 | if (existsSync(metadataPath)) { 34 | expectedMeta = (await readFixture(metadataPath)) 35 | // Replace tab and line feed entries with their escape chars 36 | .replace(/^(\s?\[[0-9]+\] 0A)/gm, "$1 \\n") 37 | .replace(/^(\s?\[[0-9]+\] 09)/gm, "$1 \\t") 38 | // Remove extra code length lengths that don't exist in the original file 39 | .replace(/^\s?\[_\]\s+[0-9]+ CLL \(val: 0\)\n/gm, ""); 40 | } 41 | 42 | let out = Buffer.alloc(expectedOut.length); 43 | let { metadata } = gzinflate(input, out); 44 | 45 | assert.is(out.toString("utf8"), expectedOut); 46 | 47 | if (expectedMeta) { 48 | assert.is(formatMetadata(metadata), expectedMeta); 49 | } 50 | 51 | // logMetadata(metadata); 52 | // await writeFile( 53 | // fixture(testFile + "-metadata.json"), 54 | // JSON.stringify(metadata, null, 2), 55 | // "utf8" 56 | // ); 57 | const metadataFixturePath = fixture(testFile + "-metadata.json"); 58 | const metadataFixture = await readFixture(metadataFixturePath); 59 | assert.fixture(JSON.stringify(metadata, null, 2), metadataFixture); 60 | 61 | let bitSize = getTotalEncodedBitSize(metadata); 62 | let expectedLen = input.length * 8; 63 | let byteRoundedSize = bitSize + (bitSize % 8 == 0 ? 0 : 8 - (bitSize % 8)); 64 | assert.is( 65 | byteRoundedSize, 66 | expectedLen, 67 | "compute size does not match actual size" 68 | ); 69 | 70 | let actualText = metadata.reduce( 71 | (s, d) => 72 | d.type == "literal" 73 | ? s + String.fromCharCode(d.value.decoded) 74 | : d.type == "lz77" 75 | ? s + d.chars.map((v) => String.fromCharCode(v)).join("") 76 | : s, 77 | "" 78 | ); 79 | assert.is(actualText, expectedOut); 80 | 81 | let reconstructedBits = reconstructBinary(metadata, input); 82 | assert.equal( 83 | Array.from(reconstructedBits).map((v) => v.toString(2).padStart(8, "0")), 84 | Array.from(new Uint8Array(input)).map((v) => 85 | v.toString(2).padStart(8, "0") 86 | ), 87 | "reconstructed binary should match input binary" 88 | ); 89 | }); 90 | }); 91 | 92 | test.run(); 93 | -------------------------------------------------------------------------------- /webapp/shared/computeStats.js: -------------------------------------------------------------------------------- 1 | import { getCodeLengthSize, getLZ77TotalBitSize } from "../../src/utils.js"; 2 | 3 | /** 4 | * @typedef CompressedStats 5 | * @property {number} count 6 | * @property {number} bitsCompressed 7 | * @property {number} bytesExpanded 8 | * 9 | * @typedef Stats 10 | * @property {{byteLength: number}} gzipHeader 11 | * @property {{byteLength: number}} gzipFooter 12 | * @property {{bitsCompressed: number}} metadata 13 | * @property {{bitsCompressed: number}} codeLengthTables 14 | * @property {CompressedStats} literals 15 | * @property {CompressedStats} lz77s 16 | * 17 | * @param {Metadata} data 18 | * @returns {Stats} 19 | */ 20 | export function computeStats(data) { 21 | /** @type {Stats} */ 22 | const stats = { 23 | gzipHeader: { byteLength: 0 }, 24 | gzipFooter: { byteLength: 0 }, 25 | metadata: { bitsCompressed: 0 }, 26 | codeLengthTables: { bitsCompressed: 0 }, 27 | literals: { count: 0, bitsCompressed: 0, bytesExpanded: 0 }, 28 | lz77s: { count: 0, bitsCompressed: 0, bytesExpanded: 0 }, 29 | }; 30 | 31 | for (let datum of data) { 32 | switch (datum.type) { 33 | case "gzip_header": 34 | // TODO: Why is this null when running in the bin test? 35 | stats.gzipHeader.byteLength = datum.bytes?.byteLength ?? 0; 36 | break; 37 | case "gzip_footer": 38 | // TODO: Why is this null when running in the bin test? 39 | stats.gzipFooter.byteLength = datum.bytes?.byteLength ?? 0; 40 | break; 41 | case "bfinal": 42 | case "btype": 43 | case "hlit": 44 | case "hdist": 45 | case "hclen": 46 | case "block_end": 47 | stats.metadata.bitsCompressed += datum.value.size; 48 | break; 49 | case "literal": 50 | stats.literals.count += 1; 51 | stats.literals.bitsCompressed += datum.value.size; 52 | stats.literals.bytesExpanded += 1; 53 | break; 54 | case "lz77": 55 | stats.lz77s.count += 1; 56 | stats.lz77s.bitsCompressed += getLZ77TotalBitSize(datum); 57 | stats.lz77s.bytesExpanded += datum.chars.length; 58 | break; 59 | case "code_length": 60 | case "repeat_code_length": 61 | stats.codeLengthTables.bitsCompressed += getCodeLengthSize(datum); 62 | break; 63 | default: 64 | assertNever( 65 | datum, 66 | `Metadata type not handled: ${JSON.stringify(datum)}` 67 | ); 68 | } 69 | } 70 | 71 | return stats; 72 | } 73 | 74 | /** @type {(stats: Stats) => number} */ 75 | export function getBitsCompressed(stats) { 76 | return ( 77 | stats.gzipHeader.byteLength * 8 + 78 | stats.gzipFooter.byteLength * 8 + 79 | stats.metadata.bitsCompressed + 80 | stats.codeLengthTables.bitsCompressed + 81 | stats.literals.bitsCompressed + 82 | stats.lz77s.bitsCompressed 83 | ); 84 | } 85 | 86 | /** @type {(stats: Stats) => number} */ 87 | export function getBytesCompressed(stats) { 88 | return Math.ceil(getBitsCompressed(stats) / 8); 89 | } 90 | 91 | /** @type {(stats: Stats) => number} */ 92 | export function getBytesExpanded(stats) { 93 | return stats.literals.bytesExpanded + stats.lz77s.bytesExpanded; 94 | } 95 | 96 | /** 97 | * @param {never} val 98 | * @param {string} msg 99 | */ 100 | function assertNever(val, msg) { 101 | throw new Error(msg); 102 | } 103 | -------------------------------------------------------------------------------- /tests/bin.test.js: -------------------------------------------------------------------------------- 1 | import { existsSync } from "fs"; 2 | import { readFile, writeFile, mkdtemp } from "fs/promises"; 3 | import { execFileSync } from "child_process"; 4 | import { join } from "path"; 5 | import { pathToFileURL } from "url"; 6 | import rimraf from "rimraf"; 7 | import { suite } from "uvu"; 8 | import * as assert from "uvu/assert"; 9 | import puppeteer from "puppeteer"; 10 | import prettier from "prettier"; 11 | import { fixture, testPath } from "./utils/paths.js"; 12 | 13 | const binPath = testPath("../bin/gz-heatmap.js"); 14 | 15 | /** 16 | * @typedef BinSuiteContext 17 | * @property {import('puppeteer').Browser} browser 18 | * @property {import('puppeteer').Page} page 19 | * @property {string} output 20 | */ 21 | 22 | /** 23 | * @type {import('uvu').Test} 24 | */ 25 | const bin = suite("bin"); 26 | 27 | bin.before(async (ctx) => { 28 | ctx.browser = await puppeteer.launch(); 29 | }); 30 | 31 | bin.before.each(async (ctx) => { 32 | ctx.output = await mkdtemp("gz-heatmap-tests-"); 33 | ctx.page = await ctx.browser.newPage(); 34 | }); 35 | 36 | bin.after.each(async (ctx) => { 37 | await ctx.page.close(); 38 | await rimraf(ctx.output); 39 | ctx.output = ""; 40 | }); 41 | 42 | bin.after(async (ctx) => { 43 | await ctx.browser.close(); 44 | }); 45 | 46 | /** @type {(outputDir: string) => string} */ 47 | const getIndexUrl = (outputDir) => 48 | pathToFileURL(join(outputDir, "index.html")).toString(); 49 | 50 | /** 51 | * @param {import('puppeteer').Page} page 52 | * @returns {Promise} 53 | */ 54 | async function getPageContent(page) { 55 | const gzHeatMapEndTag = ``; 56 | let content = await page.content(); 57 | if (content.includes(gzHeatMapEndTag)) { 58 | const heatmapContents = await page.evaluate(() => 59 | Array.from(document.querySelectorAll("gz-heatmap")).map( 60 | (el) => el.shadowRoot?.innerHTML ?? "" 61 | ) 62 | ); 63 | 64 | let i = 0; 65 | content = content.replace(gzHeatMapEndTag, () => { 66 | return heatmapContents[i++] + gzHeatMapEndTag; 67 | }); 68 | } 69 | 70 | return content; 71 | } 72 | 73 | /** @type {(rawHtml: string) => string} */ 74 | function formatHtml(rawHtml) { 75 | rawHtml = rawHtml 76 | .replace(/([^\n])/g, "$1\n"); 78 | 79 | return prettier.format(rawHtml, { parser: "html" }); 80 | } 81 | 82 | /** 83 | * @param {BinSuiteContext} ctx 84 | * @param {string} fixtureDir 85 | * @param {string} inputFile 86 | */ 87 | async function validateFixture(ctx, fixtureDir, inputFile) { 88 | const inputFixture = fixture(fixtureDir, inputFile); 89 | execFileSync("node", [binPath, inputFixture, "--out", ctx.output]); 90 | 91 | await ctx.page.goto(getIndexUrl(ctx.output), { waitUntil: "networkidle2" }); 92 | const html = formatHtml(await getPageContent(ctx.page)); 93 | 94 | const expectedFixture = fixture(fixtureDir, "binExpected.html"); 95 | const expectedHtml = await readFile(expectedFixture, "utf8"); 96 | await writeFile(expectedFixture, html, "utf8"); 97 | 98 | assert.fixture( 99 | html, 100 | expectedHtml, 101 | `output doesn't match expected for "${inputFixture}"` 102 | ); 103 | } 104 | 105 | bin("HTML should only reference files that exist", async (ctx) => { 106 | const fixturePath = fixture("svg-7-hex/image.svg"); 107 | execFileSync("node", [binPath, fixturePath, "--out", ctx.output]); 108 | const html = await readFile(join(ctx.output, "index.html"), "utf8"); 109 | const scriptTags = html.matchAll(/ 26 | 27 | 28 |
29 |

GZ Heatmap

30 |

Upload a text file to see how GZip compresses your file.

31 |
41 | 50 |
51 | 57 |
58 |
59 |

google.html

60 |

Compressed size: 53,210 B

61 | 62 | 188 | 189 |

Stats

190 |
191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 |
CountCompressed bytesExpanded bytes
Literals22,02619,128 B22,026 B
LZ77 Backrefs14,67533,934 B176,903 B
Code Length tables123 B
Other compression metadata26 B
227 |
228 |

229 | File too large to show character breakdown analysis (size: 198,929 B) 230 |

231 | 263 | 272 |
273 |
274 | 275 | 276 | -------------------------------------------------------------------------------- /tests/fixtures/svg-7-hex/defdb.txt: -------------------------------------------------------------------------------- 1 | [1] Last block (val: 1) 2 | [2] Dynamic Huffman Tree block (val: 2) 3 | [5] HLIT 267 (val:10) 4 | [5] HDIST 13 (val:12) 5 | [4] HCLEN 18 (val:14) 6 | [3] 16 CLL (val: 5) 7 | [3] 17 CLL (val: 4) 8 | [3] 18 CLL (val: 4) 9 | [3] 0 CLL (val: 2) 10 | [3] 8 CLL (val: 0) 11 | [3] 7 CLL (val: 4) 12 | [3] 9 CLL (val: 0) 13 | [3] 6 CLL (val: 2) 14 | [3] 10 CLL (val: 0) 15 | [3] 5 CLL (val: 3) 16 | [3] 11 CLL (val: 0) 17 | [3] 4 CLL (val: 4) 18 | [3] 12 CLL (val: 0) 19 | [3] 3 CLL (val: 5) 20 | [3] 13 CLL (val: 0) 21 | [3] 2 CLL (val: 5) 22 | [3] 14 CLL (val: 0) 23 | [3] 1 CLL (val: 5) 24 | [_] 15 CLL (val: 0) 25 | [11] ZREP (32 times) 26 | [_] 0x00 CL (val: 0) 27 | [_] 0x01 CL (val: 0) 28 | [_] 0x02 CL (val: 0) 29 | [_] 0x03 CL (val: 0) 30 | [_] 0x04 CL (val: 0) 31 | [_] 0x05 CL (val: 0) 32 | [_] 0x06 CL (val: 0) 33 | [_] 0x07 CL (val: 0) 34 | [_] 0x08 CL (val: 0) 35 | [_] 0x09 CL (val: 0) 36 | [_] 0x0A CL (val: 0) 37 | [_] 0x0B CL (val: 0) 38 | [_] 0x0C CL (val: 0) 39 | [_] 0x0D CL (val: 0) 40 | [_] 0x0E CL (val: 0) 41 | [_] 0x0F CL (val: 0) 42 | [_] 0x10 CL (val: 0) 43 | [_] 0x11 CL (val: 0) 44 | [_] 0x12 CL (val: 0) 45 | [_] 0x13 CL (val: 0) 46 | [_] 0x14 CL (val: 0) 47 | [_] 0x15 CL (val: 0) 48 | [_] 0x16 CL (val: 0) 49 | [_] 0x17 CL (val: 0) 50 | [_] 0x18 CL (val: 0) 51 | [_] 0x19 CL (val: 0) 52 | [_] 0x1A CL (val: 0) 53 | [_] 0x1B CL (val: 0) 54 | [_] 0x1C CL (val: 0) 55 | [_] 0x1D CL (val: 0) 56 | [_] 0x1E CL (val: 0) 57 | [_] 0x1F CL (val: 0) 58 | [4] 0x20 CL (val: 4) 59 | [2] 0x21 CL (val: 0) 60 | [4] 0x22 CL (val: 4) 61 | [4] 0x23 CL (val: 7) 62 | [7] ZREP (9 times) 63 | [_] 0x24 CL (val: 0) 64 | [_] 0x25 CL (val: 0) 65 | [_] 0x26 CL (val: 0) 66 | [_] 0x27 CL (val: 0) 67 | [_] 0x28 CL (val: 0) 68 | [_] 0x29 CL (val: 0) 69 | [_] 0x2A CL (val: 0) 70 | [_] 0x2B CL (val: 0) 71 | [_] 0x2C CL (val: 0) 72 | [2] 0x2D CL (val: 6) 73 | [2] 0x2E CL (val: 6) 74 | [4] 0x2F CL (val: 4) 75 | [5] 0x30 CL (val: 3) 76 | [2] 0x31 CL (val: 0) 77 | [3] 0x32 CL (val: 5) 78 | [3] 0x33 CL (val: 5) 79 | [2] 0x34 CL (val: 0) 80 | [2] 0x35 CL (val: 6) 81 | [7] ZREP (4 times) 82 | [_] 0x36 CL (val: 0) 83 | [_] 0x37 CL (val: 0) 84 | [_] 0x38 CL (val: 0) 85 | [_] 0x39 CL (val: 0) 86 | [2] 0x3A CL (val: 6) 87 | [2] 0x3B CL (val: 0) 88 | [2] 0x3C CL (val: 6) 89 | [3] 0x3D CL (val: 5) 90 | [2] 0x3E CL (val: 6) 91 | [7] ZREP (3 times) 92 | [_] 0x3F CL (val: 0) 93 | [_] 0x40 CL (val: 0) 94 | [_] 0x41 CL (val: 0) 95 | [4] 0x42 CL (val: 7) 96 | [11] ZREP (30 times) 97 | [_] 0x43 CL (val: 0) 98 | [_] 0x44 CL (val: 0) 99 | [_] 0x45 CL (val: 0) 100 | [_] 0x46 CL (val: 0) 101 | [_] 0x47 CL (val: 0) 102 | [_] 0x48 CL (val: 0) 103 | [_] 0x49 CL (val: 0) 104 | [_] 0x4A CL (val: 0) 105 | [_] 0x4B CL (val: 0) 106 | [_] 0x4C CL (val: 0) 107 | [_] 0x4D CL (val: 0) 108 | [_] 0x4E CL (val: 0) 109 | [_] 0x4F CL (val: 0) 110 | [_] 0x50 CL (val: 0) 111 | [_] 0x51 CL (val: 0) 112 | [_] 0x52 CL (val: 0) 113 | [_] 0x53 CL (val: 0) 114 | [_] 0x54 CL (val: 0) 115 | [_] 0x55 CL (val: 0) 116 | [_] 0x56 CL (val: 0) 117 | [_] 0x57 CL (val: 0) 118 | [_] 0x58 CL (val: 0) 119 | [_] 0x59 CL (val: 0) 120 | [_] 0x5A CL (val: 0) 121 | [_] 0x5B CL (val: 0) 122 | [_] 0x5C CL (val: 0) 123 | [_] 0x5D CL (val: 0) 124 | [_] 0x5E CL (val: 0) 125 | [_] 0x5F CL (val: 0) 126 | [_] 0x60 CL (val: 0) 127 | [4] 0x61 CL (val: 7) 128 | [2] 0x62 CL (val: 0) 129 | [2] 0x63 CL (val: 0) 130 | [2] 0x64 CL (val: 6) 131 | [2] 0x65 CL (val: 6) 132 | [3] 0x66 CL (val: 5) 133 | [2] 0x67 CL (val: 6) 134 | [3] 0x68 CL (val: 5) 135 | [2] 0x69 CL (val: 6) 136 | [2] 0x6A CL (val: 0) 137 | [2] 0x6B CL (val: 0) 138 | [3] 0x6C CL (val: 5) 139 | [2] 0x6D CL (val: 6) 140 | [7] LREP (3 times) 141 | [_] 0x6E CL (val: 6) 142 | [_] 0x6F CL (val: 6) 143 | [_] 0x70 CL (val: 6) 144 | [2] 0x71 CL (val: 0) 145 | [2] 0x72 CL (val: 6) 146 | [2] 0x73 CL (val: 6) 147 | [3] 0x74 CL (val: 5) 148 | [2] 0x75 CL (val: 0) 149 | [3] 0x76 CL (val: 5) 150 | [4] 0x77 CL (val: 4) 151 | [2] 0x78 CL (val: 6) 152 | [11] ZREP (135 times) 153 | [_] 0x79 CL (val: 0) 154 | [_] 0x7A CL (val: 0) 155 | [_] 0x7B CL (val: 0) 156 | [_] 0x7C CL (val: 0) 157 | [_] 0x7D CL (val: 0) 158 | [_] 0x7E CL (val: 0) 159 | [_] 0x7F CL (val: 0) 160 | [_] 0x80 CL (val: 0) 161 | [_] 0x81 CL (val: 0) 162 | [_] 0x82 CL (val: 0) 163 | [_] 0x83 CL (val: 0) 164 | [_] 0x84 CL (val: 0) 165 | [_] 0x85 CL (val: 0) 166 | [_] 0x86 CL (val: 0) 167 | [_] 0x87 CL (val: 0) 168 | [_] 0x88 CL (val: 0) 169 | [_] 0x89 CL (val: 0) 170 | [_] 0x8A CL (val: 0) 171 | [_] 0x8B CL (val: 0) 172 | [_] 0x8C CL (val: 0) 173 | [_] 0x8D CL (val: 0) 174 | [_] 0x8E CL (val: 0) 175 | [_] 0x8F CL (val: 0) 176 | [_] 0x90 CL (val: 0) 177 | [_] 0x91 CL (val: 0) 178 | [_] 0x92 CL (val: 0) 179 | [_] 0x93 CL (val: 0) 180 | [_] 0x94 CL (val: 0) 181 | [_] 0x95 CL (val: 0) 182 | [_] 0x96 CL (val: 0) 183 | [_] 0x97 CL (val: 0) 184 | [_] 0x98 CL (val: 0) 185 | [_] 0x99 CL (val: 0) 186 | [_] 0x9A CL (val: 0) 187 | [_] 0x9B CL (val: 0) 188 | [_] 0x9C CL (val: 0) 189 | [_] 0x9D CL (val: 0) 190 | [_] 0x9E CL (val: 0) 191 | [_] 0x9F CL (val: 0) 192 | [_] 0xA0 CL (val: 0) 193 | [_] 0xA1 CL (val: 0) 194 | [_] 0xA2 CL (val: 0) 195 | [_] 0xA3 CL (val: 0) 196 | [_] 0xA4 CL (val: 0) 197 | [_] 0xA5 CL (val: 0) 198 | [_] 0xA6 CL (val: 0) 199 | [_] 0xA7 CL (val: 0) 200 | [_] 0xA8 CL (val: 0) 201 | [_] 0xA9 CL (val: 0) 202 | [_] 0xAA CL (val: 0) 203 | [_] 0xAB CL (val: 0) 204 | [_] 0xAC CL (val: 0) 205 | [_] 0xAD CL (val: 0) 206 | [_] 0xAE CL (val: 0) 207 | [_] 0xAF CL (val: 0) 208 | [_] 0xB0 CL (val: 0) 209 | [_] 0xB1 CL (val: 0) 210 | [_] 0xB2 CL (val: 0) 211 | [_] 0xB3 CL (val: 0) 212 | [_] 0xB4 CL (val: 0) 213 | [_] 0xB5 CL (val: 0) 214 | [_] 0xB6 CL (val: 0) 215 | [_] 0xB7 CL (val: 0) 216 | [_] 0xB8 CL (val: 0) 217 | [_] 0xB9 CL (val: 0) 218 | [_] 0xBA CL (val: 0) 219 | [_] 0xBB CL (val: 0) 220 | [_] 0xBC CL (val: 0) 221 | [_] 0xBD CL (val: 0) 222 | [_] 0xBE CL (val: 0) 223 | [_] 0xBF CL (val: 0) 224 | [_] 0xC0 CL (val: 0) 225 | [_] 0xC1 CL (val: 0) 226 | [_] 0xC2 CL (val: 0) 227 | [_] 0xC3 CL (val: 0) 228 | [_] 0xC4 CL (val: 0) 229 | [_] 0xC5 CL (val: 0) 230 | [_] 0xC6 CL (val: 0) 231 | [_] 0xC7 CL (val: 0) 232 | [_] 0xC8 CL (val: 0) 233 | [_] 0xC9 CL (val: 0) 234 | [_] 0xCA CL (val: 0) 235 | [_] 0xCB CL (val: 0) 236 | [_] 0xCC CL (val: 0) 237 | [_] 0xCD CL (val: 0) 238 | [_] 0xCE CL (val: 0) 239 | [_] 0xCF CL (val: 0) 240 | [_] 0xD0 CL (val: 0) 241 | [_] 0xD1 CL (val: 0) 242 | [_] 0xD2 CL (val: 0) 243 | [_] 0xD3 CL (val: 0) 244 | [_] 0xD4 CL (val: 0) 245 | [_] 0xD5 CL (val: 0) 246 | [_] 0xD6 CL (val: 0) 247 | [_] 0xD7 CL (val: 0) 248 | [_] 0xD8 CL (val: 0) 249 | [_] 0xD9 CL (val: 0) 250 | [_] 0xDA CL (val: 0) 251 | [_] 0xDB CL (val: 0) 252 | [_] 0xDC CL (val: 0) 253 | [_] 0xDD CL (val: 0) 254 | [_] 0xDE CL (val: 0) 255 | [_] 0xDF CL (val: 0) 256 | [_] 0xE0 CL (val: 0) 257 | [_] 0xE1 CL (val: 0) 258 | [_] 0xE2 CL (val: 0) 259 | [_] 0xE3 CL (val: 0) 260 | [_] 0xE4 CL (val: 0) 261 | [_] 0xE5 CL (val: 0) 262 | [_] 0xE6 CL (val: 0) 263 | [_] 0xE7 CL (val: 0) 264 | [_] 0xE8 CL (val: 0) 265 | [_] 0xE9 CL (val: 0) 266 | [_] 0xEA CL (val: 0) 267 | [_] 0xEB CL (val: 0) 268 | [_] 0xEC CL (val: 0) 269 | [_] 0xED CL (val: 0) 270 | [_] 0xEE CL (val: 0) 271 | [_] 0xEF CL (val: 0) 272 | [_] 0xF0 CL (val: 0) 273 | [_] 0xF1 CL (val: 0) 274 | [_] 0xF2 CL (val: 0) 275 | [_] 0xF3 CL (val: 0) 276 | [_] 0xF4 CL (val: 0) 277 | [_] 0xF5 CL (val: 0) 278 | [_] 0xF6 CL (val: 0) 279 | [_] 0xF7 CL (val: 0) 280 | [_] 0xF8 CL (val: 0) 281 | [_] 0xF9 CL (val: 0) 282 | [_] 0xFA CL (val: 0) 283 | [_] 0xFB CL (val: 0) 284 | [_] 0xFC CL (val: 0) 285 | [_] 0xFD CL (val: 0) 286 | [_] 0xFE CL (val: 0) 287 | [_] 0xFF CL (val: 0) 288 | [4] EofB CL (val: 7) 289 | [2] l_00 CL (val: 6) (length 3) 290 | [2] l_01 CL (val: 6) (length 4) 291 | [2] l_02 CL (val: 0) (length 5) 292 | [2] l_03 CL (val: 6) (length 6) 293 | [7] ZREP (4 times) 294 | [_] l_04 CL (val: 0) (length 7) 295 | [_] l_05 CL (val: 0) (length 8) 296 | [_] l_06 CL (val: 0) (length 9) 297 | [_] l_07 CL (val: 0) (length 10) 298 | [2] l_08 CL (val: 6) (lengths [11-12]) 299 | [2] l_09 CL (val: 6) (lengths [13-14]) 300 | [7] ZREP (9 times) 301 | [_] d_00 CL (val: 0) (distance 1) 302 | [_] d_01 CL (val: 0) (distance 2) 303 | [_] d_02 CL (val: 0) (distance 3) 304 | [_] d_03 CL (val: 0) (distance 4) 305 | [_] d_04 CL (val: 0) (distances [5-6]) 306 | [_] d_05 CL (val: 0) (distances [7-8]) 307 | [_] d_06 CL (val: 0) (distances [9-12]) 308 | [_] d_07 CL (val: 0) (distances [13-16]) 309 | [_] d_08 CL (val: 0) (distances [17-24]) 310 | [5] d_09 CL (val: 2) (distances [25-32]) 311 | [5] d_10 CL (val: 1) (distances [33-48]) 312 | [2] d_11 CL (val: 0) (distances [49-64]) 313 | [5] d_12 CL (val: 2) (distances [65-96]) 314 | [6] 3C < 315 | [6] 73 s 316 | [5] 76 v 317 | [6] 67 g 318 | [4] 20 319 | [6] 78 x 320 | [6] 6D m 321 | [5] 6C l 322 | [6] 6E n 323 | [6] 73 s 324 | [5] 3D = 325 | [4] 22 " 326 | [5] 68 h 327 | [5] 74 t 328 | [5] 74 t 329 | [6] 70 p 330 | [6] 3A : 331 | [4] 2F / 332 | [4] 2F / 333 | [4] 77 w 334 | [4] 77 w 335 | [4] 77 w 336 | [6] 2E . 337 | [4] 77 w 338 | [5] 33 3 339 | [6] 2E . 340 | [6] 6F o 341 | [6] 72 r 342 | [6] 67 g 343 | [4] 2F / 344 | [5] 32 2 345 | [3] 30 0 346 | [3] 30 0 347 | [3] 30 0 348 | [4] 2F / 349 | [11] (3,34) 350 | [4] 22 " 351 | [4] 20 352 | [5] 76 v 353 | [6] 69 i 354 | [6] 65 e 355 | [4] 77 w 356 | [7] 42 B 357 | [6] 6F o 358 | [6] 78 x 359 | [5] 3D = 360 | [4] 22 " 361 | [3] 30 0 362 | [4] 20 363 | [3] 30 0 364 | [4] 20 365 | [6] 35 5 366 | [4] 20 367 | [6] 35 5 368 | [4] 22 " 369 | [6] 3E > 370 | [6] 3C < 371 | [6] 70 p 372 | [7] 61 a 373 | [5] 74 t 374 | [5] 68 h 375 | [4] 20 376 | [5] 66 f 377 | [6] 69 i 378 | [5] 6C l 379 | [5] 6C l 380 | [5] 3D = 381 | [4] 22 " 382 | [7] 23 # 383 | [5] 66 f 384 | [3] 30 0 385 | [3] 30 0 386 | [4] 22 " 387 | [4] 20 388 | [6] 64 d 389 | [5] 3D = 390 | [4] 22 " 391 | [6] 6D m 392 | [11] (3,31) 393 | [5] 68 h 394 | [5] 33 3 395 | [5] 76 v 396 | [5] 33 3 397 | [5] 68 h 398 | [6] 2D - 399 | [5] 33 3 400 | [4] 22 " 401 | [4] 2F / 402 | [12] (14,35) 403 | [3] 30 0 404 | [3] 30 0 405 | [5] 66 f 406 | [11] (6,35) 407 | [5] 32 2 408 | [4] 20 409 | [5] 32 2 410 | [12] (11,35) 411 | [13] (4,95) 412 | [6] 3E > 413 | [7] EofB 414 | -------------------------------------------------------------------------------- /tests/fixtures/svg-6-backrefs/defdb.txt: -------------------------------------------------------------------------------- 1 | [1] Last block (val: 1) 2 | [2] Dynamic Huffman Tree block (val: 2) 3 | [5] HLIT 267 (val:10) 4 | [5] HDIST 13 (val:12) 5 | [4] HCLEN 18 (val:14) 6 | [3] 16 CLL (val: 6) 7 | [3] 17 CLL (val: 3) 8 | [3] 18 CLL (val: 4) 9 | [3] 0 CLL (val: 2) 10 | [3] 8 CLL (val: 0) 11 | [3] 7 CLL (val: 0) 12 | [3] 9 CLL (val: 0) 13 | [3] 6 CLL (val: 2) 14 | [3] 10 CLL (val: 0) 15 | [3] 5 CLL (val: 3) 16 | [3] 11 CLL (val: 0) 17 | [3] 4 CLL (val: 3) 18 | [3] 12 CLL (val: 0) 19 | [3] 3 CLL (val: 0) 20 | [3] 13 CLL (val: 0) 21 | [3] 2 CLL (val: 5) 22 | [3] 14 CLL (val: 0) 23 | [3] 1 CLL (val: 6) 24 | [_] 15 CLL (val: 0) 25 | [11] ZREP (32 times) 26 | [_] 0x00 CL (val: 0) 27 | [_] 0x01 CL (val: 0) 28 | [_] 0x02 CL (val: 0) 29 | [_] 0x03 CL (val: 0) 30 | [_] 0x04 CL (val: 0) 31 | [_] 0x05 CL (val: 0) 32 | [_] 0x06 CL (val: 0) 33 | [_] 0x07 CL (val: 0) 34 | [_] 0x08 CL (val: 0) 35 | [_] 0x09 CL (val: 0) 36 | [_] 0x0A CL (val: 0) 37 | [_] 0x0B CL (val: 0) 38 | [_] 0x0C CL (val: 0) 39 | [_] 0x0D CL (val: 0) 40 | [_] 0x0E CL (val: 0) 41 | [_] 0x0F CL (val: 0) 42 | [_] 0x10 CL (val: 0) 43 | [_] 0x11 CL (val: 0) 44 | [_] 0x12 CL (val: 0) 45 | [_] 0x13 CL (val: 0) 46 | [_] 0x14 CL (val: 0) 47 | [_] 0x15 CL (val: 0) 48 | [_] 0x16 CL (val: 0) 49 | [_] 0x17 CL (val: 0) 50 | [_] 0x18 CL (val: 0) 51 | [_] 0x19 CL (val: 0) 52 | [_] 0x1A CL (val: 0) 53 | [_] 0x1B CL (val: 0) 54 | [_] 0x1C CL (val: 0) 55 | [_] 0x1D CL (val: 0) 56 | [_] 0x1E CL (val: 0) 57 | [_] 0x1F CL (val: 0) 58 | [3] 0x20 CL (val: 4) 59 | [2] 0x21 CL (val: 0) 60 | [3] 0x22 CL (val: 4) 61 | [2] 0x23 CL (val: 6) 62 | [6] ZREP (9 times) 63 | [_] 0x24 CL (val: 0) 64 | [_] 0x25 CL (val: 0) 65 | [_] 0x26 CL (val: 0) 66 | [_] 0x27 CL (val: 0) 67 | [_] 0x28 CL (val: 0) 68 | [_] 0x29 CL (val: 0) 69 | [_] 0x2A CL (val: 0) 70 | [_] 0x2B CL (val: 0) 71 | [_] 0x2C CL (val: 0) 72 | [2] 0x2D CL (val: 6) 73 | [2] 0x2E CL (val: 6) 74 | [3] 0x2F CL (val: 4) 75 | [3] 0x30 CL (val: 4) 76 | [2] 0x31 CL (val: 0) 77 | [3] 0x32 CL (val: 5) 78 | [3] 0x33 CL (val: 5) 79 | [2] 0x34 CL (val: 0) 80 | [2] 0x35 CL (val: 6) 81 | [6] ZREP (4 times) 82 | [_] 0x36 CL (val: 0) 83 | [_] 0x37 CL (val: 0) 84 | [_] 0x38 CL (val: 0) 85 | [_] 0x39 CL (val: 0) 86 | [2] 0x3A CL (val: 6) 87 | [2] 0x3B CL (val: 0) 88 | [3] 0x3C CL (val: 5) 89 | [3] 0x3D CL (val: 5) 90 | [2] 0x3E CL (val: 6) 91 | [6] ZREP (3 times) 92 | [_] 0x3F CL (val: 0) 93 | [_] 0x40 CL (val: 0) 94 | [_] 0x41 CL (val: 0) 95 | [2] 0x42 CL (val: 6) 96 | [11] ZREP (30 times) 97 | [_] 0x43 CL (val: 0) 98 | [_] 0x44 CL (val: 0) 99 | [_] 0x45 CL (val: 0) 100 | [_] 0x46 CL (val: 0) 101 | [_] 0x47 CL (val: 0) 102 | [_] 0x48 CL (val: 0) 103 | [_] 0x49 CL (val: 0) 104 | [_] 0x4A CL (val: 0) 105 | [_] 0x4B CL (val: 0) 106 | [_] 0x4C CL (val: 0) 107 | [_] 0x4D CL (val: 0) 108 | [_] 0x4E CL (val: 0) 109 | [_] 0x4F CL (val: 0) 110 | [_] 0x50 CL (val: 0) 111 | [_] 0x51 CL (val: 0) 112 | [_] 0x52 CL (val: 0) 113 | [_] 0x53 CL (val: 0) 114 | [_] 0x54 CL (val: 0) 115 | [_] 0x55 CL (val: 0) 116 | [_] 0x56 CL (val: 0) 117 | [_] 0x57 CL (val: 0) 118 | [_] 0x58 CL (val: 0) 119 | [_] 0x59 CL (val: 0) 120 | [_] 0x5A CL (val: 0) 121 | [_] 0x5B CL (val: 0) 122 | [_] 0x5C CL (val: 0) 123 | [_] 0x5D CL (val: 0) 124 | [_] 0x5E CL (val: 0) 125 | [_] 0x5F CL (val: 0) 126 | [_] 0x60 CL (val: 0) 127 | [2] 0x61 CL (val: 6) 128 | [2] 0x62 CL (val: 0) 129 | [2] 0x63 CL (val: 0) 130 | [2] 0x64 CL (val: 6) 131 | [8] LREP (3 times) 132 | [_] 0x65 CL (val: 6) 133 | [_] 0x66 CL (val: 6) 134 | [_] 0x67 CL (val: 6) 135 | [3] 0x68 CL (val: 5) 136 | [2] 0x69 CL (val: 6) 137 | [2] 0x6A CL (val: 0) 138 | [2] 0x6B CL (val: 0) 139 | [3] 0x6C CL (val: 5) 140 | [2] 0x6D CL (val: 6) 141 | [2] 0x6E CL (val: 6) 142 | [3] 0x6F CL (val: 5) 143 | [2] 0x70 CL (val: 6) 144 | [2] 0x71 CL (val: 0) 145 | [2] 0x72 CL (val: 6) 146 | [2] 0x73 CL (val: 6) 147 | [3] 0x74 CL (val: 5) 148 | [2] 0x75 CL (val: 0) 149 | [3] 0x76 CL (val: 5) 150 | [3] 0x77 CL (val: 4) 151 | [3] 0x78 CL (val: 5) 152 | [11] ZREP (135 times) 153 | [_] 0x79 CL (val: 0) 154 | [_] 0x7A CL (val: 0) 155 | [_] 0x7B CL (val: 0) 156 | [_] 0x7C CL (val: 0) 157 | [_] 0x7D CL (val: 0) 158 | [_] 0x7E CL (val: 0) 159 | [_] 0x7F CL (val: 0) 160 | [_] 0x80 CL (val: 0) 161 | [_] 0x81 CL (val: 0) 162 | [_] 0x82 CL (val: 0) 163 | [_] 0x83 CL (val: 0) 164 | [_] 0x84 CL (val: 0) 165 | [_] 0x85 CL (val: 0) 166 | [_] 0x86 CL (val: 0) 167 | [_] 0x87 CL (val: 0) 168 | [_] 0x88 CL (val: 0) 169 | [_] 0x89 CL (val: 0) 170 | [_] 0x8A CL (val: 0) 171 | [_] 0x8B CL (val: 0) 172 | [_] 0x8C CL (val: 0) 173 | [_] 0x8D CL (val: 0) 174 | [_] 0x8E CL (val: 0) 175 | [_] 0x8F CL (val: 0) 176 | [_] 0x90 CL (val: 0) 177 | [_] 0x91 CL (val: 0) 178 | [_] 0x92 CL (val: 0) 179 | [_] 0x93 CL (val: 0) 180 | [_] 0x94 CL (val: 0) 181 | [_] 0x95 CL (val: 0) 182 | [_] 0x96 CL (val: 0) 183 | [_] 0x97 CL (val: 0) 184 | [_] 0x98 CL (val: 0) 185 | [_] 0x99 CL (val: 0) 186 | [_] 0x9A CL (val: 0) 187 | [_] 0x9B CL (val: 0) 188 | [_] 0x9C CL (val: 0) 189 | [_] 0x9D CL (val: 0) 190 | [_] 0x9E CL (val: 0) 191 | [_] 0x9F CL (val: 0) 192 | [_] 0xA0 CL (val: 0) 193 | [_] 0xA1 CL (val: 0) 194 | [_] 0xA2 CL (val: 0) 195 | [_] 0xA3 CL (val: 0) 196 | [_] 0xA4 CL (val: 0) 197 | [_] 0xA5 CL (val: 0) 198 | [_] 0xA6 CL (val: 0) 199 | [_] 0xA7 CL (val: 0) 200 | [_] 0xA8 CL (val: 0) 201 | [_] 0xA9 CL (val: 0) 202 | [_] 0xAA CL (val: 0) 203 | [_] 0xAB CL (val: 0) 204 | [_] 0xAC CL (val: 0) 205 | [_] 0xAD CL (val: 0) 206 | [_] 0xAE CL (val: 0) 207 | [_] 0xAF CL (val: 0) 208 | [_] 0xB0 CL (val: 0) 209 | [_] 0xB1 CL (val: 0) 210 | [_] 0xB2 CL (val: 0) 211 | [_] 0xB3 CL (val: 0) 212 | [_] 0xB4 CL (val: 0) 213 | [_] 0xB5 CL (val: 0) 214 | [_] 0xB6 CL (val: 0) 215 | [_] 0xB7 CL (val: 0) 216 | [_] 0xB8 CL (val: 0) 217 | [_] 0xB9 CL (val: 0) 218 | [_] 0xBA CL (val: 0) 219 | [_] 0xBB CL (val: 0) 220 | [_] 0xBC CL (val: 0) 221 | [_] 0xBD CL (val: 0) 222 | [_] 0xBE CL (val: 0) 223 | [_] 0xBF CL (val: 0) 224 | [_] 0xC0 CL (val: 0) 225 | [_] 0xC1 CL (val: 0) 226 | [_] 0xC2 CL (val: 0) 227 | [_] 0xC3 CL (val: 0) 228 | [_] 0xC4 CL (val: 0) 229 | [_] 0xC5 CL (val: 0) 230 | [_] 0xC6 CL (val: 0) 231 | [_] 0xC7 CL (val: 0) 232 | [_] 0xC8 CL (val: 0) 233 | [_] 0xC9 CL (val: 0) 234 | [_] 0xCA CL (val: 0) 235 | [_] 0xCB CL (val: 0) 236 | [_] 0xCC CL (val: 0) 237 | [_] 0xCD CL (val: 0) 238 | [_] 0xCE CL (val: 0) 239 | [_] 0xCF CL (val: 0) 240 | [_] 0xD0 CL (val: 0) 241 | [_] 0xD1 CL (val: 0) 242 | [_] 0xD2 CL (val: 0) 243 | [_] 0xD3 CL (val: 0) 244 | [_] 0xD4 CL (val: 0) 245 | [_] 0xD5 CL (val: 0) 246 | [_] 0xD6 CL (val: 0) 247 | [_] 0xD7 CL (val: 0) 248 | [_] 0xD8 CL (val: 0) 249 | [_] 0xD9 CL (val: 0) 250 | [_] 0xDA CL (val: 0) 251 | [_] 0xDB CL (val: 0) 252 | [_] 0xDC CL (val: 0) 253 | [_] 0xDD CL (val: 0) 254 | [_] 0xDE CL (val: 0) 255 | [_] 0xDF CL (val: 0) 256 | [_] 0xE0 CL (val: 0) 257 | [_] 0xE1 CL (val: 0) 258 | [_] 0xE2 CL (val: 0) 259 | [_] 0xE3 CL (val: 0) 260 | [_] 0xE4 CL (val: 0) 261 | [_] 0xE5 CL (val: 0) 262 | [_] 0xE6 CL (val: 0) 263 | [_] 0xE7 CL (val: 0) 264 | [_] 0xE8 CL (val: 0) 265 | [_] 0xE9 CL (val: 0) 266 | [_] 0xEA CL (val: 0) 267 | [_] 0xEB CL (val: 0) 268 | [_] 0xEC CL (val: 0) 269 | [_] 0xED CL (val: 0) 270 | [_] 0xEE CL (val: 0) 271 | [_] 0xEF CL (val: 0) 272 | [_] 0xF0 CL (val: 0) 273 | [_] 0xF1 CL (val: 0) 274 | [_] 0xF2 CL (val: 0) 275 | [_] 0xF3 CL (val: 0) 276 | [_] 0xF4 CL (val: 0) 277 | [_] 0xF5 CL (val: 0) 278 | [_] 0xF6 CL (val: 0) 279 | [_] 0xF7 CL (val: 0) 280 | [_] 0xF8 CL (val: 0) 281 | [_] 0xF9 CL (val: 0) 282 | [_] 0xFA CL (val: 0) 283 | [_] 0xFB CL (val: 0) 284 | [_] 0xFC CL (val: 0) 285 | [_] 0xFD CL (val: 0) 286 | [_] 0xFE CL (val: 0) 287 | [_] 0xFF CL (val: 0) 288 | [2] EofB CL (val: 6) 289 | [2] l_00 CL (val: 6) (length 3) 290 | [2] l_01 CL (val: 6) (length 4) 291 | [2] l_02 CL (val: 0) (length 5) 292 | [2] l_03 CL (val: 6) (length 6) 293 | [6] ZREP (4 times) 294 | [_] l_04 CL (val: 0) (length 7) 295 | [_] l_05 CL (val: 0) (length 8) 296 | [_] l_06 CL (val: 0) (length 9) 297 | [_] l_07 CL (val: 0) (length 10) 298 | [2] l_08 CL (val: 6) (lengths [11-12]) 299 | [2] l_09 CL (val: 6) (lengths [13-14]) 300 | [6] ZREP (9 times) 301 | [_] d_00 CL (val: 0) (distance 1) 302 | [_] d_01 CL (val: 0) (distance 2) 303 | [_] d_02 CL (val: 0) (distance 3) 304 | [_] d_03 CL (val: 0) (distance 4) 305 | [_] d_04 CL (val: 0) (distances [5-6]) 306 | [_] d_05 CL (val: 0) (distances [7-8]) 307 | [_] d_06 CL (val: 0) (distances [9-12]) 308 | [_] d_07 CL (val: 0) (distances [13-16]) 309 | [_] d_08 CL (val: 0) (distances [17-24]) 310 | [5] d_09 CL (val: 2) (distances [25-32]) 311 | [6] d_10 CL (val: 1) (distances [33-48]) 312 | [2] d_11 CL (val: 0) (distances [49-64]) 313 | [5] d_12 CL (val: 2) (distances [65-96]) 314 | [5] 3C < 315 | [6] 73 s 316 | [5] 76 v 317 | [6] 67 g 318 | [4] 20 319 | [5] 78 x 320 | [6] 6D m 321 | [5] 6C l 322 | [6] 6E n 323 | [6] 73 s 324 | [5] 3D = 325 | [4] 22 " 326 | [5] 68 h 327 | [5] 74 t 328 | [5] 74 t 329 | [6] 70 p 330 | [6] 3A : 331 | [4] 2F / 332 | [4] 2F / 333 | [4] 77 w 334 | [4] 77 w 335 | [4] 77 w 336 | [6] 2E . 337 | [4] 77 w 338 | [5] 33 3 339 | [6] 2E . 340 | [5] 6F o 341 | [6] 72 r 342 | [6] 67 g 343 | [4] 2F / 344 | [5] 32 2 345 | [4] 30 0 346 | [4] 30 0 347 | [4] 30 0 348 | [4] 2F / 349 | [11] (3,34) 350 | [4] 22 " 351 | [4] 20 352 | [5] 76 v 353 | [6] 69 i 354 | [6] 65 e 355 | [4] 77 w 356 | [6] 42 B 357 | [5] 6F o 358 | [5] 78 x 359 | [5] 3D = 360 | [4] 22 " 361 | [4] 30 0 362 | [4] 20 363 | [4] 30 0 364 | [4] 20 365 | [6] 35 5 366 | [4] 20 367 | [6] 35 5 368 | [4] 22 " 369 | [6] 3E > 370 | [5] 3C < 371 | [6] 70 p 372 | [6] 61 a 373 | [5] 74 t 374 | [5] 68 h 375 | [4] 20 376 | [6] 66 f 377 | [6] 69 i 378 | [5] 6C l 379 | [5] 6C l 380 | [5] 3D = 381 | [4] 22 " 382 | [6] 72 r 383 | [6] 65 e 384 | [6] 64 d 385 | [4] 22 " 386 | [4] 20 387 | [6] 64 d 388 | [5] 3D = 389 | [4] 22 " 390 | [6] 6D m 391 | [11] (3,30) 392 | [5] 68 h 393 | [5] 33 3 394 | [5] 76 v 395 | [5] 33 3 396 | [5] 68 h 397 | [6] 2D - 398 | [5] 33 3 399 | [4] 22 " 400 | [4] 2F / 401 | [12] (13,34) 402 | [6] 23 # 403 | [4] 30 0 404 | [4] 30 0 405 | [6] 66 f 406 | [11] (6,35) 407 | [5] 32 2 408 | [4] 20 409 | [5] 32 2 410 | [12] (11,35) 411 | [13] (4,94) 412 | [6] 3E > 413 | [6] EofB 414 | -------------------------------------------------------------------------------- /webapp/shared/GZHeatMap.js: -------------------------------------------------------------------------------- 1 | import { computeStats, getBytesExpanded } from "./computeStats.js"; 2 | import { constructBackRefs } from "./constructBackRefs.js"; 3 | import { constructHeatMap } from "./constructHeatMap.js"; 4 | import { formatNum } from "./utils.js"; 5 | 6 | const template = document.createElement("template"); 7 | template.innerHTML = ` 8 | 100 | 101 |

Stats

102 |
103 |

104 |
105 |

Heatmap

106 |

107 | Each character in the gzip stream is given a color representing approximately 108 | the number of bytes it takes up in the gzip stream. Open the color legend to 109 | see what colors correspond to what byte sizes. 110 |

111 |
112 | Color legend 113 |
    114 |
  1. <1 B
  2. 115 |
  3. <2 B
  4. 116 |
  5. <3 B
  6. 117 |
  7. <4 B
  8. 118 |
  9. <5 B
  10. 119 |
  11. <6 B
  12. 120 |
  13. <7 B
  14. 121 |
  15. <8 B
  16. 122 |
  17. <9 B
  18. 123 |
  19. <10 B
  20. 124 |
  21. <11 B
  22. 125 |
  23. <12 B
  24. 126 |
  25. <13 B
  26. 127 |
  27. <14 B
  28. 128 |
  29. <15 B
  30. 129 |
  31. <16 B
  32. 130 |
  33. >=17 B
  34. 131 |
132 |
133 |
134 |
135 |
136 |

Back references

137 |

138 | Orange text represents literal text from the gzip stream. 139 | Blue text is test that is a back reference to previous text 140 | in the gzip stream. Hover over a back references to see what 141 | text it references. 142 |

143 |
144 |
145 | `; 146 | 147 | class GZHeatMap extends HTMLElement { 148 | /** @type {ShadowRoot} */ 149 | #root; 150 | /** @type {Metadata | null | undefined} */ 151 | #_gzdata; 152 | /** @type {HTMLElement} */ 153 | #message; 154 | /** @type {HTMLElement} */ 155 | #statsContainer; 156 | /** @type {HTMLElement} */ 157 | #heatmapContainer; 158 | /** @type {HTMLElement} */ 159 | #backrefContainer; 160 | 161 | constructor() { 162 | super(); 163 | this.#root = this.attachShadow({ mode: "open" }); 164 | this.#_gzdata = null; 165 | 166 | this.#root.appendChild(template.content.cloneNode(true)); 167 | this.#message = /** @type {HTMLElement} */ ( 168 | this.#root.querySelector(".message") 169 | ); 170 | this.#statsContainer = /** @type {HTMLElement} */ ( 171 | this.#root.querySelector("[part=stats]") 172 | ); 173 | this.#heatmapContainer = /** @type {HTMLElement} */ ( 174 | this.#root.querySelector(".gz-container.heatmap") 175 | ); 176 | this.#backrefContainer = /** @type {HTMLElement} */ ( 177 | this.#root.querySelector(".gz-container.backref") 178 | ); 179 | } 180 | 181 | connectedCallback() { 182 | this.#upgradeProperty("gzdata"); 183 | } 184 | 185 | /** @param {Metadata | null | undefined} value */ 186 | set gzdata(value) { 187 | this.#render(value); 188 | this.#_gzdata = value; 189 | } 190 | /** @returns {Metadata | null | undefined} */ 191 | get gzdata() { 192 | return this.#_gzdata; 193 | } 194 | 195 | get debug() { 196 | return this.hasAttribute("debug"); 197 | } 198 | set debug(value) { 199 | if (value) { 200 | this.setAttribute("debug", ""); 201 | } else { 202 | this.removeAttribute("debug"); 203 | } 204 | } 205 | 206 | /** 207 | * Check if a property has an instance value. If so, copy the value, and 208 | * delete the instance property so it doesn't shadow the class property 209 | * setter. Finally, pass the value to the class property setter so it can 210 | * trigger any side effects. This is to safe guard against cases where, for 211 | * instance, a framework may have added the element to the page and set a 212 | * value on one of its properties, but lazy loaded its definition. Without 213 | * this guard, the upgraded element would miss that property and the instance 214 | * property would prevent the class property setter from ever being called. 215 | * @see https://web.dev/custom-elements-best-practices/#make-properties-lazy 216 | * @param {keyof GZHeatMap} prop 217 | */ 218 | #upgradeProperty(prop) { 219 | if (this.hasOwnProperty(prop)) { 220 | let value = this[prop]; 221 | delete this[prop]; 222 | // @ts-expect-error this[prop] is using all properties of HTMLElement, 223 | // some of which are readonly. We only care about local properties, e.g. 224 | // `data` 225 | this[prop] = value; 226 | } 227 | } 228 | 229 | /** @param {Metadata | null | undefined} gzdata */ 230 | #render(gzdata) { 231 | const heatmapSection = /**@type {HTMLElement}*/ ( 232 | this.#root.querySelector("section.heatmap") 233 | ); 234 | const backRefSection = /**@type {HTMLElement}*/ ( 235 | this.#root.querySelector("section.backref") 236 | ); 237 | 238 | this.#message.textContent = ""; 239 | this.#heatmapContainer.textContent = ""; 240 | this.#backrefContainer.textContent = ""; 241 | 242 | if (gzdata) { 243 | const debug = this.debug; 244 | // const debug = true; 245 | const stats = computeStats(gzdata); 246 | this.#setStats(stats); 247 | 248 | const bytesExpanded = getBytesExpanded(stats); 249 | if (bytesExpanded < 50e3) { 250 | // Only show character breakdown for small files 251 | heatmapSection.hidden = false; 252 | backRefSection.hidden = false; 253 | constructHeatMap(gzdata, this.#heatmapContainer, { debug }); 254 | constructBackRefs(gzdata, this.#backrefContainer, { debug }); 255 | } else { 256 | heatmapSection.hidden = true; 257 | backRefSection.hidden = true; 258 | 259 | const sizeStr = formatNum(bytesExpanded); 260 | this.#message.textContent = `File too large to show character breakdown analysis (size: ${sizeStr} B)`; 261 | } 262 | } 263 | } 264 | 265 | /** @param {import('../shared/computeStats').Stats} stats*/ 266 | #setStats(stats) { 267 | const compressionMetadata = 268 | stats.gzipHeader.byteLength + 269 | stats.gzipFooter.byteLength + 270 | bitsToBytes(stats.metadata.bitsCompressed); 271 | 272 | this.#statsContainer.innerHTML = ` 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 |
CountCompressed bytesExpanded bytes
Literals${formatNum(stats.literals.count)}${formatNum(bitsToBytes(stats.literals.bitsCompressed))} B${formatNum(stats.literals.bytesExpanded)} B
LZ77 Backrefs${formatNum(stats.lz77s.count)}${formatNum(bitsToBytes(stats.lz77s.bitsCompressed))} B${formatNum(stats.lz77s.bytesExpanded)} B
Code Length tables${formatNum(bitsToBytes(stats.codeLengthTables.bitsCompressed))} B
Other compression metadata${formatNum(compressionMetadata)} B
308 | `; 309 | } 310 | } 311 | 312 | /** @type {(bits: number) => number} */ 313 | function bitsToBytes(bits) { 314 | return Math.ceil(bits / 8); 315 | } 316 | 317 | window.customElements.define("gz-heatmap", GZHeatMap); 318 | -------------------------------------------------------------------------------- /tests/fixtures/svg-5-lowercase/defdb.txt: -------------------------------------------------------------------------------- 1 | [1] Last block (val: 1) 2 | [2] Dynamic Huffman Tree block (val: 2) 3 | [5] HLIT 267 (val:10) 4 | [5] HDIST 13 (val:12) 5 | [4] HCLEN 18 (val:14) 6 | [3] 16 CLL (val: 4) 7 | [3] 17 CLL (val: 3) 8 | [3] 18 CLL (val: 4) 9 | [3] 0 CLL (val: 2) 10 | [3] 8 CLL (val: 0) 11 | [3] 7 CLL (val: 0) 12 | [3] 9 CLL (val: 0) 13 | [3] 6 CLL (val: 2) 14 | [3] 10 CLL (val: 0) 15 | [3] 5 CLL (val: 3) 16 | [3] 11 CLL (val: 0) 17 | [3] 4 CLL (val: 4) 18 | [3] 12 CLL (val: 0) 19 | [3] 3 CLL (val: 0) 20 | [3] 13 CLL (val: 0) 21 | [3] 2 CLL (val: 5) 22 | [3] 14 CLL (val: 0) 23 | [3] 1 CLL (val: 5) 24 | [_] 15 CLL (val: 0) 25 | [11] ZREP (32 times) 26 | [_] 0x00 CL (val: 0) 27 | [_] 0x01 CL (val: 0) 28 | [_] 0x02 CL (val: 0) 29 | [_] 0x03 CL (val: 0) 30 | [_] 0x04 CL (val: 0) 31 | [_] 0x05 CL (val: 0) 32 | [_] 0x06 CL (val: 0) 33 | [_] 0x07 CL (val: 0) 34 | [_] 0x08 CL (val: 0) 35 | [_] 0x09 CL (val: 0) 36 | [_] 0x0A CL (val: 0) 37 | [_] 0x0B CL (val: 0) 38 | [_] 0x0C CL (val: 0) 39 | [_] 0x0D CL (val: 0) 40 | [_] 0x0E CL (val: 0) 41 | [_] 0x0F CL (val: 0) 42 | [_] 0x10 CL (val: 0) 43 | [_] 0x11 CL (val: 0) 44 | [_] 0x12 CL (val: 0) 45 | [_] 0x13 CL (val: 0) 46 | [_] 0x14 CL (val: 0) 47 | [_] 0x15 CL (val: 0) 48 | [_] 0x16 CL (val: 0) 49 | [_] 0x17 CL (val: 0) 50 | [_] 0x18 CL (val: 0) 51 | [_] 0x19 CL (val: 0) 52 | [_] 0x1A CL (val: 0) 53 | [_] 0x1B CL (val: 0) 54 | [_] 0x1C CL (val: 0) 55 | [_] 0x1D CL (val: 0) 56 | [_] 0x1E CL (val: 0) 57 | [_] 0x1F CL (val: 0) 58 | [4] 0x20 CL (val: 4) 59 | [2] 0x21 CL (val: 0) 60 | [4] 0x22 CL (val: 4) 61 | [2] 0x23 CL (val: 6) 62 | [6] ZREP (10 times) 63 | [_] 0x24 CL (val: 0) 64 | [_] 0x25 CL (val: 0) 65 | [_] 0x26 CL (val: 0) 66 | [_] 0x27 CL (val: 0) 67 | [_] 0x28 CL (val: 0) 68 | [_] 0x29 CL (val: 0) 69 | [_] 0x2A CL (val: 0) 70 | [_] 0x2B CL (val: 0) 71 | [_] 0x2C CL (val: 0) 72 | [_] 0x2D CL (val: 0) 73 | [2] 0x2E CL (val: 6) 74 | [4] 0x2F CL (val: 4) 75 | [4] 0x30 CL (val: 4) 76 | [2] 0x31 CL (val: 0) 77 | [3] 0x32 CL (val: 5) 78 | [3] 0x33 CL (val: 5) 79 | [2] 0x34 CL (val: 0) 80 | [3] 0x35 CL (val: 5) 81 | [6] ZREP (4 times) 82 | [_] 0x36 CL (val: 0) 83 | [_] 0x37 CL (val: 0) 84 | [_] 0x38 CL (val: 0) 85 | [_] 0x39 CL (val: 0) 86 | [2] 0x3A CL (val: 6) 87 | [2] 0x3B CL (val: 0) 88 | [2] 0x3C CL (val: 6) 89 | [3] 0x3D CL (val: 5) 90 | [2] 0x3E CL (val: 6) 91 | [6] ZREP (3 times) 92 | [_] 0x3F CL (val: 0) 93 | [_] 0x40 CL (val: 0) 94 | [_] 0x41 CL (val: 0) 95 | [2] 0x42 CL (val: 6) 96 | [6] ZREP (5 times) 97 | [_] 0x43 CL (val: 0) 98 | [_] 0x44 CL (val: 0) 99 | [_] 0x45 CL (val: 0) 100 | [_] 0x46 CL (val: 0) 101 | [_] 0x47 CL (val: 0) 102 | [2] 0x48 CL (val: 6) 103 | [11] ZREP (24 times) 104 | [_] 0x49 CL (val: 0) 105 | [_] 0x4A CL (val: 0) 106 | [_] 0x4B CL (val: 0) 107 | [_] 0x4C CL (val: 0) 108 | [_] 0x4D CL (val: 0) 109 | [_] 0x4E CL (val: 0) 110 | [_] 0x4F CL (val: 0) 111 | [_] 0x50 CL (val: 0) 112 | [_] 0x51 CL (val: 0) 113 | [_] 0x52 CL (val: 0) 114 | [_] 0x53 CL (val: 0) 115 | [_] 0x54 CL (val: 0) 116 | [_] 0x55 CL (val: 0) 117 | [_] 0x56 CL (val: 0) 118 | [_] 0x57 CL (val: 0) 119 | [_] 0x58 CL (val: 0) 120 | [_] 0x59 CL (val: 0) 121 | [_] 0x5A CL (val: 0) 122 | [_] 0x5B CL (val: 0) 123 | [_] 0x5C CL (val: 0) 124 | [_] 0x5D CL (val: 0) 125 | [_] 0x5E CL (val: 0) 126 | [_] 0x5F CL (val: 0) 127 | [_] 0x60 CL (val: 0) 128 | [2] 0x61 CL (val: 6) 129 | [2] 0x62 CL (val: 0) 130 | [2] 0x63 CL (val: 0) 131 | [3] 0x64 CL (val: 5) 132 | [2] 0x65 CL (val: 6) 133 | [2] 0x66 CL (val: 6) 134 | [2] 0x67 CL (val: 6) 135 | [3] 0x68 CL (val: 5) 136 | [2] 0x69 CL (val: 6) 137 | [2] 0x6A CL (val: 0) 138 | [2] 0x6B CL (val: 0) 139 | [3] 0x6C CL (val: 5) 140 | [2] 0x6D CL (val: 6) 141 | [6] LREP (3 times) 142 | [_] 0x6E CL (val: 6) 143 | [_] 0x6F CL (val: 6) 144 | [_] 0x70 CL (val: 6) 145 | [2] 0x71 CL (val: 0) 146 | [2] 0x72 CL (val: 6) 147 | [2] 0x73 CL (val: 6) 148 | [3] 0x74 CL (val: 5) 149 | [2] 0x75 CL (val: 0) 150 | [3] 0x76 CL (val: 5) 151 | [4] 0x77 CL (val: 4) 152 | [3] 0x78 CL (val: 5) 153 | [11] ZREP (135 times) 154 | [_] 0x79 CL (val: 0) 155 | [_] 0x7A CL (val: 0) 156 | [_] 0x7B CL (val: 0) 157 | [_] 0x7C CL (val: 0) 158 | [_] 0x7D CL (val: 0) 159 | [_] 0x7E CL (val: 0) 160 | [_] 0x7F CL (val: 0) 161 | [_] 0x80 CL (val: 0) 162 | [_] 0x81 CL (val: 0) 163 | [_] 0x82 CL (val: 0) 164 | [_] 0x83 CL (val: 0) 165 | [_] 0x84 CL (val: 0) 166 | [_] 0x85 CL (val: 0) 167 | [_] 0x86 CL (val: 0) 168 | [_] 0x87 CL (val: 0) 169 | [_] 0x88 CL (val: 0) 170 | [_] 0x89 CL (val: 0) 171 | [_] 0x8A CL (val: 0) 172 | [_] 0x8B CL (val: 0) 173 | [_] 0x8C CL (val: 0) 174 | [_] 0x8D CL (val: 0) 175 | [_] 0x8E CL (val: 0) 176 | [_] 0x8F CL (val: 0) 177 | [_] 0x90 CL (val: 0) 178 | [_] 0x91 CL (val: 0) 179 | [_] 0x92 CL (val: 0) 180 | [_] 0x93 CL (val: 0) 181 | [_] 0x94 CL (val: 0) 182 | [_] 0x95 CL (val: 0) 183 | [_] 0x96 CL (val: 0) 184 | [_] 0x97 CL (val: 0) 185 | [_] 0x98 CL (val: 0) 186 | [_] 0x99 CL (val: 0) 187 | [_] 0x9A CL (val: 0) 188 | [_] 0x9B CL (val: 0) 189 | [_] 0x9C CL (val: 0) 190 | [_] 0x9D CL (val: 0) 191 | [_] 0x9E CL (val: 0) 192 | [_] 0x9F CL (val: 0) 193 | [_] 0xA0 CL (val: 0) 194 | [_] 0xA1 CL (val: 0) 195 | [_] 0xA2 CL (val: 0) 196 | [_] 0xA3 CL (val: 0) 197 | [_] 0xA4 CL (val: 0) 198 | [_] 0xA5 CL (val: 0) 199 | [_] 0xA6 CL (val: 0) 200 | [_] 0xA7 CL (val: 0) 201 | [_] 0xA8 CL (val: 0) 202 | [_] 0xA9 CL (val: 0) 203 | [_] 0xAA CL (val: 0) 204 | [_] 0xAB CL (val: 0) 205 | [_] 0xAC CL (val: 0) 206 | [_] 0xAD CL (val: 0) 207 | [_] 0xAE CL (val: 0) 208 | [_] 0xAF CL (val: 0) 209 | [_] 0xB0 CL (val: 0) 210 | [_] 0xB1 CL (val: 0) 211 | [_] 0xB2 CL (val: 0) 212 | [_] 0xB3 CL (val: 0) 213 | [_] 0xB4 CL (val: 0) 214 | [_] 0xB5 CL (val: 0) 215 | [_] 0xB6 CL (val: 0) 216 | [_] 0xB7 CL (val: 0) 217 | [_] 0xB8 CL (val: 0) 218 | [_] 0xB9 CL (val: 0) 219 | [_] 0xBA CL (val: 0) 220 | [_] 0xBB CL (val: 0) 221 | [_] 0xBC CL (val: 0) 222 | [_] 0xBD CL (val: 0) 223 | [_] 0xBE CL (val: 0) 224 | [_] 0xBF CL (val: 0) 225 | [_] 0xC0 CL (val: 0) 226 | [_] 0xC1 CL (val: 0) 227 | [_] 0xC2 CL (val: 0) 228 | [_] 0xC3 CL (val: 0) 229 | [_] 0xC4 CL (val: 0) 230 | [_] 0xC5 CL (val: 0) 231 | [_] 0xC6 CL (val: 0) 232 | [_] 0xC7 CL (val: 0) 233 | [_] 0xC8 CL (val: 0) 234 | [_] 0xC9 CL (val: 0) 235 | [_] 0xCA CL (val: 0) 236 | [_] 0xCB CL (val: 0) 237 | [_] 0xCC CL (val: 0) 238 | [_] 0xCD CL (val: 0) 239 | [_] 0xCE CL (val: 0) 240 | [_] 0xCF CL (val: 0) 241 | [_] 0xD0 CL (val: 0) 242 | [_] 0xD1 CL (val: 0) 243 | [_] 0xD2 CL (val: 0) 244 | [_] 0xD3 CL (val: 0) 245 | [_] 0xD4 CL (val: 0) 246 | [_] 0xD5 CL (val: 0) 247 | [_] 0xD6 CL (val: 0) 248 | [_] 0xD7 CL (val: 0) 249 | [_] 0xD8 CL (val: 0) 250 | [_] 0xD9 CL (val: 0) 251 | [_] 0xDA CL (val: 0) 252 | [_] 0xDB CL (val: 0) 253 | [_] 0xDC CL (val: 0) 254 | [_] 0xDD CL (val: 0) 255 | [_] 0xDE CL (val: 0) 256 | [_] 0xDF CL (val: 0) 257 | [_] 0xE0 CL (val: 0) 258 | [_] 0xE1 CL (val: 0) 259 | [_] 0xE2 CL (val: 0) 260 | [_] 0xE3 CL (val: 0) 261 | [_] 0xE4 CL (val: 0) 262 | [_] 0xE5 CL (val: 0) 263 | [_] 0xE6 CL (val: 0) 264 | [_] 0xE7 CL (val: 0) 265 | [_] 0xE8 CL (val: 0) 266 | [_] 0xE9 CL (val: 0) 267 | [_] 0xEA CL (val: 0) 268 | [_] 0xEB CL (val: 0) 269 | [_] 0xEC CL (val: 0) 270 | [_] 0xED CL (val: 0) 271 | [_] 0xEE CL (val: 0) 272 | [_] 0xEF CL (val: 0) 273 | [_] 0xF0 CL (val: 0) 274 | [_] 0xF1 CL (val: 0) 275 | [_] 0xF2 CL (val: 0) 276 | [_] 0xF3 CL (val: 0) 277 | [_] 0xF4 CL (val: 0) 278 | [_] 0xF5 CL (val: 0) 279 | [_] 0xF6 CL (val: 0) 280 | [_] 0xF7 CL (val: 0) 281 | [_] 0xF8 CL (val: 0) 282 | [_] 0xF9 CL (val: 0) 283 | [_] 0xFA CL (val: 0) 284 | [_] 0xFB CL (val: 0) 285 | [_] 0xFC CL (val: 0) 286 | [_] 0xFD CL (val: 0) 287 | [_] 0xFE CL (val: 0) 288 | [_] 0xFF CL (val: 0) 289 | [2] EofB CL (val: 6) 290 | [6] LREP (4 times) 291 | [_] l_00 CL (val: 6) (length 3) 292 | [_] l_01 CL (val: 6) (length 4) 293 | [_] l_02 CL (val: 6) (length 5) 294 | [_] l_03 CL (val: 6) (length 6) 295 | [6] ZREP (5 times) 296 | [_] l_04 CL (val: 0) (length 7) 297 | [_] l_05 CL (val: 0) (length 8) 298 | [_] l_06 CL (val: 0) (length 9) 299 | [_] l_07 CL (val: 0) (length 10) 300 | [_] l_08 CL (val: 0) (lengths [11-12]) 301 | [2] l_09 CL (val: 6) (lengths [13-14]) 302 | [6] ZREP (9 times) 303 | [_] d_00 CL (val: 0) (distance 1) 304 | [_] d_01 CL (val: 0) (distance 2) 305 | [_] d_02 CL (val: 0) (distance 3) 306 | [_] d_03 CL (val: 0) (distance 4) 307 | [_] d_04 CL (val: 0) (distances [5-6]) 308 | [_] d_05 CL (val: 0) (distances [7-8]) 309 | [_] d_06 CL (val: 0) (distances [9-12]) 310 | [_] d_07 CL (val: 0) (distances [13-16]) 311 | [_] d_08 CL (val: 0) (distances [17-24]) 312 | [5] d_09 CL (val: 2) (distances [25-32]) 313 | [5] d_10 CL (val: 1) (distances [33-48]) 314 | [2] d_11 CL (val: 0) (distances [49-64]) 315 | [5] d_12 CL (val: 2) (distances [65-96]) 316 | [6] 3C < 317 | [6] 73 s 318 | [5] 76 v 319 | [6] 67 g 320 | [4] 20 321 | [5] 78 x 322 | [6] 6D m 323 | [5] 6C l 324 | [6] 6E n 325 | [6] 73 s 326 | [5] 3D = 327 | [4] 22 " 328 | [5] 68 h 329 | [5] 74 t 330 | [5] 74 t 331 | [6] 70 p 332 | [6] 3A : 333 | [4] 2F / 334 | [4] 2F / 335 | [4] 77 w 336 | [4] 77 w 337 | [4] 77 w 338 | [6] 2E . 339 | [4] 77 w 340 | [5] 33 3 341 | [6] 2E . 342 | [6] 6F o 343 | [6] 72 r 344 | [6] 67 g 345 | [4] 2F / 346 | [5] 32 2 347 | [4] 30 0 348 | [4] 30 0 349 | [4] 30 0 350 | [4] 2F / 351 | [11] (3,34) 352 | [4] 22 " 353 | [4] 20 354 | [5] 76 v 355 | [6] 69 i 356 | [6] 65 e 357 | [4] 77 w 358 | [6] 42 B 359 | [6] 6F o 360 | [5] 78 x 361 | [5] 3D = 362 | [4] 22 " 363 | [4] 30 0 364 | [4] 20 365 | [4] 30 0 366 | [4] 20 367 | [5] 35 5 368 | [4] 20 369 | [5] 35 5 370 | [4] 22 " 371 | [6] 3E > 372 | [6] 3C < 373 | [6] 70 p 374 | [6] 61 a 375 | [5] 74 t 376 | [5] 68 h 377 | [4] 20 378 | [6] 66 f 379 | [6] 69 i 380 | [5] 6C l 381 | [5] 6C l 382 | [5] 3D = 383 | [4] 22 " 384 | [6] 72 r 385 | [6] 65 e 386 | [5] 64 d 387 | [4] 22 " 388 | [4] 20 389 | [5] 64 d 390 | [5] 3D = 391 | [4] 22 " 392 | [6] 6D m 393 | [11] (3,30) 394 | [5] 68 h 395 | [5] 33 3 396 | [5] 76 v 397 | [5] 33 3 398 | [6] 48 H 399 | [4] 30 0 400 | [4] 22 " 401 | [4] 2F / 402 | [12] (13,33) 403 | [6] 23 # 404 | [4] 30 0 405 | [4] 30 0 406 | [6] 66 f 407 | [11] (6,34) 408 | [5] 32 2 409 | [4] 20 410 | [5] 32 2 411 | [11] (5,34) 412 | [5] 32 2 413 | [11] (4,34) 414 | [13] (4,92) 415 | [6] 3E > 416 | [6] EofB 417 | -------------------------------------------------------------------------------- /tests/website.test.js: -------------------------------------------------------------------------------- 1 | import { readdirSync } from "fs"; 2 | import { readFile, writeFile } from "fs/promises"; 3 | import { ChildProcess, spawn } from "child_process"; 4 | import { join, dirname } from "path"; 5 | import { fileURLToPath } from "url"; 6 | import { suite } from "uvu"; 7 | import * as assert from "uvu/assert"; 8 | import puppeteer from "puppeteer"; 9 | import prettier from "prettier"; 10 | import stripAnsi from "strip-ansi"; 11 | import treeKill from "tree-kill"; 12 | import { fixture } from "./utils/paths.js"; 13 | import ViteConfig from "../vite.config.js"; 14 | import { promisify } from "util"; 15 | 16 | const __dirname = dirname(fileURLToPath(import.meta.url)); 17 | /** @type {(...args: string[]) => string} */ 18 | const repoRoot = (...args) => join(__dirname, "..", ...args); 19 | 20 | const viteConfig = /** @type {import('vite').UserConfig} */ (ViteConfig); 21 | const treeKillAsync = promisify(treeKill); 22 | 23 | /** 24 | * @typedef WebsiteSuiteContext 25 | * @property {import('puppeteer').Browser} browser 26 | * @property {import('puppeteer').Page} page 27 | * @property {{url: string; server: ChildProcess }} serverInfo 28 | */ 29 | /** 30 | * @typedef {import('puppeteer').Page} Page 31 | */ 32 | 33 | /** @type {import('uvu').Test} */ 34 | const website = suite("website"); 35 | 36 | const serverInfo = await startServer(); 37 | const browser = await puppeteer.launch(); 38 | 39 | website.before.each(async (ctx) => { 40 | ctx.serverInfo = serverInfo; 41 | ctx.browser = browser; 42 | ctx.page = await ctx.browser.newPage(); 43 | ctx.page.setDefaultTimeout(10e3); 44 | }); 45 | 46 | website.after.each(async (ctx) => { 47 | await ctx.page.close(); 48 | }); 49 | 50 | website.after(async (ctx) => { 51 | if (ctx.serverInfo && ctx.serverInfo.server.pid) { 52 | await treeKillAsync(ctx.serverInfo.server.pid); 53 | } 54 | await ctx.browser?.close(); 55 | }); 56 | 57 | /** @returns {Promise<{url: string; server: ChildProcess }>} */ 58 | function startServer(timeoutMs = 3e3) { 59 | return new Promise((resolve, reject) => { 60 | const server = spawn("npm", ["run", "preview"], { 61 | cwd: repoRoot(), 62 | stdio: "pipe", 63 | }); 64 | 65 | /** @type {NodeJS.Timeout} */ 66 | let timeout; 67 | if (timeoutMs > 0) { 68 | timeout = setTimeout(() => { 69 | server.off("data", onStdOutChunk); 70 | server.kill(); 71 | reject( 72 | new Error( 73 | "Timed out waiting for Vite server to get set up. Did it output a URL?" 74 | ) 75 | ); 76 | }, timeoutMs); 77 | } 78 | 79 | // Look for lines like: 80 | // Local: http://localhost:4173/gz-heatmap/ 81 | const urlLine = /Local:\s+(https?:\/\/localhost:[0-9]+\/gz-heatmap\/?)/; 82 | let output = ""; 83 | 84 | /** @param {Buffer | string} chunk */ 85 | function onStdOutChunk(chunk) { 86 | chunk = chunk.toString("utf8"); 87 | 88 | process.stdout.write(chunk); 89 | output += stripAnsi(chunk); 90 | let match = output.match(urlLine); 91 | if (match) { 92 | server.off("data", onStdOutChunk); 93 | clearTimeout(timeout); 94 | resolve({ url: match[1], server }); 95 | } 96 | } 97 | 98 | server.stdout.on("data", onStdOutChunk); 99 | }); 100 | } 101 | 102 | /** 103 | * @param {import('puppeteer').Page} page 104 | * @returns {Promise} 105 | */ 106 | async function getPageContent(page) { 107 | const gzHeatMapEndTag = ``; 108 | let content = await page.content(); 109 | if (content.includes(gzHeatMapEndTag)) { 110 | const heatmapContents = await page.evaluate(() => 111 | Array.from(document.querySelectorAll("gz-heatmap")).map( 112 | (el) => el.shadowRoot?.innerHTML ?? "" 113 | ) 114 | ); 115 | 116 | let i = 0; 117 | content = content.replace(gzHeatMapEndTag, () => { 118 | return heatmapContents[i++] + gzHeatMapEndTag; 119 | }); 120 | } 121 | 122 | return content; 123 | } 124 | 125 | /** @type {(rawHtml: string) => string} */ 126 | function formatHtml(rawHtml) { 127 | rawHtml = rawHtml 128 | .replace(/([^\n])/g, "$1\n"); 130 | 131 | return prettier.format(rawHtml, { parser: "html" }); 132 | } 133 | 134 | /** 135 | * @param {WebsiteSuiteContext} ctx 136 | * @param {string} fixtureDir 137 | */ 138 | async function validateFixture(ctx, fixtureDir = "svg-7-hex") { 139 | let actualHtml = formatHtml(await getPageContent(ctx.page)); 140 | 141 | const expectedFixturePath = fixture(fixtureDir, "websiteExpected.html"); 142 | let expectedHtml = await readFile(expectedFixturePath, "utf8"); 143 | 144 | const indexHashRegex = /index-\w+\.js/g; 145 | actualHtml = actualHtml.replace(indexHashRegex, "index.js"); 146 | expectedHtml = expectedHtml.replace(indexHashRegex, "index.js"); 147 | 148 | await writeFile(expectedFixturePath, actualHtml, "utf8"); 149 | 150 | assert.fixture( 151 | actualHtml, 152 | expectedHtml, 153 | `page html did not match expected fixture` 154 | ); 155 | } 156 | 157 | /** @type {string} */ 158 | let exampleURL = ""; 159 | /** @type {string} */ 160 | let examplePath = ""; 161 | 162 | /** @type {(...args: string[]) => string} */ 163 | const assetsDir = (...args) => repoRoot("dist/assets", ...args); 164 | for (let entry of readdirSync(assetsDir())) { 165 | if (entry.endsWith(".svg")) { 166 | examplePath = assetsDir(entry); 167 | exampleURL = examplePath 168 | .replace(repoRoot("dist"), viteConfig.base ?? "/") 169 | .replace(/\/\//g, "/"); 170 | } 171 | } 172 | 173 | if (!examplePath || !exampleURL) { 174 | serverInfo.server.kill(); 175 | await browser.close(); 176 | throw new Error(`Could not find example SVG in assets dir: ${assetsDir()}`); 177 | } 178 | 179 | /** @type {(page: Page, url: string) => Promise} */ 180 | async function loadURL(page, url = exampleURL) { 181 | // Click the input 3 times to select all text in the input so what we type 182 | // next overrides any existing value 183 | await page.click(`input[name=url]`, { clickCount: 3 }); 184 | await page.type(`input[name=url]`, url); 185 | await page.click(`input[type=submit]`); 186 | } 187 | 188 | /** @type {(page: Page) => Promise} */ 189 | async function validateSuccessfulLoad(page) { 190 | const gzheatmap = await page.waitForSelector("gz-heatmap"); 191 | assert.ok(gzheatmap, `Expected to find a gz-heatmap element.`); 192 | 193 | const errorElements = await page.$$(".error"); 194 | assert.equal( 195 | errorElements.length, 196 | 0, 197 | `Expected 0 error elements. Got ${errorElements.length}.` 198 | ); 199 | } 200 | 201 | /** @type {(page: Page) => Promise} */ 202 | async function validateErrorUI(page) { 203 | const errorElements = await page.waitForSelector(".error"); 204 | assert.ok(errorElements, `Expected an error element.`); 205 | 206 | const gzheatmap = await page.$$("gz-heatmap"); 207 | assert.equal( 208 | gzheatmap.length, 209 | 0, 210 | `Expected 0 gz-heatmap element. Got ${gzheatmap.length}.` 211 | ); 212 | } 213 | 214 | /** @type {(page: Page, expectedURLParam?: string) => Promise} */ 215 | async function validateURL(page, expectedURLParam = exampleURL) { 216 | const url = new URL(page.url()); 217 | const actual = url.searchParams.get("url"); 218 | 219 | if (expectedURLParam) { 220 | assert.equal( 221 | actual, 222 | expectedURLParam, 223 | `Expected "url" param to be "${expectedURLParam}". Got "${actual}"` 224 | ); 225 | } else { 226 | assert.ok( 227 | !url.searchParams.has("url") || actual === "", 228 | `Expected not to have a url parameter or have an empty url parameter. Got "${actual}" instead.` 229 | ); 230 | } 231 | } 232 | 233 | website("should show gz analysis for valid URL", async (ctx) => { 234 | await ctx.page.goto(serverInfo.url); 235 | await loadURL(ctx.page, exampleURL); 236 | await validateSuccessfulLoad(ctx.page); 237 | await validateURL(ctx.page); 238 | await validateFixture(ctx); 239 | }); 240 | 241 | website("should only show stats for large file", async (ctx) => { 242 | await ctx.page.goto(serverInfo.url); 243 | const [fileChooser] = await Promise.all([ 244 | ctx.page.waitForFileChooser(), 245 | ctx.page.click("input[type=file]"), 246 | ]); 247 | await fileChooser.accept([repoRoot("tests/fixtures/large-file/google.html")]); 248 | await ctx.page.click("input[type=submit]"); 249 | 250 | await validateSuccessfulLoad(ctx.page); 251 | await validateFixture(ctx, "large-file"); 252 | }); 253 | 254 | website("should show gz analysis for valid file upload", async (ctx) => { 255 | await ctx.page.goto(serverInfo.url); 256 | const [fileChooser] = await Promise.all([ 257 | ctx.page.waitForFileChooser(), 258 | ctx.page.click("input[type=file]"), 259 | ]); 260 | await fileChooser.accept([examplePath]); 261 | await ctx.page.click("input[type=submit]"); 262 | 263 | await validateSuccessfulLoad(ctx.page); 264 | }); 265 | 266 | website("should load example", async (ctx) => { 267 | await ctx.page.goto(serverInfo.url); 268 | await ctx.page.click("button[data-test-id=load-example]"); 269 | await validateSuccessfulLoad(ctx.page); 270 | await validateURL(ctx.page); 271 | }); 272 | 273 | website("should show error for submitting empty form", async (ctx) => { 274 | await ctx.page.goto(serverInfo.url); 275 | await loadURL(ctx.page, ""); 276 | await validateErrorUI(ctx.page); 277 | await validateURL(ctx.page, ""); 278 | }); 279 | 280 | website("should show error for submitting a 404 URL", async (ctx) => { 281 | const url = "/fake-url/does-not-exist"; 282 | await ctx.page.goto(serverInfo.url); 283 | await loadURL(ctx.page, url); 284 | await validateErrorUI(ctx.page); 285 | await validateURL(ctx.page, url); 286 | }); 287 | 288 | website( 289 | "should clear error and update URL when recovering from bad URL", 290 | async (ctx) => { 291 | const url = "/fake-url/does-not-exist"; 292 | 293 | await ctx.page.goto(serverInfo.url); 294 | await loadURL(ctx.page, url); 295 | await validateErrorUI(ctx.page); 296 | await validateURL(ctx.page, url); 297 | 298 | await loadURL(ctx.page, exampleURL); 299 | await validateSuccessfulLoad(ctx.page); 300 | await validateURL(ctx.page); 301 | } 302 | ); 303 | 304 | website( 305 | "should clear gz analysis and update URL when changing to bad URL", 306 | async (ctx) => { 307 | const url = "/fake-url/does-not-exist"; 308 | 309 | await ctx.page.goto(serverInfo.url); 310 | await loadURL(ctx.page, exampleURL); 311 | await validateSuccessfulLoad(ctx.page); 312 | await validateURL(ctx.page); 313 | 314 | await loadURL(ctx.page, url); 315 | await validateErrorUI(ctx.page); 316 | await validateURL(ctx.page, url); 317 | } 318 | ); 319 | 320 | website.run(); 321 | -------------------------------------------------------------------------------- /tests/fixtures/svg-3-viewbox/defdb.txt: -------------------------------------------------------------------------------- 1 | [1] Last block (val: 1) 2 | [2] Dynamic Huffman Tree block (val: 2) 3 | [5] HLIT 267 (val:10) 4 | [5] HDIST 13 (val:12) 5 | [4] HCLEN 18 (val:14) 6 | [3] 16 CLL (val: 4) 7 | [3] 17 CLL (val: 3) 8 | [3] 18 CLL (val: 4) 9 | [3] 0 CLL (val: 2) 10 | [3] 8 CLL (val: 0) 11 | [3] 7 CLL (val: 0) 12 | [3] 9 CLL (val: 0) 13 | [3] 6 CLL (val: 2) 14 | [3] 10 CLL (val: 0) 15 | [3] 5 CLL (val: 3) 16 | [3] 11 CLL (val: 0) 17 | [3] 4 CLL (val: 4) 18 | [3] 12 CLL (val: 0) 19 | [3] 3 CLL (val: 0) 20 | [3] 13 CLL (val: 0) 21 | [3] 2 CLL (val: 5) 22 | [3] 14 CLL (val: 0) 23 | [3] 1 CLL (val: 5) 24 | [_] 15 CLL (val: 0) 25 | [11] ZREP (32 times) 26 | [_] 0x00 CL (val: 0) 27 | [_] 0x01 CL (val: 0) 28 | [_] 0x02 CL (val: 0) 29 | [_] 0x03 CL (val: 0) 30 | [_] 0x04 CL (val: 0) 31 | [_] 0x05 CL (val: 0) 32 | [_] 0x06 CL (val: 0) 33 | [_] 0x07 CL (val: 0) 34 | [_] 0x08 CL (val: 0) 35 | [_] 0x09 CL (val: 0) 36 | [_] 0x0A CL (val: 0) 37 | [_] 0x0B CL (val: 0) 38 | [_] 0x0C CL (val: 0) 39 | [_] 0x0D CL (val: 0) 40 | [_] 0x0E CL (val: 0) 41 | [_] 0x0F CL (val: 0) 42 | [_] 0x10 CL (val: 0) 43 | [_] 0x11 CL (val: 0) 44 | [_] 0x12 CL (val: 0) 45 | [_] 0x13 CL (val: 0) 46 | [_] 0x14 CL (val: 0) 47 | [_] 0x15 CL (val: 0) 48 | [_] 0x16 CL (val: 0) 49 | [_] 0x17 CL (val: 0) 50 | [_] 0x18 CL (val: 0) 51 | [_] 0x19 CL (val: 0) 52 | [_] 0x1A CL (val: 0) 53 | [_] 0x1B CL (val: 0) 54 | [_] 0x1C CL (val: 0) 55 | [_] 0x1D CL (val: 0) 56 | [_] 0x1E CL (val: 0) 57 | [_] 0x1F CL (val: 0) 58 | [4] 0x20 CL (val: 4) 59 | [2] 0x21 CL (val: 0) 60 | [4] 0x22 CL (val: 4) 61 | [2] 0x23 CL (val: 6) 62 | [6] ZREP (10 times) 63 | [_] 0x24 CL (val: 0) 64 | [_] 0x25 CL (val: 0) 65 | [_] 0x26 CL (val: 0) 66 | [_] 0x27 CL (val: 0) 67 | [_] 0x28 CL (val: 0) 68 | [_] 0x29 CL (val: 0) 69 | [_] 0x2A CL (val: 0) 70 | [_] 0x2B CL (val: 0) 71 | [_] 0x2C CL (val: 0) 72 | [_] 0x2D CL (val: 0) 73 | [2] 0x2E CL (val: 6) 74 | [4] 0x2F CL (val: 4) 75 | [4] 0x30 CL (val: 4) 76 | [2] 0x31 CL (val: 0) 77 | [3] 0x32 CL (val: 5) 78 | [3] 0x33 CL (val: 5) 79 | [2] 0x34 CL (val: 0) 80 | [2] 0x35 CL (val: 6) 81 | [6] ZREP (4 times) 82 | [_] 0x36 CL (val: 0) 83 | [_] 0x37 CL (val: 0) 84 | [_] 0x38 CL (val: 0) 85 | [_] 0x39 CL (val: 0) 86 | [2] 0x3A CL (val: 6) 87 | [2] 0x3B CL (val: 0) 88 | [2] 0x3C CL (val: 6) 89 | [3] 0x3D CL (val: 5) 90 | [2] 0x3E CL (val: 6) 91 | [6] ZREP (3 times) 92 | [_] 0x3F CL (val: 0) 93 | [_] 0x40 CL (val: 0) 94 | [_] 0x41 CL (val: 0) 95 | [2] 0x42 CL (val: 6) 96 | [6] ZREP (5 times) 97 | [_] 0x43 CL (val: 0) 98 | [_] 0x44 CL (val: 0) 99 | [_] 0x45 CL (val: 0) 100 | [_] 0x46 CL (val: 0) 101 | [_] 0x47 CL (val: 0) 102 | [2] 0x48 CL (val: 6) 103 | [6] ZREP (4 times) 104 | [_] 0x49 CL (val: 0) 105 | [_] 0x4A CL (val: 0) 106 | [_] 0x4B CL (val: 0) 107 | [_] 0x4C CL (val: 0) 108 | [2] 0x4D CL (val: 6) 109 | [11] ZREP (19 times) 110 | [_] 0x4E CL (val: 0) 111 | [_] 0x4F CL (val: 0) 112 | [_] 0x50 CL (val: 0) 113 | [_] 0x51 CL (val: 0) 114 | [_] 0x52 CL (val: 0) 115 | [_] 0x53 CL (val: 0) 116 | [_] 0x54 CL (val: 0) 117 | [_] 0x55 CL (val: 0) 118 | [_] 0x56 CL (val: 0) 119 | [_] 0x57 CL (val: 0) 120 | [_] 0x58 CL (val: 0) 121 | [_] 0x59 CL (val: 0) 122 | [_] 0x5A CL (val: 0) 123 | [_] 0x5B CL (val: 0) 124 | [_] 0x5C CL (val: 0) 125 | [_] 0x5D CL (val: 0) 126 | [_] 0x5E CL (val: 0) 127 | [_] 0x5F CL (val: 0) 128 | [_] 0x60 CL (val: 0) 129 | [2] 0x61 CL (val: 6) 130 | [2] 0x62 CL (val: 0) 131 | [2] 0x63 CL (val: 0) 132 | [2] 0x64 CL (val: 6) 133 | [6] LREP (3 times) 134 | [_] 0x65 CL (val: 6) 135 | [_] 0x66 CL (val: 6) 136 | [_] 0x67 CL (val: 6) 137 | [3] 0x68 CL (val: 5) 138 | [2] 0x69 CL (val: 6) 139 | [2] 0x6A CL (val: 0) 140 | [2] 0x6B CL (val: 0) 141 | [3] 0x6C CL (val: 5) 142 | [2] 0x6D CL (val: 6) 143 | [6] LREP (3 times) 144 | [_] 0x6E CL (val: 6) 145 | [_] 0x6F CL (val: 6) 146 | [_] 0x70 CL (val: 6) 147 | [2] 0x71 CL (val: 0) 148 | [2] 0x72 CL (val: 6) 149 | [2] 0x73 CL (val: 6) 150 | [3] 0x74 CL (val: 5) 151 | [2] 0x75 CL (val: 0) 152 | [3] 0x76 CL (val: 5) 153 | [4] 0x77 CL (val: 4) 154 | [2] 0x78 CL (val: 6) 155 | [2] 0x79 CL (val: 0) 156 | [2] 0x7A CL (val: 6) 157 | [11] ZREP (133 times) 158 | [_] 0x7B CL (val: 0) 159 | [_] 0x7C CL (val: 0) 160 | [_] 0x7D CL (val: 0) 161 | [_] 0x7E CL (val: 0) 162 | [_] 0x7F CL (val: 0) 163 | [_] 0x80 CL (val: 0) 164 | [_] 0x81 CL (val: 0) 165 | [_] 0x82 CL (val: 0) 166 | [_] 0x83 CL (val: 0) 167 | [_] 0x84 CL (val: 0) 168 | [_] 0x85 CL (val: 0) 169 | [_] 0x86 CL (val: 0) 170 | [_] 0x87 CL (val: 0) 171 | [_] 0x88 CL (val: 0) 172 | [_] 0x89 CL (val: 0) 173 | [_] 0x8A CL (val: 0) 174 | [_] 0x8B CL (val: 0) 175 | [_] 0x8C CL (val: 0) 176 | [_] 0x8D CL (val: 0) 177 | [_] 0x8E CL (val: 0) 178 | [_] 0x8F CL (val: 0) 179 | [_] 0x90 CL (val: 0) 180 | [_] 0x91 CL (val: 0) 181 | [_] 0x92 CL (val: 0) 182 | [_] 0x93 CL (val: 0) 183 | [_] 0x94 CL (val: 0) 184 | [_] 0x95 CL (val: 0) 185 | [_] 0x96 CL (val: 0) 186 | [_] 0x97 CL (val: 0) 187 | [_] 0x98 CL (val: 0) 188 | [_] 0x99 CL (val: 0) 189 | [_] 0x9A CL (val: 0) 190 | [_] 0x9B CL (val: 0) 191 | [_] 0x9C CL (val: 0) 192 | [_] 0x9D CL (val: 0) 193 | [_] 0x9E CL (val: 0) 194 | [_] 0x9F CL (val: 0) 195 | [_] 0xA0 CL (val: 0) 196 | [_] 0xA1 CL (val: 0) 197 | [_] 0xA2 CL (val: 0) 198 | [_] 0xA3 CL (val: 0) 199 | [_] 0xA4 CL (val: 0) 200 | [_] 0xA5 CL (val: 0) 201 | [_] 0xA6 CL (val: 0) 202 | [_] 0xA7 CL (val: 0) 203 | [_] 0xA8 CL (val: 0) 204 | [_] 0xA9 CL (val: 0) 205 | [_] 0xAA CL (val: 0) 206 | [_] 0xAB CL (val: 0) 207 | [_] 0xAC CL (val: 0) 208 | [_] 0xAD CL (val: 0) 209 | [_] 0xAE CL (val: 0) 210 | [_] 0xAF CL (val: 0) 211 | [_] 0xB0 CL (val: 0) 212 | [_] 0xB1 CL (val: 0) 213 | [_] 0xB2 CL (val: 0) 214 | [_] 0xB3 CL (val: 0) 215 | [_] 0xB4 CL (val: 0) 216 | [_] 0xB5 CL (val: 0) 217 | [_] 0xB6 CL (val: 0) 218 | [_] 0xB7 CL (val: 0) 219 | [_] 0xB8 CL (val: 0) 220 | [_] 0xB9 CL (val: 0) 221 | [_] 0xBA CL (val: 0) 222 | [_] 0xBB CL (val: 0) 223 | [_] 0xBC CL (val: 0) 224 | [_] 0xBD CL (val: 0) 225 | [_] 0xBE CL (val: 0) 226 | [_] 0xBF CL (val: 0) 227 | [_] 0xC0 CL (val: 0) 228 | [_] 0xC1 CL (val: 0) 229 | [_] 0xC2 CL (val: 0) 230 | [_] 0xC3 CL (val: 0) 231 | [_] 0xC4 CL (val: 0) 232 | [_] 0xC5 CL (val: 0) 233 | [_] 0xC6 CL (val: 0) 234 | [_] 0xC7 CL (val: 0) 235 | [_] 0xC8 CL (val: 0) 236 | [_] 0xC9 CL (val: 0) 237 | [_] 0xCA CL (val: 0) 238 | [_] 0xCB CL (val: 0) 239 | [_] 0xCC CL (val: 0) 240 | [_] 0xCD CL (val: 0) 241 | [_] 0xCE CL (val: 0) 242 | [_] 0xCF CL (val: 0) 243 | [_] 0xD0 CL (val: 0) 244 | [_] 0xD1 CL (val: 0) 245 | [_] 0xD2 CL (val: 0) 246 | [_] 0xD3 CL (val: 0) 247 | [_] 0xD4 CL (val: 0) 248 | [_] 0xD5 CL (val: 0) 249 | [_] 0xD6 CL (val: 0) 250 | [_] 0xD7 CL (val: 0) 251 | [_] 0xD8 CL (val: 0) 252 | [_] 0xD9 CL (val: 0) 253 | [_] 0xDA CL (val: 0) 254 | [_] 0xDB CL (val: 0) 255 | [_] 0xDC CL (val: 0) 256 | [_] 0xDD CL (val: 0) 257 | [_] 0xDE CL (val: 0) 258 | [_] 0xDF CL (val: 0) 259 | [_] 0xE0 CL (val: 0) 260 | [_] 0xE1 CL (val: 0) 261 | [_] 0xE2 CL (val: 0) 262 | [_] 0xE3 CL (val: 0) 263 | [_] 0xE4 CL (val: 0) 264 | [_] 0xE5 CL (val: 0) 265 | [_] 0xE6 CL (val: 0) 266 | [_] 0xE7 CL (val: 0) 267 | [_] 0xE8 CL (val: 0) 268 | [_] 0xE9 CL (val: 0) 269 | [_] 0xEA CL (val: 0) 270 | [_] 0xEB CL (val: 0) 271 | [_] 0xEC CL (val: 0) 272 | [_] 0xED CL (val: 0) 273 | [_] 0xEE CL (val: 0) 274 | [_] 0xEF CL (val: 0) 275 | [_] 0xF0 CL (val: 0) 276 | [_] 0xF1 CL (val: 0) 277 | [_] 0xF2 CL (val: 0) 278 | [_] 0xF3 CL (val: 0) 279 | [_] 0xF4 CL (val: 0) 280 | [_] 0xF5 CL (val: 0) 281 | [_] 0xF6 CL (val: 0) 282 | [_] 0xF7 CL (val: 0) 283 | [_] 0xF8 CL (val: 0) 284 | [_] 0xF9 CL (val: 0) 285 | [_] 0xFA CL (val: 0) 286 | [_] 0xFB CL (val: 0) 287 | [_] 0xFC CL (val: 0) 288 | [_] 0xFD CL (val: 0) 289 | [_] 0xFE CL (val: 0) 290 | [_] 0xFF CL (val: 0) 291 | [2] EofB CL (val: 6) 292 | [3] l_00 CL (val: 5) (length 3) 293 | [2] l_01 CL (val: 6) (length 4) 294 | [2] l_02 CL (val: 6) (length 5) 295 | [2] l_03 CL (val: 6) (length 6) 296 | [6] ZREP (5 times) 297 | [_] l_04 CL (val: 0) (length 7) 298 | [_] l_05 CL (val: 0) (length 8) 299 | [_] l_06 CL (val: 0) (length 9) 300 | [_] l_07 CL (val: 0) (length 10) 301 | [_] l_08 CL (val: 0) (lengths [11-12]) 302 | [2] l_09 CL (val: 6) (lengths [13-14]) 303 | [6] ZREP (9 times) 304 | [_] d_00 CL (val: 0) (distance 1) 305 | [_] d_01 CL (val: 0) (distance 2) 306 | [_] d_02 CL (val: 0) (distance 3) 307 | [_] d_03 CL (val: 0) (distance 4) 308 | [_] d_04 CL (val: 0) (distances [5-6]) 309 | [_] d_05 CL (val: 0) (distances [7-8]) 310 | [_] d_06 CL (val: 0) (distances [9-12]) 311 | [_] d_07 CL (val: 0) (distances [13-16]) 312 | [_] d_08 CL (val: 0) (distances [17-24]) 313 | [5] d_09 CL (val: 2) (distances [25-32]) 314 | [5] d_10 CL (val: 1) (distances [33-48]) 315 | [2] d_11 CL (val: 0) (distances [49-64]) 316 | [5] d_12 CL (val: 2) (distances [65-96]) 317 | [6] 3C < 318 | [6] 73 s 319 | [5] 76 v 320 | [6] 67 g 321 | [4] 20 322 | [6] 78 x 323 | [6] 6D m 324 | [5] 6C l 325 | [6] 6E n 326 | [6] 73 s 327 | [5] 3D = 328 | [4] 22 " 329 | [5] 68 h 330 | [5] 74 t 331 | [5] 74 t 332 | [6] 70 p 333 | [6] 3A : 334 | [4] 2F / 335 | [4] 2F / 336 | [4] 77 w 337 | [4] 77 w 338 | [4] 77 w 339 | [6] 2E . 340 | [4] 77 w 341 | [5] 33 3 342 | [6] 2E . 343 | [6] 6F o 344 | [6] 72 r 345 | [6] 67 g 346 | [4] 2F / 347 | [5] 32 2 348 | [4] 30 0 349 | [4] 30 0 350 | [4] 30 0 351 | [4] 2F / 352 | [10] (3,34) 353 | [4] 22 " 354 | [4] 20 355 | [5] 76 v 356 | [6] 69 i 357 | [6] 65 e 358 | [4] 77 w 359 | [6] 42 B 360 | [6] 6F o 361 | [6] 78 x 362 | [5] 3D = 363 | [4] 22 " 364 | [4] 30 0 365 | [4] 20 366 | [4] 30 0 367 | [4] 20 368 | [6] 35 5 369 | [4] 20 370 | [6] 35 5 371 | [4] 22 " 372 | [6] 3E > 373 | [6] 3C < 374 | [6] 70 p 375 | [6] 61 a 376 | [5] 74 t 377 | [5] 68 h 378 | [4] 20 379 | [6] 66 f 380 | [6] 69 i 381 | [5] 6C l 382 | [5] 6C l 383 | [5] 3D = 384 | [4] 22 " 385 | [6] 72 r 386 | [6] 65 e 387 | [6] 64 d 388 | [4] 22 " 389 | [4] 20 390 | [6] 64 d 391 | [5] 3D = 392 | [4] 22 " 393 | [6] 4D M 394 | [10] (3,30) 395 | [5] 68 h 396 | [5] 33 3 397 | [5] 76 v 398 | [5] 33 3 399 | [6] 48 H 400 | [4] 30 0 401 | [6] 7A z 402 | [4] 22 " 403 | [4] 2F / 404 | [12] (13,34) 405 | [6] 23 # 406 | [4] 30 0 407 | [4] 30 0 408 | [6] 66 f 409 | [11] (6,35) 410 | [5] 32 2 411 | [4] 20 412 | [5] 32 2 413 | [11] (5,35) 414 | [5] 32 2 415 | [11] (5,35) 416 | [13] (4,94) 417 | [6] 3E > 418 | [6] EofB 419 | -------------------------------------------------------------------------------- /tests/fixtures/svg-2-svgo/defdb.txt: -------------------------------------------------------------------------------- 1 | [1] Last block (val: 1) 2 | [2] Dynamic Huffman Tree block (val: 2) 3 | [5] HLIT 267 (val:10) 4 | [5] HDIST 13 (val:12) 5 | [4] HCLEN 18 (val:14) 6 | [3] 16 CLL (val: 4) 7 | [3] 17 CLL (val: 3) 8 | [3] 18 CLL (val: 4) 9 | [3] 0 CLL (val: 2) 10 | [3] 8 CLL (val: 0) 11 | [3] 7 CLL (val: 0) 12 | [3] 9 CLL (val: 0) 13 | [3] 6 CLL (val: 2) 14 | [3] 10 CLL (val: 0) 15 | [3] 5 CLL (val: 3) 16 | [3] 11 CLL (val: 0) 17 | [3] 4 CLL (val: 4) 18 | [3] 12 CLL (val: 0) 19 | [3] 3 CLL (val: 5) 20 | [3] 13 CLL (val: 0) 21 | [3] 2 CLL (val: 6) 22 | [3] 14 CLL (val: 0) 23 | [3] 1 CLL (val: 6) 24 | [_] 15 CLL (val: 0) 25 | [11] ZREP (32 times) 26 | [_] 0x00 CL (val: 0) 27 | [_] 0x01 CL (val: 0) 28 | [_] 0x02 CL (val: 0) 29 | [_] 0x03 CL (val: 0) 30 | [_] 0x04 CL (val: 0) 31 | [_] 0x05 CL (val: 0) 32 | [_] 0x06 CL (val: 0) 33 | [_] 0x07 CL (val: 0) 34 | [_] 0x08 CL (val: 0) 35 | [_] 0x09 CL (val: 0) 36 | [_] 0x0A CL (val: 0) 37 | [_] 0x0B CL (val: 0) 38 | [_] 0x0C CL (val: 0) 39 | [_] 0x0D CL (val: 0) 40 | [_] 0x0E CL (val: 0) 41 | [_] 0x0F CL (val: 0) 42 | [_] 0x10 CL (val: 0) 43 | [_] 0x11 CL (val: 0) 44 | [_] 0x12 CL (val: 0) 45 | [_] 0x13 CL (val: 0) 46 | [_] 0x14 CL (val: 0) 47 | [_] 0x15 CL (val: 0) 48 | [_] 0x16 CL (val: 0) 49 | [_] 0x17 CL (val: 0) 50 | [_] 0x18 CL (val: 0) 51 | [_] 0x19 CL (val: 0) 52 | [_] 0x1A CL (val: 0) 53 | [_] 0x1B CL (val: 0) 54 | [_] 0x1C CL (val: 0) 55 | [_] 0x1D CL (val: 0) 56 | [_] 0x1E CL (val: 0) 57 | [_] 0x1F CL (val: 0) 58 | [4] 0x20 CL (val: 4) 59 | [2] 0x21 CL (val: 0) 60 | [4] 0x22 CL (val: 4) 61 | [2] 0x23 CL (val: 6) 62 | [6] ZREP (10 times) 63 | [_] 0x24 CL (val: 0) 64 | [_] 0x25 CL (val: 0) 65 | [_] 0x26 CL (val: 0) 66 | [_] 0x27 CL (val: 0) 67 | [_] 0x28 CL (val: 0) 68 | [_] 0x29 CL (val: 0) 69 | [_] 0x2A CL (val: 0) 70 | [_] 0x2B CL (val: 0) 71 | [_] 0x2C CL (val: 0) 72 | [_] 0x2D CL (val: 0) 73 | [2] 0x2E CL (val: 6) 74 | [4] 0x2F CL (val: 4) 75 | [4] 0x30 CL (val: 4) 76 | [2] 0x31 CL (val: 6) 77 | [2] 0x32 CL (val: 6) 78 | [2] 0x33 CL (val: 6) 79 | [3] 0x34 CL (val: 5) 80 | [2] 0x35 CL (val: 0) 81 | [2] 0x36 CL (val: 6) 82 | [6] ZREP (3 times) 83 | [_] 0x37 CL (val: 0) 84 | [_] 0x38 CL (val: 0) 85 | [_] 0x39 CL (val: 0) 86 | [2] 0x3A CL (val: 6) 87 | [2] 0x3B CL (val: 0) 88 | [2] 0x3C CL (val: 6) 89 | [3] 0x3D CL (val: 5) 90 | [2] 0x3E CL (val: 6) 91 | [6] ZREP (3 times) 92 | [_] 0x3F CL (val: 0) 93 | [_] 0x40 CL (val: 0) 94 | [_] 0x41 CL (val: 0) 95 | [2] 0x42 CL (val: 6) 96 | [6] ZREP (5 times) 97 | [_] 0x43 CL (val: 0) 98 | [_] 0x44 CL (val: 0) 99 | [_] 0x45 CL (val: 0) 100 | [_] 0x46 CL (val: 0) 101 | [_] 0x47 CL (val: 0) 102 | [2] 0x48 CL (val: 6) 103 | [6] ZREP (4 times) 104 | [_] 0x49 CL (val: 0) 105 | [_] 0x4A CL (val: 0) 106 | [_] 0x4B CL (val: 0) 107 | [_] 0x4C CL (val: 0) 108 | [2] 0x4D CL (val: 6) 109 | [11] ZREP (19 times) 110 | [_] 0x4E CL (val: 0) 111 | [_] 0x4F CL (val: 0) 112 | [_] 0x50 CL (val: 0) 113 | [_] 0x51 CL (val: 0) 114 | [_] 0x52 CL (val: 0) 115 | [_] 0x53 CL (val: 0) 116 | [_] 0x54 CL (val: 0) 117 | [_] 0x55 CL (val: 0) 118 | [_] 0x56 CL (val: 0) 119 | [_] 0x57 CL (val: 0) 120 | [_] 0x58 CL (val: 0) 121 | [_] 0x59 CL (val: 0) 122 | [_] 0x5A CL (val: 0) 123 | [_] 0x5B CL (val: 0) 124 | [_] 0x5C CL (val: 0) 125 | [_] 0x5D CL (val: 0) 126 | [_] 0x5E CL (val: 0) 127 | [_] 0x5F CL (val: 0) 128 | [_] 0x60 CL (val: 0) 129 | [2] 0x61 CL (val: 6) 130 | [2] 0x62 CL (val: 0) 131 | [2] 0x63 CL (val: 0) 132 | [2] 0x64 CL (val: 6) 133 | [6] LREP (3 times) 134 | [_] 0x65 CL (val: 6) 135 | [_] 0x66 CL (val: 6) 136 | [_] 0x67 CL (val: 6) 137 | [3] 0x68 CL (val: 5) 138 | [2] 0x69 CL (val: 6) 139 | [2] 0x6A CL (val: 0) 140 | [2] 0x6B CL (val: 0) 141 | [3] 0x6C CL (val: 5) 142 | [2] 0x6D CL (val: 6) 143 | [6] LREP (3 times) 144 | [_] 0x6E CL (val: 6) 145 | [_] 0x6F CL (val: 6) 146 | [_] 0x70 CL (val: 6) 147 | [2] 0x71 CL (val: 0) 148 | [2] 0x72 CL (val: 6) 149 | [2] 0x73 CL (val: 6) 150 | [3] 0x74 CL (val: 5) 151 | [2] 0x75 CL (val: 0) 152 | [3] 0x76 CL (val: 5) 153 | [4] 0x77 CL (val: 4) 154 | [2] 0x78 CL (val: 6) 155 | [2] 0x79 CL (val: 0) 156 | [2] 0x7A CL (val: 6) 157 | [11] ZREP (133 times) 158 | [_] 0x7B CL (val: 0) 159 | [_] 0x7C CL (val: 0) 160 | [_] 0x7D CL (val: 0) 161 | [_] 0x7E CL (val: 0) 162 | [_] 0x7F CL (val: 0) 163 | [_] 0x80 CL (val: 0) 164 | [_] 0x81 CL (val: 0) 165 | [_] 0x82 CL (val: 0) 166 | [_] 0x83 CL (val: 0) 167 | [_] 0x84 CL (val: 0) 168 | [_] 0x85 CL (val: 0) 169 | [_] 0x86 CL (val: 0) 170 | [_] 0x87 CL (val: 0) 171 | [_] 0x88 CL (val: 0) 172 | [_] 0x89 CL (val: 0) 173 | [_] 0x8A CL (val: 0) 174 | [_] 0x8B CL (val: 0) 175 | [_] 0x8C CL (val: 0) 176 | [_] 0x8D CL (val: 0) 177 | [_] 0x8E CL (val: 0) 178 | [_] 0x8F CL (val: 0) 179 | [_] 0x90 CL (val: 0) 180 | [_] 0x91 CL (val: 0) 181 | [_] 0x92 CL (val: 0) 182 | [_] 0x93 CL (val: 0) 183 | [_] 0x94 CL (val: 0) 184 | [_] 0x95 CL (val: 0) 185 | [_] 0x96 CL (val: 0) 186 | [_] 0x97 CL (val: 0) 187 | [_] 0x98 CL (val: 0) 188 | [_] 0x99 CL (val: 0) 189 | [_] 0x9A CL (val: 0) 190 | [_] 0x9B CL (val: 0) 191 | [_] 0x9C CL (val: 0) 192 | [_] 0x9D CL (val: 0) 193 | [_] 0x9E CL (val: 0) 194 | [_] 0x9F CL (val: 0) 195 | [_] 0xA0 CL (val: 0) 196 | [_] 0xA1 CL (val: 0) 197 | [_] 0xA2 CL (val: 0) 198 | [_] 0xA3 CL (val: 0) 199 | [_] 0xA4 CL (val: 0) 200 | [_] 0xA5 CL (val: 0) 201 | [_] 0xA6 CL (val: 0) 202 | [_] 0xA7 CL (val: 0) 203 | [_] 0xA8 CL (val: 0) 204 | [_] 0xA9 CL (val: 0) 205 | [_] 0xAA CL (val: 0) 206 | [_] 0xAB CL (val: 0) 207 | [_] 0xAC CL (val: 0) 208 | [_] 0xAD CL (val: 0) 209 | [_] 0xAE CL (val: 0) 210 | [_] 0xAF CL (val: 0) 211 | [_] 0xB0 CL (val: 0) 212 | [_] 0xB1 CL (val: 0) 213 | [_] 0xB2 CL (val: 0) 214 | [_] 0xB3 CL (val: 0) 215 | [_] 0xB4 CL (val: 0) 216 | [_] 0xB5 CL (val: 0) 217 | [_] 0xB6 CL (val: 0) 218 | [_] 0xB7 CL (val: 0) 219 | [_] 0xB8 CL (val: 0) 220 | [_] 0xB9 CL (val: 0) 221 | [_] 0xBA CL (val: 0) 222 | [_] 0xBB CL (val: 0) 223 | [_] 0xBC CL (val: 0) 224 | [_] 0xBD CL (val: 0) 225 | [_] 0xBE CL (val: 0) 226 | [_] 0xBF CL (val: 0) 227 | [_] 0xC0 CL (val: 0) 228 | [_] 0xC1 CL (val: 0) 229 | [_] 0xC2 CL (val: 0) 230 | [_] 0xC3 CL (val: 0) 231 | [_] 0xC4 CL (val: 0) 232 | [_] 0xC5 CL (val: 0) 233 | [_] 0xC6 CL (val: 0) 234 | [_] 0xC7 CL (val: 0) 235 | [_] 0xC8 CL (val: 0) 236 | [_] 0xC9 CL (val: 0) 237 | [_] 0xCA CL (val: 0) 238 | [_] 0xCB CL (val: 0) 239 | [_] 0xCC CL (val: 0) 240 | [_] 0xCD CL (val: 0) 241 | [_] 0xCE CL (val: 0) 242 | [_] 0xCF CL (val: 0) 243 | [_] 0xD0 CL (val: 0) 244 | [_] 0xD1 CL (val: 0) 245 | [_] 0xD2 CL (val: 0) 246 | [_] 0xD3 CL (val: 0) 247 | [_] 0xD4 CL (val: 0) 248 | [_] 0xD5 CL (val: 0) 249 | [_] 0xD6 CL (val: 0) 250 | [_] 0xD7 CL (val: 0) 251 | [_] 0xD8 CL (val: 0) 252 | [_] 0xD9 CL (val: 0) 253 | [_] 0xDA CL (val: 0) 254 | [_] 0xDB CL (val: 0) 255 | [_] 0xDC CL (val: 0) 256 | [_] 0xDD CL (val: 0) 257 | [_] 0xDE CL (val: 0) 258 | [_] 0xDF CL (val: 0) 259 | [_] 0xE0 CL (val: 0) 260 | [_] 0xE1 CL (val: 0) 261 | [_] 0xE2 CL (val: 0) 262 | [_] 0xE3 CL (val: 0) 263 | [_] 0xE4 CL (val: 0) 264 | [_] 0xE5 CL (val: 0) 265 | [_] 0xE6 CL (val: 0) 266 | [_] 0xE7 CL (val: 0) 267 | [_] 0xE8 CL (val: 0) 268 | [_] 0xE9 CL (val: 0) 269 | [_] 0xEA CL (val: 0) 270 | [_] 0xEB CL (val: 0) 271 | [_] 0xEC CL (val: 0) 272 | [_] 0xED CL (val: 0) 273 | [_] 0xEE CL (val: 0) 274 | [_] 0xEF CL (val: 0) 275 | [_] 0xF0 CL (val: 0) 276 | [_] 0xF1 CL (val: 0) 277 | [_] 0xF2 CL (val: 0) 278 | [_] 0xF3 CL (val: 0) 279 | [_] 0xF4 CL (val: 0) 280 | [_] 0xF5 CL (val: 0) 281 | [_] 0xF6 CL (val: 0) 282 | [_] 0xF7 CL (val: 0) 283 | [_] 0xF8 CL (val: 0) 284 | [_] 0xF9 CL (val: 0) 285 | [_] 0xFA CL (val: 0) 286 | [_] 0xFB CL (val: 0) 287 | [_] 0xFC CL (val: 0) 288 | [_] 0xFD CL (val: 0) 289 | [_] 0xFE CL (val: 0) 290 | [_] 0xFF CL (val: 0) 291 | [2] EofB CL (val: 6) 292 | [6] LREP (4 times) 293 | [_] l_00 CL (val: 6) (length 3) 294 | [_] l_01 CL (val: 6) (length 4) 295 | [_] l_02 CL (val: 6) (length 5) 296 | [_] l_03 CL (val: 6) (length 6) 297 | [6] ZREP (5 times) 298 | [_] l_04 CL (val: 0) (length 7) 299 | [_] l_05 CL (val: 0) (length 8) 300 | [_] l_06 CL (val: 0) (length 9) 301 | [_] l_07 CL (val: 0) (length 10) 302 | [_] l_08 CL (val: 0) (lengths [11-12]) 303 | [2] l_09 CL (val: 6) (lengths [13-14]) 304 | [2] d_00 CL (val: 0) (distance 1) 305 | [2] d_01 CL (val: 0) (distance 2) 306 | [5] d_02 CL (val: 3) (distance 3) 307 | [6] ZREP (6 times) 308 | [_] d_03 CL (val: 0) (distance 4) 309 | [_] d_04 CL (val: 0) (distances [5-6]) 310 | [_] d_05 CL (val: 0) (distances [7-8]) 311 | [_] d_06 CL (val: 0) (distances [9-12]) 312 | [_] d_07 CL (val: 0) (distances [13-16]) 313 | [_] d_08 CL (val: 0) (distances [17-24]) 314 | [6] d_09 CL (val: 2) (distances [25-32]) 315 | [6] d_10 CL (val: 1) (distances [33-48]) 316 | [2] d_11 CL (val: 0) (distances [49-64]) 317 | [5] d_12 CL (val: 3) (distances [65-96]) 318 | [6] 3C < 319 | [6] 73 s 320 | [5] 76 v 321 | [6] 67 g 322 | [4] 20 323 | [6] 78 x 324 | [6] 6D m 325 | [5] 6C l 326 | [6] 6E n 327 | [6] 73 s 328 | [5] 3D = 329 | [4] 22 " 330 | [5] 68 h 331 | [5] 74 t 332 | [5] 74 t 333 | [6] 70 p 334 | [6] 3A : 335 | [4] 2F / 336 | [4] 2F / 337 | [4] 77 w 338 | [4] 77 w 339 | [4] 77 w 340 | [6] 2E . 341 | [4] 77 w 342 | [6] 33 3 343 | [6] 2E . 344 | [6] 6F o 345 | [6] 72 r 346 | [6] 67 g 347 | [4] 2F / 348 | [6] 32 2 349 | [4] 30 0 350 | [4] 30 0 351 | [4] 30 0 352 | [4] 2F / 353 | [11] (3,34) 354 | [4] 22 " 355 | [4] 20 356 | [5] 76 v 357 | [6] 69 i 358 | [6] 65 e 359 | [4] 77 w 360 | [6] 42 B 361 | [6] 6F o 362 | [6] 78 x 363 | [5] 3D = 364 | [4] 22 " 365 | [4] 30 0 366 | [4] 20 367 | [4] 30 0 368 | [4] 20 369 | [6] 31 1 370 | [9] (4,3) 371 | [4] 22 " 372 | [6] 3E > 373 | [6] 3C < 374 | [6] 70 p 375 | [6] 61 a 376 | [5] 74 t 377 | [5] 68 h 378 | [4] 20 379 | [6] 66 f 380 | [6] 69 i 381 | [5] 6C l 382 | [5] 6C l 383 | [5] 3D = 384 | [4] 22 " 385 | [6] 72 r 386 | [6] 65 e 387 | [6] 64 d 388 | [4] 22 " 389 | [4] 20 390 | [6] 64 d 391 | [5] 3D = 392 | [4] 22 " 393 | [6] 4D M 394 | [11] (3,32) 395 | [5] 68 h 396 | [6] 36 6 397 | [5] 76 v 398 | [6] 36 6 399 | [6] 48 H 400 | [4] 30 0 401 | [6] 7A z 402 | [4] 22 " 403 | [4] 2F / 404 | [12] (13,34) 405 | [6] 23 # 406 | [4] 30 0 407 | [4] 30 0 408 | [6] 66 f 409 | [11] (6,35) 410 | [5] 34 4 411 | [4] 20 412 | [5] 34 4 413 | [11] (5,35) 414 | [5] 34 4 415 | [11] (5,35) 416 | [14] (4,96) 417 | [6] 3E > 418 | [6] EofB 419 | -------------------------------------------------------------------------------- /tests/fixtures/svg-4-unclosed/defdb.txt: -------------------------------------------------------------------------------- 1 | [1] Last block (val: 1) 2 | [2] Dynamic Huffman Tree block (val: 2) 3 | [5] HLIT 267 (val:10) 4 | [5] HDIST 13 (val:12) 5 | [4] HCLEN 18 (val:14) 6 | [3] 16 CLL (val: 4) 7 | [3] 17 CLL (val: 3) 8 | [3] 18 CLL (val: 4) 9 | [3] 0 CLL (val: 2) 10 | [3] 8 CLL (val: 0) 11 | [3] 7 CLL (val: 0) 12 | [3] 9 CLL (val: 0) 13 | [3] 6 CLL (val: 2) 14 | [3] 10 CLL (val: 0) 15 | [3] 5 CLL (val: 3) 16 | [3] 11 CLL (val: 0) 17 | [3] 4 CLL (val: 4) 18 | [3] 12 CLL (val: 0) 19 | [3] 3 CLL (val: 0) 20 | [3] 13 CLL (val: 0) 21 | [3] 2 CLL (val: 5) 22 | [3] 14 CLL (val: 0) 23 | [3] 1 CLL (val: 5) 24 | [_] 15 CLL (val: 0) 25 | [11] ZREP (32 times) 26 | [_] 0x00 CL (val: 0) 27 | [_] 0x01 CL (val: 0) 28 | [_] 0x02 CL (val: 0) 29 | [_] 0x03 CL (val: 0) 30 | [_] 0x04 CL (val: 0) 31 | [_] 0x05 CL (val: 0) 32 | [_] 0x06 CL (val: 0) 33 | [_] 0x07 CL (val: 0) 34 | [_] 0x08 CL (val: 0) 35 | [_] 0x09 CL (val: 0) 36 | [_] 0x0A CL (val: 0) 37 | [_] 0x0B CL (val: 0) 38 | [_] 0x0C CL (val: 0) 39 | [_] 0x0D CL (val: 0) 40 | [_] 0x0E CL (val: 0) 41 | [_] 0x0F CL (val: 0) 42 | [_] 0x10 CL (val: 0) 43 | [_] 0x11 CL (val: 0) 44 | [_] 0x12 CL (val: 0) 45 | [_] 0x13 CL (val: 0) 46 | [_] 0x14 CL (val: 0) 47 | [_] 0x15 CL (val: 0) 48 | [_] 0x16 CL (val: 0) 49 | [_] 0x17 CL (val: 0) 50 | [_] 0x18 CL (val: 0) 51 | [_] 0x19 CL (val: 0) 52 | [_] 0x1A CL (val: 0) 53 | [_] 0x1B CL (val: 0) 54 | [_] 0x1C CL (val: 0) 55 | [_] 0x1D CL (val: 0) 56 | [_] 0x1E CL (val: 0) 57 | [_] 0x1F CL (val: 0) 58 | [4] 0x20 CL (val: 4) 59 | [2] 0x21 CL (val: 0) 60 | [4] 0x22 CL (val: 4) 61 | [2] 0x23 CL (val: 6) 62 | [6] ZREP (10 times) 63 | [_] 0x24 CL (val: 0) 64 | [_] 0x25 CL (val: 0) 65 | [_] 0x26 CL (val: 0) 66 | [_] 0x27 CL (val: 0) 67 | [_] 0x28 CL (val: 0) 68 | [_] 0x29 CL (val: 0) 69 | [_] 0x2A CL (val: 0) 70 | [_] 0x2B CL (val: 0) 71 | [_] 0x2C CL (val: 0) 72 | [_] 0x2D CL (val: 0) 73 | [2] 0x2E CL (val: 6) 74 | [4] 0x2F CL (val: 4) 75 | [4] 0x30 CL (val: 4) 76 | [2] 0x31 CL (val: 0) 77 | [3] 0x32 CL (val: 5) 78 | [3] 0x33 CL (val: 5) 79 | [2] 0x34 CL (val: 0) 80 | [2] 0x35 CL (val: 6) 81 | [6] ZREP (4 times) 82 | [_] 0x36 CL (val: 0) 83 | [_] 0x37 CL (val: 0) 84 | [_] 0x38 CL (val: 0) 85 | [_] 0x39 CL (val: 0) 86 | [2] 0x3A CL (val: 6) 87 | [2] 0x3B CL (val: 0) 88 | [2] 0x3C CL (val: 6) 89 | [3] 0x3D CL (val: 5) 90 | [2] 0x3E CL (val: 6) 91 | [6] ZREP (3 times) 92 | [_] 0x3F CL (val: 0) 93 | [_] 0x40 CL (val: 0) 94 | [_] 0x41 CL (val: 0) 95 | [2] 0x42 CL (val: 6) 96 | [6] ZREP (5 times) 97 | [_] 0x43 CL (val: 0) 98 | [_] 0x44 CL (val: 0) 99 | [_] 0x45 CL (val: 0) 100 | [_] 0x46 CL (val: 0) 101 | [_] 0x47 CL (val: 0) 102 | [2] 0x48 CL (val: 6) 103 | [6] ZREP (4 times) 104 | [_] 0x49 CL (val: 0) 105 | [_] 0x4A CL (val: 0) 106 | [_] 0x4B CL (val: 0) 107 | [_] 0x4C CL (val: 0) 108 | [2] 0x4D CL (val: 6) 109 | [11] ZREP (19 times) 110 | [_] 0x4E CL (val: 0) 111 | [_] 0x4F CL (val: 0) 112 | [_] 0x50 CL (val: 0) 113 | [_] 0x51 CL (val: 0) 114 | [_] 0x52 CL (val: 0) 115 | [_] 0x53 CL (val: 0) 116 | [_] 0x54 CL (val: 0) 117 | [_] 0x55 CL (val: 0) 118 | [_] 0x56 CL (val: 0) 119 | [_] 0x57 CL (val: 0) 120 | [_] 0x58 CL (val: 0) 121 | [_] 0x59 CL (val: 0) 122 | [_] 0x5A CL (val: 0) 123 | [_] 0x5B CL (val: 0) 124 | [_] 0x5C CL (val: 0) 125 | [_] 0x5D CL (val: 0) 126 | [_] 0x5E CL (val: 0) 127 | [_] 0x5F CL (val: 0) 128 | [_] 0x60 CL (val: 0) 129 | [2] 0x61 CL (val: 6) 130 | [2] 0x62 CL (val: 0) 131 | [2] 0x63 CL (val: 0) 132 | [2] 0x64 CL (val: 6) 133 | [6] LREP (3 times) 134 | [_] 0x65 CL (val: 6) 135 | [_] 0x66 CL (val: 6) 136 | [_] 0x67 CL (val: 6) 137 | [3] 0x68 CL (val: 5) 138 | [2] 0x69 CL (val: 6) 139 | [2] 0x6A CL (val: 0) 140 | [2] 0x6B CL (val: 0) 141 | [3] 0x6C CL (val: 5) 142 | [2] 0x6D CL (val: 6) 143 | [6] LREP (3 times) 144 | [_] 0x6E CL (val: 6) 145 | [_] 0x6F CL (val: 6) 146 | [_] 0x70 CL (val: 6) 147 | [2] 0x71 CL (val: 0) 148 | [2] 0x72 CL (val: 6) 149 | [3] 0x73 CL (val: 5) 150 | [3] 0x74 CL (val: 5) 151 | [2] 0x75 CL (val: 0) 152 | [3] 0x76 CL (val: 5) 153 | [4] 0x77 CL (val: 4) 154 | [3] 0x78 CL (val: 5) 155 | [11] ZREP (135 times) 156 | [_] 0x79 CL (val: 0) 157 | [_] 0x7A CL (val: 0) 158 | [_] 0x7B CL (val: 0) 159 | [_] 0x7C CL (val: 0) 160 | [_] 0x7D CL (val: 0) 161 | [_] 0x7E CL (val: 0) 162 | [_] 0x7F CL (val: 0) 163 | [_] 0x80 CL (val: 0) 164 | [_] 0x81 CL (val: 0) 165 | [_] 0x82 CL (val: 0) 166 | [_] 0x83 CL (val: 0) 167 | [_] 0x84 CL (val: 0) 168 | [_] 0x85 CL (val: 0) 169 | [_] 0x86 CL (val: 0) 170 | [_] 0x87 CL (val: 0) 171 | [_] 0x88 CL (val: 0) 172 | [_] 0x89 CL (val: 0) 173 | [_] 0x8A CL (val: 0) 174 | [_] 0x8B CL (val: 0) 175 | [_] 0x8C CL (val: 0) 176 | [_] 0x8D CL (val: 0) 177 | [_] 0x8E CL (val: 0) 178 | [_] 0x8F CL (val: 0) 179 | [_] 0x90 CL (val: 0) 180 | [_] 0x91 CL (val: 0) 181 | [_] 0x92 CL (val: 0) 182 | [_] 0x93 CL (val: 0) 183 | [_] 0x94 CL (val: 0) 184 | [_] 0x95 CL (val: 0) 185 | [_] 0x96 CL (val: 0) 186 | [_] 0x97 CL (val: 0) 187 | [_] 0x98 CL (val: 0) 188 | [_] 0x99 CL (val: 0) 189 | [_] 0x9A CL (val: 0) 190 | [_] 0x9B CL (val: 0) 191 | [_] 0x9C CL (val: 0) 192 | [_] 0x9D CL (val: 0) 193 | [_] 0x9E CL (val: 0) 194 | [_] 0x9F CL (val: 0) 195 | [_] 0xA0 CL (val: 0) 196 | [_] 0xA1 CL (val: 0) 197 | [_] 0xA2 CL (val: 0) 198 | [_] 0xA3 CL (val: 0) 199 | [_] 0xA4 CL (val: 0) 200 | [_] 0xA5 CL (val: 0) 201 | [_] 0xA6 CL (val: 0) 202 | [_] 0xA7 CL (val: 0) 203 | [_] 0xA8 CL (val: 0) 204 | [_] 0xA9 CL (val: 0) 205 | [_] 0xAA CL (val: 0) 206 | [_] 0xAB CL (val: 0) 207 | [_] 0xAC CL (val: 0) 208 | [_] 0xAD CL (val: 0) 209 | [_] 0xAE CL (val: 0) 210 | [_] 0xAF CL (val: 0) 211 | [_] 0xB0 CL (val: 0) 212 | [_] 0xB1 CL (val: 0) 213 | [_] 0xB2 CL (val: 0) 214 | [_] 0xB3 CL (val: 0) 215 | [_] 0xB4 CL (val: 0) 216 | [_] 0xB5 CL (val: 0) 217 | [_] 0xB6 CL (val: 0) 218 | [_] 0xB7 CL (val: 0) 219 | [_] 0xB8 CL (val: 0) 220 | [_] 0xB9 CL (val: 0) 221 | [_] 0xBA CL (val: 0) 222 | [_] 0xBB CL (val: 0) 223 | [_] 0xBC CL (val: 0) 224 | [_] 0xBD CL (val: 0) 225 | [_] 0xBE CL (val: 0) 226 | [_] 0xBF CL (val: 0) 227 | [_] 0xC0 CL (val: 0) 228 | [_] 0xC1 CL (val: 0) 229 | [_] 0xC2 CL (val: 0) 230 | [_] 0xC3 CL (val: 0) 231 | [_] 0xC4 CL (val: 0) 232 | [_] 0xC5 CL (val: 0) 233 | [_] 0xC6 CL (val: 0) 234 | [_] 0xC7 CL (val: 0) 235 | [_] 0xC8 CL (val: 0) 236 | [_] 0xC9 CL (val: 0) 237 | [_] 0xCA CL (val: 0) 238 | [_] 0xCB CL (val: 0) 239 | [_] 0xCC CL (val: 0) 240 | [_] 0xCD CL (val: 0) 241 | [_] 0xCE CL (val: 0) 242 | [_] 0xCF CL (val: 0) 243 | [_] 0xD0 CL (val: 0) 244 | [_] 0xD1 CL (val: 0) 245 | [_] 0xD2 CL (val: 0) 246 | [_] 0xD3 CL (val: 0) 247 | [_] 0xD4 CL (val: 0) 248 | [_] 0xD5 CL (val: 0) 249 | [_] 0xD6 CL (val: 0) 250 | [_] 0xD7 CL (val: 0) 251 | [_] 0xD8 CL (val: 0) 252 | [_] 0xD9 CL (val: 0) 253 | [_] 0xDA CL (val: 0) 254 | [_] 0xDB CL (val: 0) 255 | [_] 0xDC CL (val: 0) 256 | [_] 0xDD CL (val: 0) 257 | [_] 0xDE CL (val: 0) 258 | [_] 0xDF CL (val: 0) 259 | [_] 0xE0 CL (val: 0) 260 | [_] 0xE1 CL (val: 0) 261 | [_] 0xE2 CL (val: 0) 262 | [_] 0xE3 CL (val: 0) 263 | [_] 0xE4 CL (val: 0) 264 | [_] 0xE5 CL (val: 0) 265 | [_] 0xE6 CL (val: 0) 266 | [_] 0xE7 CL (val: 0) 267 | [_] 0xE8 CL (val: 0) 268 | [_] 0xE9 CL (val: 0) 269 | [_] 0xEA CL (val: 0) 270 | [_] 0xEB CL (val: 0) 271 | [_] 0xEC CL (val: 0) 272 | [_] 0xED CL (val: 0) 273 | [_] 0xEE CL (val: 0) 274 | [_] 0xEF CL (val: 0) 275 | [_] 0xF0 CL (val: 0) 276 | [_] 0xF1 CL (val: 0) 277 | [_] 0xF2 CL (val: 0) 278 | [_] 0xF3 CL (val: 0) 279 | [_] 0xF4 CL (val: 0) 280 | [_] 0xF5 CL (val: 0) 281 | [_] 0xF6 CL (val: 0) 282 | [_] 0xF7 CL (val: 0) 283 | [_] 0xF8 CL (val: 0) 284 | [_] 0xF9 CL (val: 0) 285 | [_] 0xFA CL (val: 0) 286 | [_] 0xFB CL (val: 0) 287 | [_] 0xFC CL (val: 0) 288 | [_] 0xFD CL (val: 0) 289 | [_] 0xFE CL (val: 0) 290 | [_] 0xFF CL (val: 0) 291 | [2] EofB CL (val: 6) 292 | [6] LREP (4 times) 293 | [_] l_00 CL (val: 6) (length 3) 294 | [_] l_01 CL (val: 6) (length 4) 295 | [_] l_02 CL (val: 6) (length 5) 296 | [_] l_03 CL (val: 6) (length 6) 297 | [6] ZREP (5 times) 298 | [_] l_04 CL (val: 0) (length 7) 299 | [_] l_05 CL (val: 0) (length 8) 300 | [_] l_06 CL (val: 0) (length 9) 301 | [_] l_07 CL (val: 0) (length 10) 302 | [_] l_08 CL (val: 0) (lengths [11-12]) 303 | [2] l_09 CL (val: 6) (lengths [13-14]) 304 | [6] ZREP (9 times) 305 | [_] d_00 CL (val: 0) (distance 1) 306 | [_] d_01 CL (val: 0) (distance 2) 307 | [_] d_02 CL (val: 0) (distance 3) 308 | [_] d_03 CL (val: 0) (distance 4) 309 | [_] d_04 CL (val: 0) (distances [5-6]) 310 | [_] d_05 CL (val: 0) (distances [7-8]) 311 | [_] d_06 CL (val: 0) (distances [9-12]) 312 | [_] d_07 CL (val: 0) (distances [13-16]) 313 | [_] d_08 CL (val: 0) (distances [17-24]) 314 | [5] d_09 CL (val: 2) (distances [25-32]) 315 | [5] d_10 CL (val: 1) (distances [33-48]) 316 | [2] d_11 CL (val: 0) (distances [49-64]) 317 | [5] d_12 CL (val: 2) (distances [65-96]) 318 | [6] 3C < 319 | [5] 73 s 320 | [5] 76 v 321 | [6] 67 g 322 | [4] 20 323 | [5] 78 x 324 | [6] 6D m 325 | [5] 6C l 326 | [6] 6E n 327 | [5] 73 s 328 | [5] 3D = 329 | [4] 22 " 330 | [5] 68 h 331 | [5] 74 t 332 | [5] 74 t 333 | [6] 70 p 334 | [6] 3A : 335 | [4] 2F / 336 | [4] 2F / 337 | [4] 77 w 338 | [4] 77 w 339 | [4] 77 w 340 | [6] 2E . 341 | [4] 77 w 342 | [5] 33 3 343 | [6] 2E . 344 | [6] 6F o 345 | [6] 72 r 346 | [6] 67 g 347 | [4] 2F / 348 | [5] 32 2 349 | [4] 30 0 350 | [4] 30 0 351 | [4] 30 0 352 | [4] 2F / 353 | [11] (3,34) 354 | [4] 22 " 355 | [4] 20 356 | [5] 76 v 357 | [6] 69 i 358 | [6] 65 e 359 | [4] 77 w 360 | [6] 42 B 361 | [6] 6F o 362 | [5] 78 x 363 | [5] 3D = 364 | [4] 22 " 365 | [4] 30 0 366 | [4] 20 367 | [4] 30 0 368 | [4] 20 369 | [6] 35 5 370 | [4] 20 371 | [6] 35 5 372 | [4] 22 " 373 | [6] 3E > 374 | [6] 3C < 375 | [6] 70 p 376 | [6] 61 a 377 | [5] 74 t 378 | [5] 68 h 379 | [4] 20 380 | [6] 66 f 381 | [6] 69 i 382 | [5] 6C l 383 | [5] 6C l 384 | [5] 3D = 385 | [4] 22 " 386 | [6] 72 r 387 | [6] 65 e 388 | [6] 64 d 389 | [4] 22 " 390 | [4] 20 391 | [6] 64 d 392 | [5] 3D = 393 | [4] 22 " 394 | [6] 4D M 395 | [11] (3,30) 396 | [5] 68 h 397 | [5] 33 3 398 | [5] 76 v 399 | [5] 33 3 400 | [6] 48 H 401 | [4] 30 0 402 | [4] 22 " 403 | [4] 2F / 404 | [12] (13,33) 405 | [6] 23 # 406 | [4] 30 0 407 | [4] 30 0 408 | [6] 66 f 409 | [11] (6,34) 410 | [5] 32 2 411 | [4] 20 412 | [5] 32 2 413 | [11] (5,34) 414 | [5] 32 2 415 | [11] (4,34) 416 | [13] (4,92) 417 | [6] 3E > 418 | [6] EofB 419 | -------------------------------------------------------------------------------- /tests/fixtures/svg-1-original/defdb.txt: -------------------------------------------------------------------------------- 1 | [1] Last block (val: 1) 2 | [2] Dynamic Huffman Tree block (val: 2) 3 | [5] HLIT 272 (val:15) 4 | [5] HDIST 15 (val:14) 5 | [4] HCLEN 16 (val:12) 6 | [3] 16 CLL (val: 0) 7 | [3] 17 CLL (val: 4) 8 | [3] 18 CLL (val: 5) 9 | [3] 0 CLL (val: 2) 10 | [3] 8 CLL (val: 0) 11 | [3] 7 CLL (val: 2) 12 | [3] 9 CLL (val: 0) 13 | [3] 6 CLL (val: 3) 14 | [3] 10 CLL (val: 0) 15 | [3] 5 CLL (val: 3) 16 | [3] 11 CLL (val: 0) 17 | [3] 4 CLL (val: 4) 18 | [3] 12 CLL (val: 0) 19 | [3] 3 CLL (val: 4) 20 | [3] 13 CLL (val: 0) 21 | [3] 2 CLL (val: 5) 22 | [_] 14 CLL (val: 0) 23 | [_] 1 CLL (val: 0) 24 | [_] 15 CLL (val: 0) 25 | [7] ZREP (9 times) 26 | [_] 0x00 CL (val: 0) 27 | [_] 0x01 CL (val: 0) 28 | [_] 0x02 CL (val: 0) 29 | [_] 0x03 CL (val: 0) 30 | [_] 0x04 CL (val: 0) 31 | [_] 0x05 CL (val: 0) 32 | [_] 0x06 CL (val: 0) 33 | [_] 0x07 CL (val: 0) 34 | [_] 0x08 CL (val: 0) 35 | [2] 0x09 CL (val: 7) 36 | [2] 0x0A CL (val: 7) 37 | [12] ZREP (21 times) 38 | [_] 0x0B CL (val: 0) 39 | [_] 0x0C CL (val: 0) 40 | [_] 0x0D CL (val: 0) 41 | [_] 0x0E CL (val: 0) 42 | [_] 0x0F CL (val: 0) 43 | [_] 0x10 CL (val: 0) 44 | [_] 0x11 CL (val: 0) 45 | [_] 0x12 CL (val: 0) 46 | [_] 0x13 CL (val: 0) 47 | [_] 0x14 CL (val: 0) 48 | [_] 0x15 CL (val: 0) 49 | [_] 0x16 CL (val: 0) 50 | [_] 0x17 CL (val: 0) 51 | [_] 0x18 CL (val: 0) 52 | [_] 0x19 CL (val: 0) 53 | [_] 0x1A CL (val: 0) 54 | [_] 0x1B CL (val: 0) 55 | [_] 0x1C CL (val: 0) 56 | [_] 0x1D CL (val: 0) 57 | [_] 0x1E CL (val: 0) 58 | [_] 0x1F CL (val: 0) 59 | [4] 0x20 CL (val: 4) 60 | [2] 0x21 CL (val: 0) 61 | [4] 0x22 CL (val: 4) 62 | [12] ZREP (11 times) 63 | [_] 0x23 CL (val: 0) 64 | [_] 0x24 CL (val: 0) 65 | [_] 0x25 CL (val: 0) 66 | [_] 0x26 CL (val: 0) 67 | [_] 0x27 CL (val: 0) 68 | [_] 0x28 CL (val: 0) 69 | [_] 0x29 CL (val: 0) 70 | [_] 0x2A CL (val: 0) 71 | [_] 0x2B CL (val: 0) 72 | [_] 0x2C CL (val: 0) 73 | [_] 0x2D CL (val: 0) 74 | [3] 0x2E CL (val: 6) 75 | [4] 0x2F CL (val: 4) 76 | [4] 0x30 CL (val: 4) 77 | [2] 0x31 CL (val: 7) 78 | [2] 0x32 CL (val: 7) 79 | [2] 0x33 CL (val: 7) 80 | [3] 0x34 CL (val: 6) 81 | [2] 0x35 CL (val: 0) 82 | [2] 0x36 CL (val: 7) 83 | [7] ZREP (3 times) 84 | [_] 0x37 CL (val: 0) 85 | [_] 0x38 CL (val: 0) 86 | [_] 0x39 CL (val: 0) 87 | [2] 0x3A CL (val: 7) 88 | [2] 0x3B CL (val: 0) 89 | [3] 0x3C CL (val: 5) 90 | [3] 0x3D CL (val: 5) 91 | [3] 0x3E CL (val: 6) 92 | [7] ZREP (3 times) 93 | [_] 0x3F CL (val: 0) 94 | [_] 0x40 CL (val: 0) 95 | [_] 0x41 CL (val: 0) 96 | [2] 0x42 CL (val: 7) 97 | [12] ZREP (31 times) 98 | [_] 0x43 CL (val: 0) 99 | [_] 0x44 CL (val: 0) 100 | [_] 0x45 CL (val: 0) 101 | [_] 0x46 CL (val: 0) 102 | [_] 0x47 CL (val: 0) 103 | [_] 0x48 CL (val: 0) 104 | [_] 0x49 CL (val: 0) 105 | [_] 0x4A CL (val: 0) 106 | [_] 0x4B CL (val: 0) 107 | [_] 0x4C CL (val: 0) 108 | [_] 0x4D CL (val: 0) 109 | [_] 0x4E CL (val: 0) 110 | [_] 0x4F CL (val: 0) 111 | [_] 0x50 CL (val: 0) 112 | [_] 0x51 CL (val: 0) 113 | [_] 0x52 CL (val: 0) 114 | [_] 0x53 CL (val: 0) 115 | [_] 0x54 CL (val: 0) 116 | [_] 0x55 CL (val: 0) 117 | [_] 0x56 CL (val: 0) 118 | [_] 0x57 CL (val: 0) 119 | [_] 0x58 CL (val: 0) 120 | [_] 0x59 CL (val: 0) 121 | [_] 0x5A CL (val: 0) 122 | [_] 0x5B CL (val: 0) 123 | [_] 0x5C CL (val: 0) 124 | [_] 0x5D CL (val: 0) 125 | [_] 0x5E CL (val: 0) 126 | [_] 0x5F CL (val: 0) 127 | [_] 0x60 CL (val: 0) 128 | [_] 0x61 CL (val: 0) 129 | [2] 0x62 CL (val: 7) 130 | [2] 0x63 CL (val: 7) 131 | [3] 0x64 CL (val: 6) 132 | [4] 0x65 CL (val: 4) 133 | [2] 0x66 CL (val: 7) 134 | [3] 0x67 CL (val: 5) 135 | [3] 0x68 CL (val: 5) 136 | [3] 0x69 CL (val: 5) 137 | [2] 0x6A CL (val: 0) 138 | [2] 0x6B CL (val: 0) 139 | [3] 0x6C CL (val: 5) 140 | [2] 0x6D CL (val: 7) 141 | [2] 0x6E CL (val: 7) 142 | [3] 0x6F CL (val: 6) 143 | [2] 0x70 CL (val: 7) 144 | [2] 0x71 CL (val: 0) 145 | [3] 0x72 CL (val: 5) 146 | [3] 0x73 CL (val: 6) 147 | [4] 0x74 CL (val: 4) 148 | [2] 0x75 CL (val: 7) 149 | [3] 0x76 CL (val: 6) 150 | [4] 0x77 CL (val: 4) 151 | [3] 0x78 CL (val: 6) 152 | [2] 0x79 CL (val: 7) 153 | [12] ZREP (134 times) 154 | [_] 0x7A CL (val: 0) 155 | [_] 0x7B CL (val: 0) 156 | [_] 0x7C CL (val: 0) 157 | [_] 0x7D CL (val: 0) 158 | [_] 0x7E CL (val: 0) 159 | [_] 0x7F CL (val: 0) 160 | [_] 0x80 CL (val: 0) 161 | [_] 0x81 CL (val: 0) 162 | [_] 0x82 CL (val: 0) 163 | [_] 0x83 CL (val: 0) 164 | [_] 0x84 CL (val: 0) 165 | [_] 0x85 CL (val: 0) 166 | [_] 0x86 CL (val: 0) 167 | [_] 0x87 CL (val: 0) 168 | [_] 0x88 CL (val: 0) 169 | [_] 0x89 CL (val: 0) 170 | [_] 0x8A CL (val: 0) 171 | [_] 0x8B CL (val: 0) 172 | [_] 0x8C CL (val: 0) 173 | [_] 0x8D CL (val: 0) 174 | [_] 0x8E CL (val: 0) 175 | [_] 0x8F CL (val: 0) 176 | [_] 0x90 CL (val: 0) 177 | [_] 0x91 CL (val: 0) 178 | [_] 0x92 CL (val: 0) 179 | [_] 0x93 CL (val: 0) 180 | [_] 0x94 CL (val: 0) 181 | [_] 0x95 CL (val: 0) 182 | [_] 0x96 CL (val: 0) 183 | [_] 0x97 CL (val: 0) 184 | [_] 0x98 CL (val: 0) 185 | [_] 0x99 CL (val: 0) 186 | [_] 0x9A CL (val: 0) 187 | [_] 0x9B CL (val: 0) 188 | [_] 0x9C CL (val: 0) 189 | [_] 0x9D CL (val: 0) 190 | [_] 0x9E CL (val: 0) 191 | [_] 0x9F CL (val: 0) 192 | [_] 0xA0 CL (val: 0) 193 | [_] 0xA1 CL (val: 0) 194 | [_] 0xA2 CL (val: 0) 195 | [_] 0xA3 CL (val: 0) 196 | [_] 0xA4 CL (val: 0) 197 | [_] 0xA5 CL (val: 0) 198 | [_] 0xA6 CL (val: 0) 199 | [_] 0xA7 CL (val: 0) 200 | [_] 0xA8 CL (val: 0) 201 | [_] 0xA9 CL (val: 0) 202 | [_] 0xAA CL (val: 0) 203 | [_] 0xAB CL (val: 0) 204 | [_] 0xAC CL (val: 0) 205 | [_] 0xAD CL (val: 0) 206 | [_] 0xAE CL (val: 0) 207 | [_] 0xAF CL (val: 0) 208 | [_] 0xB0 CL (val: 0) 209 | [_] 0xB1 CL (val: 0) 210 | [_] 0xB2 CL (val: 0) 211 | [_] 0xB3 CL (val: 0) 212 | [_] 0xB4 CL (val: 0) 213 | [_] 0xB5 CL (val: 0) 214 | [_] 0xB6 CL (val: 0) 215 | [_] 0xB7 CL (val: 0) 216 | [_] 0xB8 CL (val: 0) 217 | [_] 0xB9 CL (val: 0) 218 | [_] 0xBA CL (val: 0) 219 | [_] 0xBB CL (val: 0) 220 | [_] 0xBC CL (val: 0) 221 | [_] 0xBD CL (val: 0) 222 | [_] 0xBE CL (val: 0) 223 | [_] 0xBF CL (val: 0) 224 | [_] 0xC0 CL (val: 0) 225 | [_] 0xC1 CL (val: 0) 226 | [_] 0xC2 CL (val: 0) 227 | [_] 0xC3 CL (val: 0) 228 | [_] 0xC4 CL (val: 0) 229 | [_] 0xC5 CL (val: 0) 230 | [_] 0xC6 CL (val: 0) 231 | [_] 0xC7 CL (val: 0) 232 | [_] 0xC8 CL (val: 0) 233 | [_] 0xC9 CL (val: 0) 234 | [_] 0xCA CL (val: 0) 235 | [_] 0xCB CL (val: 0) 236 | [_] 0xCC CL (val: 0) 237 | [_] 0xCD CL (val: 0) 238 | [_] 0xCE CL (val: 0) 239 | [_] 0xCF CL (val: 0) 240 | [_] 0xD0 CL (val: 0) 241 | [_] 0xD1 CL (val: 0) 242 | [_] 0xD2 CL (val: 0) 243 | [_] 0xD3 CL (val: 0) 244 | [_] 0xD4 CL (val: 0) 245 | [_] 0xD5 CL (val: 0) 246 | [_] 0xD6 CL (val: 0) 247 | [_] 0xD7 CL (val: 0) 248 | [_] 0xD8 CL (val: 0) 249 | [_] 0xD9 CL (val: 0) 250 | [_] 0xDA CL (val: 0) 251 | [_] 0xDB CL (val: 0) 252 | [_] 0xDC CL (val: 0) 253 | [_] 0xDD CL (val: 0) 254 | [_] 0xDE CL (val: 0) 255 | [_] 0xDF CL (val: 0) 256 | [_] 0xE0 CL (val: 0) 257 | [_] 0xE1 CL (val: 0) 258 | [_] 0xE2 CL (val: 0) 259 | [_] 0xE3 CL (val: 0) 260 | [_] 0xE4 CL (val: 0) 261 | [_] 0xE5 CL (val: 0) 262 | [_] 0xE6 CL (val: 0) 263 | [_] 0xE7 CL (val: 0) 264 | [_] 0xE8 CL (val: 0) 265 | [_] 0xE9 CL (val: 0) 266 | [_] 0xEA CL (val: 0) 267 | [_] 0xEB CL (val: 0) 268 | [_] 0xEC CL (val: 0) 269 | [_] 0xED CL (val: 0) 270 | [_] 0xEE CL (val: 0) 271 | [_] 0xEF CL (val: 0) 272 | [_] 0xF0 CL (val: 0) 273 | [_] 0xF1 CL (val: 0) 274 | [_] 0xF2 CL (val: 0) 275 | [_] 0xF3 CL (val: 0) 276 | [_] 0xF4 CL (val: 0) 277 | [_] 0xF5 CL (val: 0) 278 | [_] 0xF6 CL (val: 0) 279 | [_] 0xF7 CL (val: 0) 280 | [_] 0xF8 CL (val: 0) 281 | [_] 0xF9 CL (val: 0) 282 | [_] 0xFA CL (val: 0) 283 | [_] 0xFB CL (val: 0) 284 | [_] 0xFC CL (val: 0) 285 | [_] 0xFD CL (val: 0) 286 | [_] 0xFE CL (val: 0) 287 | [_] 0xFF CL (val: 0) 288 | [2] EofB CL (val: 7) 289 | [2] l_00 CL (val: 7) (length 3) 290 | [3] l_01 CL (val: 5) (length 4) 291 | [3] l_02 CL (val: 5) (length 5) 292 | [7] ZREP (5 times) 293 | [_] l_03 CL (val: 0) (length 6) 294 | [_] l_04 CL (val: 0) (length 7) 295 | [_] l_05 CL (val: 0) (length 8) 296 | [_] l_06 CL (val: 0) (length 9) 297 | [_] l_07 CL (val: 0) (length 10) 298 | [2] l_08 CL (val: 7) (lengths [11-12]) 299 | [7] ZREP (5 times) 300 | [_] l_09 CL (val: 0) (lengths [13-14]) 301 | [_] l_10 CL (val: 0) (lengths [15-16]) 302 | [_] l_11 CL (val: 0) (lengths [17-18]) 303 | [_] l_12 CL (val: 0) (lengths [19-22]) 304 | [_] l_13 CL (val: 0) (lengths [23-26]) 305 | [2] l_14 CL (val: 7) (lengths [27-30]) 306 | [2] d_00 CL (val: 0) (distance 1) 307 | [2] d_01 CL (val: 0) (distance 2) 308 | [4] d_02 CL (val: 3) (distance 3) 309 | [2] d_03 CL (val: 0) (distance 4) 310 | [4] d_04 CL (val: 3) (distances [5-6]) 311 | [2] d_05 CL (val: 0) (distances [7-8]) 312 | [4] d_06 CL (val: 3) (distances [9-12]) 313 | [2] d_07 CL (val: 0) (distances [13-16]) 314 | [4] d_08 CL (val: 3) (distances [17-24]) 315 | [2] d_09 CL (val: 0) (distances [25-32]) 316 | [4] d_10 CL (val: 3) (distances [33-48]) 317 | [5] d_11 CL (val: 2) (distances [49-64]) 318 | [2] d_12 CL (val: 0) (distances [65-96]) 319 | [2] d_13 CL (val: 0) (distances [97-128]) 320 | [4] d_14 CL (val: 3) (distances [129-192]) 321 | [5] 3C < 322 | [6] 73 s 323 | [6] 76 v 324 | [5] 67 g 325 | [4] 20 326 | [6] 78 x 327 | [7] 6D m 328 | [5] 6C l 329 | [7] 6E n 330 | [6] 73 s 331 | [5] 3D = 332 | [4] 22 " 333 | [5] 68 h 334 | [4] 74 t 335 | [4] 74 t 336 | [7] 70 p 337 | [7] 3A : 338 | [4] 2F / 339 | [4] 2F / 340 | [4] 77 w 341 | [4] 77 w 342 | [4] 77 w 343 | [6] 2E . 344 | [4] 77 w 345 | [7] 33 3 346 | [6] 2E . 347 | [6] 6F o 348 | [5] 72 r 349 | [5] 67 g 350 | [4] 2F / 351 | [7] 32 2 352 | [4] 30 0 353 | [4] 30 0 354 | [4] 30 0 355 | [4] 2F / 356 | [14] (3,34) 357 | [4] 22 " 358 | [4] 20 359 | [6] 76 v 360 | [5] 69 i 361 | [4] 65 e 362 | [4] 77 w 363 | [7] 42 B 364 | [6] 6F o 365 | [6] 78 x 366 | [5] 3D = 367 | [4] 22 " 368 | [4] 30 0 369 | [4] 20 370 | [4] 30 0 371 | [4] 20 372 | [7] 31 1 373 | [8] (4,3) 374 | [4] 22 " 375 | [6] 3E > 376 | [7] 0A 377 | [7] 09 378 | [5] 3C < 379 | [5] 72 r 380 | [4] 65 e 381 | [7] 63 c 382 | [4] 74 t 383 | [4] 20 384 | [11] (4,22) 385 | [4] 22 " 386 | [4] 20 387 | [7] 79 y 388 | [9] (5,6) 389 | [4] 77 w 390 | [5] 69 i 391 | [6] 64 d 392 | [4] 74 t 393 | [5] 68 h 394 | [5] 3D = 395 | [4] 22 " 396 | [7] 36 6 397 | [4] 22 " 398 | [4] 20 399 | [5] 68 h 400 | [4] 65 e 401 | [5] 69 i 402 | [5] 67 g 403 | [5] 68 h 404 | [4] 74 t 405 | [10] (5,11) 406 | [7] 66 f 407 | [5] 69 i 408 | [5] 6C l 409 | [5] 6C l 410 | [5] 3D = 411 | [4] 22 " 412 | [5] 72 r 413 | [4] 65 e 414 | [6] 64 d 415 | [4] 22 " 416 | [4] 20 417 | [4] 2F / 418 | [14] (12,54) 419 | [6] 34 4 420 | [11] (5,54) 421 | [6] 34 4 422 | [15] (29,54) 423 | [7] 62 b 424 | [5] 6C l 425 | [7] 75 u 426 | [4] 65 e 427 | [11] (5,55) 428 | [5] 3C < 429 | [14] (4,137) 430 | [6] 3E > 431 | [7] EofB 432 | -------------------------------------------------------------------------------- /tests/fixtures/simple/binExpected.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | GZ Heatmap 7 | 16 | 17 | 18 |
19 | 20 | 146 | 147 |

Stats

148 |
149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 |
CountCompressed bytesExpanded bytes
Literals1313 B13 B
LZ77 Backrefs59 B30 B
Code Length tables0 B
Other compression metadata2 B
185 |
186 |

187 |
188 |

Heatmap

189 |

190 | Each character in the gzip stream is given a color representing 191 | approximately the number of bytes it takes up in the gzip stream. 192 | Open the color legend to see what colors correspond to what byte 193 | sizes. 194 |

195 |
196 | Color legend 197 |
    198 |
  1. <1 B
  2. 199 |
  3. <2 B
  4. 200 |
  5. <3 B
  6. 201 |
  7. <4 B
  8. 202 |
  9. <5 B
  10. 203 |
  11. <6 B
  12. 204 |
  13. <7 B
  14. 205 |
  15. <8 B
  16. 206 |
  17. <9 B
  18. 207 |
  19. <10 B
  20. 208 |
  21. <11 B
  22. 209 |
  23. <12 B
  24. 210 |
  25. <13 B
  26. 211 |
  27. <14 B
  28. 212 |
  29. <15 B
  30. 213 |
  31. <16 B
  32. 214 |
  33. >=17 B
  34. 215 |
216 |
217 |
218 |
219 | h
220 | a
221 | m
222 |  
223 | h
224 | a
225 | m
226 | b
227 | u
228 | r
229 | g
230 | e
231 | r
232 |  ham
233 |  ha
234 |  hamburg
235 |  hamb
236 |  hamburger
237 | 
238 |
239 |
240 |
241 |

Back references

242 |

243 | Orange text represents literal text from the gzip stream. Blue text 244 | is test that is a back reference to previous text in the gzip 245 | stream. Hover over a back references to see what text it references. 246 |

247 |
248 | 249 |
250 | h
251 | a
252 | m
253 |  
254 | h
255 | a
256 | m
257 | b
258 | u
259 | r
260 | g
261 | e
262 | r
263 | 
264 |  
265 | h
266 | a
267 | m
268 | 
269 |  
270 | h
271 | a
272 | 
273 |  
274 | h
275 | a
276 | m
277 | b
278 | u
279 | r
280 | g
281 | 
282 |  
283 | h
284 | a
285 | m
286 | b
287 | 
288 |  
289 | h
290 | a
291 | m
292 | b
293 | u
294 | r
295 | g
296 | e
297 | r
298 | 
299 |
300 |
301 |
302 |
303 | 304 | 305 | 311 | 312 | 313 | -------------------------------------------------------------------------------- /tests/utils/log.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import { getLZ77TotalBitSize } from "../../src/utils.js"; 4 | 5 | /** 6 | * @param {Metadata} metadata 7 | */ 8 | export function logMetadata(metadata) { 9 | console.log(formatMetadata(metadata)); 10 | } 11 | 12 | const lengthCodeLabels = [ 13 | "3", 14 | "4", 15 | "5", 16 | "6", 17 | "7", 18 | "8", 19 | "9", 20 | "10", 21 | "[11-12]", 22 | "[13-14]", 23 | "[15-16]", 24 | "[17-18]", 25 | "[19-22]", 26 | "[23-26]", 27 | "[27-30]", 28 | ]; 29 | 30 | const distanceCodeLabels = [ 31 | "1", 32 | "2", 33 | "3", 34 | "4", 35 | "[5-6]", 36 | "[7-8]", 37 | "[9-12]", 38 | "[13-16]", 39 | "[17-24]", 40 | "[25-32]", 41 | "[33-48]", 42 | "[49-64]", 43 | "[65-96]", 44 | "[97-128]", 45 | "[129-192]", 46 | ]; 47 | 48 | /** 49 | * @param {Metadata} metadata 50 | */ 51 | export function formatMetadata(metadata) { 52 | let out = ""; 53 | 54 | for (let info of metadata) { 55 | switch (info.type) { 56 | case "bfinal": 57 | let bfinal = info.value.decoded; 58 | out += log({ 59 | size: info.value.size, 60 | msg: 61 | bfinal == 1 62 | ? `Last block (val: ${bfinal})` 63 | : `Not final (val: ${bfinal})`, 64 | }); 65 | break; 66 | 67 | case "btype": 68 | let btype = info.value.decoded; 69 | let msg = 70 | btype == 0 71 | ? `Uncompressed block (val: ${btype})` 72 | : btype == 1 73 | ? `Fixed Huffman Tree block (val: ${btype})` 74 | : `Dynamic Huffman Tree block (val: ${btype})`; 75 | 76 | out += log({ size: info.value.size, msg }); 77 | break; 78 | 79 | case "hlit": 80 | let hlit = info.value.decoded; 81 | out += log({ 82 | size: info.value.size, 83 | msg: `HLIT ${hlit.toString().padStart(3)} (val:${hlit - 257})`, 84 | }); 85 | break; 86 | 87 | case "hdist": 88 | let hdist = info.value.decoded; 89 | out += log({ 90 | size: info.value.size, 91 | msg: `HDIST ${hdist.toString().padStart(3)} (val:${hdist - 1})`, 92 | }); 93 | break; 94 | 95 | case "hclen": 96 | let hclen = info.value.decoded; 97 | out += log({ 98 | size: info.value.size, 99 | msg: `HCLEN ${hclen.toString().padStart(3)} (val:${hclen - 4})`, 100 | }); 101 | break; 102 | 103 | case "code_length": { 104 | out += log({ 105 | size: info.value.size, 106 | msg: getCodeLengthMessage( 107 | info.category, 108 | info.char, 109 | info.huffmanCodeLength 110 | ), 111 | }); 112 | break; 113 | } 114 | case "repeat_code_length": { 115 | let label = info.huffmanCodeLength == 0 ? "ZREP" : "LREP"; 116 | out += log({ 117 | size: info.symbol.size + info.repeatCount.size, 118 | msg: `${label} (${info.repeatCount.decoded} times)`, 119 | }); 120 | 121 | for (let symbol of info.chars) { 122 | out += log({ 123 | size: null, 124 | msg: getCodeLengthMessage( 125 | info.category, 126 | symbol, 127 | info.huffmanCodeLength 128 | ), 129 | }); 130 | } 131 | 132 | break; 133 | } 134 | case "literal": { 135 | let sym = info.value.decoded; 136 | out += log({ 137 | size: info.value.size, 138 | msg: `${toHex(sym)} ${toChar(sym)}`, 139 | }); 140 | break; 141 | } 142 | case "lz77": { 143 | out += log({ 144 | size: getLZ77TotalBitSize(info), 145 | msg: `(${info.length.value},${info.dist.value})`, 146 | }); 147 | break; 148 | } 149 | case "block_end": 150 | out += log({ 151 | size: info.value.size, 152 | msg: `EofB`, 153 | }); 154 | break; 155 | } 156 | } 157 | 158 | return out; 159 | } 160 | 161 | /** 162 | * @param {{ size: number | null; msg: string; }} props 163 | */ 164 | function log({ size, msg }) { 165 | if (size == null) { 166 | return ` [_] ${msg}\n`; 167 | } else if (size < 10) { 168 | return ` [${size}] ${msg}\n`; 169 | } else { 170 | return `[${size}] ${msg}\n`; 171 | } 172 | } 173 | 174 | /** 175 | * @param {CodeLengthCategory} category 176 | * @param {number} symbol 177 | * @param {number} huffmanCodeLength 178 | */ 179 | function getCodeLengthMessage(category, symbol, huffmanCodeLength) { 180 | let symbolLabel; 181 | if (category == "run_length_table") { 182 | symbolLabel = symbol.toString(10).padStart(2); 183 | } else if (category == "lz77_length_table") { 184 | if (symbol < 256) { 185 | symbolLabel = `0x${toHex(symbol)}`; 186 | } else if (symbol == 256) { 187 | symbolLabel = `EofB`; 188 | } else { 189 | symbolLabel = `l_${(symbol - 257).toString(10).padStart(2, "0")}`; 190 | } 191 | } else { 192 | symbolLabel = `d_${symbol.toString(10).padStart(2, "0")}`; 193 | } 194 | 195 | let suffix = ""; 196 | if (category == "lz77_length_table" && symbol > 256) { 197 | let index = symbol - 257; 198 | let label = "length" + (index < 8 ? "" : "s"); 199 | suffix = ` (${label} ${lengthCodeLabels[index]})`; 200 | } else if (category == "lz77_dist_table") { 201 | let label = "distance" + (symbol < 4 ? "" : "s"); 202 | suffix = ` (${label} ${distanceCodeLabels[symbol]})`; 203 | } 204 | 205 | let cat = category == "run_length_table" ? "CLL" : "CL"; 206 | return `${symbolLabel} ${cat} (val: ${huffmanCodeLength})${suffix}`; 207 | } 208 | 209 | /** 210 | * @param {number} num 211 | * @returns {string} 212 | */ 213 | function toHex(num) { 214 | return num.toString(16).toUpperCase().padStart(2, "0"); 215 | } 216 | 217 | /** 218 | * @param {number} num 219 | * @returns {string} 220 | */ 221 | function toChar(num) { 222 | let ch = String.fromCharCode(num); 223 | if (/\s/.test(ch)) { 224 | return JSON.stringify(ch).slice(1, -1); 225 | } else { 226 | return ch; 227 | } 228 | } 229 | 230 | /** 231 | * @param {Uint8Array} uint8 232 | */ 233 | export function uint8ToBitString(uint8) { 234 | return Array.from(uint8) 235 | .map((v) => v.toString(2)) 236 | .join(""); 237 | } 238 | 239 | /** 240 | * @param {number} num 241 | */ 242 | function toByteStr(num) { 243 | return num.toString(2).padStart(8, "0"); 244 | } 245 | 246 | /** 247 | * @param {number} value 248 | * @param {number} length 249 | */ 250 | function invertBits(value, length) { 251 | let invertedValue = 0; 252 | while (length--) { 253 | invertedValue = (invertedValue << 1) | (value & 1); 254 | value >>>= 1; 255 | } 256 | 257 | return invertedValue; 258 | } 259 | 260 | /** 261 | * @param {Metadata} metadata 262 | * @returns {number} 263 | */ 264 | export function getTotalEncodedBitSize(metadata) { 265 | return metadata.reduce((sum, datum) => { 266 | if (datum.type == "lz77") { 267 | return sum + getLZ77TotalBitSize(datum); 268 | } else if (datum.type == "repeat_code_length") { 269 | return sum + datum.symbol.size + datum.repeatCount.size; 270 | } else if (datum.type == "gzip_header" || datum.type == "gzip_footer") { 271 | return sum + datum.bytes.length * 8; 272 | } else { 273 | return sum + datum.value.size; 274 | } 275 | }, 0); 276 | } 277 | 278 | /** 279 | * @param {Metadata} metadata 280 | * @param {Uint8Array} inputUint8 281 | * @returns {Uint8Array} 282 | */ 283 | export function reconstructBinary(metadata, inputUint8) { 284 | const input = Array.from(inputUint8); 285 | 286 | // Relevant section from spec: 287 | // 3.1.1. Packing into bytes 288 | // 289 | // This document does not address the issue of the order in which bits of a 290 | // byte are transmitted on a bit-sequential medium, since the final data 291 | // format described here is byte- rather than bit-oriented. However, we 292 | // describe the compressed block format in below, as a sequence of data 293 | // elements of various bit lengths, not a sequence of bytes. We must 294 | // therefore specify how to pack these data elements into bytes to form the 295 | // final compressed byte sequence: 296 | // 297 | // * Data elements are packed into bytes in order of 298 | // increasing bit number within the byte, i.e., starting 299 | // with the least-significant bit of the byte. 300 | // * Data elements other than Huffman codes are packed 301 | // starting with the least-significant bit of the data 302 | // element. 303 | // * Huffman codes are packed starting with the most- 304 | // significant bit of the code. 305 | // 306 | // In other words, if one were to print out the compressed data as a sequence 307 | // of bytes, starting with the first byte at the *right* margin and 308 | // proceeding to the *left*, with the most- significant bit of each byte on 309 | // the left as usual, one would be able to parse the result from right to 310 | // left, with fixed-width elements in the correct MSB-to-LSB order and 311 | // Huffman codes in bit-reversed order (i.e., with the first bit of the code 312 | // in the relative LSB position). 313 | 314 | let byteSize = Math.ceil(getTotalEncodedBitSize(metadata) / 8); 315 | 316 | let resultIndex = 0; 317 | let byteBuffer = 0; 318 | let bitCount = 0; 319 | let result = new Uint8Array(byteSize); 320 | 321 | /** @type {(bits: number, length: number) => void} */ 322 | const writeBitsToResult = (bits, length) => { 323 | while (length--) { 324 | let bitToSet = bits & 1; 325 | bits = bits >> 1; 326 | 327 | byteBuffer = byteBuffer | (bitToSet << bitCount); 328 | bitCount++; 329 | 330 | if (bitCount == 8) { 331 | if (byteBuffer !== input[resultIndex]) { 332 | throw new Error( 333 | `Expected ${toByteStr(byteBuffer)} to be ${toByteStr( 334 | input[resultIndex] 335 | )} at index ${resultIndex}.` 336 | ); 337 | } 338 | 339 | result.set([byteBuffer], resultIndex); 340 | resultIndex++; 341 | byteBuffer = bitCount = 0; 342 | } 343 | } 344 | }; 345 | 346 | for (let datum of metadata) { 347 | switch (datum.type) { 348 | case "gzip_header": 349 | result.set(datum.bytes, resultIndex); 350 | resultIndex += datum.bytes.length; 351 | break; 352 | case "gzip_footer": 353 | if (bitCount > 0) { 354 | result.set([byteBuffer], resultIndex); 355 | resultIndex++; 356 | byteBuffer = bitCount = 0; 357 | } 358 | 359 | result.set(datum.bytes, resultIndex); 360 | resultIndex += datum.bytes.length; 361 | break; 362 | case "bfinal": 363 | case "btype": 364 | case "hlit": 365 | case "hdist": 366 | case "hclen": 367 | writeBitsToResult(datum.value.bits, datum.value.size); 368 | break; 369 | case "block_end": 370 | case "literal": { 371 | let datumSize = datum.value.size; 372 | let datumValue = invertBits(datum.value.bits, datumSize); 373 | writeBitsToResult(datumValue, datumSize); 374 | break; 375 | } 376 | case "code_length": { 377 | let datumLength = datum.value.size; 378 | let datumValue = datum.value.bits; 379 | if (datum.category !== "run_length_table") { 380 | datumValue = invertBits(datumValue, datumLength); 381 | } 382 | 383 | writeBitsToResult(datumValue, datumLength); 384 | break; 385 | } 386 | case "repeat_code_length": { 387 | let invertedBits = invertBits(datum.symbol.bits, datum.symbol.size); 388 | writeBitsToResult(invertedBits, datum.symbol.size); 389 | writeBitsToResult(datum.repeatCount.bits, datum.repeatCount.size); 390 | break; 391 | } 392 | case "lz77": { 393 | let info = datum.length; 394 | let invertedValue = invertBits(info.symbol.bits, info.symbol.size); 395 | writeBitsToResult(invertedValue, info.symbol.size); 396 | writeBitsToResult(info.extraBits.bits, info.extraBits.size); 397 | 398 | info = datum.dist; 399 | invertedValue = invertBits(info.symbol.bits, info.symbol.size); 400 | writeBitsToResult(invertedValue, info.symbol.size); 401 | writeBitsToResult(info.extraBits.bits, info.extraBits.size); 402 | break; 403 | } 404 | default: 405 | assertNever( 406 | datum, 407 | `Metadata type not handled: ${JSON.stringify(datum)}` 408 | ); 409 | } 410 | } 411 | 412 | return result; 413 | } 414 | 415 | /** 416 | * @param {never} val 417 | * @param {string} msg 418 | */ 419 | function assertNever(val, msg) { 420 | throw new Error(msg); 421 | } 422 | -------------------------------------------------------------------------------- /tests/fixtures/svg-7-hex/binExpected.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | GZ Heatmap 7 | 16 | 17 | 18 |
19 | 20 | 146 | 147 |

Stats

148 |
149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 |
CountCompressed bytesExpanded bytes
Literals9357 B93 B
LZ77 Backrefs69 B41 B
Code Length tables34 B
Other compression metadata3 B
185 |
186 |

187 |
188 |

Heatmap

189 |

190 | Each character in the gzip stream is given a color representing 191 | approximately the number of bytes it takes up in the gzip stream. 192 | Open the color legend to see what colors correspond to what byte 193 | sizes. 194 |

195 |
196 | Color legend 197 |
    198 |
  1. <1 B
  2. 199 |
  3. <2 B
  4. 200 |
  5. <3 B
  6. 201 |
  7. <4 B
  8. 202 |
  9. <5 B
  10. 203 |
  11. <6 B
  12. 204 |
  13. <7 B
  14. 205 |
  15. <8 B
  16. 206 |
  17. <9 B
  18. 207 |
  19. <10 B
  20. 208 |
  21. <11 B
  22. 209 |
  23. <12 B
  24. 210 |
  25. <13 B
  26. 211 |
  27. <14 B
  28. 212 |
  29. <15 B
  30. 213 |
  31. <16 B
  32. 214 |
  33. >=17 B
  34. 215 |
216 |
217 |
218 |
219 | <
220 | s
221 | v
222 | g
223 |  
224 | x
225 | m
226 | l
227 | n
228 | s
229 | =
230 | "
231 | h
232 | t
233 | t
234 | p
235 | :
236 | /
237 | /
238 | w
239 | w
240 | w
241 | .
242 | w
243 | 3
244 | .
245 | o
246 | r
247 | g
248 | /
249 | 2
250 | 0
251 | 0
252 | 0
253 | /
254 | svg
255 | "
256 |  
257 | v
258 | i
259 | e
260 | w
261 | B
262 | o
263 | x
264 | =
265 | "
266 | 0
267 |  
268 | 0
269 |  
270 | 5
271 |  
272 | 5
273 | "
274 | >
275 | <
276 | p
277 | a
278 | t
279 | h
280 |  
281 | f
282 | i
283 | l
284 | l
285 | =
286 | "
287 | #
288 | f
289 | 0
290 | 0
291 | "
292 |  
293 | d
294 | =
295 | "
296 | m
297 | 0 0
298 | h
299 | 3
300 | v
301 | 3
302 | h
303 | -
304 | 3
305 | "
306 | /
307 | ><path fill="#
308 | 0
309 | 0
310 | f
311 | " d="m
312 | 2
313 |  
314 | 2
315 | h3v3h-3"/><
316 | /svg
317 | >
318 | 
319 |
320 |
321 |
322 |

Back references

323 |

324 | Orange text represents literal text from the gzip stream. Blue text 325 | is test that is a back reference to previous text in the gzip 326 | stream. Hover over a back references to see what text it references. 327 |

328 |
329 | 330 |
331 | <
332 | s
333 | v
334 | g
335 |  
336 | x
337 | m
338 | l
339 | n
340 | s
341 | =
342 | "
343 | h
344 | t
345 | t
346 | p
347 | :
348 | /
349 | /
350 | w
351 | w
352 | w
353 | .
354 | w
355 | 3
356 | .
357 | o
358 | r
359 | g
360 | /
361 | 2
362 | 0
363 | 0
364 | 0
365 | /
366 | 
367 | s
368 | v
369 | g
370 | "
371 |  
372 | v
373 | i
374 | e
375 | w
376 | B
377 | o
378 | x
379 | =
380 | "
381 | 0
382 |  
383 | 0
384 |  
385 | 5
386 |  
387 | 5
388 | "
389 | >
390 | <
391 | p
392 | a
393 | t
394 | h
395 |  
396 | f
397 | i
398 | l
399 | l
400 | =
401 | "
402 | #
403 | f
404 | 0
405 | 0
406 | "
407 |  
408 | d
409 | =
410 | "
411 | m
412 | 
413 | 0
414 |  
415 | 0
416 | h
417 | 3
418 | v
419 | 3
420 | h
421 | -
422 | 3
423 | "
424 | /
425 | 
426 | >
427 | <
428 | p
429 | a
430 | t
431 | h
432 |  
433 | f
434 | i
435 | l
436 | l
437 | =
438 | "
439 | #
440 | 0
441 | 0
442 | f
443 | 
444 | "
445 |  
446 | d
447 | =
448 | "
449 | m
450 | 2
451 |  
452 | 2
453 | 
454 | h
455 | 3
456 | v
457 | 3
458 | h
459 | -
460 | 3
461 | "
462 | /
463 | >
464 | <
465 | 
466 | /
467 | s
468 | v
469 | g
470 | >
471 | 
472 |
473 |
474 |
475 |
476 | 477 | 478 | 484 | 485 | 486 | --------------------------------------------------------------------------------