Full Code of microsoft/lepton_jpeg_rust for AI

main 241d66906dd0 cached
129 files
19.1 MB
155.8k tokens
670 symbols
1 requests
Download .txt
Showing preview only (640K chars total). Download the full file or copy to clipboard to get everything.
Repository: microsoft/lepton_jpeg_rust
Branch: main
Commit: 241d66906dd0
Files: 129
Total size: 19.1 MB

Directory structure:
gitextract_8bpxdk9j/

├── .cargo/
│   └── config.toml
├── .config/
│   ├── 1espt/
│   │   └── PipelineAutobaseliningConfig.yml
│   ├── guardian/
│   │   └── .gdnbaselines
│   └── nextest.toml
├── .github/
│   └── workflows/
│       ├── publish.yml
│       ├── publishwheels.yml
│       └── rust.yml
├── .gitignore
├── .vscode/
│   ├── launch.json
│   └── tasks.json
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Cargo.toml
├── DESIGN.md
├── LICENSE.txt
├── NOTICE.txt
├── README.md
├── SECURITY.md
├── azure-pipelines.yml
├── benches/
│   └── benches.rs
├── dll/
│   ├── Cargo.toml
│   └── src/
│       └── lib.rs
├── fuzz/
│   ├── .cargo/
│   │   └── config.toml
│   ├── .gitignore
│   ├── Cargo.toml
│   ├── fuzz_targets/
│   │   └── fuzz_target_1.rs
│   └── rust-toolchain.toml
├── images/
│   ├── android.lep
│   ├── androidcrop.lep
│   ├── androidcropoptions.lep
│   ├── androidprogressive.lep
│   ├── androidprogressive_garbage.lep
│   ├── androidtrail.lep
│   ├── cathedral_db_non_int.lep
│   ├── cathedral_db_non_int_rustold.lep
│   ├── colorswap.lep
│   ├── eof_and_trailinghdrdata.lep
│   ├── eof_and_trailingrst.lep
│   ├── gray2sf.lep
│   ├── grayscale.lep
│   ├── half_scan.lep
│   ├── half_scan_rust55.lep
│   ├── hq.lep
│   ├── iphone.lep
│   ├── iphonecity.lep
│   ├── iphonecity_with_16KGarbage.jpgoutput
│   ├── iphonecity_with_16KGarbage.lep
│   ├── iphonecity_with_16KGarbage.lepoutput
│   ├── iphonecity_with_1MGarbage.lep
│   ├── iphonecrop.lep
│   ├── iphonecrop2.lep
│   ├── iphoneprogressive.lep
│   ├── iphoneprogressive2.lep
│   ├── mathoverflow_16.lep
│   ├── mathoverflow_32.lep
│   ├── mathoverflow_scalar.lep
│   ├── narrowrst.lep
│   ├── nofsync.lep
│   ├── out_of_order_dqt.lep
│   ├── pixelated.lep
│   ├── progressive_late_dht.lep
│   ├── slrcity.lep
│   ├── slrhills.lep
│   ├── slrindoor.lep
│   ├── t.jpgoutput
│   ├── t.lep
│   ├── t.lepoutput
│   ├── tiny.lep
│   ├── trailingrst.lep
│   ├── trailingrst2.lep
│   ├── trailingrst_missing_in_jpg.lep
│   ├── trunc.lep
│   ├── truncate4.lep
│   ├── truncatedzerorun.lep
│   ├── truncbad.lep
│   └── zeros_in_dqt_tables.lep
├── lib/
│   ├── Cargo.toml
│   └── src/
│       ├── consts.rs
│       ├── enabled_features.rs
│       ├── helpers.rs
│       ├── jpeg/
│       │   ├── bit_reader.rs
│       │   ├── bit_writer.rs
│       │   ├── block_based_image.rs
│       │   ├── component_info.rs
│       │   ├── jpeg_code.rs
│       │   ├── jpeg_header.rs
│       │   ├── jpeg_position_state.rs
│       │   ├── jpeg_read.rs
│       │   ├── jpeg_write.rs
│       │   ├── mod.rs
│       │   ├── row_spec.rs
│       │   └── truncate_components.rs
│       ├── lepton_error.rs
│       ├── lib.rs
│       ├── metrics.rs
│       ├── micro_benchmark.rs
│       └── structs/
│           ├── block_context.rs
│           ├── branch.rs
│           ├── idct.rs
│           ├── lepton_decoder.rs
│           ├── lepton_encoder.rs
│           ├── lepton_file_reader.rs
│           ├── lepton_file_writer.rs
│           ├── lepton_header.rs
│           ├── mod.rs
│           ├── model.rs
│           ├── multiplexer.rs
│           ├── neighbor_summary.rs
│           ├── partial_buffer.rs
│           ├── probability_tables.rs
│           ├── quantization_tables.rs
│           ├── simple_hash.rs
│           ├── simple_threadpool.rs
│           ├── thread_handoff.rs
│           ├── vpx_bool_reader.rs
│           └── vpx_bool_writer.rs
├── package/
│   └── Lepton.Jpeg.Rust.nuspec
├── python/
│   ├── Cargo.toml
│   ├── README.md
│   ├── pyproject.toml
│   ├── src/
│   │   └── lib.rs
│   └── tests/
│       └── test_compress.py
├── rustfmt.toml
├── tests/
│   ├── end_to_end.rs
│   ├── verifycompression.cmd
│   └── verifydir.cmd
└── util/
    ├── Cargo.toml
    └── src/
        ├── main.rs
        └── verifydir.rs

================================================
FILE CONTENTS
================================================

================================================
FILE: .cargo/config.toml
================================================
# -Cehcont_guard: Enable EH Continuation Metadata (https://learn.microsoft.com/en-us/cpp/build/reference/guard-enable-eh-continuation-metadata).
# -Ccontrol-flow-guard: Enable Control Flow Guard, needed for OneBranch's post-build analysis (https://learn.microsoft.com/en-us/cpp/build/reference/guard-enable-control-flow-guard).
# -Ctarget-feature=+crt-static: Statically link the CRT (required to link the spectre-mitigated CRT).
[target.'cfg(target_os = "windows")']
rustflags = ["-Ccontrol-flow-guard", "-Ctarget-feature=+crt-static"]

# -Clink-args=/DYNAMICBASE /CETCOMPAT: Enable "shadow stack" (https://learn.microsoft.com/en-us/cpp/build/reference/cetcompat)
[target.'cfg(all(target_os = "windows", any(target_arch = "i686", target_arch = "x86_64")))']
rustflags = ["-Clink-arg=/DYNAMICBASE", "-Clink-arg=/CETCOMPAT"]

[registries]

[env]
WORKSPACE_ROOT = { value = "", relative = true }

================================================
FILE: .config/1espt/PipelineAutobaseliningConfig.yml
================================================
## DO NOT MODIFY THIS FILE MANUALLY. This is part of auto-baselining from 1ES Pipeline Templates. Go to [https://aka.ms/1espt-autobaselining] for more details.

pipelines:
  9128:
    retail:
      source:
        eslint:
          lastModifiedDate: 2026-01-27
        psscriptanalyzer:
          lastModifiedDate: 2026-01-27
        armory:
          lastModifiedDate: 2026-01-27
        accessibilityinsights:
          lastModifiedDate: 2026-01-27
      binary:
        binskim:
          lastModifiedDate: 2026-01-27
        spotbugs:
          lastModifiedDate: 2026-01-27


================================================
FILE: .config/guardian/.gdnbaselines
================================================
{
  "properties": {
    "helpUri": "https://eng.ms/docs/microsoft-security/security/azure-security/cloudai-security-fundamentals-engineering/security-integration/guardian-wiki/microsoft-guardian/general/baselines"
  },
  "version": "1.0.0",
  "baselines": {
    "default": {
      "name": "default",
      "createdDate": "2026-01-27 06:17:01Z",
      "lastUpdatedDate": "2026-01-27 06:17:01Z"
    }
  },
  "results": {
    "7888556c1e034138d9cf4c682b73c492a353bb423ec11dc085e477365358d5b5": {
      "signature": "7888556c1e034138d9cf4c682b73c492a353bb423ec11dc085e477365358d5b5",
      "alternativeSignatures": [
        "f363807b3905e1c28a3a5fb6ffcb9b91c52b725244e6a57f8d2f41e3b70fbc02"
      ],
      "target": "target/release/lepton_jpeg.dll",
      "memberOf": [
        "default"
      ],
      "tool": "binskim",
      "ruleId": "BA2007",
      "createdDate": "2026-01-27 06:17:01Z",
      "expirationDate": "2026-07-16 06:19:42Z",
      "justification": "This error is baselined with an expiration date of 180 days from 2026-01-27 06:19:42Z"
    },
    "82dae63401a13132179fdd7f28cb9935eb07f6808da120db385d4537f6c7e781": {
      "signature": "82dae63401a13132179fdd7f28cb9935eb07f6808da120db385d4537f6c7e781",
      "alternativeSignatures": [
        "03acf8c325bf5b05a5e79b1b417f263e3526c9f06cfbb942d7f9b740840f3516"
      ],
      "target": "target/release/lepton_jpeg_avx2.dll",
      "memberOf": [
        "default"
      ],
      "tool": "binskim",
      "ruleId": "BA2007",
      "createdDate": "2026-01-27 06:17:01Z",
      "expirationDate": "2026-07-16 06:19:42Z",
      "justification": "This error is baselined with an expiration date of 180 days from 2026-01-27 06:19:42Z"
    },
    "34d7aee5ca8519db58d0fa6d7ddf78e892c1fc7f8c905926a5fbc8c0cb080af0": {
      "signature": "34d7aee5ca8519db58d0fa6d7ddf78e892c1fc7f8c905926a5fbc8c0cb080af0",
      "alternativeSignatures": [
        "e2af46751ad6876b19468b60518f5e41adfd3dcd204794acb0ebc401d7733573"
      ],
      "target": "target/release/lepton_jpeg_python.dll",
      "memberOf": [
        "default"
      ],
      "tool": "binskim",
      "ruleId": "BA2007",
      "createdDate": "2026-01-27 06:17:01Z",
      "expirationDate": "2026-07-16 06:19:42Z",
      "justification": "This error is baselined with an expiration date of 180 days from 2026-01-27 06:19:42Z"
    },
    "c359baf101a3b163e44bb6577cb8492ed745c10c9f3bd182f8b935057bfd0bf2": {
      "signature": "c359baf101a3b163e44bb6577cb8492ed745c10c9f3bd182f8b935057bfd0bf2",
      "alternativeSignatures": [
        "4be395a1280a6d3ced21b0ad815572da5d13632d75ea6dcb76f4e9b6ca3753ab"
      ],
      "target": "target/release/lepton_jpeg_util.exe",
      "memberOf": [
        "default"
      ],
      "tool": "binskim",
      "ruleId": "BA2007",
      "createdDate": "2026-01-27 06:17:01Z",
      "expirationDate": "2026-07-16 06:19:42Z",
      "justification": "This error is baselined with an expiration date of 180 days from 2026-01-27 06:19:42Z"
    },
    "ee719806d1996ca8d823f90d73903cc9f5da08a3960af2c0a1eb0dd1a54c99d0": {
      "signature": "ee719806d1996ca8d823f90d73903cc9f5da08a3960af2c0a1eb0dd1a54c99d0",
      "alternativeSignatures": [
        "ba93e14514af2d2f711daad10f312379d730bc77ef208901c9cf06e07bf01d84"
      ],
      "target": "target/release/lepton_jpeg_util_avx2.exe",
      "memberOf": [
        "default"
      ],
      "tool": "binskim",
      "ruleId": "BA2007",
      "createdDate": "2026-01-27 06:17:01Z",
      "expirationDate": "2026-07-16 06:19:42Z",
      "justification": "This error is baselined with an expiration date of 180 days from 2026-01-27 06:19:42Z"
    },
    "cd6b9720c2019ba2c72ef61db8542b1ce290ba22d587eb3955ab755d14d6f4ed": {
      "signature": "cd6b9720c2019ba2c72ef61db8542b1ce290ba22d587eb3955ab755d14d6f4ed",
      "alternativeSignatures": [
        "1ed2e30b47b86b4ed9ca74beff17a7312994572936ef2333bbc6ef9bc17dacd3"
      ],
      "target": "target/release/deps/default_boxed_derive-63de623f2e43e138.dll",
      "memberOf": [
        "default"
      ],
      "tool": "binskim",
      "ruleId": "BA2007",
      "createdDate": "2026-01-27 06:17:01Z",
      "expirationDate": "2026-07-16 06:19:42Z",
      "justification": "This error is baselined with an expiration date of 180 days from 2026-01-27 06:19:42Z"
    },
    "363faeb4073c8417f384af5227032d0daa483689d56ad0fac59f3328e751b183": {
      "signature": "363faeb4073c8417f384af5227032d0daa483689d56ad0fac59f3328e751b183",
      "alternativeSignatures": [
        "0a863a85465581440a18aeb7b257b269e75c704621b9d7dced6ed89204d950f6"
      ],
      "target": "target/release/deps/default_boxed_derive-a563f94fdc621d90.dll",
      "memberOf": [
        "default"
      ],
      "tool": "binskim",
      "ruleId": "BA2007",
      "createdDate": "2026-01-27 06:17:01Z",
      "expirationDate": "2026-07-16 06:19:42Z",
      "justification": "This error is baselined with an expiration date of 180 days from 2026-01-27 06:19:42Z"
    },
    "12a8462656e61be1c0ef31be295c12ac6e85b261c25adee4cf97e2d32819b315": {
      "signature": "12a8462656e61be1c0ef31be295c12ac6e85b261c25adee4cf97e2d32819b315",
      "alternativeSignatures": [
        "29e6fbebe0ea89a075a6e11c87b2f776f2cada75471317093729862c1f4cd60d"
      ],
      "target": "target/release/deps/git_version_macro-81a02dafe74069f0.dll",
      "memberOf": [
        "default"
      ],
      "tool": "binskim",
      "ruleId": "BA2007",
      "createdDate": "2026-01-27 06:17:01Z",
      "expirationDate": "2026-07-16 06:19:42Z",
      "justification": "This error is baselined with an expiration date of 180 days from 2026-01-27 06:19:42Z"
    },
    "f9cb8789538579745e4a5881ebfe2de000c3a924099948e9df510235d8e63326": {
      "signature": "f9cb8789538579745e4a5881ebfe2de000c3a924099948e9df510235d8e63326",
      "alternativeSignatures": [
        "495638cb4ea6541aa8abbfb904b5bc968502f7c3d2eda51fc8009b842627cd5c"
      ],
      "target": "target/release/deps/git_version_macro-84dcd42a3b51464a.dll",
      "memberOf": [
        "default"
      ],
      "tool": "binskim",
      "ruleId": "BA2007",
      "createdDate": "2026-01-27 06:17:01Z",
      "expirationDate": "2026-07-16 06:19:42Z",
      "justification": "This error is baselined with an expiration date of 180 days from 2026-01-27 06:19:42Z"
    },
    "0015b41486ed72ac681952fc1e5117467edc31cc458a8ebe0bc2428040501432": {
      "signature": "0015b41486ed72ac681952fc1e5117467edc31cc458a8ebe0bc2428040501432",
      "alternativeSignatures": [
        "a14a0079e1028b5a3a85807dd85687ff60f1e614e10d6174e8f8d85d5ffad6f9"
      ],
      "target": "target/release/deps/indoc-0ef44e389295250a.dll",
      "memberOf": [
        "default"
      ],
      "tool": "binskim",
      "ruleId": "BA2007",
      "createdDate": "2026-01-27 06:17:01Z",
      "expirationDate": "2026-07-16 06:19:42Z",
      "justification": "This error is baselined with an expiration date of 180 days from 2026-01-27 06:19:42Z"
    },
    "54b6fbb3b25a55dd7124f9172228d97a8e208a2b2f310fb98f52120d2555e9a0": {
      "signature": "54b6fbb3b25a55dd7124f9172228d97a8e208a2b2f310fb98f52120d2555e9a0",
      "alternativeSignatures": [
        "5586663f943c7c47c916fba1ac930ea1eed0c8231090913f36b98ace3158a3e0"
      ],
      "target": "target/release/deps/indoc-1d196f6d756468dd.dll",
      "memberOf": [
        "default"
      ],
      "tool": "binskim",
      "ruleId": "BA2007",
      "createdDate": "2026-01-27 06:17:01Z",
      "expirationDate": "2026-07-16 06:19:42Z",
      "justification": "This error is baselined with an expiration date of 180 days from 2026-01-27 06:19:42Z"
    },
    "a571bdcd0bc935822e84ea12d95ffc432c5f99381b681b9cc292f7ed8ec32b06": {
      "signature": "a571bdcd0bc935822e84ea12d95ffc432c5f99381b681b9cc292f7ed8ec32b06",
      "alternativeSignatures": [
        "bcf8ae23a38f46f4b1fbad99d2a0d4c1b72c372bc8aedb5dd2d20543ad7c18da"
      ],
      "target": "target/release/deps/lepton_jpeg.dll",
      "memberOf": [
        "default"
      ],
      "tool": "binskim",
      "ruleId": "BA2007",
      "createdDate": "2026-01-27 06:17:01Z",
      "expirationDate": "2026-07-16 06:19:42Z",
      "justification": "This error is baselined with an expiration date of 180 days from 2026-01-27 06:19:42Z"
    },
    "4156fba8fbda87c312c40f8644080f0444e119c7ad022a7a1cd5bc153472c8ed": {
      "signature": "4156fba8fbda87c312c40f8644080f0444e119c7ad022a7a1cd5bc153472c8ed",
      "alternativeSignatures": [
        "867001d871648777be53eee5134a29693823d0c842475176bc0a738f448ab9d1"
      ],
      "target": "target/release/deps/lepton_jpeg_python.dll",
      "memberOf": [
        "default"
      ],
      "tool": "binskim",
      "ruleId": "BA2007",
      "createdDate": "2026-01-27 06:17:01Z",
      "expirationDate": "2026-07-16 06:19:42Z",
      "justification": "This error is baselined with an expiration date of 180 days from 2026-01-27 06:19:42Z"
    },
    "149befb9280c911d3f0b709dd16c3b495937aacddf5e0ab770addce09e6f7ab6": {
      "signature": "149befb9280c911d3f0b709dd16c3b495937aacddf5e0ab770addce09e6f7ab6",
      "alternativeSignatures": [
        "91f1eab664b17bcc61e3585f933ef033800549b55f938091f80a75c3e0e6958d"
      ],
      "target": "target/release/deps/lepton_jpeg_util.exe",
      "memberOf": [
        "default"
      ],
      "tool": "binskim",
      "ruleId": "BA2007",
      "createdDate": "2026-01-27 06:17:01Z",
      "expirationDate": "2026-07-16 06:19:42Z",
      "justification": "This error is baselined with an expiration date of 180 days from 2026-01-27 06:19:42Z"
    },
    "903069c0ae93b67c9b06d4d760af5b12c07ce30db727be83f46507875fd1856c": {
      "signature": "903069c0ae93b67c9b06d4d760af5b12c07ce30db727be83f46507875fd1856c",
      "alternativeSignatures": [
        "8357b47447b55a4058ac2d9b7cbc881f412384528a90e66a88509fea88f974ff"
      ],
      "target": "target/release/deps/pyo3_macros-0883c55e16fc46dd.dll",
      "memberOf": [
        "default"
      ],
      "tool": "binskim",
      "ruleId": "BA2007",
      "createdDate": "2026-01-27 06:17:01Z",
      "expirationDate": "2026-07-16 06:19:42Z",
      "justification": "This error is baselined with an expiration date of 180 days from 2026-01-27 06:19:42Z"
    },
    "ef9d7c4fdf143066f64d95af451456f5547eba3e89156ba0cbda5dc92b9eed0c": {
      "signature": "ef9d7c4fdf143066f64d95af451456f5547eba3e89156ba0cbda5dc92b9eed0c",
      "alternativeSignatures": [
        "954a842978f48d0a377246cec186dcf2afd17423cae579f197e6d7e081657935"
      ],
      "target": "target/release/deps/pyo3_macros-ead3c9c3859ec605.dll",
      "memberOf": [
        "default"
      ],
      "tool": "binskim",
      "ruleId": "BA2007",
      "createdDate": "2026-01-27 06:17:01Z",
      "expirationDate": "2026-07-16 06:19:42Z",
      "justification": "This error is baselined with an expiration date of 180 days from 2026-01-27 06:19:42Z"
    },
    "544e0bdd76e7c149e17e870fb0b32aa8d35af936a96e12f73891061d25b64485": {
      "signature": "544e0bdd76e7c149e17e870fb0b32aa8d35af936a96e12f73891061d25b64485",
      "alternativeSignatures": [
        "e6f1ebffea3eb268804be426a462e535249f01dc46a9ef43dd1f2c7aa899bb96"
      ],
      "target": "target/release/deps/rustversion-60c5a5f87e0f5de5.dll",
      "memberOf": [
        "default"
      ],
      "tool": "binskim",
      "ruleId": "BA2007",
      "createdDate": "2026-01-27 06:17:01Z",
      "expirationDate": "2026-07-16 06:19:42Z",
      "justification": "This error is baselined with an expiration date of 180 days from 2026-01-27 06:19:42Z"
    },
    "3bd252ba75ede9998cae2e3283370157bef89d7b2de12562cb8ad3472f1ee620": {
      "signature": "3bd252ba75ede9998cae2e3283370157bef89d7b2de12562cb8ad3472f1ee620",
      "alternativeSignatures": [
        "ba5c335ba47831bfb30973ec0e423518ed2b198f8d8d691fd3f856a886a924c6"
      ],
      "target": "target/release/deps/rustversion-ae37400f19b3f17f.dll",
      "memberOf": [
        "default"
      ],
      "tool": "binskim",
      "ruleId": "BA2007",
      "createdDate": "2026-01-27 06:17:01Z",
      "expirationDate": "2026-07-16 06:19:42Z",
      "justification": "This error is baselined with an expiration date of 180 days from 2026-01-27 06:19:42Z"
    },
    "4cf9241015129625b09af906ce68f0424cafdf3661358bd4081e29d8e945024b": {
      "signature": "4cf9241015129625b09af906ce68f0424cafdf3661358bd4081e29d8e945024b",
      "alternativeSignatures": [
        "901556be5d52b05739e219d3911c9ca20b435456fe22d3e7d1fe994e18faa043"
      ],
      "target": "target/release/deps/time_macros-17f74972c8766b75.dll",
      "memberOf": [
        "default"
      ],
      "tool": "binskim",
      "ruleId": "BA2007",
      "createdDate": "2026-01-27 06:17:01Z",
      "expirationDate": "2026-07-16 06:19:42Z",
      "justification": "This error is baselined with an expiration date of 180 days from 2026-01-27 06:19:42Z"
    },
    "3ad2f2c6ad81bbb12175b4e299f09319a2c7e26e2e91386e8cdf2bb7f66bb6b4": {
      "signature": "3ad2f2c6ad81bbb12175b4e299f09319a2c7e26e2e91386e8cdf2bb7f66bb6b4",
      "alternativeSignatures": [
        "f55823c74a027e8a3e03b58709e244f185e585d3729015841df513f514964799"
      ],
      "target": "target/release/deps/time_macros-6674f0d9cd1fe1c0.dll",
      "memberOf": [
        "default"
      ],
      "tool": "binskim",
      "ruleId": "BA2007",
      "createdDate": "2026-01-27 06:17:01Z",
      "expirationDate": "2026-07-16 06:19:42Z",
      "justification": "This error is baselined with an expiration date of 180 days from 2026-01-27 06:19:42Z"
    },
    "51a37a91abff68ac93176d40a7ebe4254f8bd2d59b3f067eac8e63fbf344dc96": {
      "signature": "51a37a91abff68ac93176d40a7ebe4254f8bd2d59b3f067eac8e63fbf344dc96",
      "alternativeSignatures": [
        "2b069009ab0383fb0ff18c24cda15d0e3a2787753d56e1d062739be4d1f24ad6"
      ],
      "target": "target/release/deps/windows_implement-131e219ba8366c19.dll",
      "memberOf": [
        "default"
      ],
      "tool": "binskim",
      "ruleId": "BA2007",
      "createdDate": "2026-01-27 06:17:01Z",
      "expirationDate": "2026-07-16 06:19:42Z",
      "justification": "This error is baselined with an expiration date of 180 days from 2026-01-27 06:19:42Z"
    },
    "d08a22af13bbb9c4df920b594dc86a5191f4ab28301a3fda5a8c99b19909d39f": {
      "signature": "d08a22af13bbb9c4df920b594dc86a5191f4ab28301a3fda5a8c99b19909d39f",
      "alternativeSignatures": [
        "556ad3740e06bf41c0476ceabdabef20085c886ff93eafa7dac49a3f34bf216b"
      ],
      "target": "target/release/deps/windows_implement-9fc3e36e619e31c4.dll",
      "memberOf": [
        "default"
      ],
      "tool": "binskim",
      "ruleId": "BA2007",
      "createdDate": "2026-01-27 06:17:01Z",
      "expirationDate": "2026-07-16 06:19:42Z",
      "justification": "This error is baselined with an expiration date of 180 days from 2026-01-27 06:19:42Z"
    },
    "7c4b27fd4d70c9af21f0770b95de543c7c5b1c43b091d4e97628aa611981c936": {
      "signature": "7c4b27fd4d70c9af21f0770b95de543c7c5b1c43b091d4e97628aa611981c936",
      "alternativeSignatures": [
        "ec50c72748b2290ad8ad44fba6be6392c1a97b8b7a82cf40cfa02fbf8616a19d"
      ],
      "target": "target/release/deps/windows_interface-3fdabd2e927b6dbf.dll",
      "memberOf": [
        "default"
      ],
      "tool": "binskim",
      "ruleId": "BA2007",
      "createdDate": "2026-01-27 06:17:01Z",
      "expirationDate": "2026-07-16 06:19:42Z",
      "justification": "This error is baselined with an expiration date of 180 days from 2026-01-27 06:19:42Z"
    },
    "3f2ca4517e5e7715572fca9ef646b6c5738b01f2d1eddda8da452bcb35ace81b": {
      "signature": "3f2ca4517e5e7715572fca9ef646b6c5738b01f2d1eddda8da452bcb35ace81b",
      "alternativeSignatures": [
        "c7424dad4782f04900eea0009b9db79dc37ea5b18cb982fafba9135e2bb47aef"
      ],
      "target": "target/release/deps/windows_interface-d6a6711b2754ade3.dll",
      "memberOf": [
        "default"
      ],
      "tool": "binskim",
      "ruleId": "BA2007",
      "createdDate": "2026-01-27 06:17:01Z",
      "expirationDate": "2026-07-16 06:19:42Z",
      "justification": "This error is baselined with an expiration date of 180 days from 2026-01-27 06:19:42Z"
    }
  }
}

================================================
FILE: .config/nextest.toml
================================================
[profile.ci.junit]
path = "junit.xml"

================================================
FILE: .github/workflows/publish.yml
================================================
name: Publish Crate

permissions:
  contents: read

on:
  push:
    tags:
      - "v*.*.*"  # Triggers only for version tag pushes

jobs:
  publish:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout code with full history
      uses: actions/checkout@v3
      with:
        fetch-depth: 0  # Needed to compare commits and access tag history

    - name: Ensure tag is at tip of main
      id: verify_tag_commit
      run: |
        echo "🔍 Verifying tag points to main branch tip..."
        git fetch origin main

        TAG_COMMIT=$(git rev-parse ${{ github.ref }})
        MAIN_COMMIT=$(git rev-parse origin/main)

        echo "Tag commit:  $TAG_COMMIT"
        echo "Main commit: $MAIN_COMMIT"

        if [ "$TAG_COMMIT" != "$MAIN_COMMIT" ]; then
          echo "❌ Tag is not at tip of main. Aborting."
          exit 1
        fi
        echo "✅ Tag is at tip of main."

    - name: Extract tag version
      id: tag_version
      run: |
        echo "TAG_VERSION=${GITHUB_REF#refs/tags/v}" >> "$GITHUB_OUTPUT"

    - name: Read version from Cargo.toml
      id: cargo_version
      run: |
        CARGO_VERSION=$(grep '^version\s*=' lib/Cargo.toml | head -1 | sed -E 's/version\s*=\s*"([^"]+)"/\1/')
        echo "CARGO_VERSION=$CARGO_VERSION" >> "$GITHUB_OUTPUT"

    - name: Check tag version matches Cargo.toml
      run: |
        echo "🔍 Comparing tag and Cargo.toml versions..."
        echo "Tag:          ${{ steps.tag_version.outputs.TAG_VERSION }}"
        echo "Cargo.toml:   ${{ steps.cargo_version.outputs.CARGO_VERSION }}"

        if [ "${{ steps.tag_version.outputs.TAG_VERSION }}" != "${{ steps.cargo_version.outputs.CARGO_VERSION }}" ]; then
          echo "❌ Version mismatch: tag does not match Cargo.toml"
          exit 1
        fi
        echo "✅ Tag version matches Cargo.toml."

    - name: Set up Rust
      uses: dtolnay/rust-toolchain@stable
      with:
        toolchain: stable

    - name: Publish to crates.io
      env:
        CARGO_REGISTRY_TOKEN: ${{ secrets.CRATE_PUBLISH }}
      run: cargo publish --verbose --package lepton_jpeg


================================================
FILE: .github/workflows/publishwheels.yml
================================================
name: Publish Wheels

permissions:
  contents: read
  
on:
  push:
    tags:
      - "v*.*.*"  # Triggers only for version tag pushes

jobs:
  build:
    name: Build and upload wheels
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
        python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]

    steps:
      - name: Set up Rust
        uses: dtolnay/rust-toolchain@stable
        with:
          toolchain: stable    
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}

      - name: Create virtual environment
        shell: bash
        run: |
          python -m venv .venv
          if [ -f ".venv/bin/activate" ]; then
              source .venv/bin/activate
          else
              source .venv/Scripts/activate
          fi          
          python -m pip install --upgrade pip maturin

      - name: Build wheel
        shell: bash
        run: |
          if [ -f ".venv/bin/activate" ]; then
              source .venv/bin/activate
          else
              source .venv/Scripts/activate
          fi

          cd python
          maturin build --release

      - name: Upload to TestPyPI
        shell: bash
        run: |
          if [ -f ".venv/bin/activate" ]; then
              source .venv/bin/activate
          else
              source .venv/Scripts/activate
          fi

          cd python
          maturin upload --skip-existing $GITHUB_WORKSPACE/target/wheels/*
        env:
          MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }}  

================================================
FILE: .github/workflows/rust.yml
================================================
name: Rust

permissions:
  contents: read
  checks: write
  pull-requests: write 

on:
  push:
    branches: ["main"]
  pull_request:

env:
  CARGO_TERM_COLOR: always

jobs:
  build:
    runs-on: windows-latest

    steps:
      - uses: actions/checkout@v3
      - uses: dtolnay/rust-toolchain@stable
        with:
          toolchain: stable
          targets: wasm32-wasip1,aarch64-unknown-linux-musl,x86_64-pc-windows-msvc,x86_64-unknown-linux-gnu
          components: rustfmt,clippy

      # Install nextest
      - uses: taiki-e/install-action@v2
        with:
          tool: nextest

      - name: Check formatting
        run: cargo fmt --check --all
      - name: Build default target
        run: cargo build --locked --workspace
      - name: Build wasm32-wasip1
        run: cargo build --locked --target wasm32-wasip1 --manifest-path lib/Cargo.toml
      - name: Build aarch64-unknown-linux-musl
        run: cargo build --locked --target aarch64-unknown-linux-musl --manifest-path lib/Cargo.toml
      - name: Build x86_64-pc-windows-msvc
        run: cargo build --locked --target x86_64-pc-windows-msvc --lib --workspace
      - name: Build x86_64-pc-windows-msvc release
        run: cargo build --locked --target x86_64-pc-windows-msvc --lib --workspace --release
      - name: Test python interface build
        run: | 
          cd python
          cargo build --locked
          python -m venv .env
          .env\Scripts\activate
          pip install maturin pytest
          maturin develop --locked
          pytest --junitxml=results.xml

      # Run tests with nextest and output JUnit results
      - name: Run tests
        run: |
          cargo nextest run --workspace --profile ci

      # Upload test results so GitHub shows pass/fail per test
      - name: Upload test results
        uses: EnricoMi/publish-unit-test-result-action/windows@v2
        if: always() # Upload even if tests fail
        with:
          files: |
             target/nextest/ci/junit.xml
             python/results.xml
        

================================================
FILE: .gitignore
================================================
# Generated by Cargo
# will have compiled files and executables
/target/

# These are backup files generated by rustfmt
**/*.rs.bk

# VSCode
.vs/

# don't checkin lock file for fuzz as it should get autogen
fuzz/Cargo.lock

# ignore python virtual env
.env/
__pycache__

================================================
FILE: .vscode/launch.json
================================================
{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "(Windows) Launch",
            "type": "cppvsdbg",
            "request": "launch",
            "program": "${workspaceFolder}/target/debug/lepton_jpeg_util.exe",
            "args": ["-dump", "${workspaceFolder}\\images\\slrcity.jpg"],
            "stopAtEntry": false,
            "cwd": "${fileDirname}",
            "environment": [],
            "console": "externalTerminal",
        },
        {
            "name": "Debug unit test",
            "type": "cppvsdbg",
            "request": "launch",
            "program": "${workspaceFolder}/target/debug/deps/end_to_end-5c5d5b533f217bea.exe",
            "args": [ "verify_extern_16bit_math_retry" ],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "console": "externalTerminal",
            "preLaunchTask": "rust: cargo test norun",
        },
    ]
}

================================================
FILE: .vscode/tasks.json
================================================
{
    "version": "2.0.0",
    "tasks": [
        {
            "type": "cargo",
            "command": "test",
            "args": [
                "--no-run"
            ],
            "problemMatcher": [
                "$rustc"
            ],
            "group": "test",
            "label": "rust: cargo test norun"
        },
        {
            "type": "cargo",
            "command": "build",
            "problemMatcher": [
                "$rustc"
            ],
            "args": [
                "--all"
            ],
            "group": "build",
            "label": "rust: cargo build"
        }
    ]
}

================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Microsoft Open Source Code of Conduct

This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).

Resources:

- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing

This project welcomes contributions and suggestions. Most contributions require you to
agree to a Contributor License Agreement (CLA) declaring that you have the right to,
and actually do, grant us the rights to use your contribution. For details, visit
https://cla.microsoft.com.

When you submit a pull request, a CLA-bot will automatically determine whether you need
to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the
instructions provided by the bot. You will only need to do this once across all repositories using our CLA.

This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.

================================================
FILE: Cargo.toml
================================================
[package]
name = "lepton_jpeg_root"
edition = "2024"
authors = ["Kristof Roomp <kristofr@microsoft.com>"]

[workspace.package]
version = "0.5.8"
edition = "2024"

[profile.release]
debug = true
lto = true

[workspace]
members = ["lib", "dll", "util", "python"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dev-dependencies]
lepton_jpeg = { path = "lib", features = ["micro_benchmark"] }
rstest = "0.22"
rand = "0.8"
rand_chacha = "0.3"
siphasher = "1"
criterion = "0.7"

[[bench]]
name = "benches"
harness = false

================================================
FILE: DESIGN.md
================================================
# Design

## Overall approach

This library is designed to encode/decode JPEGs in a compressed file format that typically compresses files by about 20%. The overall approach is as follows:

- Split JPEG into metadata/headers (stored as an binary array) and scan data (which is stored as a set of arrays of 8x8 16 bit coefficients per color channel)
- The headers/metadata are compressed via Zlib and stored at the beginning of the lepton compressed files
- The scan data is Huffman decoded, while verifying that it was encoded canonically (this is important since we canonically encode so that it is binary identical)
- The scan data is encoded using the VP8 CABAC, with coefficients binarized using [Exponential-Golomb coding](https://en.wikipedia.org/wiki/Exponential-Golomb_coding). The bins for the CABAC encoder are determined by a fairly complex predictor model for:
  - DC (the top left corner coefficient)
  - The top and left edges (which are correlated to the previous blocks)
  - The 7x7  block (the remaining 49 coefficients that are not the DC or the edges)
  - It is vital that the model is identically and deterministically updated during encoding and decoding, since any discrepancy will rapidly cause the encoder and decoder to get out of sync and fail to decode the image
- In order to increase response time, the scan data is partitioned by up to 8 into horizontal sections, each of which can be encoded/decode on a separate thread. 
- Progressive JPEGs are handled slightly differently since they cannot be partitioned during the JPEG encoding step, since each progressive scan requires access to the entire image data.
- As a last verification, the entire process is run in reverse to ensure that we can recreate the binary-identical JPEG

## Layers

The main layers of the library are as follows:

- `lepton_format.rs` implements reading and writing Lepton format files and launching partitioned decoder/encoder threads
- `lepton_encoder.rs` / `lepton_decoder.rs` perform the actual scan encoding/decoding using `model.rs` to track the bin probabilities in `branch.rs`
- JPEGs are read and written by `jpeg_header.rs, jpeg_read.rs, jpeg_write.rs`, `jpeg_position_state.rs` which are invoked by `lepton_format.rs`
- `bit_reader.rs / bit_writer.rs` are used by the Huffman encoding/decoding for reading writing JPEG format scan data
- `vpx_bool_reader.rs / vpx_bool_writer.rs` are the CABAC encoder/decoder that using an arithmetic encoded binary stream with the probability of each bin is calculated in `brach.rs`. 
- `idct.rs` performs an inverse DCT of the JPEG coefficients as part of predicting the pixel values of neighbouring blocks
- `thread_handoff.rs` used to partition the JPEG scan data so that multiple threads can process the same image. 

================================================
FILE: LICENSE.txt
================================================

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: NOTICE.txt
================================================
Lepton JPEG compression Rust Port Copyright (c) Microsoft Corporation

NOTICES AND INFORMATION
Do Not Translate or Localize

This software incorporates material from third parties.
Microsoft makes certain open source code available at https://3rdpartysource.microsoft.com,
or you may send a check or money order for US $5.00, including the product name,
the open source component name, platform, and version number, to:

Source Code Compliance Team
Microsoft Corporation
One Microsoft Way
Redmond, WA 98052
USA

Notwithstanding any other terms, you may reverse engineer this software to the extent
required to debug changes to any libraries licensed under the GNU Lesser General Public License.

-------------------

This software includes parts of the Dropbox Lepton project (https://github.com/dropbox/lepton). 
Lepton is a tool and file format for losslessly compressing JPEGs by an average of 22%. Lepton is
licensed under Apache License 2.0, you can find a copy of this license at https://github.com/dropbox/lepton/blob/master/LICENSE

-------------------

This software includes parts of the Libwebp project https://github.com/webmproject/libwebp
licensed under BSD 3-Clause License, you can find a copy of this license at https://github.com/webmproject/libwebp/blob/main/COPYING

----------------

This software includes parts of the uncmpJPG project, which is a library to for lossless JPEG decompression
licensed under BSD 2-Clause License, you can find a copy of this license at  http://packjpg.encode.su/?page_id=178


================================================
FILE: README.md
================================================
# Lepton JPEG Compression in Rust 
[![Rust Community](https://img.shields.io/badge/Rust_Community%20-Join_us-brightgreen?style=plastic&logo=rust)](https://www.rust-lang.org/community)

This is a port of the C++ Lepton JPEG compression tool that was released by DropBox [dropbox/lepton](https://github.com/dropbox/lepton). We developed a port of the library to Rust, which has basically the same performance characteristics with the advantage of all the safety features that Rust has to offer, due to the work involved in performing an exhaustive security check on the C++ code and the fact that DropBox has deprecated the codebase.

With precise bit-by-bit recovery of the original JPEG, the Lepton compression library is designed for lossless compression of baseline and progressive JPEGs up to 22%. JPEG storage in a cloud storage system is the main application case. Even metadata headers and invalid content are kept in good condition.

## How to Use This Library

### Rust

The libary is published on crates.io as [lepton_jpeg](https://crates.io/crates/lepton_jpeg). 

### Python 

The library is published on PyPI as *lepton_jpeg_python*.

```
pip install lepton_jpeg_python
```

``` Python
import lepton_jpeg_python

with open("../images/slrcity.jpg", "rb") as f:
    jpg_data = f.read()

compressed = lepton_jpeg_python.compress_bytes(jpg_data, config)
decompressed = lepton_jpeg_python.decompress_bytes(compressed, config)

assert jpg_data == decompressed
```

### Building From Source

- [Rust 1.89 or Above](https://www.rust-lang.org/tools/install)

``` bash
git clone https://github.com/microsoft/lepton_jpeg_rust
cd lepton_jpeg_rust
cargo build
cargo test
cargo build --release
```

Some operations of this library are vectorized such as the IDCT using the [Wide](https://crates.io/crates/wide) crate, so you can get a significant boost if you enable +AVX2.

### Executable

Building the Rust project generates an `lepton_jpeg_util.exe` wrapper that is built as part of the project. It can be used to compress/decompress and also to verify the test end-to-end on a given JPEG. If the input file has a `.jpg` extension, it will encode. If the input file has a `.lep` extension, it will decode back to the original`.jpg`.

It supports the following options:

`lepton_jpeg_util.exe [options] <inputfile> [<outputfile>]`

| Option                  | Description                                                  |
| ----------------------- | ------------------------------------------------------------ |
| `-threads:n`            | Runs with a maximum of n threads. For encoding, this limits the amount of parallelism that can be gotten out of the decoder. |
| `-dump`                 | Dumps the contents of a JPG or LEP file, with the `-all` option, it will also dump the cooefficient image blocks. |
| `-noprogressive`        | Will cause an error if we encounter a progressive file rather than trying to encode it. |
| `-acceptdqtswithzeros`  | Accept images with DQTs with zeros (may cause divide-by-zero). |
| `-iter:n`               | Runs N iterations of the operation. Useful when we are running inside a profiler. |
| `-max-width:n`          | Limit the maximum image width to n pixels, instead of the default 16386. Fails with an error if limit is exceeded. |
| `-max-height:n`         | Limit the maximum image height to n pixels, instead of the default 16386. Fails with an error il limit is exceeded. |

## Contributing

There are many ways in which you can participate in this project, for example:

* [Submit bugs and feature requests](https://github.com/microsoft/lepton_jpeg_rust/issues), and help us verify as they are checked in
* Review [source code changes](https://github.com/microsoft/lepton_jpeg_rust/pulls) or submit your own features as pull requests.
* The library uses only **stable features**, so if you want to take advantage of SIMD features such as AVX2, use the Wide crate (see the idct.rs as an example) rather than intrinsics. 

## Code of Conduct

This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.

## License

Copyright (c) Microsoft Corporation. All rights reserved.

Licensed under the [Apache 2.0](LICENSE.txt) license.



================================================
FILE: SECURITY.md
================================================
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.8 BLOCK -->

## Security

Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).

If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.

## Reporting Security Issues

**Please do not report security vulnerabilities through public GitHub issues.**

Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).

If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com).  If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).

You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 

Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:

  * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
  * Full paths of source file(s) related to the manifestation of the issue
  * The location of the affected source code (tag/branch/commit or direct URL)
  * Any special configuration required to reproduce the issue
  * Step-by-step instructions to reproduce the issue
  * Proof-of-concept or exploit code (if possible)
  * Impact of the issue, including how an attacker might exploit the issue

This information will help us triage your report more quickly.

If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.

## Preferred Languages

We prefer all communications to be in English.

## Policy

Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).

<!-- END MICROSOFT SECURITY.MD BLOCK -->


================================================
FILE: azure-pipelines.yml
================================================
trigger:
  branches:
    include:
    - main
  tags:
    include:
    - v*.*.*

pr:
  branches:
    include:
    - main

resources:
  repositories:
  - repository: odspPipelines
    type: git
    name: EFun/ODSPTemplates
    ref: refs/heads/main

variables:
- name: toolchainFeed
  value: https://onedrive.pkgs.visualstudio.com/b52099a6-3b13-4b08-9270-a07884a10e3d/_packaging/RustTools/nuget/v3/index.json
- name: cratesIoFeed
  value: sparse+https://onedrive.pkgs.visualstudio.com/b52099a6-3b13-4b08-9270-a07884a10e3d/_packaging/RustCratesIO/Cargo/index/

extends:
  template: v1/OdspPipeline.yml@odspPipelines
  parameters:
    settings:
      template: Official
    sdl:
      clippy:
        enabled: false
    stages:

    ## For more details on the Rust build workflow, see https://eng.ms/docs/cloud-ai-platform/devdiv/one-engineering-system-1es/1es-docs/1es-pipeline-templates/features/buildworkflows/rust
    - stage: BuildStage
      displayName: 🏗️ Cargo build
      pool:
        name: 1ESHostedAgents_Windows2022_v2
        os: windows
      jobs:
          - job: BuildJob
            displayName: 🏗️ Cargo build
            templateContext:
              type: buildJob
              workflow: Rust
              rust:
                rustToolchain:
                  version: ms-prod-1.90
                  toolchainFeed: $(toolchainFeed)
                  cratesIoFeed: $(cratesIoFeed)
                target: x86_64-pc-windows-msvc
                command: custom
              sdl:
                componentgovernance:
                  enabled: true
                  failOnAlert: true
              postBuildSteps:
                - script: |
                    cargo build --workspace --locked 2>&1
                    cargo test --no-run --workspace --locked 2>&1

                  displayName: "Build debug"

                - script: |
                    cargo install junit-test
                    junit-test
                    copy junit.xml $(System.DefaultWorkingDirectory)\TEST-rust.xml
                    rd /s /q target\debug
                  displayName: 'Test debug'

                - task: PublishTestResults@2
                  displayName: 'Publish Test Results **/TEST-*.xml'
                  inputs:
                    mergeTestResults: true

                - script: |
                    set CL=/Qspectre /sdl /Zi /W3
                    set RUSTFLAGS=-Ccontrol-flow-guard -Ctarget-feature=+crt-static,+avx2,+lzcnt -Clink-args=/DYNAMICBASE -Clink-args=/CETCOMPAT
                    cargo build --workspace --locked --release 2>&1
                    copy target\release\lepton_jpeg.dll target\release\lepton_jpeg_avx2.dll
                    copy target\release\lepton_jpeg.pdb target\release\lepton_jpeg_avx2.pdb
                    copy target\release\lepton_jpeg_util.exe target\release\lepton_jpeg_util_avx2.exe
                    copy target\release\lepton_jpeg_util.pdb target\release\lepton_jpeg_util_avx2.pdb
                    set RUSTFLAGS=-Ccontrol-flow-guard -Ctarget-feature=+crt-static -Clink-args=/DYNAMICBASE -Clink-args=/CETCOMPAT
                    cargo build --workspace --locked --release 2>&1
                    rd /s /q target\release\build

                  displayName: 'Build Release'

                - task: UseDotNet@2
                  inputs:
                    packageType: 'sdk'
                    version: '6.x'

                - task: EsrpCodeSigning@5
                  inputs:
                    ConnectedServiceName: 'ESRP CodeSigningV2-OneDrive Service'
                    AppRegistrationClientId: 'bd3fbc52-4cf5-4cca-a25d-94160e5ed309'
                    AppRegistrationTenantId: 'cdc5aeea-15c5-4db6-b079-fcadd2505dc2'
                    AuthAKVName: 'ODSP-ESRP'
                    AuthCertName: 'ODSP-ESRP-Auth-V2'
                    AuthSignCertName: 'CodeSigningCertificate'
                    FolderPath: '$(Build.SourcesDirectory)'
                    Pattern: '
                      target\release\lepton_jpeg.dll,
                      target\release\lepton_jpeg_avx2.dll,
                      target\release\lepton_jpeg_util.exe,
                      target\release\lepton_jpeg_util_avx2.exe'
                    signConfigType: 'inlineSignParams'
                    inlineOperation: |
                      [
                      {
                        "KeyCode": "CP-401405",
                        "OperationCode": "SigntoolSign",
                        "ToolName": "sign",
                        "ToolVersion": "1.0",
                        "Parameters": {
                        "OpusName": "Microsoft",
                        "OpusInfo": "https://www.microsoft.com",
                        "FileDigest": "/fd SHA256",
                        "PageHash": "/NPH",
                        "TimeStamp": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"
                        }
                      },
                      {
                        "KeyCode": "CP-401405",
                        "OperationCode": "SigntoolVerify",
                        "ToolName": "sign",
                        "ToolVersion": "1.0",
                        "Parameters": {}
                      }
                      ]
                    SessionTimeout: '60'
                    MaxConcurrency: '50'
                    MaxRetryAttempts: '5'
                    PendingAnalysisWaitTimeoutMinutes: '5'

                - task: CopyFiles@2
                  displayName: 'Copy Rust output files to: $(Build.ArtifactStagingDirectory) copy'
                  inputs:
                    SourceFolder: '$(Build.SourcesDirectory)'
                    Contents: |
                      target\debug\?(*.dll|*.exe|*.pdb)
                      target\release\?(*.dll|*.exe|*.pdb)

                    TargetFolder: '$(Build.ArtifactStagingDirectory)'

                - task: PublishSymbols@2
                  displayName: 'Publish symbols copy'
                  inputs:
                    SymbolsFolder: '$(Build.ArtifactStagingDirectory)'
                    SearchPattern: '**\*.pdb'
                    SymbolServerType: TeamServices

                - task: NuGetCommand@2
                  displayName: 'NuGet pack'
                  inputs:
                    command: pack
                    packagesToPack: package/Lepton.Jpeg.Rust.nuspec

                - task: 1ES.PublishNuGet@1
                  displayName: 'NuGet push'
                  condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/v'))
                  inputs:
                    packageParentPath: '$(Pipeline.Workspace)'
                    packagesToPush: '$(Build.ArtifactStagingDirectory)\*.nupkg'
                    publishVstsFeed: 'b87285d9-99ab-48db-a000-cb0cc8a2a1b5'
                    allowPackageConflicts: true


================================================
FILE: benches/benches.rs
================================================
use std::{io::Cursor, time::Duration};

use criterion::{Criterion, criterion_group, criterion_main};
use lepton_jpeg::{EnabledFeatures, SingleThreadPool};

fn read_file(filename: &str, ext: &str) -> Vec<u8> {
    let filename = std::path::Path::new(env!("WORKSPACE_ROOT"))
        .join("images")
        .join(filename.to_owned() + ext);
    //println!("reading {0}", filename.to_str().unwrap());
    let mut f = std::fs::File::open(filename).unwrap();

    let mut content = Vec::new();
    std::io::Read::read_to_end(&mut f, &mut content).unwrap();

    content
}

fn end_to_end_benches(c: &mut Criterion) {
    let thread_pool = SingleThreadPool::default();
    let mut g = c.benchmark_group("end_to_end");
    g.sampling_mode(criterion::SamplingMode::Flat);
    g.warm_up_time(Duration::from_secs(1));
    g.measurement_time(Duration::from_secs(10));

    let jpeg = read_file("iphone", ".jpg");
    let lep = read_file("iphone", ".lep");

    g.bench_function("Lepton encode", |b| {
        b.iter(|| {
            let mut output = Vec::with_capacity(jpeg.len());
            lepton_jpeg::encode_lepton(
                &mut Cursor::new(&jpeg),
                &mut Cursor::new(&mut output),
                &EnabledFeatures::compat_lepton_vector_write(),
                &thread_pool,
            )
        })
    });

    g.bench_function("Lepton decode", |b| {
        b.iter(|| {
            let mut output = Vec::with_capacity(lep.len());
            lepton_jpeg::decode_lepton(
                &mut Cursor::new(&lep),
                &mut Cursor::new(&mut output),
                &EnabledFeatures::compat_lepton_vector_write(),
                &thread_pool,
            )
        })
    });

    g.finish();
}

criterion_group!(group1, end_to_end_benches);

fn micro_benchmarks(c: &mut Criterion) {
    use lepton_jpeg::micro_benchmark::{
        benchmark_idct, benchmark_read_block, benchmark_read_jpeg, benchmark_roundtrip_coefficient,
        benchmark_write_block, benchmark_write_jpeg,
    };

    c.bench_function("jpeg read", |b| b.iter(benchmark_read_jpeg()));

    c.bench_function("jpeg write", |b| b.iter(benchmark_write_jpeg()));

    c.bench_function("roundtrip coefficient write", |b| {
        b.iter(benchmark_roundtrip_coefficient())
    });

    c.bench_function("idct benchmark", |b| b.iter(benchmark_idct()));

    c.bench_function("jpeg read block", |b| b.iter(benchmark_read_block()));

    c.bench_function("jpeg write block", |b| b.iter(benchmark_write_block()));
}

criterion_group!(group2, micro_benchmarks);

criterion_main!(group1, group2);


================================================
FILE: dll/Cargo.toml
================================================
[package]
name = "lepton_jpeg_dll"
version.workspace = true
edition = "2024"
authors = ["Kristof Roomp <kristofr@microsoft.com>"]

[dependencies]
lepton_jpeg = { path = "../lib" }
rayon = "1"
msvc_spectre_libs = "0.1.3"

[dev-dependencies]
rstest = "0.22"

[lib]
crate-type = ["cdylib"]
name = "lepton_jpeg"

================================================
FILE: dll/src/lib.rs
================================================
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the Apache License, Version 2.0. See LICENSE.txt in the project root for license information.
 *  This software incorporates material from third parties. See NOTICE.txt for details.
 *--------------------------------------------------------------------------------------------*/

#![forbid(trivial_numeric_casts)]

use std::{
    collections::VecDeque,
    io::Cursor,
    sync::{
        LazyLock,
        atomic::{AtomicU32, Ordering},
    },
};

use lepton_jpeg::{
    DEFAULT_THREAD_POOL, EnabledFeatures, ExitCode, LeptonFileReader, LeptonThreadPool,
    SingleThreadPool, ThreadPoolHolder, catch_unwind_result, decode_lepton, encode_lepton,
    get_git_version,
};

/// copies a string into a limited length zero terminated utf8 buffer
fn copy_cstring_utf8_to_buffer(str: &str, target_error_string: &mut [u8]) {
    if target_error_string.len() == 0 {
        return;
    }

    // copy error string into the buffer as utf8
    let b = std::ffi::CString::new(str).unwrap();
    let b = b.as_bytes();

    let copy_len = std::cmp::min(b.len(), target_error_string.len() - 1);

    // copy string into buffer as much as fits
    target_error_string[0..copy_len].copy_from_slice(&b[0..copy_len]);

    // always null terminated
    target_error_string[copy_len] = 0;
}

struct RayonThreadPool {
    pool: LazyLock<rayon::ThreadPool>,
}

impl LeptonThreadPool for RayonThreadPool {
    fn max_parallelism(&self) -> usize {
        NUM_THREADS.load(Ordering::SeqCst) as usize
    }
    fn run(&self, f: Box<dyn FnOnce() + Send + 'static>) {
        self.pool.spawn(f);
    }
}

static NUM_THREADS: AtomicU32 = AtomicU32::new(8);

static RAYON_THREAD_POOL: RayonThreadPool = RayonThreadPool {
    pool: LazyLock::new(|| {
        rayon::ThreadPoolBuilder::new()
            .num_threads(NUM_THREADS.load(Ordering::SeqCst) as usize) // default to 8 threads, can be adjusted
            .build()
            .unwrap()
    }),
};

/// C ABI interface for setting the number of threads to use for compression and decompression
/// This can only be called before any compression or decompression is done, as we cannot
/// change the number of threads in the threadpool once it is created.
pub unsafe extern "C" fn set_num_threads(num_threads: u32) {
    NUM_THREADS.store(num_threads, Ordering::SeqCst);
}

/// C ABI interface for compressing image, exposed from DLL
#[unsafe(no_mangle)]
#[allow(non_snake_case, unsafe_op_in_unsafe_fn)]
pub unsafe extern "C" fn WrapperCompressImage(
    input_buffer: *const u8,
    input_buffer_size: u64,
    output_buffer: *mut u8,
    output_buffer_size: u64,
    number_of_threads: i32,
    result_size: *mut u64,
) -> i32 {
    let mut cpu_usage: u64 = 0;
    WrapperCompressImage3(
        input_buffer,
        input_buffer_size,
        output_buffer,
        output_buffer_size,
        number_of_threads as u32,
        result_size,
        (&mut cpu_usage) as *mut u64,
        0,
        std::ptr::null_mut(),
        0,
    )
}

/// C ABI interface for compressing image, exposed from DLL
#[unsafe(no_mangle)]
#[allow(non_snake_case, unsafe_op_in_unsafe_fn)]
pub unsafe extern "C" fn WrapperCompressImage2(
    input_buffer: *const u8,
    input_buffer_size: u64,
    output_buffer: *mut u8,
    output_buffer_size: u64,
    number_of_threads: u32,
    result_size: *mut u64,
    cpu_usage: *mut u64,
    flags: u32,
) -> i32 {
    WrapperCompressImage3(
        input_buffer,
        input_buffer_size,
        output_buffer,
        output_buffer_size,
        number_of_threads,
        result_size,
        cpu_usage,
        flags,
        std::ptr::null_mut(),
        0,
    )
}

/// C ABI interface for compressing image, exposed from DLL
#[unsafe(no_mangle)]
#[allow(non_snake_case, unsafe_op_in_unsafe_fn)]
pub unsafe extern "C" fn WrapperCompressImage3(
    input_buffer: *const u8,
    input_buffer_size: u64,
    output_buffer: *mut u8,
    output_buffer_size: u64,
    number_of_threads: u32,
    result_size: *mut u64,
    cpu_usage: *mut u64,
    flags: u32,
    error_string: *mut std::os::raw::c_uchar,
    error_string_buffer_len: u64,
) -> i32 {
    match catch_unwind_result(|| {
        let input = std::slice::from_raw_parts(input_buffer, input_buffer_size as usize);

        let output = std::slice::from_raw_parts_mut(output_buffer, output_buffer_size as usize);

        let mut reader = Cursor::new(input);
        let mut writer = Cursor::new(output);

        let mut features = EnabledFeatures::compat_lepton_vector_write();
        if number_of_threads > 0 {
            features.max_partitions = number_of_threads;
        }

        let thread_pool: &dyn LeptonThreadPool = if flags & USE_RAYON_THREAD_POOL != 0 {
            &RAYON_THREAD_POOL
        } else if flags & USE_SINGLE_THREAD_POOL != 0 {
            &SingleThreadPool::default()
        } else {
            &DEFAULT_THREAD_POOL
        };

        let metrics = encode_lepton(&mut reader, &mut writer, &features, thread_pool)?;

        *result_size = writer.position().into();
        *cpu_usage = metrics.get_cpu_time_worker_time().as_millis() as u64;

        Ok(())
    }) {
        Ok(()) => {
            return 0;
        }
        Err(e) => {
            if error_string_buffer_len > 0 {
                copy_cstring_utf8_to_buffer(
                    e.message(),
                    std::slice::from_raw_parts_mut(error_string, error_string_buffer_len as usize),
                );
            }

            return e.exit_code().as_integer_error_code();
        }
    }
}

/// C ABI interface for decompressing image, exposed from DLL
#[unsafe(no_mangle)]
#[allow(non_snake_case, unsafe_op_in_unsafe_fn)]
pub unsafe extern "C" fn WrapperDecompressImage(
    input_buffer: *const u8,
    input_buffer_size: u64,
    output_buffer: *mut u8,
    output_buffer_size: u64,
    number_of_threads: i32,
    result_size: *mut u64,
) -> i32 {
    let mut cpu_usage: u64 = 0;
    return WrapperDecompressImage4(
        input_buffer,
        input_buffer_size,
        output_buffer,
        output_buffer_size,
        number_of_threads as u32,
        result_size,
        (&mut cpu_usage) as *mut u64,
        0,
        std::ptr::null_mut(),
        0,
    );
}

/// C ABI interface for decompressing image, exposed from DLL.
/// use_16bit_dc_estimate argument should be set to true only for images
/// that were compressed by C++ version of Leptron (see comments below).
#[unsafe(no_mangle)]
#[allow(non_snake_case, unsafe_op_in_unsafe_fn)]
pub unsafe extern "C" fn WrapperDecompressImageEx(
    input_buffer: *const u8,
    input_buffer_size: u64,
    output_buffer: *mut u8,
    output_buffer_size: u64,
    number_of_threads: i32,
    result_size: *mut u64,
    use_16bit_dc_estimate: bool,
) -> i32 {
    let mut cpu_usage: u64 = 0;
    WrapperDecompressImage4(
        input_buffer,
        input_buffer_size,
        output_buffer,
        output_buffer_size,
        number_of_threads as u32,
        result_size,
        (&mut cpu_usage) as *mut u64,
        if use_16bit_dc_estimate {
            DECOMPRESS_USE_16BIT_DC_ESTIMATE
        } else {
            0
        },
        std::ptr::null_mut(),
        0,
    )
}

/// C ABI interface for decompressing image, exposed from DLL.
#[unsafe(no_mangle)]
#[allow(non_snake_case, unsafe_op_in_unsafe_fn)]
pub unsafe extern "C" fn WrapperDecompressImage3(
    input_buffer: *const u8,
    input_buffer_size: u64,
    output_buffer: *mut u8,
    output_buffer_size: u64,
    number_of_threads: u32,
    result_size: *mut u64,
    cpu_usage: *mut u64,
    flags: u32,
) -> i32 {
    WrapperDecompressImage4(
        input_buffer,
        input_buffer_size,
        output_buffer,
        output_buffer_size,
        number_of_threads,
        result_size,
        cpu_usage,
        flags,
        std::ptr::null_mut(),
        0,
    )
}

/// C ABI interface for decompressing image, exposed from DLL.
#[unsafe(no_mangle)]
#[allow(non_snake_case, unsafe_op_in_unsafe_fn)]
pub unsafe extern "C" fn WrapperDecompressImage4(
    input_buffer: *const u8,
    input_buffer_size: u64,
    output_buffer: *mut u8,
    output_buffer_size: u64,
    number_of_threads: u32,
    result_size: *mut u64,
    cpu_usage: *mut u64,
    flags: u32,
    error_string: *mut std::os::raw::c_uchar,
    error_string_buffer_len: u64,
) -> i32 {
    match catch_unwind_result(|| {
        // For back-compat with C++ version we allow decompression of images with zeros in DQT tables

        // C++ version has a bug where it uses 16 bit math in the SIMD path and 32 bit math in the scalar path
        // depending on the compiler options. If use_16bit_dc_estimate=true, the decompression uses a back-compat
        // mode that considers it. The caller should set use_16bit_dc_estimate to true only for images that were
        // compressed by C++ version with relevant compiler options.

        // this is a bit of a mess since for a while we were encoded a mix of 16 and 32 bit math
        // (hence the two parameters in features).

        let mut enabled_features = EnabledFeatures {
            use_16bit_dc_estimate: (flags & DECOMPRESS_USE_16BIT_DC_ESTIMATE != 0),
            ..EnabledFeatures::compat_lepton_vector_read()
        };

        if number_of_threads > 0 {
            enabled_features.max_partitions = number_of_threads;
        }

        let thread_pool: &dyn LeptonThreadPool = if flags & USE_RAYON_THREAD_POOL != 0 {
            &RAYON_THREAD_POOL
        } else if flags & USE_SINGLE_THREAD_POOL != 0 {
            &SingleThreadPool::default()
        } else {
            &DEFAULT_THREAD_POOL
        };

        loop {
            let input = std::slice::from_raw_parts(input_buffer, input_buffer_size as usize);
            let output = std::slice::from_raw_parts_mut(output_buffer, output_buffer_size as usize);

            let mut reader = Cursor::new(input);
            let mut writer = Cursor::new(output);

            match decode_lepton(&mut reader, &mut writer, &mut enabled_features, thread_pool) {
                Ok(metrics) => {
                    *result_size = writer.position().into();
                    *cpu_usage = metrics.get_cpu_time_worker_time().as_millis() as u64;
                    return Ok(());
                }
                Err(e) => {
                    // The retry logic below runs if the caller did not pass use_16bit_dc_estimate=true, but the decompression
                    // encountered StreamInconsistent failure which is commonly caused by the the C++ 16 bit bug. In this case
                    // we retry the decompression with use_16bit_dc_estimate=true.
                    // Note that it's prefferable for the caller to pass use_16bit_dc_estimate properly and not to rely on this
                    // retry logic, that may miss some cases leading to bad (corrupted) decompression results.
                    if e.exit_code() == ExitCode::StreamInconsistent
                        && !enabled_features.use_16bit_dc_estimate
                    {
                        enabled_features.use_16bit_dc_estimate = true;
                        continue;
                    }

                    return Err(e.into());
                }
            }
        }
    }) {
        Ok(()) => {
            return 0;
        }
        Err(e) => {
            if error_string_buffer_len > 0 {
                copy_cstring_utf8_to_buffer(
                    e.message(),
                    std::slice::from_raw_parts_mut(error_string, error_string_buffer_len as usize),
                );
            }
            return e.exit_code().as_integer_error_code();
        }
    }
}

static PACKAGE_VERSION: &str = env!("CARGO_PKG_VERSION");

pub fn get_version_string() -> String {
    format!("{}-{}", PACKAGE_VERSION, get_git_version())
}

#[unsafe(no_mangle)]
pub unsafe extern "C" fn get_version(
    package: &mut *const std::os::raw::c_char,
    git: &mut *const std::os::raw::c_char,
) {
    *git = get_git_version().as_ptr() as *const std::os::raw::c_char;
    *package = PACKAGE_VERSION.as_ptr() as *const std::os::raw::c_char;
}

// wraps unmanaged context for decompression and tries to ensure that if is valid
// when passed in from C# or C++ code and that it is freed only once.
//
// Of course, there aren't any guarantees since passing raw pointers around is inherently unsafe,
// but we do our best to catch common mistakes and point the blame in the right direction.
struct DecompressionContext<'a> {
    magic: u32,
    internal: LeptonFileReader<'a>,
    extra_data: VecDeque<u8>,
}

const MAGIC_DECOMRESSION_CONTEXT: u32 = 0xdec0de00;

impl<'a> DecompressionContext<'a> {
    /// casts c pointer to a reference, verifying the magic number is OK so we can catch
    /// some common mistakes early. This is no guarantee, but helps crash early in many cases.
    unsafe fn from_pointer(ptr: *mut std::ffi::c_void) -> &'a mut Self {
        unsafe {
            let context = ptr as *mut DecompressionContext;
            assert_eq!(
                (*context).magic,
                MAGIC_DECOMRESSION_CONTEXT,
                "invalid context passed in"
            );
            &mut *context
        }
    }

    /// allocates a new context and returns a pointer to it
    unsafe fn new(internal: LeptonFileReader<'a>) -> *mut std::ffi::c_void {
        let context = Box::new(Self {
            magic: MAGIC_DECOMRESSION_CONTEXT,
            internal,
            extra_data: VecDeque::new(),
        });

        Box::into_raw(context) as *mut std::ffi::c_void
    }

    unsafe fn free(ptr: *mut std::ffi::c_void) {
        unsafe {
            let mut context = Box::from_raw(ptr as *mut DecompressionContext);
            assert_eq!(
                (*context).magic,
                MAGIC_DECOMRESSION_CONTEXT,
                "invalid context passed in"
            );
            // invalidate magic to catch double free
            context.magic = 0xdeaddead;

            // context is freed now by going out of scope
        }
    }
}

const DECOMPRESS_USE_16BIT_DC_ESTIMATE: u32 = 1;
const USE_RAYON_THREAD_POOL: u32 = 2;
const USE_SINGLE_THREAD_POOL: u32 = 4;

#[unsafe(no_mangle)]
pub unsafe extern "C" fn create_decompression_context(features: u32) -> *mut std::ffi::c_void {
    let enabled_features = EnabledFeatures {
        use_16bit_dc_estimate: (features & DECOMPRESS_USE_16BIT_DC_ESTIMATE != 0),
        ..EnabledFeatures::compat_lepton_vector_read()
    };

    let thread_pool: ThreadPoolHolder = if features & USE_RAYON_THREAD_POOL != 0 {
        ThreadPoolHolder::Dyn(&RAYON_THREAD_POOL)
    } else if features & USE_SINGLE_THREAD_POOL != 0 {
        ThreadPoolHolder::Owned(Box::new(SingleThreadPool::default()))
    } else {
        ThreadPoolHolder::Dyn(&DEFAULT_THREAD_POOL)
    };

    unsafe { DecompressionContext::new(LeptonFileReader::new(enabled_features, thread_pool)) }
}

#[unsafe(no_mangle)]
#[allow(unsafe_op_in_unsafe_fn)]
pub unsafe extern "C" fn get_decompression_cpu(context: *mut std::ffi::c_void) -> u64 {
    let context = DecompressionContext::from_pointer(context);

    context
        .internal
        .metrics()
        .get_cpu_time_worker_time()
        .as_millis() as u64
}

#[unsafe(no_mangle)]
#[allow(unsafe_op_in_unsafe_fn)]
pub unsafe extern "C" fn free_decompression_context(context: *mut std::ffi::c_void) {
    DecompressionContext::free(context);
}

/// partially decompresses an image from a Lepton file.
///
/// Returns -1 if more data is needed or if there is more data available, or 0 if done successfully.
/// Returns > 0 if there is an error
#[unsafe(no_mangle)]
#[allow(unsafe_op_in_unsafe_fn)]
pub unsafe extern "C" fn decompress_image(
    context: *mut std::ffi::c_void,
    input_buffer: *const u8,
    input_buffer_size: u64,
    input_complete: bool,
    output_buffer: *mut u8,
    output_buffer_size: u64,
    result_size: *mut u64,
    error_string: *mut std::os::raw::c_uchar,
    error_string_buffer_len: u64,
) -> i32 {
    match catch_unwind_result(|| {
        let context = DecompressionContext::from_pointer(context);

        let input = std::slice::from_raw_parts(input_buffer, input_buffer_size as usize);
        let output = std::slice::from_raw_parts_mut(output_buffer, output_buffer_size as usize);

        let (done, size) = context.internal.process_limited_buffer(
            input,
            input_complete,
            output,
            &mut context.extra_data,
        )?;

        *result_size = size as u64;
        Ok(done)
    }) {
        Ok(done) => {
            if done {
                0
            } else {
                -1
            }
        }
        Err(e) => {
            if error_string_buffer_len > 0 {
                copy_cstring_utf8_to_buffer(
                    e.message(),
                    std::slice::from_raw_parts_mut(error_string, error_string_buffer_len as usize),
                );
            }
            e.exit_code().as_integer_error_code()
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    use rstest::rstest;

    fn read_file(filename: &str, ext: &str) -> Vec<u8> {
        let filename = std::path::Path::new(env!("WORKSPACE_ROOT"))
            .join("images")
            .join(filename.to_owned() + ext);
        //println!("reading {0}", filename.to_str().unwrap());
        let mut f = std::fs::File::open(filename).unwrap();

        let mut content = Vec::new();
        std::io::Read::read_to_end(&mut f, &mut content).unwrap();

        content
    }

    #[test]
    fn test_copy_cstring_utf8_to_buffer() {
        // test utf8
        let mut buffer = [0u8; 10];
        copy_cstring_utf8_to_buffer("h\u{00E1}llo", &mut buffer);
        assert_eq!(buffer, [b'h', 0xc3, 0xa1, b'l', b'l', b'o', 0, 0, 0, 0]);

        // test null termination
        let mut buffer = [0u8; 10];
        copy_cstring_utf8_to_buffer("helloeveryone", &mut buffer);
        assert_eq!(
            buffer,
            [b'h', b'e', b'l', b'l', b'o', b'e', b'v', b'e', b'r', 0]
        );
    }

    /// test original version of external interface that just delegates to the new one
    #[test]
    fn extern_interface() {
        let input = read_file("slrcity", ".jpg");

        let mut compressed = Vec::new();

        compressed.resize(input.len() + 10000, 0);

        let mut result_size: u64 = 0;

        unsafe {
            let retval = WrapperCompressImage(
                input[..].as_ptr(),
                input.len() as u64,
                compressed[..].as_mut_ptr(),
                compressed.len() as u64,
                8,
                (&mut result_size) as *mut u64,
            );

            assert_eq!(retval, 0);
        }

        let mut original = Vec::new();
        original.resize(input.len() + 10000, 0);

        let mut original_size: u64 = 0;
        unsafe {
            let retval = WrapperDecompressImageEx(
                compressed[..].as_ptr(),
                result_size,
                original[..].as_mut_ptr(),
                original.len() as u64,
                8,
                (&mut original_size) as *mut u64,
                false,
            );

            assert_eq!(retval, 0);
        }
        assert_eq!(input.len() as u64, original_size);
        assert_eq!(input[..], original[..(original_size as usize)]);
    }

    /// test version 2 of external interface
    #[test]
    fn extern_interface_2() {
        let input = read_file("slrcity", ".jpg");

        let mut compressed = Vec::new();

        compressed.resize(input.len() + 10000, 0);

        let mut result_size: u64 = 0;
        let mut cpu_usage: u64 = 0;

        unsafe {
            let retval = WrapperCompressImage2(
                input[..].as_ptr(),
                input.len() as u64,
                compressed[..].as_mut_ptr(),
                compressed.len() as u64,
                8,
                (&mut result_size) as *mut u64,
                (&mut cpu_usage) as *mut u64,
                0,
            );

            assert_eq!(retval, 0);
        }

        let mut original = Vec::new();
        original.resize(input.len() + 10000, 0);

        let mut original_size: u64 = 0;
        unsafe {
            let retval = WrapperDecompressImage3(
                compressed[..].as_ptr(),
                result_size,
                original[..].as_mut_ptr(),
                original.len() as u64,
                8,
                (&mut original_size) as *mut u64,
                (&mut cpu_usage) as *mut u64,
                0,
            );

            assert_eq!(retval, 0);
        }
        assert_eq!(input.len() as u64, original_size);
        assert_eq!(input[..], original[..(original_size as usize)]);
    }

    /// test version 2 of external interface with single thread
    #[test]
    fn extern_interface_2_single_thread() {
        let input = read_file("slrcity", ".jpg");

        let mut compressed = Vec::new();

        compressed.resize(input.len() + 10000, 0);

        let mut result_size: u64 = 0;
        let mut cpu_usage: u64 = 0;

        unsafe {
            let retval = WrapperCompressImage2(
                input[..].as_ptr(),
                input.len() as u64,
                compressed[..].as_mut_ptr(),
                compressed.len() as u64,
                8,
                (&mut result_size) as *mut u64,
                (&mut cpu_usage) as *mut u64,
                USE_SINGLE_THREAD_POOL,
            );

            assert_eq!(retval, 0);
        }

        let mut original = Vec::new();
        original.resize(input.len() + 10000, 0);

        let mut original_size: u64 = 0;
        unsafe {
            let retval = WrapperDecompressImage3(
                compressed[..].as_ptr(),
                result_size,
                original[..].as_mut_ptr(),
                original.len() as u64,
                8,
                (&mut original_size) as *mut u64,
                (&mut cpu_usage) as *mut u64,
                USE_SINGLE_THREAD_POOL,
            );

            assert_eq!(retval, 0);
        }
        assert_eq!(input.len() as u64, original_size);
        assert_eq!(input[..], original[..(original_size as usize)]);
    }

    /// test version 3 of external interface with single thread
    #[test]
    fn extern_interface_3_single_thread() {
        let input = read_file("slrcity", ".jpg");

        let mut compressed = Vec::new();

        compressed.resize(input.len() + 10000, 0);

        let mut result_size: u64 = 0;
        let mut cpu_usage: u64 = 0;

        let mut error_string = [0u8; 1024];

        unsafe {
            let retval = WrapperCompressImage3(
                input[..].as_ptr(),
                0,
                compressed[..].as_mut_ptr(),
                compressed.len() as u64,
                8,
                (&mut result_size) as *mut u64,
                (&mut cpu_usage) as *mut u64,
                USE_SINGLE_THREAD_POOL,
                error_string.as_mut_ptr(),
                error_string.len() as u64,
            );
            // error string should complain about invalid input
            assert_ne!(retval, 0);

            // convert null terminated error_string into str
            let error_str = std::str::from_utf8(&error_string)
                .unwrap()
                .trim_end_matches(char::from(0));

            assert!(error_str.contains("jpeg must start with with 0xff 0xd8"));

            let retval = WrapperCompressImage3(
                input[..].as_ptr(),
                input.len() as u64,
                compressed[..].as_mut_ptr(),
                compressed.len() as u64,
                8,
                (&mut result_size) as *mut u64,
                (&mut cpu_usage) as *mut u64,
                USE_SINGLE_THREAD_POOL,
                error_string.as_mut_ptr(),
                error_string.len() as u64,
            );

            assert_eq!(retval, 0);
        }

        let mut original = Vec::new();
        original.resize(input.len() + 10000, 0);

        let mut original_size: u64 = 0;
        unsafe {
            let retval = WrapperDecompressImage4(
                compressed[..].as_ptr(),
                result_size,
                original[..].as_mut_ptr(),
                original.len() as u64,
                8,
                (&mut original_size) as *mut u64,
                (&mut cpu_usage) as *mut u64,
                USE_SINGLE_THREAD_POOL,
                error_string.as_mut_ptr(),
                error_string.len() as u64,
            );

            assert_eq!(retval, 0);
        }
        assert_eq!(input.len() as u64, original_size);
        assert_eq!(input[..], original[..(original_size as usize)]);
    }

    /// tests the chunked decompression interface
    #[rstest]
    fn extern_interface_decompress_chunked(
        #[values(DECOMPRESS_USE_16BIT_DC_ESTIMATE,DECOMPRESS_USE_16BIT_DC_ESTIMATE|USE_RAYON_THREAD_POOL)]
        flags: u32,
    ) {
        use std::io::Read;

        let input = read_file("slrcity", ".lep");

        let mut output = Vec::new();

        unsafe {
            let context = create_decompression_context(flags);

            let mut file_read = Cursor::new(input);
            let mut input_buffer = [0u8; 7];
            let mut output_buffer = [0u8; 13];

            let mut error_string = [0u8; 1024];

            loop {
                let amount_read = file_read.read(&mut input_buffer).unwrap();

                let mut result_size = 0;
                let result = decompress_image(
                    context,
                    input_buffer.as_ptr(),
                    amount_read as u64,
                    amount_read == 0,
                    output_buffer.as_mut_ptr(),
                    output_buffer.len() as u64,
                    &mut result_size,
                    error_string.as_mut_ptr(),
                    error_string.len() as u64,
                );

                output.extend_from_slice(&output_buffer[..result_size as usize]);

                match result {
                    -1 => {
                        // need more data
                    }
                    0 => {
                        break;
                    }
                    _ => {
                        panic!("unexpected error {0}", result);
                    }
                }
            }
            free_decompression_context(context);
        }

        let test_result = read_file("slrcity", ".jpg");
        assert_eq!(test_result.len(), output.len());
        assert!(test_result[..] == output[..]);
    }

    #[rstest]
    fn verify_extern_interface_rejects_compression_of_unsupported_jpegs(
        #[values(
        ("zeros_in_dqt_tables", ExitCode::UnsupportedJpegWithZeroIdct0), 
        ("nonoptimalprogressive", ExitCode::UnsupportedJpeg))]
        file: (&str, ExitCode),
    ) {
        let input = read_file(file.0, ".jpg");

        let mut compressed = Vec::new();
        compressed.resize(input.len() + 10000, 0);
        let mut result_size: u64 = 0;
        let mut cpu_usage: u64 = 0;

        unsafe {
            let retval = WrapperCompressImage2(
                input[..].as_ptr(),
                input.len() as u64,
                compressed[..].as_mut_ptr(),
                compressed.len() as u64,
                8,
                (&mut result_size) as *mut u64,
                (&mut cpu_usage) as *mut u64,
                0,
            );

            assert_eq!(retval, file.1.as_integer_error_code());
        }
    }

    /// While we prevent compression of images with zeros in DQT tables, since it may lead to divide-by-zero, we support decompression of
    /// previously compressed images with this characteristics for back-compat.
    #[rstest]
    fn verify_extern_interface_supports_decompression_with_zeros_in_dqt_tables(
        #[values("zeros_in_dqt_tables")] file: &str,
    ) {
        let compressed = read_file(file, ".lep");
        let original = read_file(file, ".jpg");

        let mut decompressed = Vec::new();
        decompressed.resize(original.len() + 10000, 0);

        let mut decompressed_size: u64 = 0;
        let mut cpu_usage: u64 = 0;

        unsafe {
            let retval = WrapperDecompressImage3(
                compressed[..].as_ptr(),
                compressed.len() as u64,
                decompressed[..].as_mut_ptr(),
                decompressed.len() as u64,
                8,
                (&mut decompressed_size) as *mut u64,
                (&mut cpu_usage) as *mut u64,
                0,
            );

            assert_eq!(retval, 0);
        }

        assert_eq!(original.len() as u64, decompressed_size);
        assert_eq!(original[..], decompressed[..(decompressed_size as usize)]);
    }

    /// Verifies that the decode will accept existing Lepton files and generate
    /// exactly the same jpeg from them when called by an external interface
    /// with use_16bit_dc_estimate=true for C++ backward compatibility.
    /// Used to detect unexpected divergences in coding format.
    #[rstest]
    fn verify_decode_external_interface_with_use_16bit_dc_estimate(
        #[values(
        "mathoverflow_16",
        "android",
        "androidcrop",
        "androidcropoptions",
        "androidprogressive",
        "androidprogressive_garbage",
        "androidtrail",
        "colorswap",
        "gray2sf",
        "grayscale",
        "hq",
        "iphone",
        "iphonecity",
        "iphonecity_with_16KGarbage",
        "iphonecity_with_1MGarbage",
        "iphonecrop",
        "iphonecrop2",
        "iphoneprogressive",
        "iphoneprogressive2",
        "progressive_late_dht", // image has huffman tables that come very late which causes a verification failure 
        "out_of_order_dqt",     // image with quanatization table dqt that comes after image definition SOF
        "narrowrst",
        "nofsync",
        "slrcity",
        "slrhills",
        "slrindoor",
        "tiny",
        "trailingrst",
        "trailingrst2",
        "trunc",
        "eof_and_trailingrst",    // the lepton format has a wrongly set unexpected eof and trailing rst
        "eof_and_trailinghdrdata" // the lepton format has a wrongly set unexpected eof and trailing header data
    )]
        file: &str,
    ) {
        println!("decoding {0:?}", file);

        let compressed = read_file(file, ".lep");
        let jpg_file_name = match file {
            "mathoverflow_16" => "mathoverflow",
            _ => file,
        };
        let input = read_file(jpg_file_name, ".jpg");

        let mut original = Vec::new();
        original.resize(input.len() + 10000, 0);

        let mut original_size: u64 = 0;
        let mut cpu_usage: u64 = 0;

        unsafe {
            let retval = WrapperDecompressImage3(
                compressed[..].as_ptr(),
                compressed.len() as u64,
                original[..].as_mut_ptr(),
                original.len() as u64,
                8,
                (&mut original_size) as *mut u64,
                (&mut cpu_usage) as *mut u64,
                DECOMPRESS_USE_16BIT_DC_ESTIMATE,
            );

            assert_eq!(retval, 0);
        }
        assert_eq!(input.len() as u64, original_size);
        assert_eq!(input[..], original[..(original_size as usize)]);
    }

    #[test]
    fn verify_extern_16bit_math_retry() {
        // verify retry logic for 16 bit math encoded image
        let compressed = read_file("mathoverflow_16", ".lep");

        let input = read_file("mathoverflow", ".jpg");

        let mut original = Vec::new();
        original.resize(input.len() + 10000, 0);

        let mut original_size: u64 = 0;
        let mut cpu_usage: u64 = 0;

        unsafe {
            let retval = WrapperDecompressImage3(
                compressed[..].as_ptr(),
                compressed.len() as u64,
                original[..].as_mut_ptr(),
                original.len() as u64,
                8,
                (&mut original_size) as *mut u64,
                (&mut cpu_usage) as *mut u64,
                0,
            );

            assert_eq!(retval, 0);
        }
        assert_eq!(input.len() as u64, original_size);
        assert_eq!(input[..], original[..(original_size as usize)]);
    }
}


================================================
FILE: fuzz/.cargo/config.toml
================================================
[target.x86_64-unknown-linux-gnu]
rustflags = ["-Ctarget_cpu=native"]

================================================
FILE: fuzz/.gitignore
================================================
target
corpus
artifacts
coverage
*.log

================================================
FILE: fuzz/Cargo.toml
================================================
[package]
name = "lepton_jpeg-fuzz"
version = "0.0.0"
publish = false
edition = "2024"

[package.metadata]
cargo-fuzz = true

[dependencies]
libfuzzer-sys = "0.4"

[dependencies.lepton_jpeg]
path = "../lib"

# Prevent this from interfering with workspaces
[workspace]
members = ["."]

[profile.release]
debug = 1

[[bin]]
name = "fuzz_target_1"
path = "fuzz_targets/fuzz_target_1.rs"
test = false
doc = false


================================================
FILE: fuzz/fuzz_targets/fuzz_target_1.rs
================================================
#![no_main]

use std::io::Cursor;

use lepton_jpeg::{decode_lepton, encode_lepton, EnabledFeatures, DEFAULT_THREAD_POOL};

use libfuzzer_sys::fuzz_target;

fuzz_target!(|data: &[u8]| {
    let r;

    let mut output = Vec::new();

    let use_16bit = match data.len() % 2 { 0 => false, _ => true };
    let accept_invalid_dht = match (data.len() / 2) % 2 { 0 => false, _ => true };

    // keep the jpeg dimensions small otherwise the fuzzer gets really slow
    let features = EnabledFeatures {
        progressive: true,
        reject_dqts_with_zeros: true,
        max_jpeg_height: 1024,
        max_jpeg_width: 1024,
        use_16bit_dc_estimate: use_16bit,
        use_16bit_adv_predict: use_16bit,
        accept_invalid_dht: accept_invalid_dht,
        .. EnabledFeatures::compat_lepton_vector_write()
    };

    {
        let mut writer = Cursor::new(&mut output);

        r = encode_lepton(&mut Cursor::new(&data), &mut writer, &features, &DEFAULT_THREAD_POOL);
    }

    let mut original = Vec::new();

    match r {
        Ok(_) => {
            let _ = decode_lepton(&mut Cursor::new(&output), &mut original, &features, &DEFAULT_THREAD_POOL);
        }
        Err(_) => {}
    }
});


================================================
FILE: fuzz/rust-toolchain.toml
================================================
[toolchain]
channel = "nightly"

================================================
FILE: images/hq.lep
================================================
[File too large to display: 18.5 MB]

================================================
FILE: images/iphonecity_with_16KGarbage.jpgoutput
================================================


================================================
FILE: images/t.lepoutput
================================================


================================================
FILE: lib/Cargo.toml
================================================
[package]
name = "lepton_jpeg"
version.workspace = true
edition = "2024"
authors = ["Kristof Roomp <kristofr@microsoft.com>"]

# requires scoped threads, IsTerminal, let chains
rust-version = "1.89"
description = "Rust port of the Lepton lossless JPEG compression library"
readme = "../README.md"
repository = "https://github.com/microsoft/lepton_jpeg_rust"
license = "Apache-2.0"

categories = ["multimedia::images", "multimedia::encoding", "compression"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[features]
default = []
compression_stats = []
detailed_tracing = []

# used to expose internal functions for micro benchmarking
micro_benchmark = []

[dependencies]
bytemuck = "1"
byteorder = "1.4"
flate2 = "1.0"
default-boxed = "0.2"
wide = "0.8"
log = "0.4"
git-version = "0.3"

[target.'cfg(target_os = "windows")'.dependencies]
cpu-time = "1.0"
thread-priority = "1.0"

[target.'cfg(target_os = "linux")'.dependencies]
thread-priority = "1.0"

[dev-dependencies]
rand = "0.8"
rand_chacha = "0.3"
siphasher = "1"

[lib]
crate-type = ["lib"]


================================================
FILE: lib/src/consts.rs
================================================
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the Apache License, Version 2.0. See LICENSE.txt in the project root for license information.
 *  This software incorporates material from third parties. See NOTICE.txt for details.
 *--------------------------------------------------------------------------------------------*/

use crate::jpeg::jpeg_code;

#[derive(PartialEq, Debug)]
pub enum JpegDecodeStatus {
    DecodeInProgress,
    RestartIntervalExpired,
    ScanCompleted,
}

#[derive(PartialEq, Debug, Copy, Clone)]
pub enum JpegType {
    Unknown,
    Sequential,
    Progressive,
}

pub const COLOR_CHANNEL_NUM_BLOCK_TYPES: usize = 3;

pub const RASTER_TO_ZIGZAG: [u8; 64] = [
    0, 1, 5, 6, 14, 15, 27, 28, 2, 4, 7, 13, 16, 26, 29, 42, 3, 8, 12, 17, 25, 30, 41, 43, 9, 11,
    18, 24, 31, 40, 44, 53, 10, 19, 23, 32, 39, 45, 52, 54, 20, 22, 33, 38, 46, 51, 55, 60, 21, 34,
    37, 47, 50, 56, 59, 61, 35, 36, 48, 49, 57, 58, 62, 63,
];

// pub const ZIGZAG_TO_RASTER: [u8; 64] = [
//     0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20,
//     13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59,
//     52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63,
// ];

pub const ZIGZAG_TO_TRANSPOSED: [u8; 64] = [
    0, 8, 1, 2, 9, 16, 24, 17, 10, 3, 4, 11, 18, 25, 32, 40, 33, 26, 19, 12, 5, 6, 13, 20, 27, 34,
    41, 48, 56, 49, 42, 35, 28, 21, 14, 7, 15, 22, 29, 36, 43, 50, 57, 58, 51, 44, 37, 30, 23, 31,
    38, 45, 52, 59, 60, 53, 46, 39, 47, 54, 61, 62, 55, 63,
];

// pub const UNZIGZAG_49: [u8; 49] = [
//     9, 10, 17, 25, 18, 11, 12, 19, 26, 33, 41, 34, 27, 20, 13, 14, 21, 28, 35, 42, 49, 57, 50, 43,
//     36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62,
//     63,
// ];

pub const UNZIGZAG_49_TR: [u8; 49] = [
    9, 17, 10, 11, 18, 25, 33, 26, 19, 12, 13, 20, 27, 34, 41, 49, 42, 35, 28, 21, 14, 15, 22, 29,
    36, 43, 50, 57, 58, 51, 44, 37, 30, 23, 31, 38, 45, 52, 59, 60, 53, 46, 39, 47, 54, 61, 62, 55,
    63,
];

// precalculated int base values for 8x8 IDCT scaled by 8192
// DC coef is zeroed intentionally
pub const ICOS_BASED_8192_SCALED: [i32; 8] = [0, 11363, 10703, 9633, 8192, 6436, 4433, 2260];

pub const ICOS_BASED_8192_SCALED_PM: [i32; 8] =
    [8192, -11363, 10703, -9633, 8192, -6436, 4433, -2260];

pub const FREQ_MAX: [u16; 14] = [
    931, 985, 968, 1020, 968, 1020, 1020, 932, 985, 967, 1020, 969, 1020, 1020,
];

// used to get prediction branches basing on nonzero-number predictor `num_non_zeros_context`
pub const NON_ZERO_TO_BIN: [u8; 26] = [
    0, 1, 2, 3, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8,
];

// used to get prediction branches basing on current `num_non_zeros_left_7x7`, 0th element is not used
pub const NON_ZERO_TO_BIN_7X7: [u8; 50] = [
    0, 0, 1, 2, 3, 3, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
];

pub const RESIDUAL_NOISE_FLOOR: usize = 7;

pub const LEPTON_VERSION: u8 = 1; // Lepton version, same as used by Lepton C++ since we support the same format

pub const SMALL_FILE_BYTES_PER_ENCDOING_THREAD: usize = 125000;
pub const MAX_THREADS_SUPPORTED_BY_LEPTON_FORMAT: usize = 16; // Number of threads minus 1 should fit in 4 bits

//pub const SingleFFByte : [u8;1] = [ 0xFF ];
pub const EOI: [u8; 2] = [0xFF, jpeg_code::EOI]; // EOI segment
pub const SOI: [u8; 2] = [0xFF, jpeg_code::SOI]; // SOI segment
pub const LEPTON_FILE_HEADER: [u8; 2] = [0xcf, 0x84]; // the tau symbol for a tau lepton in utf-8
pub const LEPTON_HEADER_BASELINE_JPEG_TYPE: [u8; 1] = [b'Z'];
pub const LEPTON_HEADER_PROGRESSIVE_JPEG_TYPE: [u8; 1] = [b'X'];
pub const LEPTON_HEADER_MARKER: [u8; 3] = *b"HDR";
pub const LEPTON_HEADER_PAD_MARKER: [u8; 3] = *b"P0D";
pub const LEPTON_HEADER_JPG_RESTARTS_MARKER: [u8; 3] = *b"CRS";
pub const LEPTON_HEADER_JPG_RESTART_ERRORS_MARKER: [u8; 3] = *b"FRS";
pub const LEPTON_HEADER_LUMA_SPLIT_MARKER: [u8; 2] = *b"HH";
pub const LEPTON_HEADER_EARLY_EOF_MARKER: [u8; 3] = *b"EEE";
pub const LEPTON_HEADER_PREFIX_GARBAGE_MARKER: [u8; 3] = *b"PGR";
pub const LEPTON_HEADER_GARBAGE_MARKER: [u8; 3] = *b"GRB";
pub const LEPTON_HEADER_COMPLETION_MARKER: [u8; 3] = *b"CMP";
//pub const ChunkedLeptonHeaderSizeMarker : [u8;3] = *b"SIZ" ;
//pub const ChunkedLeptonHeaderJpgHeaderDataRangeMarker : [u8;3] = *b"JHR";


================================================
FILE: lib/src/enabled_features.rs
================================================
/// Features that are enabled in the encoder. Turn off for potential backward compat issues.
#[derive(Debug, Clone)]
pub struct EnabledFeatures {
    /// enables/disables reading of progressive images
    pub progressive: bool,

    /// reject/accept images with DQTs with zeros (may cause divide-by-zero)
    pub reject_dqts_with_zeros: bool,

    /// maximum jpeg width
    pub max_jpeg_width: u32,

    /// maximum jpeg height
    pub max_jpeg_height: u32,

    /// Sadly C++ version has a bug where it uses 16 bit math in the SIMD path and 32 bit math in the scalar path
    pub use_16bit_dc_estimate: bool,

    /// Sadly C++ version has a bug where it uses 16 bit math in the SIMD path and 32 bit math in the scalar path
    pub use_16bit_adv_predict: bool,

    /// Accept JPEG files that have invalid DHT tables
    pub accept_invalid_dht: bool,

    /// number of partitions used for encoding
    pub max_partitions: u32,

    /// maximum number of threads to use for encoding/decoding
    pub max_processor_threads: u32,

    /// maximum size of a jpeg file
    pub max_jpeg_file_size: u32,

    /// stop reading at the end of the valid JPEG file. This is useful if
    /// the stream contains other data after the EOI marker.
    ///
    /// This also disallows handling truncated JPEG files since by definition
    /// they don't have an EOI marker, instead you will get a ShortRead error.
    pub stop_reading_at_eoi: bool,
}

impl EnabledFeatures {
    /// parameters that allow everything for encoding that is compatible with c++ lepton compiled with SIMD
    #[allow(dead_code)]
    pub fn compat_lepton_vector_write() -> Self {
        Self {
            progressive: true,
            reject_dqts_with_zeros: true,
            max_jpeg_height: 16386,
            max_jpeg_width: 16386,
            use_16bit_dc_estimate: true,
            use_16bit_adv_predict: true,
            accept_invalid_dht: false,
            max_partitions: 8,
            max_processor_threads: 8,
            max_jpeg_file_size: 128 * 1024 * 1024,
            stop_reading_at_eoi: false,
        }
    }

    /// parameters that allow everything for decoding c++ lepton images encoded
    /// with the scalar compile options
    #[allow(dead_code)]
    pub fn compat_lepton_scalar_read() -> Self {
        Self {
            progressive: true,
            reject_dqts_with_zeros: false,
            max_jpeg_height: u32::MAX,
            max_jpeg_width: u32::MAX,
            use_16bit_dc_estimate: false,
            use_16bit_adv_predict: false,
            accept_invalid_dht: true,
            max_partitions: 8,
            max_processor_threads: 8,
            max_jpeg_file_size: 128 * 1024 * 1024,
            stop_reading_at_eoi: false,
        }
    }

    /// parameters that allow everything for decoding c++ lepton images encoded
    /// with the vector (SSE2/AVX2) compile options
    #[allow(dead_code)]
    pub fn compat_lepton_vector_read() -> Self {
        Self {
            progressive: true,
            reject_dqts_with_zeros: false,
            max_jpeg_height: u32::MAX,
            max_jpeg_width: u32::MAX,
            use_16bit_dc_estimate: true,
            use_16bit_adv_predict: true,
            accept_invalid_dht: true,
            max_partitions: 8,
            max_processor_threads: 8,
            max_jpeg_file_size: 128 * 1024 * 1024,
            stop_reading_at_eoi: false,
        }
    }
}


================================================
FILE: lib/src/helpers.rs
================================================
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the Apache License, Version 2.0. See LICENSE.txt in the project root for license information.
 *  This software incorporates material from third parties. See NOTICE.txt for details.
 *--------------------------------------------------------------------------------------------*/

use std::panic::{AssertUnwindSafe, catch_unwind};

use crate::lepton_error::{ExitCode, LeptonError};

/// Helper function to catch panics and convert them into the appropriate LeptonError
pub fn catch_unwind_result<R>(
    f: impl FnOnce() -> Result<R, LeptonError>,
) -> Result<R, LeptonError> {
    match catch_unwind(AssertUnwindSafe(f)) {
        Ok(r) => r.map_err(|e| e.into()),
        Err(err) => {
            if let Some(message) = err.downcast_ref::<&str>() {
                Err(LeptonError::new(ExitCode::AssertionFailure, *message))
            } else if let Some(message) = err.downcast_ref::<String>() {
                Err(LeptonError::new(ExitCode::AssertionFailure, message))
            } else {
                Err(LeptonError::new(
                    ExitCode::AssertionFailure,
                    "unknown panic",
                ))
            }
        }
    }
}

#[inline(always)]
pub const fn u16_bit_length(v: u16) -> u8 {
    return 16 - v.leading_zeros() as u8;
}

#[inline(always)]
pub const fn u32_bit_length(v: u32) -> u8 {
    return 32 - v.leading_zeros() as u8;
}

pub fn buffer_prefix_matches_marker<const BS: usize, const MS: usize>(
    buffer: [u8; BS],
    marker: [u8; MS],
) -> bool {
    // Helper method, skipping checks of parameters nulls/lengths
    for i in 0..marker.len() {
        if buffer[i] != marker[i] {
            return false;
        }
    }

    return true;
}

/// returns true if the 64 bit value contains an 0xff byte.
/// Uses fancy bit manipulation to avoid branches.
#[inline(always)]
pub fn has_ff(v: u64) -> bool {
    (v & 0x8080808080808080 & !v.wrapping_add(0x0101010101010101)) != 0
}

#[inline(always)]
pub const fn devli(s: u8, value: u16) -> i16 {
    let shifted = 1 << s;

    if value & (shifted >> 1) != 0 {
        value as i16
    } else {
        value.wrapping_add(2).wrapping_add(!shifted) as i16
    }
}

/// check to make sure the behavior hasn't changed even with the optimization
#[test]
fn devli_test() {
    for s in 0u8..15 {
        for value in 0..(1 << s) {
            assert_eq!(
                devli(s, value),
                if s == 0 {
                    value as i16
                } else if value < (1 << (s as u16 - 1)) {
                    value as i16 + (-1 << s as i16) + 1
                } else {
                    value as i16
                }
            );
        }
    }
}

#[inline(always)]
pub const fn b_short(v1: u8, v2: u8) -> u16 {
    ((v1 as u16) << 8) + v2 as u16
}

#[inline(always)]
pub const fn rbits(c: u8, n: usize) -> u8 {
    return c & (0xFF >> (8 - n));
}

#[inline(always)]
pub const fn lbits(c: u8, n: usize) -> u8 {
    return c >> (8 - n);
}

#[inline(always)]
pub const fn bitn(c: u16, n: u16) -> u8 {
    return ((c >> n) & 0x1) as u8;
}

#[inline(always)]
pub fn calc_sign_index(val: i16) -> usize {
    if val == 0 {
        0
    } else {
        if val > 0 { 1 } else { 2 }
    }
}

/// This checks to see if a vector can fit additional elements without growing,
/// but does it in such a way that the optimizer understands that a subsequent
/// push or extend will not need to grow the vector.
#[inline(always)]
pub fn needs_to_grow<T>(v: &Vec<T>, additional: usize) -> bool {
    additional > v.capacity().wrapping_sub(v.len())
}

#[cfg(test)]
pub fn get_rand_from_seed(seed: [u8; 32]) -> rand_chacha::ChaCha12Rng {
    use rand_chacha::ChaCha12Rng;
    use rand_chacha::rand_core::SeedableRng;

    ChaCha12Rng::from_seed(seed)
}

/// reads a file from the images directory for testing or benchmarking purposes
#[cfg(any(test, feature = "micro_benchmark"))]
pub fn read_file(filename: &str, ext: &str) -> Vec<u8> {
    use std::io::Read;

    let filename = std::path::Path::new(env!("WORKSPACE_ROOT"))
        .join("images")
        .join(filename.to_owned() + ext);
    let mut f = std::fs::File::open(filename).unwrap();

    let mut content = Vec::new();
    f.read_to_end(&mut content).unwrap();

    content
}

/*
better way to update aritmetic encoding without using special division

const fn k16bit_length(v : u32) -> u32
{
    const LEN_TABLE256 : [i8;256] =
    [
            0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
            5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
            6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
            6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
            7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
            7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
            7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
            7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
            8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
            8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
            8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
            8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
            8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
            8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
            8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
            8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
    ];

    return if (v & 0xff00) != 0 { 8 + LEN_TABLE256[(v >> 8) as usize] } else { LEN_TABLE256[v as usize] } as u32;
}

const LOG_MAX_NUMERATOR : i32= 18;

const fn calc_divisors() -> [u32;1026]
{
    let mut intermed = [0u32;1026];

    let mut d : u32  = 1;

    while d < 1026
    {
        intermed[d as usize] = ((((1 << k16bit_length(d)) - d) << LOG_MAX_NUMERATOR) / d) + 1;
        d += 1;
    }

    return intermed;
}

const DIVISORS : [u32;1026] = calc_divisors();

#[inline(always)]
pub fn fast_divide18bit_by_10bit(num : u32, denom : u16) -> u32
{
    //debug_assert_eq!(LOG2_LENGTHS[denom as usize], (16 - denom.leading_zeros() - 1) as u8, "log2{0}", denom);

    let tmp = ((DIVISORS[denom as usize] as u64 * num as u64) >> LOG_MAX_NUMERATOR) as u32;
    let r = (tmp + ((num - tmp) >> 1)) >> (16 - denom.leading_zeros() - 1);

    debug_assert_eq!(r, num/(denom as u32));
    return r;
}

*/


================================================
FILE: lib/src/jpeg/bit_reader.rs
================================================
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the Apache License, Version 2.0. See LICENSE.txt in the project root for license information.
 *  This software incorporates material from third parties. See NOTICE.txt for details.
 *--------------------------------------------------------------------------------------------*/

use std::io::BufRead;

use super::jpeg_code;
use crate::helpers::has_ff;
use crate::lepton_error::{ExitCode, err_exit_code};
use crate::{LeptonError, StreamPosition};

// Implemenation of bit reader on top of JPEG data stream as read by a reader
pub struct BitReader<R> {
    inner: R,
    bits: u64,
    bits_left: u32,
    cpos: u32,
    eof: bool,
    truncated_ff: bool,
    read_ahead_bytes: u32,
}

impl<R: BufRead + StreamPosition> BitReader<R> {
    /// Returns the current position in the stream, which corresponds the byte that has
    /// unread bits in it.
    ///
    /// If the last byte was a 0xff, then the position is the byte before
    /// the 0xff.
    pub fn stream_position(&mut self) -> u64 {
        self.undo_read_ahead();

        let pos = self.inner.position();

        if self.bits_left > 0 && !self.eof {
            if self.bits as u8 == 0xff && !self.truncated_ff {
                return pos - 2;
            } else {
                return pos - 1;
            }
        } else {
            return pos;
        }
    }

    pub fn new(inner: R) -> Self {
        BitReader {
            inner: inner,
            bits: 0,
            bits_left: 0,
            cpos: 0,
            eof: false,
            truncated_ff: false,
            read_ahead_bytes: 0,
        }
    }
}

impl<R: BufRead> BitReader<R> {
    #[inline(always)]
    pub fn read(&mut self, bits_to_read: u32) -> std::io::Result<u16> {
        if bits_to_read == 0 {
            return Ok(0);
        }

        if self.bits_left < bits_to_read {
            self.fill_register(bits_to_read)?;
        }

        let retval =
            (self.bits >> (self.bits_left - bits_to_read) & ((1 << bits_to_read) - 1)) as u16;
        self.bits_left -= bits_to_read;
        return Ok(retval);
    }

    #[inline(always)]
    pub fn peek(&self) -> (u8, u32) {
        (
            ((self.bits.wrapping_shl(64 - self.bits_left)) >> 56) as u8,
            self.bits_left,
        )
    }

    #[inline(always)]
    pub fn advance(&mut self, bits: u32) {
        self.bits_left -= bits;
    }

    #[inline(always)]
    pub fn fill_register(&mut self, bits_to_read: u32) -> Result<(), std::io::Error> {
        // first consume the read_ahead bytes that we have now consumed
        // (otherwise we wouldn't have been called)
        self.inner.consume(self.read_ahead_bytes as usize);

        let fb = self.inner.fill_buf()?;

        // if we have 8 bytes and there is no 0xff in them, then we can just read the bits directly as big endian
        let mut v;
        if fb.len() < 8 || {
            v = u64::from_le_bytes(fb[..8].try_into().unwrap());
            has_ff(v)
        } {
            self.read_ahead_bytes = 0;
            return self.fill_register_slow(bits_to_read);
        }

        v = v.to_be();

        // only fill 63 bits not 64 to avoid having to special case
        // of self.bits << 64 which is a nop
        let bytes_to_read = (63 - self.bits_left) / 8;

        self.bits = self.bits << (bytes_to_read * 8) | v >> (64 - bytes_to_read * 8);
        self.bits_left += bytes_to_read * 8;
        self.read_ahead_bytes = (self.bits_left - bits_to_read) / 8;

        self.inner
            .consume((bytes_to_read - self.read_ahead_bytes) as usize);

        return Ok(());
    }

    #[cold]
    fn fill_register_slow(&mut self, bits_to_read: u32) -> Result<(), std::io::Error> {
        loop {
            let fb = self.inner.fill_buf()?;
            if let &[b, ..] = fb {
                self.inner.consume(1);

                // 0xff is an escape code, if the next by is zero, then it is just a normal 0
                // otherwise it is a reset code, which should also be skipped
                if b == 0xff {
                    let mut buffer = [0u8];

                    if self.inner.read(&mut buffer)? == 0 {
                        // Handle case of truncation in the middle of an escape: Since we assume that everything passed the end
                        // is a 0, if the file ends with 0xFF, then we have to assume that this was
                        // an escaped 0xff. Don't mark as eof yet, since there are still the 8 bits to read.
                        self.bits = (self.bits << 8) | 0xff;
                        self.bits_left += 8;
                        self.truncated_ff = true;

                        // continue since we still might need to read more 0 bits
                    } else if buffer[0] == 0 {
                        // this was an escaped FF
                        self.bits = (self.bits << 8) | 0xff;
                        self.bits_left += 8;
                    } else {
                        // this was not an escaped 0xff which is the only thing we accept at this part of the decoding.
                        //
                        // verify_reset_code should have gotten called in all instances where there should be a reset code,
                        // or at the end of the file we should have stopped decoding before we hit the end of file marker.
                        //
                        // Since we have no way of encoding these cases in our bitstream, we exit.
                        return Err(LeptonError::new(
                            ExitCode::InvalidResetCode,
                            format!(
                                "invalid reset {0:x} {1:x} code found in stream",
                                0xff, buffer[0]
                            ),
                        )
                        .into());
                    }
                } else {
                    self.bits = (self.bits << 8) | (b as u64);
                    self.bits_left += 8;
                }
            } else {
                // in case of a truncated file, we treat the rest of the file as zeros, but the
                // bits that were ok still get returned so that we get the partial last byte right
                // the caller periodically checks for EOF to see if it should stop encoding
                self.eof = true;
                self.bits_left += 8;
                self.bits <<= 8;

                // continue since we still might need to read more 0 bits
            }

            if self.bits_left >= bits_to_read {
                break;
            }
        }
        Ok(())
    }

    pub fn is_eof(&mut self) -> bool {
        return self.eof;
    }

    /// used to verify whether this image is using 1s or 0s as fill bits.
    /// Returns whether the fill bit was 1 or so or unknown (None)
    pub fn read_and_verify_fill_bits(
        &mut self,
        pad_bit: &mut Option<u8>,
    ) -> Result<(), LeptonError> {
        self.undo_read_ahead();

        // if there are bits left, we need to see whether they
        // are 1s or zeros.

        if (self.bits_left) > 0 && !self.eof {
            let num_bits_to_read = self.bits_left;
            let actual = self.read(num_bits_to_read)?;
            let all_one = (1 << num_bits_to_read) - 1;

            match *pad_bit {
                None => {
                    if actual == 0 {
                        *pad_bit = Some(0);
                    } else if actual == all_one {
                        *pad_bit = Some(0xff);
                    } else {
                        return err_exit_code(
                            ExitCode::InvalidPadding,
                            format!(
                                "inconsistent pad bits num_bits={0} pattern={1:b}",
                                num_bits_to_read, actual
                            ),
                        );
                    }
                }
                Some(x) => {
                    // if we already saw a padding, then it should match
                    let expected = u16::from(x) & all_one;
                    if actual != expected {
                        return err_exit_code(
                            ExitCode::InvalidPadding,
                            format!(
                                "padding of {0} bits should be set to 1 actual={1:b} expected={2:b}",
                                num_bits_to_read, actual, expected
                            ),
                        );
                    }
                }
            }
        }

        return Ok(());
    }

    pub fn verify_reset_code(&mut self) -> Result<(), LeptonError> {
        // we reached the end of a MCU, so we need to find a reset code and the huffman codes start get padded out, but the spec
        // doesn't specify whether the padding should be 1s or 0s, so we ensure that at least the file is consistant so that we
        // can recode it again just by remembering the pad bit.
        self.undo_read_ahead();

        let mut h = [0u8; 2];
        self.inner.read_exact(&mut h)?;
        if h[0] != 0xff || h[1] != (jpeg_code::RST0 + (self.cpos as u8 & 7)) {
            return err_exit_code(
                ExitCode::InvalidResetCode,
                format!("invalid reset code {0:x} {1:x} found in stream", h[0], h[1]),
            );
        }

        // start from scratch after RST
        self.cpos += 1;
        self.bits = 0;
        self.bits_left = 0;

        Ok(())
    }

    /// Retrieves the byte containing the next bit to be read in the stream, with only
    /// the bits that have already been read in it possibly set, and all the rest of the
    /// bits cleared.
    ///
    /// bitsAlreadyRead: the number of bits already read from the current byte
    /// byteBeingRead: the byte currently being read, with any bits not read from it yet cleared (0'ed)
    pub fn overhang(&mut self) -> (u8, u8) {
        self.undo_read_ahead();
        let bits_already_read = ((64 - self.bits_left) & 7) as u8; // already read bits in the current byte

        let mask = (((1 << bits_already_read) - 1) << (8 - bits_already_read)) as u8;

        return (bits_already_read, (self.bits as u8) & mask);
    }

    /// "puts back" read_ahead bits that were read ahead from the buffer but not consumed.
    ///
    /// This avoids special for many of the other non-speed-sensitive operations.
    ///
    /// After calling this method, we can be guaranteed that read_ahead_bytes is 0 and that
    /// the only bits that are left are part of the current byte.
    pub fn undo_read_ahead(&mut self) {
        while self.bits_left >= 8 && self.read_ahead_bytes > 0 {
            self.bits_left -= 8;
            self.bits >>= 8;
            self.read_ahead_bytes -= 1;
        }

        if self.read_ahead_bytes > 0 {
            self.inner.consume(self.read_ahead_bytes as usize);
            self.read_ahead_bytes = 0;
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::io::Cursor;

    // test reading a simple bit pattern with an escaped 0xff inside it.
    #[test]
    fn read_simple() {
        let arr = [0x12u8, 0x34, 0x45, 0x67, 0x89, 0xff, 00, 0xee];

        let mut b = BitReader::new(Cursor::new(&arr));

        assert_eq!(1, b.read(4).unwrap());
        assert_eq!((4, 0x10), b.overhang());
        assert_eq!(0, b.stream_position());

        assert_eq!(2, b.read(4).unwrap());
        assert_eq!((0, 0), b.overhang()); // byte is aligned should be no overhang
        assert_eq!(1, b.stream_position());

        assert_eq!(3, b.read(4).unwrap());
        assert_eq!(4, b.read(4).unwrap());
        assert_eq!(4, b.read(4).unwrap());
        assert_eq!(0x56, b.read(8).unwrap()); // 8 bits between 0x45 and 0x67
        assert_eq!(0x78, b.read(8).unwrap());

        assert_eq!(0x9f, b.read(8).unwrap());
        assert_eq!((4, 0xf0), b.overhang());
        assert_eq!(5, b.stream_position()); // should be at the beginning of the escape code

        assert_eq!(0xfe, b.read(8).unwrap());
        assert_eq!((4, 0xe0), b.overhang());
        assert_eq!(7, b.stream_position()); // now we are after the escape code

        assert_eq!(0xe, b.read(4).unwrap());
        assert_eq!((0, 0), b.overhang());
        assert_eq!(8, b.stream_position()); // now we read everything and should be at the end of the stream

        // read an empty byte passed the end of the stream.. should be zero and trigger EOF
        assert_eq!(0, b.read(8).unwrap());
        assert_eq!(true, b.is_eof());
        assert_eq!(8, b.stream_position()); // still at the same position
    }

    // what happens when a file has 0xff as the last character (assume that it is an escaped 0xff)
    #[test]
    fn read_truncate_ff() {
        let arr = [0x12u8, 0xff];

        let mut b = BitReader::new(Cursor::new(&arr));

        assert_eq!(0, b.stream_position());

        assert_eq!(0x1, b.read(4).unwrap());
        assert_eq!(0, b.stream_position());

        assert_eq!(0x2f, b.read(8).unwrap());
        assert_eq!((4, 0xf0), b.overhang());
        assert_eq!(1, b.stream_position());

        // 4 bits left, not EOF yet
        assert_eq!(false, b.is_eof());

        assert_eq!(0xf, b.read(4).unwrap());
        assert_eq!(false, b.is_eof()); // now we are at the end really
        assert_eq!(2, b.stream_position());

        assert_eq!(0, b.read(4).unwrap());
        assert_eq!(true, b.is_eof());
        assert_eq!(2, b.stream_position());
    }
}


================================================
FILE: lib/src/jpeg/bit_writer.rs
================================================
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the Apache License, Version 2.0. See LICENSE.txt in the project root for license information.
 *  This software incorporates material from third parties. See NOTICE.txt for details.
 *--------------------------------------------------------------------------------------------*/

use std::mem;

use crate::helpers::has_ff;

pub struct BitWriter {
    data_buffer: Vec<u8>,
    fill_register: u64,
    current_bit: u32,
}

// use to write varying sized bits for coding JPEG. Escapes 0xff -> [0xff,0]
impl BitWriter {
    pub fn new(data_buffer: Vec<u8>) -> Self {
        return BitWriter {
            current_bit: 64,
            fill_register: 0,
            data_buffer,
        };
    }

    /// flushes whole bytes from the register into the data buffer
    fn flush_whole_bytes(&mut self) {
        while self.current_bit <= 56 {
            let b = (self.fill_register >> 56) as u8;
            if b != 0xff {
                self.data_buffer.push(b);
            } else {
                // escape 0xff here to avoid multiple scans of the same data
                self.data_buffer.extend_from_slice(&[0xff, 0]);
            }

            self.fill_register <<= 8;
            self.current_bit += 8;
        }
    }

    /// write data
    pub fn write_byte_unescaped(&mut self, b: u8) {
        assert!(self.current_bit == 64);
        self.data_buffer.push(b);
    }

    #[inline(always)]
    pub fn write(&mut self, val: u32, new_bits: u32) {
        /// this is the slow path that is rarely called but generates a lot of code inlined
        /// so we move it out of the main function to keep the main function small with few branches.
        ///
        /// We also call this path when we are about to overflow the buffer to avoid having
        /// to inline the buffer growing logic, which is also much bigger than a simple insert.
        #[inline(never)]
        #[cold]
        fn write_ff_encoded(data_buffer: &mut Vec<u8>, fill_register: u64) {
            for i in 0..8 {
                let b = (fill_register >> (56 - (i * 8))) as u8;
                if b != 0xff {
                    data_buffer.push(b);
                } else {
                    // escape 0xff here to avoid multiple scans of the same data
                    data_buffer.extend_from_slice(&[0xff, 0]);
                }
            }
        }

        debug_assert!(
            val < (1 << new_bits),
            "value {0} should fit into the number of {1} bits provided",
            val,
            new_bits
        );

        // first see if everything fits in the current register
        if new_bits <= self.current_bit {
            self.fill_register |= (val as u64).wrapping_shl(self.current_bit - new_bits); // support corner case where new_bits is zero, we don't want to panic
            self.current_bit = self.current_bit - new_bits;
        } else {
            // if not, fill up the register so to the 64 bit boundary we can flush it hopefully without any 0xff bytes
            let fill = self.fill_register | (val as u64).wrapping_shr(new_bits - self.current_bit);

            let leftover_new_bits = new_bits - self.current_bit;
            let leftover_val = val & (1 << leftover_new_bits) - 1;

            // flush bytes slowly if we have any 0xff bytes or if we are about to overflow the buffer
            // (overflow check matches implementation in RawVec so that the optimizer can remove the buffer growing code)
            if has_ff(fill)
                || self
                    .data_buffer
                    .capacity()
                    .wrapping_sub(self.data_buffer.len())
                    < 8
            {
                write_ff_encoded(&mut self.data_buffer, fill);
            } else {
                self.data_buffer.extend_from_slice(&fill.to_be_bytes());
            }

            self.fill_register = (leftover_val as u64).wrapping_shl(64 - leftover_new_bits); // support corner case where new_bits is zero, we don't want to panic
            self.current_bit = 64 - leftover_new_bits;
        }
    }

    pub fn pad(&mut self, fillbit: u8) {
        let mut offset = 1;
        while (self.current_bit & 7) != 0 {
            self.write(if (fillbit & offset) != 0 { 1 } else { 0 }, 1);
            offset <<= 1;
        }

        self.flush_whole_bytes();

        debug_assert!(
            self.current_bit == 64,
            "there should be no remainder after padding"
        );
    }

    // flushes the data buffer while escaping all 0xff characters
    pub fn detach_buffer(&mut self) -> Vec<u8> {
        // flush any remaining whole bytes
        self.flush_whole_bytes();

        mem::take(&mut self.data_buffer)
    }

    pub fn ensure_space(&mut self, amount: usize) {
        if self.data_buffer.capacity() < amount {
            let len = self.data_buffer.len();
            self.data_buffer.reserve(amount - len);
        }
    }

    pub fn reset_from_overhang_byte_and_num_bits(&mut self, overhang_byte: u8, num_bits: u32) {
        self.data_buffer.clear();

        self.fill_register = 0;
        self.fill_register = overhang_byte as u64;
        self.fill_register <<= 56;
        self.current_bit = 64 - num_bits;
    }

    pub fn has_no_remainder(&self) -> bool {
        return self.current_bit == 64;
    }

    pub fn amount_buffered(&self) -> usize {
        self.data_buffer.len()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    use std::io::Cursor;

    use crate::helpers::u32_bit_length;
    use crate::jpeg::bit_reader::BitReader;

    // write a test pattern with an escape and see if it matches
    #[test]
    fn write_simple() {
        let arr = [0x12, 0x34, 0x45, 0x67, 0x89, 0xff, 00, 0xee];

        let mut b = BitWriter::new(Vec::with_capacity(1024));

        b.write(1, 4);
        b.write(2, 4);
        b.write(3, 4);
        b.write(4, 4);
        b.write(4, 4);
        b.write(0x56, 8);
        b.write(0x78, 8);
        b.write(0x9f, 8);
        b.write(0xfe, 8);
        b.write(0xe, 4);

        let w = b.detach_buffer();

        assert_eq!(w[..], arr);
    }

    // verify the the bits roundtrip correctly in a fairly simple scenario
    #[test]
    fn roundtrip_bits() {
        let buf;
        {
            let mut b = BitWriter::new(Vec::with_capacity(1024));
            for i in 1..2048 {
                b.write(i, u32_bit_length(i) as u32);
            }

            b.pad(0xff);

            buf = b.detach_buffer();
        }

        {
            let mut r = BitReader::new(Cursor::new(&buf));

            for i in 1..2048 {
                assert_eq!(i, r.read(u32_bit_length(i as u32) as u32).unwrap());
            }

            let mut pad = Some(0xff);
            r.read_and_verify_fill_bits(&mut pad).unwrap();
        }
    }

    /// verify the the bits roundtrip correctly with random bits
    #[test]
    fn roundtrip_randombits() {
        #[derive(Copy, Clone)]
        enum Action {
            Write(u16, u8),
            Pad(u8),
        }

        use rand::Rng;

        const ITERATIONS: usize = 10000;

        let mut rng = crate::helpers::get_rand_from_seed([0u8; 32]);
        let mut test_data = Vec::with_capacity(ITERATIONS);

        for _ in 0..ITERATIONS {
            let bits = rng.gen_range(0..=16);

            let t = rng.gen_range(0..=3);
            let v = match t {
                0 => 0,
                1 => 0xffff,
                _ => rng.gen_range(0..=65535),
            };

            let v = v & ((1 << bits) - 1);

            if rng.gen_range(0..100) == 0 {
                test_data.push(Action::Pad(0xff));
            } else {
                test_data.push(Action::Write(v as u16, bits as u8));
            }
        }
        test_data.push(Action::Pad(0xff));

        let buf;
        {
            let mut b = BitWriter::new(Vec::with_capacity(1024));
            for &i in &test_data {
                match i {
                    Action::Write(v, bits) => b.write(v as u32, bits as u32),
                    Action::Pad(fill) => b.pad(fill),
                }
            }

            buf = b.detach_buffer();
        }

        {
            let mut r = BitReader::new(Cursor::new(&buf));

            for a in test_data {
                match a {
                    Action::Write(code, numbits) => {
                        let expected_peek_byte = if numbits < 8 {
                            (code << (8 - numbits)) as u8
                        } else {
                            (code >> (numbits - 8)) as u8
                        };

                        let (peekcode, peekbits) = r.peek();
                        let num_valid_bits = peekbits.min(8).min(u32::from(numbits));

                        let mask = (0xff00 >> num_valid_bits) as u8;

                        assert_eq!(
                            expected_peek_byte & mask,
                            peekcode & mask,
                            "peek unexpected result"
                        );

                        assert_eq!(
                            code,
                            r.read(numbits as u32).unwrap(),
                            "read unexpected result"
                        );
                    }
                    Action::Pad(fill) => {
                        let mut pad = Some(fill);
                        r.read_and_verify_fill_bits(&mut pad).unwrap();
                    }
                }
            }
        }
    }
}


================================================
FILE: lib/src/jpeg/block_based_image.rs
================================================
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the Apache License, Version 2.0. See LICENSE.txt in the project root for license information.
 *  This software incorporates material from third parties. See NOTICE.txt for details.
 *--------------------------------------------------------------------------------------------*/

use crate::lepton_error::{Result, err_exit_code};
use bytemuck::{cast, cast_ref};
use log::info;
use wide::{CmpEq, i16x8};

use crate::ExitCode;
use crate::consts::ZIGZAG_TO_TRANSPOSED;

use super::jpeg_header::JpegHeader;

/// holds the 8x8 blocks for a given component. Since we do multithreaded encoding,
/// the image may only hold a subset of the components (specified by dpos_offset),
/// but they can be merged
pub struct BlockBasedImage {
    block_width: u32,

    original_height: u32,

    dpos_offset: u32,

    image: Vec<AlignedBlock>,
}

static EMPTY: AlignedBlock = AlignedBlock { raw_data: [0; 64] };

impl BlockBasedImage {
    // constructs new block image for the given y-coordinate range
    pub fn new(
        jpeg_header: &JpegHeader,
        component: usize,
        luma_y_start: u32,
        luma_y_end: u32,
    ) -> Result<Self> {
        let block_width = jpeg_header.cmp_info[component].bch;
        let original_height = jpeg_header.cmp_info[component].bcv;
        let max_size = block_width * original_height;

        let image_capacity = usize::try_from(
            (u64::from(max_size) * u64::from(luma_y_end - luma_y_start)
                + u64::from(jpeg_header.cmp_info[0].bcv - 1 /* round up */))
                / u64::from(jpeg_header.cmp_info[0].bcv),
        )
        .unwrap();

        let dpos_offset = u32::try_from(
            u64::from(max_size) * u64::from(luma_y_start) / u64::from(jpeg_header.cmp_info[0].bcv),
        )
        .unwrap();

        let mut image = Vec::new();
        if let Err(e) = image.try_reserve_exact(image_capacity) {
            // If there is an out-of-memory, this is the most likely place to happen since this is the uncompressed
            // coefficient buffer.
            //
            // Handle out of memory errors gracefully, otherwise the default oom handler kills
            // the process.
            return err_exit_code(
                ExitCode::OutOfMemory,
                format!(
                    "failed to allocate block image of size {image_capacity} for component {component} with block width {block_width} and original height {original_height} (luma_y_start = {luma_y_start}, luma_y_end = {luma_y_end}) : {e}"
                ),
            );
        }

        return Ok(BlockBasedImage {
            block_width: block_width,
            original_height: original_height,
            image,
            dpos_offset: dpos_offset,
        });
    }

    /// merges a bunch of block images generated by different threads into a single one used by progressive decoding
    pub fn merge(images: &mut Vec<Vec<BlockBasedImage>>, index: usize) -> Result<Self> {
        // figure out the total size of all the blocks so we can set the capacity correctly
        let total_size = images.iter().map(|x| x[index].image.len()).sum();

        let mut contents = Vec::new();
        if let Err(e) = contents.try_reserve_exact(total_size) {
            // If there is an out-of-memory, this is the most likely place to happen since this is the uncompressed
            // coefficient buffer.
            //
            // Handle out of memory errors gracefully, otherwise the default oom handler kills
            // the process.
            return err_exit_code(
                ExitCode::OutOfMemory,
                format!("failed to allocate merged block image of size {total_size} : {e}"),
            );
        }

        let mut block_width = None;
        let mut original_height = None;

        for v in images {
            assert!(
                v[index].dpos_offset == contents.len() as u32,
                "previous content should match new content"
            );

            if let Some(w) = block_width {
                assert_eq!(w, v[index].block_width, "all block_width must match")
            } else {
                block_width = Some(v[index].block_width);
            }

            if let Some(w) = original_height {
                assert_eq!(
                    w, v[index].original_height,
                    "all original_height must match"
                )
            } else {
                original_height = Some(v[index].original_height);
            }

            contents.append(&mut v[index].image);
        }

        return Ok(BlockBasedImage {
            block_width: block_width.unwrap(),
            original_height: original_height.unwrap(),
            image: contents,
            dpos_offset: 0,
        });
    }

    #[allow(dead_code)]
    pub fn dump(&self) {
        info!(
            "size = {0}, capacity = {1}, dpos_offset = {2}",
            self.image.len(),
            self.image.capacity(),
            self.dpos_offset
        );
    }

    pub fn get_block_width(&self) -> u32 {
        self.block_width
    }

    pub fn get_original_height(&self) -> u32 {
        self.original_height
    }

    /// ensure that the image is filled up to a given dpos with blank blocks and optionally
    /// write a block at the given position.
    #[inline(always)]
    pub fn fill_up_to_dpos(
        &mut self,
        dpos: u32,
        block_to_write: Option<AlignedBlock>,
    ) -> &mut AlignedBlock {
        // ensure that dpos_offset got set to the right value when we start writing
        if self.image.len() == 0 {
            debug_assert!(self.dpos_offset == dpos);
        }

        // should never underflow otherwise we are writing to the wrong part of the image
        let relative_offset = (dpos as usize)
            .checked_sub(self.dpos_offset as usize)
            .unwrap();

        if relative_offset < self.image.len() {
            // rewrite already written block
            if let Some(b) = block_to_write {
                self.image[relative_offset] = b;
            }
        } else {
            // need to extend the image length and add any necessary
            // zero blocks to fill the gap.
            assert!(
                relative_offset < self.image.capacity(),
                "capacity should be set to the exact image size to avoid reallocations"
            );

            // optimizer realizes that this is memset
            self.image
                .resize_with(relative_offset, || AlignedBlock::default());

            self.image.push(block_to_write.unwrap_or_default());
        }

        return &mut self.image[relative_offset];
    }

    pub fn set_block_data(&mut self, dpos: u32, block_data: AlignedBlock) {
        self.fill_up_to_dpos(dpos, Some(block_data));
    }

    pub fn get_block(&self, dpos: u32) -> &AlignedBlock {
        if (dpos - self.dpos_offset) as usize >= self.image.len() {
            return &EMPTY;
        } else {
            return &self.image[(dpos - self.dpos_offset) as usize];
        }
    }

    #[inline(always)]
    pub fn append_block(&mut self, block: AlignedBlock) {
        assert!(
            self.image.len() < self.image.capacity(),
            "capacity should be set correctly"
        );
        self.image.push(block);
    }

    #[inline(always)]
    pub fn get_block_mut(&mut self, dpos: u32) -> &mut AlignedBlock {
        self.fill_up_to_dpos(dpos, None)
    }
}

/// block of 64 coefficients in the aligned order, which is similar to zigzag except that the 7x7 lower right square comes first,
/// followed by the DC, followed by the edges
#[repr(C, align(32))]
pub struct AlignedBlock {
    raw_data: [i16; 64],
}

pub static EMPTY_BLOCK: AlignedBlock = AlignedBlock { raw_data: [0; 64] };

impl Default for AlignedBlock {
    fn default() -> Self {
        AlignedBlock { raw_data: [0; 64] }
    }
}

impl AlignedBlock {
    #[inline(always)]
    pub fn new(block: [i16; 64]) -> Self {
        AlignedBlock { raw_data: block }
    }

    #[inline(always)]
    pub fn as_i16x8(&self, index: usize) -> i16x8 {
        let v: &[i16x8; 8] = cast_ref(&self.raw_data);
        v[index]
    }

    #[allow(dead_code)]
    #[inline(always)]
    pub fn transpose(&self) -> AlignedBlock {
        return AlignedBlock::new(cast(i16x8::transpose(cast(*self.get_block()))));
    }

    #[inline(always)]
    pub fn get_dc(&self) -> i16 {
        return self.raw_data[0];
    }

    #[inline(always)]
    pub fn set_dc(&mut self, value: i16) {
        self.raw_data[0] = value
    }

    #[inline(always)]
    pub fn zigzag_to_transposed(a: [i16; 64]) -> AlignedBlock {
        AlignedBlock {
            raw_data: [
                a[0], a[2], a[3], a[9], a[10], a[20], a[21], a[35], a[1], a[4], a[8], a[11], a[19],
                a[22], a[34], a[36], a[5], a[7], a[12], a[18], a[23], a[33], a[37], a[48], a[6],
                a[13], a[17], a[24], a[32], a[38], a[47], a[49], a[14], a[16], a[25], a[31], a[39],
                a[46], a[50], a[57], a[15], a[26], a[30], a[40], a[45], a[51], a[56], a[58], a[27],
                a[29], a[41], a[44], a[52], a[55], a[59], a[62], a[28], a[42], a[43], a[53], a[54],
                a[60], a[61], a[63],
            ],
        }
    }

    #[inline(always)]
    pub fn zigzag_from_transposed(&self) -> AlignedBlock {
        let a = self.raw_data;
        AlignedBlock {
            raw_data: [
                a[0], a[8], a[1], a[2], a[9], a[16], a[24], a[17], a[10], a[3], a[4], a[11], a[18],
                a[25], a[32], a[40], a[33], a[26], a[19], a[12], a[5], a[6], a[13], a[20], a[27],
                a[34], a[41], a[48], a[56], a[49], a[42], a[35], a[28], a[21], a[14], a[7], a[15],
                a[22], a[29], a[36], a[43], a[50], a[57], a[58], a[51], a[44], a[37], a[30], a[23],
                a[31], a[38], a[45], a[52], a[59], a[60], a[53], a[46], a[39], a[47], a[54], a[61],
                a[62], a[55], a[63],
            ],
        }
    }

    #[inline(always)]
    pub fn get_block(&self) -> &[i16; 64] {
        return &self.raw_data;
    }

    #[inline(always)]
    pub fn get_block_mut(&mut self) -> &mut [i16; 64] {
        return &mut self.raw_data;
    }

    // used for debugging
    #[allow(dead_code)]
    pub fn get_hash(&self) -> i32 {
        let mut sum = 0;
        for i in 0..64 {
            sum += self.raw_data[i] as i32
        }
        return sum;
    }

    #[inline(always)]
    pub fn get_count_of_non_zeros_7x7(&self) -> u8 {
        /// counts a row of non-zero values in the 7x7 block
        #[inline(always)]
        fn count_non_zeros_7x7_row(v: i16x8) -> i16x8 {
            !v.simd_eq(i16x8::ZERO) & i16x8::new([0, 1, 1, 1, 1, 1, 1, 1])
        }

        let mut sum = i16x8::ZERO;
        for i in 1..8 {
            sum += count_non_zeros_7x7_row(self.as_i16x8(i));
        }

        return sum.reduce_add() as u8;
    }

    #[inline(always)]
    pub fn get_coefficient(&self, index: usize) -> i16 {
        return self.raw_data[index];
    }

    #[inline(always)]
    pub fn set_coefficient(&mut self, index: usize, v: i16) {
        self.raw_data[index] = v;
    }

    #[inline(always)]
    pub fn set_transposed_from_zigzag(&mut self, index: usize, v: i16) {
        self.raw_data[usize::from(ZIGZAG_TO_TRANSPOSED[index])] = v;
    }

    #[inline(always)]
    pub fn get_transposed_from_zigzag(&self, index: usize) -> i16 {
        return self.raw_data[usize::from(ZIGZAG_TO_TRANSPOSED[index])];
    }

    #[inline(always)]
    pub fn from_stride(&self, offset: usize, stride: usize) -> i16x8 {
        return i16x8::new([
            self.raw_data[offset],
            self.raw_data[offset + (1 * stride)],
            self.raw_data[offset + (2 * stride)],
            self.raw_data[offset + (3 * stride)],
            self.raw_data[offset + (4 * stride)],
            self.raw_data[offset + (5 * stride)],
            self.raw_data[offset + (6 * stride)],
            self.raw_data[offset + (7 * stride)],
        ]);
    }
}


================================================
FILE: lib/src/jpeg/component_info.rs
================================================
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the Apache License, Version 2.0. See LICENSE.txt in the project root for license information.
 *  This software incorporates material from third parties. See NOTICE.txt for details.
 *--------------------------------------------------------------------------------------------*/

#[derive(Debug, Clone)]
pub struct ComponentInfo {
    /// quantization table
    pub q_table_index: u8,

    /// no of huffman table (DC)
    pub huff_dc: u8,

    /// no of huffman table (AC)
    pub huff_ac: u8,

    /// sample factor vertical
    pub sfv: u32,

    /// sample factor horizontal
    pub sfh: u32,

    /// blocks in mcu
    pub mbs: u32,

    /// block count vertical (interleaved)
    pub bcv: u32,

    /// block count horizontal (interleaved)
    pub bch: u32,

    /// block count (all) (interleaved)
    pub bc: u32,

    /// block count vertical (non interleaved)
    pub ncv: u32,

    /// block count horizontal (non interleaved)
    pub nch: u32,

    /// block count (all) (non interleaved)
    pub nc: u32,

    /// statistical identity
    pub sid: u32,

    /// jpeg internal id
    pub jid: u8,
}

impl Default for ComponentInfo {
    fn default() -> ComponentInfo {
        return ComponentInfo {
            q_table_index: 0xff,
            sfv: u32::MAX,
            sfh: u32::MAX,
            mbs: u32::MAX,
            bcv: u32::MAX,
            bch: u32::MAX,
            bc: u32::MAX,
            ncv: u32::MAX,
            nch: u32::MAX,
            nc: u32::MAX,
            sid: u32::MAX,
            jid: 0xff,
            huff_dc: 0xff,
            huff_ac: 0xff,
        };
    }
}


================================================
FILE: lib/src/jpeg/jpeg_code.rs
================================================
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the Apache License, Version 2.0. See LICENSE.txt in the project root for license information.
 *  This software incorporates material from third parties. See NOTICE.txt for details.
 *--------------------------------------------------------------------------------------------*/

/// Start of Frame (size information), coding process: baseline DCT
pub const SOF0: u8 = 0xC0;

/// Start of Frame (size information), coding process: extended sequential DCT
pub const SOF1: u8 = 0xC1;

/// Start of Frame (size information), coding process: progressive DCT
pub const SOF2: u8 = 0xC2;

/// Huffman Table
pub const DHT: u8 = 0xC4;

/// Restart 0 segment
pub const RST0: u8 = 0xD0;

/// Start of Image
pub const SOI: u8 = 0xD8;

/// End of Image, or End of File
pub const EOI: u8 = 0xD9;

/// Start of Scan
pub const SOS: u8 = 0xDA;

/// Define Quantization Table
pub const DQT: u8 = 0xDB;

/// Define restart interval
pub const DRI: u8 = 0xDD;


================================================
FILE: lib/src/jpeg/jpeg_header.rs
================================================
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the Apache License, Version 2.0. See LICENSE.txt in the project root for license information.
 *  This software incorporates material from third parties. See NOTICE.txt for details.
 *--------------------------------------------------------------------------------------------*/

/*
Copyright (c) 2006...2016, Matthias Stirner and HTW Aalen University
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

use std::fmt::Debug;
use std::io::{Cursor, Read, Write};
use std::num::NonZeroU32;

use crate::LeptonError;
use crate::consts::JpegType;
use crate::enabled_features::EnabledFeatures;
use crate::helpers::*;
use crate::lepton_error::{AddContext, ExitCode, Result, err_exit_code};

use super::component_info::ComponentInfo;
use super::jpeg_code;
use super::truncate_components::TruncateComponents;

/// Information required to partition the coding the JPEG huffman encoded stream of a scan
/// at an arbitrary location in the stream.
///
/// Note that this only works for sequential JPEGs since progressive ones have multiple scans
/// that each process the entire image.

#[derive(Debug, Default, Clone)]
pub struct RestartSegmentCodingInfo {
    pub overhang_byte: u8,
    pub num_overhang_bits: u8,
    pub luma_y_start: u32,
    pub luma_y_end: u32,
    pub last_dc: [i16; 4],
}

impl RestartSegmentCodingInfo {
    pub fn new(
        overhang_byte: u8,
        num_overhang_bits: u8,
        last_dc: [i16; 4],
        mcu: u32,
        jf: &JpegHeader,
    ) -> Self {
        let mcu_y = mcu / jf.mcuh;
        let luma_mul = jf.cmp_info[0].bcv / jf.mcuv;

        Self {
            overhang_byte,
            num_overhang_bits,
            last_dc,
            luma_y_start: luma_mul * mcu_y,
            luma_y_end: luma_mul * (mcu_y + 1),
        }
    }
}

/// Global information required to reconstruct the JPEG exactly the way that it was, especially
/// regarding information about possible truncation and RST markers.
#[derive(Default, Clone, Debug)]
pub struct ReconstructionInfo {
    /// the maximum component in a truncated progressive image.
    ///
    /// This is meant to be used for progressive images but is not yet implemented.
    pub max_cmp: u32,

    /// the maximum band in a truncated progressive image
    ///
    /// This is meant to be used for progressive images but is not yet implemented.
    pub max_bpos: u32,

    /// The maximum bit in a truncated progressive image.
    ///
    /// This is meant to be used for progressive images but is not yet implemented.
    pub max_sah: u8,

    /// the maximum dpos in a truncated image
    pub max_dpos: [u32; 4],

    /// if we encountered EOF before the expected end of the image
    pub early_eof_encountered: bool,

    /// the mask for padding out the bitstream when we get to the end of a reset block
    pub pad_bit: Option<u8>,

    /// A list containing one entry for each scan segment. Each entry contains the number of restart intervals
    /// within the corresponding scan segment.
    ///
    /// TODO: We currently don't generate this value when we parse a JPEG (leaving rst_cnt_set as false), however when
    /// we read a Lepton file we will use this to determine whether we should generate restart markers in order
    /// to maintain backward compability for decoding Lepton files generated by the C++ version.
    ///
    /// This means that there might be some files that we could have encoded successfully that we don't, but since
    /// we are required to reverify anyway, this is not a problem (except a minor efficiency issue)
    pub rst_cnt: Vec<u32>,

    /// true if rst_cnt contains a valid set of counts
    pub rst_cnt_set: bool,

    /// information about how to truncate the image if it was partially written
    pub truncate_components: TruncateComponents,

    /// trailing RST marking information
    pub rst_err: Vec<u8>,

    /// raw jpeg header to be written back to the file when it is recreated
    pub raw_jpeg_header: Vec<u8>,

    /// garbage data (default value - empty segment - means no garbage data)
    pub garbage_data: Vec<u8>,
}

pub fn parse_jpeg_header<R: Read>(
    reader: &mut R,
    enabled_features: &EnabledFeatures,
    jpeg_header: &mut JpegHeader,
    rinfo: &mut ReconstructionInfo,
) -> Result<bool> {
    // the raw header in the lepton file can actually be spread across different sections
    // seperated by the Start-of-Scan marker. We use the mirror to write out whatever
    // data we parse until we hit the SOS

    let mut output = Vec::new();
    let mut output_cursor = Cursor::new(&mut output);

    let mut mirror = Mirror::new(reader, &mut output_cursor);

    if jpeg_header.parse(&mut mirror, enabled_features).context()? {
        // append the header if it was not the end of file marker
        rinfo.raw_jpeg_header.append(&mut output);
        return Ok(true);
    } else {
        // if the output was more than 2 bytes then was a trailing header, so keep that around as well,
        // but we don't want the EOI since that goes into the garbage data.
        if output.len() > 2 {
            rinfo.raw_jpeg_header.extend(&output[0..output.len() - 2]);
        }

        return Ok(false);
    }
}

// internal utility we use to collect the header that we read for later
struct Mirror<'a, R, W> {
    read: &'a mut R,
    output: &'a mut W,
    amount_written: usize,
}

impl<'a, R, W> Mirror<'a, R, W> {
    pub fn new(read: &'a mut R, output: &'a mut W) -> Self {
        Mirror {
            read,
            output,
            amount_written: 0,
        }
    }
}

impl<R: Read, W: Write> Read for Mirror<'_, R, W> {
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        let n = self.read.read(buf)?;
        self.output.write_all(&buf[..n])?;
        self.amount_written += n;
        Ok(n)
    }
}

#[derive(Copy, Clone, Debug)]
pub(crate) struct HuffCodes {
    pub c_val: [u16; 256],
    pub c_len: [u16; 256],
    pub c_len_plus_s: [u8; 256],
    pub c_val_shift_s: [u32; 512],
    pub max_eob_run: u16,
}

impl Default for HuffCodes {
    fn default() -> Self {
        HuffCodes {
            c_val: [0; 256],
            c_len: [0; 256],
            c_len_plus_s: [0; 256],
            c_val_shift_s: [0; 512],
            max_eob_run: 0,
        }
    }
}

impl HuffCodes {
    /// Constructs from the format encoded by JPEG
    ///
    /// Tree consists of a 16 byte table with the number of codes for each bit length,
    /// followed by the actual codes for that length appended together.
    pub fn construct_from_segment(segment: &[u8]) -> Result<Self> {
        let clen_offset = 0;
        let cval_offset = 16;

        let mut hc = HuffCodes::default();

        // creating huffman-codes
        let mut k = 0;
        let mut code = 0;

        // symbol-value of code is its position in the table
        for i in 0..16 {
            ensure_space(segment, clen_offset, i + 1).context()?;

            let mut j = 0;
            while j < segment[clen_offset + (i & 0xff)] {
                ensure_space(segment, cval_offset, k + 1).context()?;

                let len = (1 + i) as u16;

                if u32::from(code) >= (1u32 << len) {
                    return err_exit_code(
                        ExitCode::UnsupportedJpeg,
                        "invalid huffman code layout, too many codes for a given length",
                    );
                }

                hc.c_len[usize::from(segment[cval_offset + (k & 0xff)])] = len;
                hc.c_val[usize::from(segment[cval_offset + (k & 0xff)])] = code;

                if code == 65535 {
                    return err_exit_code(ExitCode::UnsupportedJpeg, "huffman code too large");
                }

                k += 1;
                code += 1;
                j += 1;
            }

            code = code << 1;
        }

        hc.post_initialize();

        Ok(hc)
    }

    /// Code to run after initializing c_len and c_val
    /// Lookup tables used for fast encoding since we already
    /// know the length of the code and the value when we write
    /// the code + bits to the bitstream
    fn post_initialize(&mut self) {
        for i in 0..256 {
            let s = i & 0xf;
            self.c_len_plus_s[i] = (self.c_len[i] + (s as u16)) as u8;
            self.c_val_shift_s[i] = u32::from(self.c_val[i]) << s;

            // calculate the value for negative coefficients, which compensates for the sign bit
            self.c_val_shift_s[i + 256] = (u32::from(self.c_val[i]) << s) | ((1u32 << s) - 1);
        }

        // find out eobrun (runs of all zero blocks) max value. This is used encoding/decoding progressive files.
        //
        // G.1.2.2 of the spec specifies that there are 15 huffman codes
        // reserved for encoding long runs of up to 32767 empty blocks.
        // Here we figure out what the largest code that could possibly
        // be encoded by this table is so that we don't exceed it when
        // we reencode the file.
        self.max_eob_run = 0;

        let mut i: i32 = 14;
        while i >= 0 {
            if self.c_len[((i << 4) & 0xff) as usize] > 0 {
                self.max_eob_run = ((2 << i) - 1) as u16;
                break;
            }

            i -= 1;
        }
    }
}

#[derive(Copy, Clone, Debug)]
pub(crate) struct HuffTree {
    pub node: [[u16; 2]; 256],
    pub peek_code: [(u8, u8); 256],
}

impl Default for HuffTree {
    fn default() -> Self {
        HuffTree {
            node: [[0; 2]; 256],
            peek_code: [(0, 0); 256],
        }
    }
}

impl HuffTree {
    /// construct the huffman tree codes from the HuffCodes as a source
    pub fn construct_hufftree(hc: &HuffCodes, accept_invalid_dht: bool) -> Result<Self> {
        let mut ht = HuffTree::default();

        let mut nextfree = 1;
        for i in 0..256 {
            // reset current node
            let mut node = 0;

            // go through each code & store path
            if hc.c_len[i] > 0 {
                let mut j = hc.c_len[i] - 1;
                while j > 0 {
                    if node <= 0xff {
                        if bitn(hc.c_val[i], j) == 1 {
                            if ht.node[node][1] == 0 {
                                ht.node[node][1] = nextfree;
                                nextfree += 1;
                            }

                            node = usize::from(ht.node[node][1]);
                        } else {
                            if ht.node[node][0] == 0 {
                                ht.node[node][0] = nextfree;
                                nextfree += 1;
                            }

                            node = usize::from(ht.node[node][0]);
                        }
                    } else {
                        // we accept any .lep file that was encoded this way
                        if !accept_invalid_dht {
                            return err_exit_code(
                                ExitCode::UnsupportedJpeg,
                                "Huffman table out of space",
                            );
                        }
                    }

                    j -= 1;
                }
            }

            if node <= 0xff {
                // last link is number of targetvalue + 256
                if hc.c_len[i] > 0 {
                    if bitn(hc.c_val[i], 0) == 1 {
                        ht.node[node][1] = (i + 256) as u16;
                    } else {
                        ht.node[node][0] = (i + 256) as u16;
                    }
                }
            } else {
                // we accept any .lep file that was encoded this way
                if !accept_invalid_dht {
                    return err_exit_code(ExitCode::UnsupportedJpeg, "Huffman table out of space");
                }
            }
        }
        for x in &mut ht.node {
            if x[0] == 0 {
                x[0] = 0xffff;
            }
            if x[1] == 0 {
                x[1] = 0xffff;
            }
        }
        // initial value for next free place

        // work through every code creating links between the nodes (represented through ints)

        // for every illegal code node, store 0xffff we should never get here, but it will avoid an infinite loop in the case of a bug

        // precalculate decoding peeking into the stream. This lets us quickly decode
        // small code without jumping through the node table
        for peekbyte in 0..256 {
            let mut node = 0;
            let mut len: u8 = 0;

            while node < 256 && len <= 7 {
                node = ht.node[usize::from(node)][(peekbyte >> (7 - len)) & 0x1];

                len += 1;
            }

            if node == 0xffff || node < 256 {
                // invalid code or code was too long to fit, so just say it requireds 256 bits
                // so we will take the long path to decode it
                ht.peek_code[peekbyte] = (0, 0xff);
            } else {
                ht.peek_code[peekbyte] = ((node - 256) as u8, len);
            }
        }
        Ok(ht)
    }
}

/// JPEG information parsed out of segments found before the image segment
#[derive(Clone)]
pub struct JpegHeader {
    /// quantization tables 4 x 64
    pub q_tables: [[u16; 64]; 4],

    /// huffman codes (access via get_huff_xx_codes)
    h_codes: [[HuffCodes; 4]; 2],

    /// huffman decoding trees (access via get_huff_xx_tree)
    h_trees: [[HuffTree; 4]; 2],

    /// 1 if huffman table is set
    ht_set: [[u8; 4]; 2],

    /// components
    pub cmp_info: [ComponentInfo; 4],

    /// component count
    pub cmpc: usize,

    /// width of image
    pub img_width: u32,

    /// height of image
    pub img_height: u32,

    pub jpeg_type: JpegType,

    /// max horizontal sample factor
    pub sfhm: u32,

    /// max verical sample factor
    pub sfvm: u32,

    // mcus per line
    pub mcuv: NonZeroU32,

    /// mcus per column
    pub mcuh: NonZeroU32,

    /// count of mcus
    pub mcuc: u32,

    /// restart interval
    pub rsti: u32,

    /// component count in current scan
    pub cs_cmpc: usize,

    /// component numbers in current scan
    pub cs_cmp: [usize; 4],

    // variables: info about current scan
    /// begin - band of current scan ( inclusive )
    pub cs_from: u8,

    /// end - band of current scan ( inclusive )
    pub cs_to: u8,

    /// successive approximation bit pos high
    pub cs_sah: u8,

    /// successive approximation bit pos low
    pub cs_sal: u8,
}

impl std::fmt::Debug for JpegHeader {
    /// Custom debug implementation to avoid printing large arrays
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("JpegHeader")
            .field("cmp_info", &self.cmp_info)
            .field("cmpc", &self.cmpc)
            .field("img_width", &self.img_width)
            .field("img_height", &self.img_height)
            .field("jpeg_type", &self.jpeg_type)
            .field("sfhm", &self.sfhm)
            .field("sfvm", &self.sfvm)
            .field("mcuv", &self.mcuv)
            .field("mcuh", &self.mcuh)
            .field("mcuc", &self.mcuc)
            .field("rsti", &self.rsti)
            .field("cs_cmpc", &self.cs_cmpc)
            .field("cs_cmp", &self.cs_cmp)
            .field("cs_from", &self.cs_from)
            .field("cs_to", &self.cs_to)
            .field("cs_sah", &self.cs_sah)
            .field("cs_sal", &self.cs_sal)
            .finish()
    }
}

enum ParseSegmentResult {
    Continue,
    EOI,
    SOS,
}

impl Default for JpegHeader {
    fn default() -> Self {
        return JpegHeader {
            q_tables: [[0; 64]; 4],
            h_codes: [[HuffCodes::default(); 4]; 2],
            h_trees: [[HuffTree::default(); 4]; 2],
            ht_set: [[0; 4]; 2],
            cmp_info: [
                ComponentInfo::default(),
                ComponentInfo::default(),
                ComponentInfo::default(),
                ComponentInfo::default(),
            ],
            cmpc: 0,
            img_width: 0,
            img_height: 0,
            jpeg_type: JpegType::Unknown,
            sfhm: 0,
            sfvm: 0,
            mcuv: NonZeroU32::MIN,
            mcuh: NonZeroU32::MIN,
            mcuc: 0,
            rsti: 0,
            cs_cmpc: 0,
            cs_from: 0,
            cs_to: 0,
            cs_sah: 0,
            cs_sal: 0,
            cs_cmp: [0; 4],
        };
    }
}

impl JpegHeader {
    /// true if this image is a single scan, which can be partitioned and decode
    /// completely independently by separate threads. If this is not the case, then
    /// we need to decode the entire image in memory and then encode the JPEG sequentially.
    pub fn is_single_scan(&self) -> bool {
        assert!(self.jpeg_type != JpegType::Unknown);

        self.jpeg_type == JpegType::Sequential && self.cmpc == self.cs_cmpc
    }

    #[inline(always)]
    pub(super) fn get_huff_dc_codes(&self, cmp: usize) -> &HuffCodes {
        &self.h_codes[0][usize::from(self.cmp_info[cmp].huff_dc)]
    }

    #[inline(always)]
    pub(super) fn get_huff_dc_tree(&self, cmp: usize) -> &HuffTree {
        &self.h_trees[0][usize::from(self.cmp_info[cmp].huff_dc)]
    }

    #[inline(always)]
    pub(super) fn get_huff_ac_codes(&self, cmp: usize) -> &HuffCodes {
        &self.h_codes[1][usize::from(self.cmp_info[cmp].huff_ac)]
    }

    #[inline(always)]
    pub(super) fn get_huff_ac_tree(&self, cmp: usize) -> &HuffTree {
        &self.h_trees[1][usize::from(self.cmp_info[cmp].huff_ac)]
    }

    /// Parses JPEG segments and updates the appropriate header fields
    /// until we hit either an SOS (image data) or EOI (end of image).
    ///
    /// Returns false if we hit EOI, true if we have an image to process.
    pub fn parse<R: Read>(
        &mut self,
        reader: &mut R,
        enabled_features: &EnabledFeatures,
    ) -> Result<bool> {
        // header parser loop
        loop {
            match self
                .parse_next_segment(reader, enabled_features)
                .context()?
            {
                ParseSegmentResult::EOI => {
                    return Ok(false);
                }
                ParseSegmentResult::SOS => {
                    break;
                }
                _ => {}
            }
        }

        // check if information is complete
        if self.cmpc == 0 {
            return err_exit_code(
                ExitCode::UnsupportedJpeg,
                "header contains incomplete information",
            );
        }

        for cmp in 0..self.cmpc {
            if (self.cmp_info[cmp].sfv == 0)
                || (self.cmp_info[cmp].sfh == 0)
                || (self.q_tables[usize::from(self.cmp_info[cmp].q_table_index)][0] == 0)
                || (self.jpeg_type == JpegType::Unknown)
            {
                return err_exit_code(
                    ExitCode::UnsupportedJpeg,
                    "header contains incomplete information (components)",
                );
            }
        }

        // do all remaining component info calculations
        for cmp in 0..self.cmpc {
            if self.cmp_info[cmp].sfh > self.sfhm {
                self.sfhm = self.cmp_info[cmp].sfh;
            }

            if self.cmp_info[cmp].sfv > self.sfvm {
                self.sfvm = self.cmp_info[cmp].sfv;
            }
        }

        self.mcuv = NonZeroU32::new(
            (1.0 * self.img_height as f64 / (8.0 * self.sfhm as f64)).ceil() as u32,
        )
        .ok_or_else(|| LeptonError::new(ExitCode::UnsupportedJpeg, "mcuv is zero"))?;

        self.mcuh =
            NonZeroU32::new((1.0 * self.img_width as f64 / (8.0 * self.sfvm as f64)).ceil() as u32)
                .ok_or_else(|| LeptonError::new(ExitCode::UnsupportedJpeg, "mcuh is zero"))?;

        self.mcuc = self.mcuv.get() * self.mcuh.get();

        for cmp in 0..self.cmpc {
            self.cmp_info[cmp].mbs = self.cmp_info[cmp].sfv * self.cmp_info[cmp].sfh;
            self.cmp_info[cmp].bcv = self.mcuv.get() * self.cmp_info[cmp].sfh;
            self.cmp_info[cmp].bch = self.mcuh.get() * self.cmp_info[cmp].sfv;
            self.cmp_info[cmp].bc = self.cmp_info[cmp].bcv * self.cmp_info[cmp].bch;
            self.cmp_info[cmp].ncv = (1.0
                * self.img_height as f64
                * (self.cmp_info[cmp].sfh as f64 / (8.0 * self.sfhm as f64)))
                .ceil() as u32;
            self.cmp_info[cmp].nch = (1.0
                * self.img_width as f64
                * (self.cmp_info[cmp].sfv as f64 / (8.0 * self.sfvm as f64)))
                .ceil() as u32;
            self.cmp_info[cmp].nc = self.cmp_info[cmp].ncv * self.cmp_info[cmp].nch;
        }

        // decide components' statistical ids
        if self.cmpc <= 3 {
            for cmp in 0..self.cmpc {
                self.cmp_info[cmp].sid = cmp as u32;
            }
        } else {
            for cmp in 0..self.cmpc {
                self.cmp_info[cmp].sid = 0;
            }
        }

        return Ok(true);
    }

    /// verifies that the huffman tables for the given types are present for the current scan, and if not, return an error
    pub fn verify_huffman_table(&self, dc_present: bool, ac_present: bool) -> Result<()> {
        for icsc in 0..self.cs_cmpc {
            let icmp = self.cs_cmp[icsc];

            if dc_present && self.ht_set[0][self.cmp_info[icmp].huff_dc as usize] == 0 {
                return err_exit_code(
                    ExitCode::UnsupportedJpeg,
                    format!("DC huffman table missing for component {0}", icmp),
                );
            } else if ac_present && self.ht_set[1][self.cmp_info[icmp].huff_ac as usize] == 0 {
                return err_exit_code(
                    ExitCode::UnsupportedJpeg,
                    format!("AC huffman table missing for component {0}", icmp),
                );
            }
        }

        Ok(())
    }

    // returns true we should continue parsing headers or false if we hit SOS and should stop
    fn parse_next_segment<R: Read>(
        &mut self,
        reader: &mut R,
        enabled_features: &EnabledFeatures,
    ) -> Result<ParseSegmentResult> {
        let mut header = [0u8; 4];

        if reader.read(&mut header[0..1]).context()? == 0 {
            // didn't get an EOI
            return Ok(ParseSegmentResult::EOI);
        }

        if header[0] != 0xff {
            return err_exit_code(ExitCode::UnsupportedJpeg, "invalid header encountered");
        }

        reader.read_exact(&mut header[1..2]).context()?;
        if header[1] == jpeg_code::EOI {
            return Ok(ParseSegmentResult::EOI);
        }

        // now read the second two bytes so we can get the size of the segment
        reader.read_exact(&mut header[2..]).context()?;

        let mut segment_data = Vec::new();

        let segment_size = b_short(header[2], header[3]);
        if segment_size < 2 {
            return err_exit_code(ExitCode::UnsupportedJpeg, "segment is too short");
        }

        segment_data.resize(usize::from(segment_size) - 2, 0);

        reader.read_exact(&mut segment_data).context()?;

        let mut hpos = 0;
        let len = segment_data.len();

        let segment = &segment_data[..];

        let btype = header[1];
        match btype
        {
            jpeg_code::DHT => // DHT segment
            {
                // build huffman trees & codes
                while hpos < len
                {
                    let lval = usize::from(lbits(segment[hpos], 4));
                    let rval = usize::from(rbits(segment[hpos], 4));
                    if (lval >= 2) || (rval >= 4)
                    {
                        break;
                    }

                    hpos+=1;

                    // build huffman codes & trees
                    self.h_codes[lval][rval] = HuffCodes::construct_from_segment(&segment[hpos..]).context()?;
                    self.h_trees[lval][rval] = HuffTree::construct_hufftree(&self.h_codes[lval][rval], enabled_features.accept_invalid_dht).context()?;
                    self.ht_set[lval][rval] = 1;

                    let mut skip = 16;

                    ensure_space(segment,hpos, 16)?;

                    for i in 0..16
                    {
                        skip += usize::from(segment[hpos + i]);
                    }

                    hpos += skip;
                }

                if hpos != len
                {
                    // if we get here, something went wrong
                    return err_exit_code(ExitCode::UnsupportedJpeg,"size mismatch in dht marker");
                }
            }

            jpeg_code::DQT => // DQT segment
            {
                // copy quantization tables to internal memory
                while hpos < len
                {
                    let lval = usize::from(lbits(segment[hpos], 4));
                    let rval = usize::from(rbits(segment[hpos], 4));
                    if lval >= 2 || rval >= 4
                    {
                        return err_exit_code(ExitCode::UnsupportedJpeg,"DQT has invalid index");
                    }

                    hpos+=1;
                    if lval == 0
                    {
                        ensure_space(segment,hpos, 64).context()?;

                        // 8 bit precision
                        for i in 0..64
                        {
                            self.q_tables[rval][i] = segment[hpos + i] as u16;
                            if self.q_tables[rval][i] == 0
                            {
                                if enabled_features.reject_dqts_with_zeros
                                {
                                    return err_exit_code(ExitCode::UnsupportedJpegWithZeroIdct0,"DQT has zero value");
                                }
                                else {
                                    break;
                                }
                            }
                        }

                        hpos += 64;
                    }
                    else
                    {
                        ensure_space(segment,hpos, 128).context()?;

                        // 16 bit precision
                        for i in 0..64
                        {
                            self.q_tables[rval][i] = b_short(segment[hpos + (2 * i)], segment[hpos + (2 * i) + 1]);
                            if self.q_tables[rval][i] == 0
                            {
                                if enabled_features.reject_dqts_with_zeros
                                {
                                    return err_exit_code(ExitCode::UnsupportedJpegWithZeroIdct0,"DQT has zero value");
                                }
                                else {
                                    break;
                                }
                            }
                        }

                        hpos += 128;
                    }
                }

                if hpos != len
                {
                    // if we get here, something went wrong
                    return err_exit_code(ExitCode::UnsupportedJpeg, "size mismatch in dqt marker");
                }

            }

            jpeg_code::DRI =>
            {  // DRI segment
                // define restart interval
                ensure_space(segment,hpos, 2).context()?;
                self.rsti = u32::from(b_short(segment[hpos], segment[hpos + 1]));
            }

            jpeg_code::SOS => // SOS segment
            {
                // prepare next scan
                ensure_space(segment,hpos, 1).context()?;

                self.cs_cmpc = usize::from(segment[hpos]);

                if self.cs_cmpc == 0
                {
                    return err_exit_code( ExitCode::UnsupportedJpeg, "zero components in scan");
                }

                if self.cs_cmpc > self.cmpc
                {
                    return err_exit_code( ExitCode::UnsupportedJpeg, format!("{0} components in scan, only {1} are allowed", self.cs_cmpc, self.cmpc));
                }

                hpos+=1;
                for i in 0..self.cs_cmpc
                {
                    ensure_space(segment,hpos, 2).context()?;

                    let mut cmp = 0;
                    while cmp < self.cmpc && segment[hpos] != self.cmp_info[cmp].jid
                    {
                        cmp+=1;
                    }

                    if cmp == self.cmpc
                    {
                        return err_exit_code(ExitCode::UnsupportedJpeg, "component id mismatch in start-of-scan");
                    }

                    self.cs_cmp[i] = cmp;
                    self.cmp_info[cmp].huff_dc = lbits(segment[hpos + 1], 4);
                    self.cmp_info[cmp].huff_ac = rbits(segment[hpos + 1], 4);

                    if (self.cmp_info[cmp].huff_dc == 0xff) || (self.cmp_info[cmp].huff_dc >= 4) ||
                        (self.cmp_info[cmp].huff_ac == 0xff) || (self.cmp_info[cmp].huff_ac >= 4)
                    {
                        return err_exit_code(ExitCode::UnsupportedJpeg,"huffman table number mismatch");
                    }

                    hpos += 2;
                }

                ensure_space(segment,hpos, 3).context()?;

                self.cs_from = segment[hpos + 0];
                self.cs_to = segment[hpos + 1];
                self.cs_sah = lbits(segment[hpos + 2], 4);
                self.cs_sal = rbits(segment[hpos + 2], 4);

                // check for errors
                if (self.cs_from > self.cs_to) || (self.cs_from > 63) || (self.cs_to > 63)
                {
                    return err_exit_code(ExitCode::UnsupportedJpeg,"spectral selection parameter out of range");
                }

                if (self.cs_sah >= 12) || (self.cs_sal >= 12)
                {
                    return err_exit_code(ExitCode::UnsupportedJpeg, "successive approximation parameter out of range");
                }

                return Ok(ParseSegmentResult::SOS);
            }

            jpeg_code::SOF0| // SOF0 segment, coding process: baseline DCT
            jpeg_code::SOF1| // SOF1 segment, coding process: extended sequential DCT
            jpeg_code::SOF2 =>  // SOF2 segment, coding process: progressive DCT
            {
                if self.jpeg_type != JpegType::Unknown
                {
                    return err_exit_code(ExitCode::UnsupportedJpeg, "image cannot have multiple SOF blocks");
                }

                // set JPEG coding type
                if btype == jpeg_code::SOF2
                {
                    self.jpeg_type = JpegType::Progressive;
                }
                else
                {
                    self.jpeg_type = JpegType::Sequential;
                }

                ensure_space(segment,hpos, 6).context()?;

                // check data precision, only 8 bit is allowed
                let lval = segment[hpos];
                if lval != 8
                {
                    return err_exit_code(ExitCode::UnsupportedJpeg, format!("{0} bit data precision is not supported", lval));
                }

                // image size, height & component count
                self.img_height = u32::from(b_short(segment[hpos + 1], segment[hpos + 2]));
                self.img_width = u32::from(b_short(segment[hpos + 3], segment[hpos + 4]));

                if self.img_height == 0 || self.img_width == 0
                {
                    return err_exit_code(ExitCode::UnsupportedJpeg, "image dimensions can't be zero");
                }

                if self.img_height > enabled_features.max_jpeg_height || self.img_width > enabled_features.max_jpeg_width
                {
                    return err_exit_code(ExitCode::UnsupportedJpeg, format!("image dimensions larger than {0}x{1}", enabled_features.max_jpeg_width, enabled_features.max_jpeg_height));
                }

                self.cmpc = usize::from(segment[hpos + 5]);

                if self.cmpc > 4
                {
                    return err_exit_code(ExitCode::UnsupportedJpeg, format!("image has {0} components, max 4 are supported", self.cmpc));
                }

                hpos += 6;

                // components contained in image
                for cmp in  0..self.cmpc
                {
                    ensure_space(segment,hpos, 3).context()?;

                    self.cmp_info[cmp].jid = segment[hpos];
                    self.cmp_info[cmp].sfv = u32::from(lbits(segment[hpos + 1], 4));
                    self.cmp_info[cmp].sfh = u32::from(rbits(segment[hpos + 1], 4));

                    if self.cmp_info[cmp].sfv > 2 || self.cmp_info[cmp].sfh > 2
                    {
                        return err_exit_code(ExitCode::SamplingBeyondTwoUnsupported, "Sampling type beyond to not supported");
                    }

                    let quantization_table_value = segment[hpos + 2];
                    if usize::from(quantization_table_value) >= self.q_tables.len()
                    {
                        return err_exit_code(ExitCode::UnsupportedJpeg,"quantizationTableValue too big");
                    }

                    self.cmp_info[cmp].q_table_index = quantization_table_value;
                    hpos += 3;
                }

            }

            0xC3 => // SOF3 segment
                {
                    // coding process: lossless sequential
                    return err_exit_code(ExitCode::UnsupportedJpeg,"sof3 marker found, image is coded lossless");
                }

            0xC5 => // SOF5 segment
                {
                    // coding process: differential sequential DCT
                    return err_exit_code(ExitCode::UnsupportedJpeg,"sof5 marker found, image is coded diff. sequential");
                }

            0xC6 => // SOF6 segment
                {
                    // coding process: differential progressive DCT
                    return err_exit_code(ExitCode::UnsupportedJpeg,"sof6 marker found, image is coded diff. progressive");
                }

            0xC7 => // SOF7 segment
                {
                    // coding process: differential lossless
                    return err_exit_code(ExitCode::UnsupportedJpeg,"sof7 marker found, image is coded diff. lossless");
                }

            0xC9 => // SOF9 segment
                {
                    // coding process: arithmetic extended sequential DCT
                    return err_exit_code(ExitCode::UnsupportedJpeg, "sof9 marker found, image is coded arithm. sequential");
                }

            0xCA => // SOF10 segment
                {
                    // coding process: arithmetic extended sequential DCT
                    return err_exit_code(ExitCode::UnsupportedJpeg, "sof10 marker found, image is coded arithm. progressive");
                }

            0xCB => // SOF11 segment
                {
                    // coding process: arithmetic extended sequential DCT
                    return err_exit_code(ExitCode::UnsupportedJpeg, "sof11 marker found, image is coded arithm. lossless");
                }

            0xCD => // SOF13 segment
                {
                    // coding process: arithmetic differntial sequential DCT
                    return err_exit_code(ExitCode::UnsupportedJpeg, "sof13 marker found, image is coded arithm. diff. sequential");
                }

            0xCE => // SOF14 segment
                {
                    // coding process: arithmetic differential progressive DCT
                    return err_exit_code(ExitCode::UnsupportedJpeg, "sof14 marker found, image is coded arithm. diff. progressive");
                }

            0xCF => // SOF15 segment
                {
                    // coding process: arithmetic differntial lossless
                    return err_exit_code(ExitCode::UnsupportedJpeg, "sof15 marker found, image is coded arithm. diff. lossless");
                }

            0xE0| // APP0 segment
            0xE1| // APP1 segment
            0xE2| // APP2 segment
            0xE3| // APP3 segment
            0xE4| // APP4 segment
            0xE5| // APP5 segment
            0xE6| // APP6 segment
            0xE7| // APP7 segment
            0xE8| // APP8 segment
            0xE9| // APP9 segment
            0xEA| // APP10 segment
            0xEB| // APP11 segment
            0xEC| // APP12segment
            0xED| // APP13 segment
            0xEE| // APP14 segment
            0xEF| // APP15 segment
            0xFE // COM segment
                // do nothing - return
                => {}

            jpeg_code::RST0| // RST0 segment
            0xD1| // RST1 segment
            0xD2| // RST2 segment
            0xD3| // RST3 segment
            0xD4| // RST4 segment
            0xD5| // RST5 segment
            0xD6| // RST6 segment
            0xD7 => // RST7 segment
                {
                    // return errormessage - RST is out of place here
                    return err_exit_code(ExitCode::UnsupportedJpeg, "rst marker found out of place");
                }

            jpeg_code::SOI => // SOI segment
                {
                    // return errormessage - start-of-image is out of place here
                    return err_exit_code(ExitCode::UnsupportedJpeg, "soi marker found out of place");
                }

            jpeg_code::EOI => // EOI segment
                {
                    // return errormessage - end-of-image is out of place here
                    return err_exit_code(ExitCode::UnsupportedJpeg,"eoi marker found out of place");
                }

            _ => // unknown marker segment
                {
                    // return errormessage - unknown marker
                    return err_exit_code(ExitCode::UnsupportedJpeg, format!("unknown marker found: FF {0:X}", btype));
                }
        }
        return Ok(ParseSegmentResult::Continue);
    }
}

fn ensure_space(segment: &[u8], hpos: usize, amount: usize) -> Result<()> {
    if hpos + amount > segment.len() {
        return err_exit_code(ExitCode::UnsupportedJpeg, "SOF too small");
    }

    Ok(())
}

/// constructs a huffman table for testing purposes from a given distribution
#[cfg(any(test, feature = "micro_benchmark"))]
pub(super) fn generate_huff_table_from_distribution(freq: &[usize; 256]) -> HuffCodes {
    use std::collections::{BinaryHeap, HashMap};

    struct Node {
        symbol: Option<u8>,
        freq: usize,
        left: Option<Box<Node>>,
        right: Option<Box<Node>>,
    }

    impl PartialOrd for Node {
        fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
            Some(self.freq.cmp(&other.freq).reverse())
        }
    }

    impl PartialEq for Node {
        fn eq(&self, other: &Self) -> bool {
            self.freq == other.freq
        }
    }

    impl Eq for Node {}

    impl Ord for Node {
        fn cmp(&self, other: &Self) -> std::cmp::Ordering {
            self.freq.cmp(&other.freq).reverse()
        }
    }

    fn build_tree(freq: &[usize]) -> Box<Node> {
        let mut pq = BinaryHeap::new();

        for (symbol, &freq) in freq.iter().enumerate() {
            if freq > 0 {
                pq.push(Box::new(Node {
                    symbol: Some(symbol as u8),
                    freq,
                    left: None,
                    right: None,
                }));
            }
        }

        while pq.len() > 1 {
            let left = pq.pop().unwrap();
            let right = pq.pop().unwrap();
            let new_node = Node {
                symbol: None,
                freq: left.freq + right.freq,
                left: Some(left),
                right: Some(right),
            };
            pq.push(Box::new(new_node));
        }

        pq.pop().unwrap()
    }

    fn generate_codes(root: &Node, codes: &mut HashMap<u8, (u16, u8)>, prefix: u16, length: u8) {
        if let Some(symbol) = root.symbol {
            codes.insert(symbol, (prefix, length));
        } else {
            if let Some(ref left) = root.left {
                generate_codes(left, codes, prefix << 1, length + 1);
            }
            if let Some(ref right) = root.right {
                generate_codes(right, codes, (prefix << 1) | 1, length + 1);
            }
        }
    }

    let root = build_tree(freq);

    let mut codes = HashMap::new();
    generate_codes(&root, &mut codes, 0, 0);

    let mut retval = HuffCodes::default();

    for (&symbol, &(code, length)) in &codes {
        retval.c_len[symbol as usize] = length.into();
        retval.c_val[symbol as usize] = code;
    }

    retval.post_initialize();

    retval
}


================================================
FILE: lib/src/jpeg/jpeg_position_state.rs
================================================
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the Apache License, Version 2.0. See LICENSE.txt in the project root for license information.
 *  This software incorporates material from third parties. See NOTICE.txt for details.
 *--------------------------------------------------------------------------------------------*/

use crate::consts::{JpegDecodeStatus, JpegType};
use crate::lepton_error::{AddContext, ExitCode, err_exit_code};
use crate::{LeptonError, Result};

use super::jpeg_header::{HuffCodes, JpegHeader};

/// used to keep track of position while encoding or decoding a jpeg
pub struct JpegPositionState {
    /// current component
    cmp: usize,

    /// current minimum coded unit (a fraction of dpos)
    mcu: u32,

    /// index of component
    csc: usize,

    /// offset within mcu
    sub: u32,

    /// current block position in image for this component
    dpos: u32,

    /// number of blocks left until reset interval
    rstw: u32,

    /// tracks long zero byte runs in progressive images
    pub eobrun: u16,

    /// if the previous value was also an eobrun then this is used to make sure
    /// that we don't have two non-maximum value runs in a row that we wouldn't be
    /// able to recode exactly the same way
    pub prev_eobrun: u16,
}

impl JpegPositionState {
    pub fn new(jf: &JpegHeader, mcu: u32) -> Self {
        let cmp = jf.cs_cmp[0];
        let mcumul = jf.cmp_info[cmp].sfv * jf.cmp_info[cmp].sfh;

        let state = JpegPositionState {
            cmp,
            mcu,
            csc: 0,
            sub: 0,
            dpos: mcu * mcumul,
            rstw: if jf.rsti != 0 {
                jf.rsti - (mcu % jf.rsti)
            } else {
                0
            },
            eobrun: 0,
            prev_eobrun: 0,
        };
        return state;
    }

    pub fn get_mcu(&self) -> u32 {
        self.mcu
    }
    pub fn get_dpos(&self) -> u32 {
        self.dpos
    }
    pub fn get_cmp(&self) -> usize {
        self.cmp
    }

    pub fn get_cumulative_reset_markers(&self, jf: &JpegHeader) -> u32 {
        if self.rstw != 0 {
            self.get_mcu() / jf.rsti
        } else {
            0
        }
    }

    pub fn reset_rstw(&mut self, jf: &JpegHeader) {
        self.rstw = jf.rsti;

        // eobruns don't span reset intervals
        self.prev_eobrun = 0;
    }

    /// calculates next position (non interleaved)
    fn next_mcu_pos_noninterleaved(&mut self, jf: &JpegHeader) -> JpegDecodeStatus {
        // increment position
        self.dpos += 1;

        let cmp_info = &jf.cmp_info[self.cmp];

        // fix for non interleaved mcu - horizontal
        if cmp_info.bch != cmp_info.nch && self.dpos % cmp_info.bch == cmp_info.nch {
            self.dpos += cmp_info.bch - cmp_info.nch;
        }

        // fix for non interleaved mcu - vertical
        if cmp_info.bcv != cmp_info.ncv && self.dpos / cmp_info.bch == cmp_info.ncv {
            self.dpos = cmp_info.bc;
        }

        // now we've updated dpos, update the current MCU to be a fraction of that
        if jf.jpeg_type == JpegType::Sequential {
            self.mcu = self.dpos / (cmp_info.sfv * cmp_info.sfh);
        }

        // check position
        if self.dpos >= cmp_info.bc {
            return JpegDecodeStatus::ScanCompleted;
        } else if jf.rsti > 0 {
            self.rstw -= 1;
            if self.rstw == 0 {
                return JpegDecodeStatus::RestartIntervalExpired;
            }
        }

        return JpegDecodeStatus::DecodeInProgress;
    }

    /// calculates next position for MCU
    pub fn next_mcu_pos(&mut self, jf: &JpegHeader) -> JpegDecodeStatus {
        // if there is just one component, go the simple route
        if jf.cs_cmpc == 1 {
            return self.next_mcu_pos_noninterleaved(jf);
        }

        let mut sta = JpegDecodeStatus::DecodeInProgress; // status
        let local_mcuh = jf.mcuh.get();
        let mut local_mcu = self.mcu;
        let mut local_cm
Download .txt
gitextract_8bpxdk9j/

├── .cargo/
│   └── config.toml
├── .config/
│   ├── 1espt/
│   │   └── PipelineAutobaseliningConfig.yml
│   ├── guardian/
│   │   └── .gdnbaselines
│   └── nextest.toml
├── .github/
│   └── workflows/
│       ├── publish.yml
│       ├── publishwheels.yml
│       └── rust.yml
├── .gitignore
├── .vscode/
│   ├── launch.json
│   └── tasks.json
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Cargo.toml
├── DESIGN.md
├── LICENSE.txt
├── NOTICE.txt
├── README.md
├── SECURITY.md
├── azure-pipelines.yml
├── benches/
│   └── benches.rs
├── dll/
│   ├── Cargo.toml
│   └── src/
│       └── lib.rs
├── fuzz/
│   ├── .cargo/
│   │   └── config.toml
│   ├── .gitignore
│   ├── Cargo.toml
│   ├── fuzz_targets/
│   │   └── fuzz_target_1.rs
│   └── rust-toolchain.toml
├── images/
│   ├── android.lep
│   ├── androidcrop.lep
│   ├── androidcropoptions.lep
│   ├── androidprogressive.lep
│   ├── androidprogressive_garbage.lep
│   ├── androidtrail.lep
│   ├── cathedral_db_non_int.lep
│   ├── cathedral_db_non_int_rustold.lep
│   ├── colorswap.lep
│   ├── eof_and_trailinghdrdata.lep
│   ├── eof_and_trailingrst.lep
│   ├── gray2sf.lep
│   ├── grayscale.lep
│   ├── half_scan.lep
│   ├── half_scan_rust55.lep
│   ├── hq.lep
│   ├── iphone.lep
│   ├── iphonecity.lep
│   ├── iphonecity_with_16KGarbage.jpgoutput
│   ├── iphonecity_with_16KGarbage.lep
│   ├── iphonecity_with_16KGarbage.lepoutput
│   ├── iphonecity_with_1MGarbage.lep
│   ├── iphonecrop.lep
│   ├── iphonecrop2.lep
│   ├── iphoneprogressive.lep
│   ├── iphoneprogressive2.lep
│   ├── mathoverflow_16.lep
│   ├── mathoverflow_32.lep
│   ├── mathoverflow_scalar.lep
│   ├── narrowrst.lep
│   ├── nofsync.lep
│   ├── out_of_order_dqt.lep
│   ├── pixelated.lep
│   ├── progressive_late_dht.lep
│   ├── slrcity.lep
│   ├── slrhills.lep
│   ├── slrindoor.lep
│   ├── t.jpgoutput
│   ├── t.lep
│   ├── t.lepoutput
│   ├── tiny.lep
│   ├── trailingrst.lep
│   ├── trailingrst2.lep
│   ├── trailingrst_missing_in_jpg.lep
│   ├── trunc.lep
│   ├── truncate4.lep
│   ├── truncatedzerorun.lep
│   ├── truncbad.lep
│   └── zeros_in_dqt_tables.lep
├── lib/
│   ├── Cargo.toml
│   └── src/
│       ├── consts.rs
│       ├── enabled_features.rs
│       ├── helpers.rs
│       ├── jpeg/
│       │   ├── bit_reader.rs
│       │   ├── bit_writer.rs
│       │   ├── block_based_image.rs
│       │   ├── component_info.rs
│       │   ├── jpeg_code.rs
│       │   ├── jpeg_header.rs
│       │   ├── jpeg_position_state.rs
│       │   ├── jpeg_read.rs
│       │   ├── jpeg_write.rs
│       │   ├── mod.rs
│       │   ├── row_spec.rs
│       │   └── truncate_components.rs
│       ├── lepton_error.rs
│       ├── lib.rs
│       ├── metrics.rs
│       ├── micro_benchmark.rs
│       └── structs/
│           ├── block_context.rs
│           ├── branch.rs
│           ├── idct.rs
│           ├── lepton_decoder.rs
│           ├── lepton_encoder.rs
│           ├── lepton_file_reader.rs
│           ├── lepton_file_writer.rs
│           ├── lepton_header.rs
│           ├── mod.rs
│           ├── model.rs
│           ├── multiplexer.rs
│           ├── neighbor_summary.rs
│           ├── partial_buffer.rs
│           ├── probability_tables.rs
│           ├── quantization_tables.rs
│           ├── simple_hash.rs
│           ├── simple_threadpool.rs
│           ├── thread_handoff.rs
│           ├── vpx_bool_reader.rs
│           └── vpx_bool_writer.rs
├── package/
│   └── Lepton.Jpeg.Rust.nuspec
├── python/
│   ├── Cargo.toml
│   ├── README.md
│   ├── pyproject.toml
│   ├── src/
│   │   └── lib.rs
│   └── tests/
│       └── test_compress.py
├── rustfmt.toml
├── tests/
│   ├── end_to_end.rs
│   ├── verifycompression.cmd
│   └── verifydir.cmd
└── util/
    ├── Cargo.toml
    └── src/
        ├── main.rs
        └── verifydir.rs
Download .txt
SYMBOL INDEX (670 symbols across 43 files)

FILE: benches/benches.rs
  function read_file (line 6) | fn read_file(filename: &str, ext: &str) -> Vec<u8> {
  function end_to_end_benches (line 19) | fn end_to_end_benches(c: &mut Criterion) {
  function micro_benchmarks (line 58) | fn micro_benchmarks(c: &mut Criterion) {

FILE: dll/src/lib.rs
  function copy_cstring_utf8_to_buffer (line 25) | fn copy_cstring_utf8_to_buffer(str: &str, target_error_string: &mut [u8]) {
  type RayonThreadPool (line 43) | struct RayonThreadPool {
  method max_parallelism (line 48) | fn max_parallelism(&self) -> usize {
  method run (line 51) | fn run(&self, f: Box<dyn FnOnce() + Send + 'static>) {
  function set_num_threads (line 70) | pub unsafe extern "C" fn set_num_threads(num_threads: u32) {
  function WrapperCompressImage (line 77) | pub unsafe extern "C" fn WrapperCompressImage(
  function WrapperCompressImage2 (line 103) | pub unsafe extern "C" fn WrapperCompressImage2(
  function WrapperCompressImage3 (line 130) | pub unsafe extern "C" fn WrapperCompressImage3(
  function WrapperDecompressImage (line 189) | pub unsafe extern "C" fn WrapperDecompressImage(
  function WrapperDecompressImageEx (line 217) | pub unsafe extern "C" fn WrapperDecompressImageEx(
  function WrapperDecompressImage3 (line 248) | pub unsafe extern "C" fn WrapperDecompressImage3(
  function WrapperDecompressImage4 (line 275) | pub unsafe extern "C" fn WrapperDecompressImage4(
  function get_version_string (line 363) | pub fn get_version_string() -> String {
  function get_version (line 368) | pub unsafe extern "C" fn get_version(
  type DecompressionContext (line 381) | struct DecompressionContext<'a> {
  constant MAGIC_DECOMRESSION_CONTEXT (line 387) | const MAGIC_DECOMRESSION_CONTEXT: u32 = 0xdec0de00;
  function from_pointer (line 392) | unsafe fn from_pointer(ptr: *mut std::ffi::c_void) -> &'a mut Self {
  function new (line 405) | unsafe fn new(internal: LeptonFileReader<'a>) -> *mut std::ffi::c_void {
  function free (line 415) | unsafe fn free(ptr: *mut std::ffi::c_void) {
  constant DECOMPRESS_USE_16BIT_DC_ESTIMATE (line 431) | const DECOMPRESS_USE_16BIT_DC_ESTIMATE: u32 = 1;
  constant USE_RAYON_THREAD_POOL (line 432) | const USE_RAYON_THREAD_POOL: u32 = 2;
  constant USE_SINGLE_THREAD_POOL (line 433) | const USE_SINGLE_THREAD_POOL: u32 = 4;
  function create_decompression_context (line 436) | pub unsafe extern "C" fn create_decompression_context(features: u32) -> ...
  function get_decompression_cpu (line 455) | pub unsafe extern "C" fn get_decompression_cpu(context: *mut std::ffi::c...
  function free_decompression_context (line 467) | pub unsafe extern "C" fn free_decompression_context(context: *mut std::f...
  function decompress_image (line 477) | pub unsafe extern "C" fn decompress_image(
  function read_file (line 529) | fn read_file(filename: &str, ext: &str) -> Vec<u8> {
  function test_copy_cstring_utf8_to_buffer (line 543) | fn test_copy_cstring_utf8_to_buffer() {
  function extern_interface (line 560) | fn extern_interface() {
  function extern_interface_2 (line 605) | fn extern_interface_2() {
  function extern_interface_2_single_thread (line 654) | fn extern_interface_2_single_thread() {
  function extern_interface_3_single_thread (line 703) | fn extern_interface_3_single_thread() {
  function extern_interface_decompress_chunked (line 780) | fn extern_interface_decompress_chunked(
  function verify_extern_interface_rejects_compression_of_unsupported_jpegs (line 838) | fn verify_extern_interface_rejects_compression_of_unsupported_jpegs(
  function verify_extern_interface_supports_decompression_with_zeros_in_dqt_tables (line 870) | fn verify_extern_interface_supports_decompression_with_zeros_in_dqt_tables(
  function verify_decode_external_interface_with_use_16bit_dc_estimate (line 906) | fn verify_decode_external_interface_with_use_16bit_dc_estimate(
  function verify_extern_16bit_math_retry (line 977) | fn verify_extern_16bit_math_retry() {

FILE: lib/src/consts.rs
  type JpegDecodeStatus (line 10) | pub enum JpegDecodeStatus {
  type JpegType (line 17) | pub enum JpegType {
  constant COLOR_CHANNEL_NUM_BLOCK_TYPES (line 23) | pub const COLOR_CHANNEL_NUM_BLOCK_TYPES: usize = 3;
  constant RASTER_TO_ZIGZAG (line 25) | pub const RASTER_TO_ZIGZAG: [u8; 64] = [
  constant ZIGZAG_TO_TRANSPOSED (line 37) | pub const ZIGZAG_TO_TRANSPOSED: [u8; 64] = [
  constant UNZIGZAG_49_TR (line 49) | pub const UNZIGZAG_49_TR: [u8; 49] = [
  constant ICOS_BASED_8192_SCALED (line 57) | pub const ICOS_BASED_8192_SCALED: [i32; 8] = [0, 11363, 10703, 9633, 819...
  constant ICOS_BASED_8192_SCALED_PM (line 59) | pub const ICOS_BASED_8192_SCALED_PM: [i32; 8] =
  constant FREQ_MAX (line 62) | pub const FREQ_MAX: [u16; 14] = [
  constant NON_ZERO_TO_BIN (line 67) | pub const NON_ZERO_TO_BIN: [u8; 26] = [
  constant NON_ZERO_TO_BIN_7X7 (line 72) | pub const NON_ZERO_TO_BIN_7X7: [u8; 50] = [
  constant RESIDUAL_NOISE_FLOOR (line 77) | pub const RESIDUAL_NOISE_FLOOR: usize = 7;
  constant LEPTON_VERSION (line 79) | pub const LEPTON_VERSION: u8 = 1;
  constant SMALL_FILE_BYTES_PER_ENCDOING_THREAD (line 81) | pub const SMALL_FILE_BYTES_PER_ENCDOING_THREAD: usize = 125000;
  constant MAX_THREADS_SUPPORTED_BY_LEPTON_FORMAT (line 82) | pub const MAX_THREADS_SUPPORTED_BY_LEPTON_FORMAT: usize = 16;
  constant EOI (line 85) | pub const EOI: [u8; 2] = [0xFF, jpeg_code::EOI];
  constant SOI (line 86) | pub const SOI: [u8; 2] = [0xFF, jpeg_code::SOI];
  constant LEPTON_FILE_HEADER (line 87) | pub const LEPTON_FILE_HEADER: [u8; 2] = [0xcf, 0x84];
  constant LEPTON_HEADER_BASELINE_JPEG_TYPE (line 88) | pub const LEPTON_HEADER_BASELINE_JPEG_TYPE: [u8; 1] = [b'Z'];
  constant LEPTON_HEADER_PROGRESSIVE_JPEG_TYPE (line 89) | pub const LEPTON_HEADER_PROGRESSIVE_JPEG_TYPE: [u8; 1] = [b'X'];
  constant LEPTON_HEADER_MARKER (line 90) | pub const LEPTON_HEADER_MARKER: [u8; 3] = *b"HDR";
  constant LEPTON_HEADER_PAD_MARKER (line 91) | pub const LEPTON_HEADER_PAD_MARKER: [u8; 3] = *b"P0D";
  constant LEPTON_HEADER_JPG_RESTARTS_MARKER (line 92) | pub const LEPTON_HEADER_JPG_RESTARTS_MARKER: [u8; 3] = *b"CRS";
  constant LEPTON_HEADER_JPG_RESTART_ERRORS_MARKER (line 93) | pub const LEPTON_HEADER_JPG_RESTART_ERRORS_MARKER: [u8; 3] = *b"FRS";
  constant LEPTON_HEADER_LUMA_SPLIT_MARKER (line 94) | pub const LEPTON_HEADER_LUMA_SPLIT_MARKER: [u8; 2] = *b"HH";
  constant LEPTON_HEADER_EARLY_EOF_MARKER (line 95) | pub const LEPTON_HEADER_EARLY_EOF_MARKER: [u8; 3] = *b"EEE";
  constant LEPTON_HEADER_PREFIX_GARBAGE_MARKER (line 96) | pub const LEPTON_HEADER_PREFIX_GARBAGE_MARKER: [u8; 3] = *b"PGR";
  constant LEPTON_HEADER_GARBAGE_MARKER (line 97) | pub const LEPTON_HEADER_GARBAGE_MARKER: [u8; 3] = *b"GRB";
  constant LEPTON_HEADER_COMPLETION_MARKER (line 98) | pub const LEPTON_HEADER_COMPLETION_MARKER: [u8; 3] = *b"CMP";

FILE: lib/src/enabled_features.rs
  type EnabledFeatures (line 3) | pub struct EnabledFeatures {
    method compat_lepton_vector_write (line 45) | pub fn compat_lepton_vector_write() -> Self {
    method compat_lepton_scalar_read (line 64) | pub fn compat_lepton_scalar_read() -> Self {
    method compat_lepton_vector_read (line 83) | pub fn compat_lepton_vector_read() -> Self {

FILE: lib/src/helpers.rs
  function catch_unwind_result (line 12) | pub fn catch_unwind_result<R>(
  function u16_bit_length (line 33) | pub const fn u16_bit_length(v: u16) -> u8 {
  function u32_bit_length (line 38) | pub const fn u32_bit_length(v: u32) -> u8 {
  function buffer_prefix_matches_marker (line 42) | pub fn buffer_prefix_matches_marker<const BS: usize, const MS: usize>(
  function has_ff (line 59) | pub fn has_ff(v: u64) -> bool {
  function devli (line 64) | pub const fn devli(s: u8, value: u16) -> i16 {
  function devli_test (line 76) | fn devli_test() {
  function b_short (line 94) | pub const fn b_short(v1: u8, v2: u8) -> u16 {
  function rbits (line 99) | pub const fn rbits(c: u8, n: usize) -> u8 {
  function lbits (line 104) | pub const fn lbits(c: u8, n: usize) -> u8 {
  function bitn (line 109) | pub const fn bitn(c: u16, n: u16) -> u8 {
  function calc_sign_index (line 114) | pub fn calc_sign_index(val: i16) -> usize {
  function needs_to_grow (line 126) | pub fn needs_to_grow<T>(v: &Vec<T>, additional: usize) -> bool {
  function get_rand_from_seed (line 131) | pub fn get_rand_from_seed(seed: [u8; 32]) -> rand_chacha::ChaCha12Rng {
  function read_file (line 140) | pub fn read_file(filename: &str, ext: &str) -> Vec<u8> {

FILE: lib/src/jpeg/bit_reader.rs
  type BitReader (line 15) | pub struct BitReader<R> {
  function stream_position (line 31) | pub fn stream_position(&mut self) -> u64 {
  function new (line 47) | pub fn new(inner: R) -> Self {
  function read (line 62) | pub fn read(&mut self, bits_to_read: u32) -> std::io::Result<u16> {
  function peek (line 78) | pub fn peek(&self) -> (u8, u32) {
  function advance (line 86) | pub fn advance(&mut self, bits: u32) {
  function fill_register (line 91) | pub fn fill_register(&mut self, bits_to_read: u32) -> Result<(), std::io...
  function fill_register_slow (line 125) | fn fill_register_slow(&mut self, bits_to_read: u32) -> Result<(), std::i...
  function is_eof (line 187) | pub fn is_eof(&mut self) -> bool {
  function read_and_verify_fill_bits (line 193) | pub fn read_and_verify_fill_bits(
  function verify_reset_code (line 242) | pub fn verify_reset_code(&mut self) -> Result<(), LeptonError> {
  function overhang (line 271) | pub fn overhang(&mut self) -> (u8, u8) {
  function undo_read_ahead (line 286) | pub fn undo_read_ahead(&mut self) {
  function read_simple (line 307) | fn read_simple() {
  function read_truncate_ff (line 346) | fn read_truncate_ff() {

FILE: lib/src/jpeg/bit_writer.rs
  type BitWriter (line 11) | pub struct BitWriter {
    method new (line 19) | pub fn new(data_buffer: Vec<u8>) -> Self {
    method flush_whole_bytes (line 28) | fn flush_whole_bytes(&mut self) {
    method write_byte_unescaped (line 44) | pub fn write_byte_unescaped(&mut self, b: u8) {
    method write (line 50) | pub fn write(&mut self, val: u32, new_bits: u32) {
    method pad (line 107) | pub fn pad(&mut self, fillbit: u8) {
    method detach_buffer (line 123) | pub fn detach_buffer(&mut self) -> Vec<u8> {
    method ensure_space (line 130) | pub fn ensure_space(&mut self, amount: usize) {
    method reset_from_overhang_byte_and_num_bits (line 137) | pub fn reset_from_overhang_byte_and_num_bits(&mut self, overhang_byte:...
    method has_no_remainder (line 146) | pub fn has_no_remainder(&self) -> bool {
    method amount_buffered (line 150) | pub fn amount_buffered(&self) -> usize {
  function write_simple (line 166) | fn write_simple() {
  function roundtrip_bits (line 189) | fn roundtrip_bits() {
  function roundtrip_randombits (line 216) | fn roundtrip_randombits() {

FILE: lib/src/jpeg/block_based_image.rs
  type BlockBasedImage (line 20) | pub struct BlockBasedImage {
    method new (line 34) | pub fn new(
    method merge (line 80) | pub fn merge(images: &mut Vec<Vec<BlockBasedImage>>, index: usize) -> ...
    method dump (line 133) | pub fn dump(&self) {
    method get_block_width (line 142) | pub fn get_block_width(&self) -> u32 {
    method get_original_height (line 146) | pub fn get_original_height(&self) -> u32 {
    method fill_up_to_dpos (line 153) | pub fn fill_up_to_dpos(
    method set_block_data (line 191) | pub fn set_block_data(&mut self, dpos: u32, block_data: AlignedBlock) {
    method get_block (line 195) | pub fn get_block(&self, dpos: u32) -> &AlignedBlock {
    method append_block (line 204) | pub fn append_block(&mut self, block: AlignedBlock) {
    method get_block_mut (line 213) | pub fn get_block_mut(&mut self, dpos: u32) -> &mut AlignedBlock {
  type AlignedBlock (line 221) | pub struct AlignedBlock {
    method new (line 235) | pub fn new(block: [i16; 64]) -> Self {
    method as_i16x8 (line 240) | pub fn as_i16x8(&self, index: usize) -> i16x8 {
    method transpose (line 247) | pub fn transpose(&self) -> AlignedBlock {
    method get_dc (line 252) | pub fn get_dc(&self) -> i16 {
    method set_dc (line 257) | pub fn set_dc(&mut self, value: i16) {
    method zigzag_to_transposed (line 262) | pub fn zigzag_to_transposed(a: [i16; 64]) -> AlignedBlock {
    method zigzag_from_transposed (line 276) | pub fn zigzag_from_transposed(&self) -> AlignedBlock {
    method get_block (line 291) | pub fn get_block(&self) -> &[i16; 64] {
    method get_block_mut (line 296) | pub fn get_block_mut(&mut self) -> &mut [i16; 64] {
    method get_hash (line 302) | pub fn get_hash(&self) -> i32 {
    method get_count_of_non_zeros_7x7 (line 311) | pub fn get_count_of_non_zeros_7x7(&self) -> u8 {
    method get_coefficient (line 327) | pub fn get_coefficient(&self, index: usize) -> i16 {
    method set_coefficient (line 332) | pub fn set_coefficient(&mut self, index: usize, v: i16) {
    method set_transposed_from_zigzag (line 337) | pub fn set_transposed_from_zigzag(&mut self, index: usize, v: i16) {
    method get_transposed_from_zigzag (line 342) | pub fn get_transposed_from_zigzag(&self, index: usize) -> i16 {
    method from_stride (line 347) | pub fn from_stride(&self, offset: usize, stride: usize) -> i16x8 {
  method default (line 228) | fn default() -> Self {

FILE: lib/src/jpeg/component_info.rs
  type ComponentInfo (line 8) | pub struct ComponentInfo {
  method default (line 53) | fn default() -> ComponentInfo {

FILE: lib/src/jpeg/jpeg_code.rs
  constant SOF0 (line 8) | pub const SOF0: u8 = 0xC0;
  constant SOF1 (line 11) | pub const SOF1: u8 = 0xC1;
  constant SOF2 (line 14) | pub const SOF2: u8 = 0xC2;
  constant DHT (line 17) | pub const DHT: u8 = 0xC4;
  constant RST0 (line 20) | pub const RST0: u8 = 0xD0;
  constant SOI (line 23) | pub const SOI: u8 = 0xD8;
  constant EOI (line 26) | pub const EOI: u8 = 0xD9;
  constant SOS (line 29) | pub const SOS: u8 = 0xDA;
  constant DQT (line 32) | pub const DQT: u8 = 0xDB;
  constant DRI (line 35) | pub const DRI: u8 = 0xDD;

FILE: lib/src/jpeg/jpeg_header.rs
  type RestartSegmentCodingInfo (line 56) | pub struct RestartSegmentCodingInfo {
    method new (line 65) | pub fn new(
  type ReconstructionInfo (line 88) | pub struct ReconstructionInfo {
  function parse_jpeg_header (line 140) | pub fn parse_jpeg_header<R: Read>(
  type Mirror (line 171) | struct Mirror<'a, R, W> {
  function new (line 178) | pub fn new(read: &'a mut R, output: &'a mut W) -> Self {
  method read (line 188) | fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
  type HuffCodes (line 197) | pub(crate) struct HuffCodes {
    method construct_from_segment (line 222) | pub fn construct_from_segment(segment: &[u8]) -> Result<Self> {
    method post_initialize (line 273) | fn post_initialize(&mut self) {
  method default (line 206) | fn default() -> Self {
  type HuffTree (line 305) | pub(crate) struct HuffTree {
    method construct_hufftree (line 321) | pub fn construct_hufftree(hc: &HuffCodes, accept_invalid_dht: bool) ->...
  method default (line 311) | fn default() -> Self {
  type JpegHeader (line 419) | pub struct JpegHeader {
    method fmt (line 486) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    method is_single_scan (line 552) | pub fn is_single_scan(&self) -> bool {
    method get_huff_dc_codes (line 559) | pub(super) fn get_huff_dc_codes(&self, cmp: usize) -> &HuffCodes {
    method get_huff_dc_tree (line 564) | pub(super) fn get_huff_dc_tree(&self, cmp: usize) -> &HuffTree {
    method get_huff_ac_codes (line 569) | pub(super) fn get_huff_ac_codes(&self, cmp: usize) -> &HuffCodes {
    method get_huff_ac_tree (line 574) | pub(super) fn get_huff_ac_tree(&self, cmp: usize) -> &HuffTree {
    method parse (line 582) | pub fn parse<R: Read>(
    method verify_huffman_table (line 677) | pub fn verify_huffman_table(&self, dc_present: bool, ac_present: bool)...
    method parse_next_segment (line 698) | fn parse_next_segment<R: Read>(
  type ParseSegmentResult (line 509) | enum ParseSegmentResult {
  method default (line 516) | fn default() -> Self {
  function ensure_space (line 1112) | fn ensure_space(segment: &[u8], hpos: usize, amount: usize) -> Result<()> {
  function generate_huff_table_from_distribution (line 1122) | pub(super) fn generate_huff_table_from_distribution(freq: &[usize; 256])...

FILE: lib/src/jpeg/jpeg_position_state.rs
  type JpegPositionState (line 14) | pub struct JpegPositionState {
    method new (line 43) | pub fn new(jf: &JpegHeader, mcu: u32) -> Self {
    method get_mcu (line 64) | pub fn get_mcu(&self) -> u32 {
    method get_dpos (line 67) | pub fn get_dpos(&self) -> u32 {
    method get_cmp (line 70) | pub fn get_cmp(&self) -> usize {
    method get_cumulative_reset_markers (line 74) | pub fn get_cumulative_reset_markers(&self, jf: &JpegHeader) -> u32 {
    method reset_rstw (line 82) | pub fn reset_rstw(&mut self, jf: &JpegHeader) {
    method next_mcu_pos_noninterleaved (line 90) | fn next_mcu_pos_noninterleaved(&mut self, jf: &JpegHeader) -> JpegDeco...
    method next_mcu_pos (line 125) | pub fn next_mcu_pos(&mut self, jf: &JpegHeader) -> JpegDecodeStatus {
    method skip_eobrun (line 196) | pub fn skip_eobrun(&mut self, jf: &JpegHeader) -> Result<JpegDecodeSta...
    method check_optimal_eobrun (line 263) | pub fn check_optimal_eobrun(

FILE: lib/src/jpeg/jpeg_read.rs
  function read_jpeg_file (line 74) | pub fn read_jpeg_file<R: BufRead + Seek, FN: FnMut(&JpegHeader, &[u8])>(
  function prepare_to_decode_next_scan (line 254) | fn prepare_to_decode_next_scan<R: Read>(
  function read_first_scan (line 285) | fn read_first_scan<R: BufRead + Seek>(
  function read_progressive_scan (line 385) | fn read_progressive_scan<R: BufRead + Seek>(
  function decode_baseline_rst (line 576) | fn decode_baseline_rst<R: BufRead + Seek>(
  function decode_block_seq (line 661) | pub(crate) fn decode_block_seq<R: BufRead>(
  function next_huff_code (line 722) | fn next_huff_code<R: BufRead>(bit_reader: &mut BitReader<R>, ctree: &Huf...
  function read_dc (line 736) | fn read_dc<R: BufRead>(bit_reader: &mut BitReader<R>, tree: &HuffTree) -...
  function read_coef (line 749) | fn read_coef<R: BufRead>(
  function decode_ac_prg_fs (line 793) | fn decode_ac_prg_fs<R: BufRead>(
  function decode_ac_prg_sa (line 847) | fn decode_ac_prg_sa<R: BufRead>(
  function decode_eobrun_sa (line 925) | fn decode_eobrun_sa<R: BufRead>(
  function decode_eobrun_bits (line 949) | fn decode_eobrun_bits(s: u8, n: u16) -> u16 {
  function read_garbage_behavior_progressive (line 964) | fn read_garbage_behavior_progressive() {
  function read_garbage_behavior_baseline (line 969) | fn read_garbage_behavior_baseline() {
  function read_garbage_behavior (line 974) | fn read_garbage_behavior(filename: &str) {
  function read_jpeg (line 1013) | fn read_jpeg<R: BufRead + Seek>(
  function test_benchmark_read_block (line 1037) | fn test_benchmark_read_block() {
  function test_benchmark_read_jpeg (line 1045) | fn test_benchmark_read_jpeg() {
  function benchmark_read_jpeg (line 1075) | pub fn benchmark_read_jpeg() -> Box<dyn FnMut()> {
  function benchmark_read_block (line 1102) | pub fn benchmark_read_block() -> Box<dyn FnMut()> {

FILE: lib/src/jpeg/jpeg_write.rs
  type JpegIncrementalWriter (line 51) | pub struct JpegIncrementalWriter<'a> {
  function new (line 61) | pub fn new(
  function amount_buffered (line 91) | pub fn amount_buffered(&self) -> usize {
  function process_row (line 95) | pub fn process_row(
  function detach_buffer (line 117) | pub fn detach_buffer(&mut self) -> Vec<u8> {
  function jpeg_write_entire_scan (line 124) | pub fn jpeg_write_entire_scan(
  function recode_one_mcu_row (line 163) | fn recode_one_mcu_row(
  function encode_block_seq (line 347) | pub(crate) fn encode_block_seq(
  function write_coef (line 416) | fn write_coef(huffw: &mut BitWriter, is_neg: bool, abs_coef: u16, z: u32...
  function encode_ac_prg_fs (line 445) | fn encode_ac_prg_fs(
  function encode_ac_prg_sa (line 500) | fn encode_ac_prg_sa(
  function encode_eobrun (line 595) | fn encode_eobrun(huffw: &mut BitWriter, actbl: &HuffCodes, state: &mut J...
  function encode_crbits (line 614) | fn encode_crbits(huffw: &mut BitWriter, correction_bits: &mut Vec<u8>) {
  function div_pow2 (line 621) | fn div_pow2(v: i16, p: u8) -> i16 {
  function encode_eobrun_bits (line 626) | fn encode_eobrun_bits(s: u8, v: u16) -> u16 {
  function round_trip_block (line 648) | fn round_trip_block(block: &AlignedBlock, expected: &[u8]) {
  function test_encode_block_seq (line 686) | fn test_encode_block_seq() {
  function test_encode_block_magnitude (line 706) | fn test_encode_block_magnitude() {
  function test_encode_block_zero_runs (line 727) | fn test_encode_block_zero_runs() {
  function test_encode_block_long_zero_cnt (line 751) | fn test_encode_block_long_zero_cnt() {
  function test_encode_block_seq_zero (line 762) | fn test_encode_block_seq_zero() {
  function roundtrip_jpeg (line 770) | fn roundtrip_jpeg<R: std::io::BufRead + std::io::Seek>(
  function roundtrip_baseline_jpeg (line 848) | fn roundtrip_baseline_jpeg() {
  function roundtrip_progressive_jpeg (line 860) | fn roundtrip_progressive_jpeg() {
  function test_benchmark_write_jpeg (line 870) | fn test_benchmark_write_jpeg() {
  function test_benchmark_write_block (line 878) | fn test_benchmark_write_block() {
  function jpeg_write_baseline_row_range (line 891) | fn jpeg_write_baseline_row_range(
  function benchmark_write_block (line 955) | pub fn benchmark_write_block() -> Box<dyn FnMut()> {
  function benchmark_write_jpeg (line 995) | pub fn benchmark_write_jpeg() -> Box<dyn FnMut()> {

FILE: lib/src/jpeg/row_spec.rs
  type RowSpec (line 11) | pub struct RowSpec {
    method get_row_spec_from_index (line 22) | pub fn get_row_spec_from_index(

FILE: lib/src/jpeg/truncate_components.rs
  type TrucateComponentsInfo (line 13) | struct TrucateComponentsInfo {
  type TruncateComponents (line 20) | pub struct TruncateComponents {
    method init (line 42) | pub fn init(&mut self, jpeg_header: &JpegHeader) {
    method get_max_coded_heights (line 55) | pub fn get_max_coded_heights(&self) -> Vec<u32> {
    method set_truncation_bounds (line 64) | pub fn set_truncation_bounds(&mut self, jpeg_header: &JpegHeader, max_...
    method get_block_height (line 75) | pub fn get_block_height(&self, cmp: usize) -> u32 {
    method set_block_count_d_pos (line 79) | fn set_block_count_d_pos(
    method get_min_vertical_extcmp_multiple (line 108) | fn get_min_vertical_extcmp_multiple(cmp_info: &ComponentInfo, mcu_coun...
    method get_component_sizes_in_blocks (line 113) | pub fn get_component_sizes_in_blocks(&self) -> Vec<u32> {
  method default (line 31) | fn default() -> Self {

FILE: lib/src/lepton_error.rs
  type ExitCode (line 15) | pub enum ExitCode {
    method as_integer_error_code (line 101) | pub fn as_integer_error_code(self) -> i32 {
  method fmt (line 93) | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
  type LeptonErrorInternal (line 108) | struct LeptonErrorInternal {
  type LeptonError (line 115) | pub struct LeptonError {
    method new (line 129) | pub fn new(exit_code: ExitCode, message: impl AsRef<str>) -> LeptonErr...
    method exit_code (line 139) | pub fn exit_code(&self) -> ExitCode {
    method message (line 144) | pub fn message(&self) -> &str {
    method add_context (line 153) | pub fn add_context(&mut self) {
    method from (line 199) | fn from(e: TryFromIntError) -> Self {
    method from (line 208) | fn from(e: std::sync::mpsc::SendError<T>) -> Self {
    method from (line 216) | fn from(e: std::sync::mpsc::RecvError) -> Self {
    method from (line 226) | fn from(e: std::io::Error) -> Self {
  type Result (line 119) | pub type Result<T> = std::result::Result<T, LeptonError>;
  method fmt (line 122) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  function err_exit_code (line 162) | pub fn err_exit_code<T>(error_code: ExitCode, message: impl AsRef<str>) ...
  type AddContext (line 168) | pub trait AddContext<T> {
    method context (line 170) | fn context(self) -> Result<T>;
  function context (line 175) | fn context(self) -> Result<T> {
  function get_io_error_exit_code (line 189) | fn get_io_error_exit_code(e: &std::io::Error) -> ExitCode {
  function from (line 242) | fn from(e: LeptonError) -> Self {
  function test_error_translation (line 248) | fn test_error_translation() {

FILE: lib/src/lib.rs
  type StreamPosition (line 67) | pub trait StreamPosition {
    method position (line 69) | fn position(&mut self) -> u64;
    method position (line 73) | fn position(&mut self) -> u64 {
  function get_version_string (line 88) | pub fn get_version_string() -> String {
  function dump_jpeg (line 94) | pub fn dump_jpeg(input_data: &[u8], all: bool, enabled_features: &Enable...

FILE: lib/src/metrics.rs
  type CpuTimeMeasure (line 8) | pub struct CpuTimeMeasure {
    method new (line 17) | pub fn new() -> Self {
    method elapsed (line 27) | pub fn elapsed(&self) -> Duration {
  type ModelSubComponent (line 40) | pub enum ModelSubComponent {
  type ModelComponent (line 49) | pub enum ModelComponent {
  type ModelComponentStatistics (line 59) | pub struct ModelComponentStatistics {
  type Metrics (line 66) | pub struct Metrics {
    method record_compression_stats (line 74) | pub fn record_compression_stats(
    method record_cpu_worker_time (line 89) | pub fn record_cpu_worker_time(&mut self, duration: Duration) {
    method print_metrics (line 95) | pub fn print_metrics(&self) {
    method drain (line 130) | pub fn drain(&mut self) -> Metrics {
    method get_cpu_time_worker_time (line 141) | pub fn get_cpu_time_worker_time(&self) -> Duration {
    method merge_from (line 146) | pub fn merge_from(&mut self, mut source_metrics: Metrics) {

FILE: lib/src/structs/block_context.rs
  type BlockContext (line 10) | pub struct BlockContext {
    method off_y (line 26) | pub fn off_y(y: u32, image_data: &BlockBasedImage) -> BlockContext {
    method get_here_index (line 46) | pub fn get_here_index(&self) -> u32 {
    method next (line 52) | pub fn next(&mut self) -> u32 {
    method here (line 60) | pub fn here<'a>(&self, image_data: &'a BlockBasedImage) -> &'a Aligned...
    method get_neighbor_data (line 65) | pub fn get_neighbor_data<'a, const ALL_PRESENT: bool>(
    method set_neighbor_summary_here (line 100) | pub fn set_neighbor_summary_here(
  type NeighborData (line 16) | pub struct NeighborData<'a> {

FILE: lib/src/structs/branch.rs
  type Branch (line 16) | pub struct Branch {
    method new (line 50) | pub fn new() -> Self {
    method set_count (line 56) | pub fn set_count(&mut self, count: u16) {
    method get_count (line 62) | pub fn get_count(&self) -> u16 {
    method get_u64 (line 68) | pub fn get_u64(&self) -> u64 {
    method get_probability (line 80) | pub fn get_probability(&self) -> u8 {
    method record_and_update_bit (line 101) | pub fn record_and_update_bit(&mut self, bit: bool) {
  method default (line 26) | fn default() -> Branch {
  function problookup (line 32) | const fn problookup() -> [u8; 65536] {
  function test_branch_update_false (line 130) | fn test_branch_update_false() {
  function test_branch_update_true (line 153) | fn test_branch_update_true() {
  function test_all_probabilities (line 177) | fn test_all_probabilities() {

FILE: lib/src/structs/idct.rs
  constant _W1 (line 12) | const _W1: i32 = 2841;
  constant _W2 (line 13) | const _W2: i32 = 2676;
  constant _W3 (line 14) | const _W3: i32 = 2408;
  constant _W5 (line 15) | const _W5: i32 = 1609;
  constant _W6 (line 16) | const _W6: i32 = 1108;
  constant _W7 (line 17) | const _W7: i32 = 565;
  constant W3 (line 19) | const W3: i32 = 2408;
  constant W6 (line 20) | const W6: i32 = 1108;
  constant W7 (line 21) | const W7: i32 = 565;
  constant W1PW7 (line 23) | const W1PW7: i32 = _W1 + _W7;
  constant W1MW7 (line 24) | const W1MW7: i32 = _W1 - _W7;
  constant W2PW6 (line 25) | const W2PW6: i32 = _W2 + _W6;
  constant W2MW6 (line 26) | const W2MW6: i32 = _W2 - _W6;
  constant W3PW5 (line 27) | const W3PW5: i32 = _W3 + _W5;
  constant W3MW5 (line 28) | const W3MW5: i32 = _W3 - _W5;
  constant R2 (line 30) | const R2: i32 = 181;
  function run_idct (line 33) | pub fn run_idct(block: &[i32x8; 8]) -> AlignedBlock {
  function get_q (line 144) | fn get_q(offset: usize, q_transposed: &AlignedBlock) -> i32x8 {
  function get_c (line 153) | fn get_c(offset: usize, q_transposed: &AlignedBlock) -> i32x8 {
  function test_idct (line 159) | fn test_idct(test_data: &AlignedBlock, test_q: &[u16; 64]) {
  function test_idct_with_simple_block (line 326) | pub fn test_idct_with_simple_block() {
  function test_idct_with_random_blocks (line 340) | pub fn test_idct_with_random_blocks() {
  function benchmark_idct (line 360) | pub fn benchmark_idct() -> Box<dyn FnMut()> {
  function test_benchmark_idct (line 375) | fn test_benchmark_idct() {

FILE: lib/src/structs/lepton_decoder.rs
  function lepton_decode_row_range (line 36) | pub fn lepton_decode_row_range<R: Read, ROW: FnMut(&RowSpec, &[BlockBase...
  function decode_row_wrapper (line 148) | fn decode_row_wrapper<R: Read>(
  function parse_token (line 211) | fn parse_token<R: Read, const ALL_PRESENT: bool>(
  function read_coefficient_block (line 249) | pub fn read_coefficient_block<const ALL_PRESENT: bool, R: Read>(
  function decode_edge (line 390) | fn decode_edge<R: Read, const ALL_PRESENT: bool>(
  function decode_one_edge (line 437) | fn decode_one_edge<R: Read, const ALL_PRESENT: bool, const HORIZONTAL: b...

FILE: lib/src/structs/lepton_encoder.rs
  function lepton_encode_row_range (line 31) | pub fn lepton_encode_row_range<W: Write>(
  function process_row (line 149) | fn process_row<W: Write>(
  function serialize_tokens (line 212) | fn serialize_tokens<W: Write, const ALL_PRESENT: bool>(
  function write_coefficient_block (line 258) | pub fn write_coefficient_block<const ALL_PRESENT: bool, W: Write>(
  function encode_edge (line 405) | fn encode_edge<W: Write, const ALL_PRESENT: bool>(
  function count_non_zero (line 461) | fn count_non_zero(v: i16) -> u8 {
  function encode_one_edge (line 465) | fn encode_one_edge<W: Write, const ALL_PRESENT: bool, const HORIZONTAL: ...
  function roundtrip_zeros (line 552) | fn roundtrip_zeros() {
  function roundtrip_dc_only (line 568) | fn roundtrip_dc_only() {
  function roundtrip_edges_only (line 585) | fn roundtrip_edges_only() {
  function roundtrip_ac_only (line 605) | fn roundtrip_ac_only() {
  function roundtrip_ones (line 628) | fn roundtrip_ones() {
  function roundtrip_large_coef (line 645) | fn roundtrip_large_coef() {
  function roundtrip_random_seed (line 676) | fn roundtrip_random_seed() {
  function roundtrip_unique (line 719) | fn roundtrip_unique() {
  function roundtrip_non_zeros_counts (line 743) | fn roundtrip_non_zeros_counts() {
  function make_random_model (line 773) | fn make_random_model() -> Box<Model> {
  function roundtrip_read_write_coefficients (line 794) | fn roundtrip_read_write_coefficients(
  function benchmark_roundtrip_coefficient (line 1070) | pub fn benchmark_roundtrip_coefficient() -> Box<dyn FnMut()> {
  function test_benchmark_roundtrip_coefficient (line 1168) | fn test_benchmark_roundtrip_coefficient() {

FILE: lib/src/structs/lepton_file_reader.rs
  function decode_lepton (line 44) | pub fn decode_lepton<R: BufRead, W: Write>(
  function decode_lepton_file_image (line 74) | pub fn decode_lepton_file_image<R: BufRead>(
  type DecoderState (line 141) | enum DecoderState {
  type LimitedOutputWriter (line 153) | struct LimitedOutputWriter<'a, W: Write> {
  method write (line 159) | fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
  method flush (line 176) | fn flush(&mut self) -> std::io::Result<()> {
  type FixedBufferOuputWriter (line 183) | struct FixedBufferOuputWriter<'a> {
  method write (line 190) | fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
  method flush (line 205) | fn flush(&mut self) -> std::io::Result<()> {
  type LeptonFileReader (line 214) | pub struct LeptonFileReader<'a> {
  function new (line 228) | pub fn new(features: EnabledFeatures, thread_pool: ThreadPoolHolder<'a>)...
  function process_buffer (line 253) | pub fn process_buffer(
  function process_limited_buffer (line 440) | pub fn process_limited_buffer(
  function take_metrics (line 468) | pub fn take_metrics(&mut self) -> Metrics {
  function metrics (line 473) | pub fn metrics(&self) -> &Metrics {
  function process_progressive (line 477) | fn process_progressive(
  function process_cmp (line 522) | fn process_cmp(
  function verify_eof_file_size (line 565) | fn verify_eof_file_size(total_read_size: u64, in_buffer: &mut PartialBuf...
  function run_lepton_decoder_threads (line 587) | fn run_lepton_decoder_threads<P: Send + 'static>(
  function write_tail (line 635) | fn write_tail(lh: &mut LeptonHeader, output: &mut impl Write) -> Result<...
  function progressive_decoding_thread (line 648) | fn progressive_decoding_thread(
  function baseline_decoding_thread (line 685) | fn baseline_decoding_thread(
  function write_garbage_data (line 766) | fn write_garbage_data(
  function parse_and_write_header (line 804) | fn parse_and_write_header() {
  function test_simple_parse_progressive (line 865) | fn test_simple_parse_progressive() {
  function test_simple_parse_baseline (line 870) | fn test_simple_parse_baseline() {
  function test_simple_parse_trailing (line 875) | fn test_simple_parse_trailing() {
  function test_zero_dqt (line 880) | fn test_zero_dqt() {
  function test_pixelated (line 886) | fn test_pixelated() {
  function test_truncate4 (line 893) | fn test_truncate4() {
  function test_decode_single_threaded (line 898) | fn test_decode_single_threaded() {
  function test_encode_single_threaded (line 919) | fn test_encode_single_threaded() {
  function test_file (line 935) | fn test_file(filename: &str) {
  type RecordStreamPosition (line 962) | struct RecordStreamPosition<W: Write> {
  method write (line 968) | fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
  method flush (line 979) | fn flush(&mut self) -> std::io::Result<()> {
  function test_streaming_results (line 985) | fn test_streaming_results() {
  function test_too_small_output (line 1011) | fn test_too_small_output() {
  function verifydecode (line 1027) | fn verifydecode(filename: &str) {
  function test_truncated_with_bad_truncation_version (line 1049) | fn test_truncated_with_bad_truncation_version() {
  function test_truncated_with_ok_truncation_version (line 1056) | fn test_truncated_with_ok_truncation_version() {
  function test_truncated_with_bad_garbage_data (line 1064) | fn test_truncated_with_bad_garbage_data() {

FILE: lib/src/structs/lepton_file_writer.rs
  function encode_lepton (line 38) | pub fn encode_lepton<R: BufRead + Seek, W: Write + StreamPosition>(
  function encode_lepton_verify (line 72) | pub fn encode_lepton_verify(
  function read_jpeg (line 126) | pub fn read_jpeg<R: BufRead + Seek>(
  function string_to_int (line 196) | const fn string_to_int(s: &str) -> u8 {
  function get_git_version (line 214) | pub fn get_git_version() -> &'static str {
  function get_cargo_pkg_version (line 218) | pub fn get_cargo_pkg_version() -> u8 {
  function get_git_revision (line 224) | fn get_git_revision(lp: &mut LeptonHeader) {
  function run_lepton_encoder_threads (line 236) | fn run_lepton_encoder_threads<W: Write>(
  function split_row_handoffs_to_threads (line 304) | fn split_row_handoffs_to_threads(
  function get_number_of_threads_for_encoding (line 360) | fn get_number_of_threads_for_encoding(
  function test_get_git_revision (line 389) | fn test_get_git_revision() {
  function test_too_small_output (line 398) | fn test_too_small_output() {
  function test_slrcity (line 415) | fn test_slrcity() {
  function test_file (line 419) | fn test_file(filename: &str) {

FILE: lib/src/structs/lepton_header.rs
  constant FIXED_HEADER_SIZE (line 17) | pub const FIXED_HEADER_SIZE: usize = 28;
  type LeptonHeader (line 20) | pub struct LeptonHeader {
    method bad_truncation_version (line 54) | pub fn bad_truncation_version(&self) -> bool {
    method read_lepton_fixed_header (line 58) | pub fn read_lepton_fixed_header(
    method read_compressed_lepton_header (line 117) | pub fn read_compressed_lepton_header<R: Read>(
    method advance_next_header_segment (line 200) | pub fn advance_next_header_segment(
    method read_lepton_compressed_header (line 218) | fn read_lepton_compressed_header<R: Read>(&mut self, src: &mut R) -> R...
    method write_lepton_header (line 335) | pub fn write_lepton_header<W: Write>(
    method write_lepton_jpeg_header (line 414) | fn write_lepton_jpeg_header<W: Write>(&self, mrw: &mut W) -> Result<()> {
    method write_lepton_pad_bit (line 427) | fn write_lepton_pad_bit<W: Write>(&self, mrw: &mut W) -> Result<()> {
    method write_lepton_luma_splits (line 437) | fn write_lepton_luma_splits<W: Write>(&self, mrw: &mut W) -> Result<()> {
    method write_lepton_jpeg_restarts_if_needed (line 447) | fn write_lepton_jpeg_restarts_if_needed<W: Write>(&self, mrw: &mut W) ...
    method write_lepton_jpeg_restart_errors_if_needed (line 462) | fn write_lepton_jpeg_restart_errors_if_needed<W: Write>(&self, mrw: &m...
    method write_lepton_early_eof_truncation_data_if_needed (line 476) | fn write_lepton_early_eof_truncation_data_if_needed<W: Write>(
    method write_lepton_jpeg_garbage_if_needed (line 496) | fn write_lepton_jpeg_garbage_if_needed<W: Write>(
  function test_roundtrip_fixed_header (line 519) | fn test_roundtrip_fixed_header() {
  function parse_and_write_header (line 569) | fn parse_and_write_header() {
  function make_minimal_lepton_header (line 613) | fn make_minimal_lepton_header() -> Box<LeptonHeader> {
  function verify_roundtrip (line 671) | fn verify_roundtrip(

FILE: lib/src/structs/model.rs
  constant BLOCK_TYPES (line 21) | const BLOCK_TYPES: usize = 2;
  constant NUMERIC_LENGTH_MAX (line 23) | const NUMERIC_LENGTH_MAX: usize = 12;
  constant MAX_EXPONENT (line 24) | pub const MAX_EXPONENT: usize = 11;
  constant COEF_BITS (line 25) | const COEF_BITS: usize = MAX_EXPONENT - 1;
  constant NON_ZERO_7X7_COUNT_BITS (line 27) | const NON_ZERO_7X7_COUNT_BITS: usize = 49_usize.ilog2() as usize + 1;
  constant NON_ZERO_EDGE_COUNT_BITS (line 28) | const NON_ZERO_EDGE_COUNT_BITS: usize = 7_usize.ilog2() as usize + 1;
  constant NUM_NON_ZERO_7X7_BINS (line 30) | const NUM_NON_ZERO_7X7_BINS: usize = 9;
  constant NUM_NON_ZERO_EDGE_BINS (line 31) | const NUM_NON_ZERO_EDGE_BINS: usize = 7;
  type NumNonZerosCountsT (line 33) | type NumNonZerosCountsT = [[[Branch; 1 << NON_ZERO_EDGE_COUNT_BITS]; 8];...
  constant RESIDUAL_THRESHOLD_COUNTS_D1 (line 35) | const RESIDUAL_THRESHOLD_COUNTS_D1: usize = 1 << (1 + RESIDUAL_NOISE_FLO...
  constant RESIDUAL_THRESHOLD_COUNTS_D2 (line 37) | const RESIDUAL_THRESHOLD_COUNTS_D2: usize = 1 + RESIDUAL_NOISE_FLOOR - 2;
  constant RESIDUAL_THRESHOLD_COUNTS_D3 (line 38) | const RESIDUAL_THRESHOLD_COUNTS_D3: usize = 1 << RESIDUAL_NOISE_FLOOR;
  type Model (line 41) | pub struct Model {
    method walk (line 57) | pub fn walk(&mut self, mut walker: impl FnMut(&mut Branch)) {
    method model_checksum (line 127) | pub fn model_checksum(&mut self) -> u64 {
    method get_per_color (line 569) | pub fn get_per_color(&mut self, color_index: usize) -> &mut ModelPerCo...
    method read_dc (line 573) | pub fn read_dc<R: Read>(
    method write_dc (line 594) | pub fn write_dc<W: Write>(
    method get_dc_branches (line 618) | fn get_dc_branches(
    method read_length_sign_coef (line 642) | fn read_length_sign_coef<const A: usize, const B: usize, R: Read>(
    method write_length_sign_coef (line 678) | fn write_length_sign_coef<const A: usize, const B: usize, W: Write>(
  type ModelPerColor (line 146) | pub struct ModelPerColor {
    method read_coef (line 187) | pub fn read_coef<R: Read>(
    method write_coef (line 209) | pub fn write_coef<W: Write>(
    method get_coef_branches (line 234) | fn get_coef_branches(
    method write_non_zero_7x7_count (line 266) | pub fn write_non_zero_7x7_count<W: Write>(
    method write_non_zero_edge_count (line 284) | pub fn write_non_zero_edge_count<W: Write, const HORIZONTAL: bool>(
    method read_non_zero_7x7_count (line 303) | pub fn read_non_zero_7x7_count<R: Read>(
    method read_non_zero_edge_count (line 316) | pub fn read_non_zero_edge_count<R: Read, const HORIZONTAL: bool>(
    method read_edge_coefficient (line 330) | pub fn read_edge_coefficient<R: Read>(
    method write_edge_coefficient (line 427) | pub fn write_edge_coefficient<W: Write>(
    method get_residual_threshold_counts_mut (line 533) | fn get_residual_threshold_counts_mut(
    method get_non_zero_counts_edge_mut (line 555) | fn get_non_zero_counts_edge_mut<const HORIZONTAL: bool>(
  type Counts7x7 (line 165) | struct Counts7x7 {
  type CountsEdge (line 171) | struct CountsEdge {
  type CountsDC (line 180) | struct CountsDC {

FILE: lib/src/structs/multiplexer.rs
  type Message (line 26) | enum Message {
  type MultiplexWriter (line 31) | pub struct MultiplexWriter {
  constant WRITE_BUFFER_SIZE (line 37) | const WRITE_BUFFER_SIZE: usize = 65536;
  method write (line 40) | fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
  method flush (line 60) | fn flush(&mut self) -> std::io::Result<()> {
  type ThreadResults (line 74) | struct ThreadResults<RESULT> {
  function new (line 79) | fn new() -> Self {
  function send_results (line 86) | fn send_results<T: FnOnce() -> Result<RESULT> + Send + 'static>(
  function receive_results (line 102) | fn receive_results(&mut self) -> Result<Vec<RESULT>> {
  function multiplex_write (line 133) | pub fn multiplex_write<WRITE, FN, RESULT>(
  type MultiplexReader (line 234) | pub struct MultiplexReader {
    method read_slow (line 268) | fn read_slow(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
  method read (line 253) | fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
  type MultiplexReaderState (line 307) | pub struct MultiplexReaderState<RESULT> {
  type State (line 316) | enum State {
  type MultiplexReadResult (line 322) | pub enum MultiplexReadResult<RESULT> {
  function multiplex_read (line 337) | pub fn multiplex_read<FN, RESULT>(
  function spawn_processor_threads (line 406) | fn spawn_processor_threads(
  function process_buffer (line 436) | pub fn process_buffer(&mut self, source: &mut PartialBuffer<'_>) -> Resu...
  function retrieve_result (line 493) | pub fn retrieve_result(&mut self, complete: bool) -> Result<Option<RESUL...
  function try_get_result (line 547) | fn try_get_result(
  function take_metrics (line 581) | pub fn take_metrics(&mut self) -> Metrics {
  function test_multiplex_end_to_end (line 598) | fn test_multiplex_end_to_end() {
  function test_read (line 623) | fn test_read(output: &[u8], w: &[usize], max_processor_threads: usize) {
  function test_multiplex_read_error (line 675) | fn test_multiplex_read_error() {
  function test_multiplex_read_panic (line 692) | fn test_multiplex_read_panic() {
  function test_multiplex_write_error (line 709) | fn test_multiplex_write_error() {
  function test_multiplex_write_panic (line 735) | fn test_multiplex_write_panic() {

FILE: lib/src/structs/neighbor_summary.rs
  type NeighborSummary (line 12) | pub struct NeighborSummary {
    method new (line 38) | pub fn new(
    method get_num_non_zeros (line 55) | pub fn get_num_non_zeros(&self) -> u8 {
    method get_vertical_pix (line 59) | pub fn get_vertical_pix(&self) -> i16x8 {
    method get_horizontal_pix (line 63) | pub fn get_horizontal_pix(&self) -> i16x8 {
    method get_vertical_coef (line 67) | pub fn get_vertical_coef(&self) -> i32x8 {
    method get_horizontal_coef (line 71) | pub fn get_horizontal_coef(&self) -> i32x8 {
    method checksum (line 77) | pub fn checksum(&self) -> u32 {
  method default (line 31) | fn default() -> Self {

FILE: lib/src/structs/partial_buffer.rs
  type PartialBuffer (line 20) | pub struct PartialBuffer<'a> {
  function new (line 32) | pub fn new(slice: &'a [u8], extra_buffer: &'a mut Vec<u8>) -> PartialBuf...
  function continue_processing (line 41) | pub fn continue_processing(&self) -> bool {
  function take (line 55) | pub fn take(&mut self, size: usize, retention_bytes: usize) -> Option<Ve...
  function take_n (line 84) | pub fn take_n<const N: usize>(&mut self, retention_bytes: usize) -> Opti...
  function test_taking_simple (line 110) | fn test_taking_simple() {
  function test_taking_simple_n (line 120) | fn test_taking_simple_n() {
  function test_taking_extra (line 130) | fn test_taking_extra() {
  function test_taking_extra_n (line 153) | fn test_taking_extra_n() {
  function test_taking_reserve (line 176) | fn test_taking_reserve() {

FILE: lib/src/structs/probability_tables.rs
  type ProbabilityTables (line 20) | pub struct ProbabilityTables {
    method new (line 40) | pub const fn new(in_left_present: bool, in_above_present: bool) -> Pro...
    method is_all_present (line 48) | pub fn is_all_present(&self) -> bool {
    method is_left_present (line 52) | pub fn is_left_present(&self) -> bool {
    method is_above_present (line 55) | pub fn is_above_present(&self) -> bool {
    method adv_predict_or_unpredict_dc (line 59) | pub fn adv_predict_or_unpredict_dc(
    method get_color_index (line 81) | pub fn get_color_index(component: usize) -> usize {
    method num_non_zeros_to_bin_7x7 (line 86) | pub fn num_non_zeros_to_bin_7x7(num_non_zeros: usize) -> usize {
    method calc_num_non_zeros_7x7_context_bin (line 90) | pub fn calc_num_non_zeros_7x7_context_bin<const ALL_PRESENT: bool>(
    method calc_coefficient_context_7x7_aavg_block (line 121) | pub fn calc_coefficient_context_7x7_aavg_block<const ALL_PRESENT: bool>(
    method predict_current_edges (line 171) | pub fn predict_current_edges(
    method predict_next_edges (line 196) | pub fn predict_next_edges(raster: &[i32x8; 8]) -> (i32x8, i32x8) {
    method calc_coefficient_context8_lak (line 212) | pub fn calc_coefficient_context8_lak<const ALL_PRESENT: bool, const HO...
    method adv_predict_dc_pix (line 241) | pub fn adv_predict_dc_pix<const ALL_PRESENT: bool>(
  type PredictDCResult (line 31) | pub struct PredictDCResult {

FILE: lib/src/structs/quantization_tables.rs
  type QuantizationTables (line 12) | pub struct QuantizationTables {
    method new (line 23) | pub fn new(jpeg_header: &JpegHeader, component: usize) -> Self {
    method new_from_table (line 29) | pub fn new_from_table(quantization_table: &[u16; 64]) -> Self {
    method construct_quantization_tables (line 66) | pub fn construct_quantization_tables(
    method get_quantization_table (line 77) | pub fn get_quantization_table(&self) -> &[u16; 64] {
    method get_quantization_table_transposed (line 81) | pub fn get_quantization_table_transposed(&self) -> &[u16; 64] {
    method get_min_noise_threshold (line 85) | pub fn get_min_noise_threshold(&self, coef: usize) -> u8 {

FILE: lib/src/structs/simple_hash.rs
  type SimpleHash (line 12) | pub struct SimpleHash {
    method new (line 39) | pub fn new() -> Self {
    method hash (line 43) | pub fn hash<T: SimpleHashProvider>(&mut self, v: T) {
    method get (line 47) | pub fn get(&self) -> u32 {
  type SimpleHashProvider (line 16) | pub trait SimpleHashProvider {
    method get_u64 (line 17) | fn get_u64(&self) -> u64;
    method get_u64 (line 21) | fn get_u64(&self) -> u64 {
    method get_u64 (line 27) | fn get_u64(&self) -> u64 {
    method get_u64 (line 33) | fn get_u64(&self) -> u64 {

FILE: lib/src/structs/simple_threadpool.rs
  type LeptonThreadPool (line 26) | pub trait LeptonThreadPool {
    method max_parallelism (line 28) | fn max_parallelism(&self) -> usize;
    method run (line 31) | fn run(&self, f: Box<dyn FnOnce() + Send + 'static>);
    method max_parallelism (line 46) | fn max_parallelism(&self) -> usize {
    method run (line 52) | fn run(&self, f: Box<dyn FnOnce() + Send + 'static>) {
    method max_parallelism (line 155) | fn max_parallelism(&self) -> usize {
    method run (line 158) | fn run(&self, f: Box<dyn FnOnce() + Send + 'static>) {
    method max_parallelism (line 191) | fn max_parallelism(&self) -> usize {
    method run (line 194) | fn run(&self, _f: Box<dyn FnOnce() + Send + 'static>) {
  type ThreadPoolHolder (line 38) | pub enum ThreadPoolHolder<'a> {
  type LeptonThreadPriority (line 62) | pub enum LeptonThreadPriority {
  type SimpleThreadPool (line 75) | pub struct SimpleThreadPool {
    method new (line 82) | pub const fn new(priority: LeptonThreadPriority) -> Self {
    method get_idle_threads (line 91) | pub fn get_idle_threads(&self) -> usize {
    method execute (line 96) | fn execute<F>(&self, f: F)
  function test_threadpool (line 166) | fn test_threadpool() {
  type SingleThreadPool (line 188) | pub struct SingleThreadPool {}

FILE: lib/src/structs/thread_handoff.rs
  type ThreadHandoff (line 14) | pub struct ThreadHandoff {
    method deserialize (line 25) | pub fn deserialize<R: Read>(num_threads: u8, data: &mut R) -> Result<V...
    method serialize (line 57) | pub fn serialize<W: Write>(data: &Vec<ThreadHandoff>, retval: &mut W) ...
    method get_combine_thread_range_segment_size (line 80) | pub fn get_combine_thread_range_segment_size(
    method combine_thread_ranges (line 88) | pub fn combine_thread_ranges(from: &ThreadHandoff, to: &ThreadHandoff)...

FILE: lib/src/structs/vpx_bool_reader.rs
  constant BITS_IN_BYTE (line 33) | const BITS_IN_BYTE: u32 = 8;
  constant BITS_IN_VALUE (line 34) | const BITS_IN_VALUE: u32 = 64;
  constant BITS_IN_VALUE_MINUS_LAST_BYTE (line 35) | const BITS_IN_VALUE_MINUS_LAST_BYTE: u32 = BITS_IN_VALUE - BITS_IN_BYTE;
  constant VALUE_MASK (line 36) | const VALUE_MASK: u64 = (1 << BITS_IN_VALUE_MINUS_LAST_BYTE) - 1;
  type VPXBoolReader (line 38) | pub struct VPXBoolReader<R> {
  function new (line 48) | pub fn new(reader: R) -> lepton_error::Result<Self> {
  function drain_stats (line 66) | pub fn drain_stats(&mut self) -> Metrics {
  function get (line 96) | pub fn get(
  function get_grid (line 159) | pub fn get_grid<const A: usize>(
  function get_unary_encoded (line 198) | pub fn get_unary_encoded<const A: usize>(
  function get_n_bits (line 296) | pub fn get_n_bits<const A: usize>(
  function get_bit (line 328) | pub fn get_bit(&mut self, branch: &mut Branch, _cmp: ModelComponent) -> ...
  function vpx_reader_fill (line 349) | fn vpx_reader_fill(mut tmp_value: u64, upstream_reader: &mut R) -> Resul...
  function mul_prob (line 376) | fn mul_prob(tmp_range: u64, probability: u64) -> u64 {

FILE: lib/src/structs/vpx_bool_writer.rs
  type VPXBoolWriter (line 32) | pub struct VPXBoolWriter<W> {
  function new (line 43) | pub fn new(writer: W) -> Result<Self> {
  function drain_stats (line 60) | pub fn drain_stats(&mut self) -> Metrics {
  function put (line 65) | pub fn put(
  function carry (line 160) | fn carry(&mut self) {
  function put_grid (line 174) | pub fn put_grid<const A: usize>(
  function put_n_bits (line 215) | pub fn put_n_bits<const A: usize>(
  function put_unary_encoded (line 244) | pub fn put_unary_encoded<const A: usize>(
  function put_bit (line 271) | pub fn put_bit(
  function finish (line 290) | pub fn finish(&mut self) -> Result<()> {
  function flush_non_final_data (line 315) | pub fn flush_non_final_data(&mut self) -> Result<()> {
  function put_6bytes (line 335) | fn put_6bytes(buffer: &mut Vec<u8>, v: u64) {
  function test_roundtrip_vpxboolwriter_n_bits (line 344) | fn test_roundtrip_vpxboolwriter_n_bits() {
  function test_roundtrip_vpxboolwriter_unary (line 382) | fn test_roundtrip_vpxboolwriter_unary() {
  function test_roundtrip_vpxboolwriter_grid (line 419) | fn test_roundtrip_vpxboolwriter_grid() {
  function test_roundtrip_vpxboolwriter_single_bit (line 450) | fn test_roundtrip_vpxboolwriter_single_bit() {

FILE: python/src/lib.rs
  type ThreadOptions (line 7) | enum ThreadOptions {
  type RayonThreadPool (line 13) | struct RayonThreadPool {
  method run (line 18) | fn run(&self, f: Box<dyn FnOnce() + Send + 'static>) {
  method max_parallelism (line 21) | fn max_parallelism(&self) -> usize {
  function parse_config (line 30) | fn parse_config(
  function compress_bytes (line 90) | pub fn compress_bytes(
  function decompress_bytes (line 117) | pub fn decompress_bytes(
  function lepton_jpeg_python (line 145) | fn lepton_jpeg_python(m: &Bound<'_, PyModule>) -> PyResult<()> {

FILE: python/tests/test_compress.py
  function test_compress_decompress (line 3) | def test_compress_decompress():

FILE: tests/end_to_end.rs
  function assert_eq_array (line 20) | pub fn assert_eq_array<T: PartialEq + std::fmt::Debug>(a: &[T], b: &[T]) {
  function read_file (line 53) | pub fn read_file(filename: &str, ext: &str) -> Vec<u8> {
  function verify_decode (line 70) | fn verify_decode(
  function verify_decode_scalar_overflow (line 134) | fn verify_decode_scalar_overflow() {
  function verify_encode (line 160) | fn verify_encode(
  function verify_fail_encode (line 221) | fn verify_fail_encode(#[values("half_scan", "narrowrst", "nofsync")] fil...
  function verify_16bitmath (line 234) | fn verify_16bitmath() {
  function verify_encode_verify (line 280) | fn verify_encode_verify(#[values("slrcity")] file: &str) {
  function assert_exception (line 291) | fn assert_exception<T>(expected_error: ExitCode, result: Result<T, Lepto...
  function verify_encode_verify_fail (line 301) | fn verify_encode_verify_fail(#[values("mismatch_encode")] file: &str) {
  function verify_encode_progressive_false (line 316) | fn verify_encode_progressive_false(
  function verify_nonoptimal (line 338) | fn verify_nonoptimal() {
  function verify_encode_image_with_zeros_in_dqt_tables (line 354) | fn verify_encode_image_with_zeros_in_dqt_tables() {
  function test_previous_fuzz_failures (line 372) | fn test_previous_fuzz_failures() {

FILE: util/src/main.rs
  type FileType (line 33) | enum FileType {
  function parse_i32 (line 38) | fn parse_i32(s: &str) -> Result<i32, &'static str> {
  function parse_u32 (line 42) | fn parse_u32(s: &str) -> Result<u32, &'static str> {
  function parse_u64 (line 46) | fn parse_u64(s: &str) -> Result<u64, &'static str> {
  function parse_path (line 50) | fn parse_path(s: &OsStr) -> Result<PathBuf, &'static str> {
  function override_if (line 54) | fn override_if<T>(
  type UtilError (line 66) | struct UtilError(LeptonError);
    method message (line 69) | fn message(&self) -> &str {
    method exit_code (line 73) | fn exit_code(&self) -> ExitCode {
    method from (line 80) | fn from(e: pico_args::Error) -> Self {
    method from (line 89) | fn from(e: LeptonError) -> Self {
    method from (line 96) | fn from(e: std::io::Error) -> Self {
  type RecordStreamPosition (line 101) | struct RecordStreamPosition<W: Write> {
  method write (line 107) | fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
  method flush (line 113) | fn flush(&mut self) -> std::io::Result<()> {
  method position (line 119) | fn position(&mut self) -> u64 {
  function main_with_result (line 125) | fn main_with_result() -> Result<(), UtilError> {
  function id_file_type (line 456) | fn id_file_type(input_data: &[u8]) -> Result<FileType, LeptonError> {
  function execute_cpp_verify (line 470) | fn execute_cpp_verify(
  function do_work (line 511) | fn do_work(
  type VerifyWriter (line 554) | struct VerifyWriter<W> {
  function new (line 563) | pub fn new<R: Read>(output: W, mut reader: R) -> Self {
  method seek (line 574) | fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
  method write (line 580) | fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
  method flush (line 600) | fn flush(&mut self) -> std::io::Result<()> {
  function main (line 605) | fn main() {
  function call_executable_with_input (line 621) | pub fn call_executable_with_input(

FILE: util/src/verifydir.rs
  type RecursiveFiles (line 10) | pub struct RecursiveFiles {
    method new (line 15) | pub fn new(root: impl AsRef<Path>) -> std::io::Result<Self> {
  type Item (line 23) | type Item = PathBuf;
  method next (line 25) | fn next(&mut self) -> Option<Self::Item> {
  type RayonPool (line 52) | struct RayonPool {}
    method max_parallelism (line 55) | fn max_parallelism(&self) -> usize {
    method run (line 59) | fn run(&self, f: Box<dyn FnOnce() + Send + 'static>) {
  function corrupt_data_if_enabled (line 65) | pub fn corrupt_data_if_enabled(seed: &mut Option<u64>, input_data: &mut ...
  function verify_dir (line 112) | pub fn verify_dir(
  function call_executable_with_input (line 129) | pub fn call_executable_with_input(
Condensed preview — 129 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (650K chars).
[
  {
    "path": ".cargo/config.toml",
    "chars": 893,
    "preview": "# -Cehcont_guard: Enable EH Continuation Metadata (https://learn.microsoft.com/en-us/cpp/build/reference/guard-enable-eh"
  },
  {
    "path": ".config/1espt/PipelineAutobaseliningConfig.yml",
    "chars": 580,
    "preview": "## DO NOT MODIFY THIS FILE MANUALLY. This is part of auto-baselining from 1ES Pipeline Templates. Go to [https://aka.ms/"
  },
  {
    "path": ".config/guardian/.gdnbaselines",
    "chars": 16159,
    "preview": "{\n  \"properties\": {\n    \"helpUri\": \"https://eng.ms/docs/microsoft-security/security/azure-security/cloudai-security-fund"
  },
  {
    "path": ".config/nextest.toml",
    "chars": 37,
    "preview": "[profile.ci.junit]\npath = \"junit.xml\""
  },
  {
    "path": ".github/workflows/publish.yml",
    "chars": 2089,
    "preview": "name: Publish Crate\n\npermissions:\n  contents: read\n\non:\n  push:\n    tags:\n      - \"v*.*.*\"  # Triggers only for version "
  },
  {
    "path": ".github/workflows/publishwheels.yml",
    "chars": 1653,
    "preview": "name: Publish Wheels\n\npermissions:\n  contents: read\n  \non:\n  push:\n    tags:\n      - \"v*.*.*\"  # Triggers only for versi"
  },
  {
    "path": ".github/workflows/rust.yml",
    "chars": 2042,
    "preview": "name: Rust\n\npermissions:\n  contents: read\n  checks: write\n  pull-requests: write \n\non:\n  push:\n    branches: [\"main\"]\n  "
  },
  {
    "path": ".gitignore",
    "chars": 269,
    "preview": "# Generated by Cargo\n# will have compiled files and executables\n/target/\n\n# These are backup files generated by rustfmt\n"
  },
  {
    "path": ".vscode/launch.json",
    "chars": 1164,
    "preview": "{\n    // Use IntelliSense to learn about possible attributes.\n    // Hover to view descriptions of existing attributes.\n"
  },
  {
    "path": ".vscode/tasks.json",
    "chars": 625,
    "preview": "{\n    \"version\": \"2.0.0\",\n    \"tasks\": [\n        {\n            \"type\": \"cargo\",\n            \"command\": \"test\",\n         "
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 444,
    "preview": "# Microsoft Open Source Code of Conduct\n\nThis project has adopted the [Microsoft Open Source Code of Conduct](https://op"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 920,
    "preview": "# Contributing\n\nThis project welcomes contributions and suggestions. Most contributions require you to\nagree to a Contri"
  },
  {
    "path": "Cargo.toml",
    "chars": 568,
    "preview": "[package]\nname = \"lepton_jpeg_root\"\nedition = \"2024\"\nauthors = [\"Kristof Roomp <kristofr@microsoft.com>\"]\n\n[workspace.pa"
  },
  {
    "path": "DESIGN.md",
    "chars": 2772,
    "preview": "# Design\n\n## Overall approach\n\nThis library is designed to encode/decode JPEGs in a compressed file format that typicall"
  },
  {
    "path": "LICENSE.txt",
    "chars": 11358,
    "preview": "\n                                 Apache License\n                           Version 2.0, January 2004\n                  "
  },
  {
    "path": "NOTICE.txt",
    "chars": 1528,
    "preview": "Lepton JPEG compression Rust Port Copyright (c) Microsoft Corporation\n\nNOTICES AND INFORMATION\nDo Not Translate or Local"
  },
  {
    "path": "README.md",
    "chars": 4454,
    "preview": "# Lepton JPEG Compression in Rust \n[![Rust Community](https://img.shields.io/badge/Rust_Community%20-Join_us-brightgreen"
  },
  {
    "path": "SECURITY.md",
    "chars": 2757,
    "preview": "<!-- BEGIN MICROSOFT SECURITY.MD V0.0.8 BLOCK -->\n\n## Security\n\nMicrosoft takes the security of our software products an"
  },
  {
    "path": "azure-pipelines.yml",
    "chars": 6886,
    "preview": "trigger:\n  branches:\n    include:\n    - main\n  tags:\n    include:\n    - v*.*.*\n\npr:\n  branches:\n    include:\n    - main\n"
  },
  {
    "path": "benches/benches.rs",
    "chars": 2583,
    "preview": "use std::{io::Cursor, time::Duration};\n\nuse criterion::{Criterion, criterion_group, criterion_main};\nuse lepton_jpeg::{E"
  },
  {
    "path": "dll/Cargo.toml",
    "chars": 307,
    "preview": "[package]\nname = \"lepton_jpeg_dll\"\nversion.workspace = true\nedition = \"2024\"\nauthors = [\"Kristof Roomp <kristofr@microso"
  },
  {
    "path": "dll/src/lib.rs",
    "chars": 32490,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "fuzz/.cargo/config.toml",
    "chars": 69,
    "preview": "[target.x86_64-unknown-linux-gnu]\nrustflags = [\"-Ctarget_cpu=native\"]"
  },
  {
    "path": "fuzz/.gitignore",
    "chars": 38,
    "preview": "target\ncorpus\nartifacts\ncoverage\n*.log"
  },
  {
    "path": "fuzz/Cargo.toml",
    "chars": 409,
    "preview": "[package]\nname = \"lepton_jpeg-fuzz\"\nversion = \"0.0.0\"\npublish = false\nedition = \"2024\"\n\n[package.metadata]\ncargo-fuzz = "
  },
  {
    "path": "fuzz/fuzz_targets/fuzz_target_1.rs",
    "chars": 1202,
    "preview": "#![no_main]\n\nuse std::io::Cursor;\n\nuse lepton_jpeg::{decode_lepton, encode_lepton, EnabledFeatures, DEFAULT_THREAD_POOL}"
  },
  {
    "path": "fuzz/rust-toolchain.toml",
    "chars": 31,
    "preview": "[toolchain]\nchannel = \"nightly\""
  },
  {
    "path": "images/iphonecity_with_16KGarbage.jpgoutput",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "images/t.lepoutput",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "lib/Cargo.toml",
    "chars": 1101,
    "preview": "[package]\nname = \"lepton_jpeg\"\nversion.workspace = true\nedition = \"2024\"\nauthors = [\"Kristof Roomp <kristofr@microsoft.c"
  },
  {
    "path": "lib/src/consts.rs",
    "chars": 4586,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/enabled_features.rs",
    "chars": 3429,
    "preview": "/// Features that are enabled in the encoder. Turn off for potential backward compat issues.\n#[derive(Debug, Clone)]\npub"
  },
  {
    "path": "lib/src/helpers.rs",
    "chars": 6460,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/jpeg/bit_reader.rs",
    "chars": 13665,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/jpeg/bit_writer.rs",
    "chars": 9645,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/jpeg/block_based_image.rs",
    "chars": 12178,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/jpeg/component_info.rs",
    "chars": 1786,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/jpeg/jpeg_code.rs",
    "chars": 1116,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/jpeg/jpeg_header.rs",
    "chars": 42291,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/jpeg/jpeg_position_state.rs",
    "chars": 9522,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/jpeg/jpeg_read.rs",
    "chars": 39687,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/jpeg/jpeg_write.rs",
    "chars": 33374,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/jpeg/mod.rs",
    "chars": 656,
    "preview": "//! Module for reading and recreation of JPEGs without the loss of any information.\n//!\n//! This means that it should be"
  },
  {
    "path": "lib/src/jpeg/row_spec.rs",
    "chars": 3455,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/jpeg/truncate_components.rs",
    "chars": 3736,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/lepton_error.rs",
    "chars": 8525,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/lib.rs",
    "chars": 5797,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/metrics.rs",
    "chars": 4601,
    "preview": "use std::collections::HashMap;\nuse std::time::Duration;\n\n#[cfg(windows)]\nuse cpu_time::ThreadTime;\n\n/// platform indepen"
  },
  {
    "path": "lib/src/micro_benchmark.rs",
    "chars": 345,
    "preview": "pub use crate::structs::{benchmark_idct, benchmark_roundtrip_coefficient};\n\npub use crate::jpeg::jpeg_write::benchmarks:"
  },
  {
    "path": "lib/src/structs/block_context.rs",
    "chars": 4014,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/structs/branch.rs",
    "chars": 9033,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/structs/idct.rs",
    "chars": 11711,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/structs/lepton_decoder.rs",
    "chars": 15703,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/structs/lepton_encoder.rs",
    "chars": 34386,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/structs/lepton_file_reader.rs",
    "chars": 36336,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/structs/lepton_file_writer.rs",
    "chars": 14635,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/structs/lepton_header.rs",
    "chars": 26359,
    "preview": "use std::cmp::min;\nuse std::io::{Cursor, ErrorKind, Read, Seek, Write};\n\nuse byteorder::{LittleEndian, ReadBytesExt, Wri"
  },
  {
    "path": "lib/src/structs/mod.rs",
    "chars": 1008,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/structs/model.rs",
    "chars": 25054,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/structs/multiplexer.rs",
    "chars": 26279,
    "preview": "//! Implements a multiplexer that reads and writes blocks to a stream from multiple partitions. Each\n//! partition can r"
  },
  {
    "path": "lib/src/structs/neighbor_summary.rs",
    "chars": 2358,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/structs/partial_buffer.rs",
    "chars": 6672,
    "preview": "use std::cmp::min;\n\n/// This struct is used to the fact that we have to take buffers\n/// as they arrive, and we might no"
  },
  {
    "path": "lib/src/structs/probability_tables.rs",
    "chars": 13438,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/structs/quantization_tables.rs",
    "chars": 3275,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/structs/simple_hash.rs",
    "chars": 1305,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/structs/simple_threadpool.rs",
    "chars": 6906,
    "preview": "/// A simple thread pool implementation that can be used to evaluate closures on separate threads.\n///\n/// The pool will"
  },
  {
    "path": "lib/src/structs/thread_handoff.rs",
    "chars": 3822,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/structs/vpx_bool_reader.rs",
    "chars": 15160,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "lib/src/structs/vpx_bool_writer.rs",
    "chars": 14902,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "package/Lepton.Jpeg.Rust.nuspec",
    "chars": 1193,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<package xmlns=\"http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd\">\n  <m"
  },
  {
    "path": "python/Cargo.toml",
    "chars": 235,
    "preview": "[package]\nname = \"lepton_jpeg_python\"\nversion.workspace = true\nedition = \"2024\"\n\n[lib]\ncrate-type = [\"cdylib\"]\n\n[depende"
  },
  {
    "path": "python/README.md",
    "chars": 2732,
    "preview": "# Lepton JPEG Compression \n\nThis is a port of the C++ Lepton JPEG compression tool that was released by DropBox [dropbox"
  },
  {
    "path": "python/pyproject.toml",
    "chars": 551,
    "preview": "[build-system]\nrequires = [\"maturin>=1.0,<2.0\"]\nbuild-backend = \"maturin\"\n\n[project]\nname = \"lepton_jpeg_python\"\nversion"
  },
  {
    "path": "python/src/lib.rs",
    "chars": 4780,
    "preview": "use lepton_jpeg::{DEFAULT_THREAD_POOL, LeptonThreadPool, SingleThreadPool};\nuse pyo3::prelude::*;\nuse pyo3::types::{PyBy"
  },
  {
    "path": "python/tests/test_compress.py",
    "chars": 646,
    "preview": "import lepton_jpeg_python\n\ndef test_compress_decompress():\n    # load slr city from images directory\n    with open(\"../i"
  },
  {
    "path": "rustfmt.toml",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/end_to_end.rs",
    "chars": 13381,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "tests/verifycompression.cmd",
    "chars": 227,
    "preview": "@echo off\n..\\target\\release\\lepton_jpeg_util.exe %1 nul > error.txt\nif errorlevel 1 (\necho %1 failed %errorlevel%\necho -"
  },
  {
    "path": "tests/verifydir.cmd",
    "chars": 106,
    "preview": "@echo off\nsetlocal enabledelayedexpansion\nfor  /r %1 %%f in (*.jpg)  do call verifycompression.cmd ^\"%%f\"^"
  },
  {
    "path": "util/Cargo.toml",
    "chars": 396,
    "preview": "[package]\nname = \"lepton_jpeg_util\"\nversion.workspace = true\nedition = \"2024\"\nauthors = [\"Kristof Roomp <kristofr@micros"
  },
  {
    "path": "util/src/main.rs",
    "chars": 20556,
    "preview": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Micros"
  },
  {
    "path": "util/src/verifydir.rs",
    "chars": 6590,
    "preview": "use std::ffi::OsStr;\nuse std::fs::{self, ReadDir};\nuse std::io::Cursor;\nuse std::path::{Path, PathBuf};\nuse std::process"
  }
]

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

About this extraction

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

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

Copied to clipboard!