mirror of
https://github.com/Devolutions/IronRDP.git
synced 2025-12-23 12:26:46 +00:00
Merge branch 'master' into ironrdp-web-add-clippy-index-slicing-lint
This commit is contained in:
commit
421d1330d3
158 changed files with 4737 additions and 2142 deletions
30
.github/workflows/ci.yml
vendored
30
.github/workflows/ci.yml
vendored
|
|
@ -5,7 +5,7 @@ on:
|
|||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
types: [ opened, synchronize, reopened ]
|
||||
types: [opened, synchronize, reopened]
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
|
|
@ -56,12 +56,12 @@ jobs:
|
|||
|
||||
checks:
|
||||
name: Checks [${{ matrix.os }}]
|
||||
needs: [formatting]
|
||||
runs-on: ${{ matrix.runner }}
|
||||
needs: formatting
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ windows, linux, macos ]
|
||||
os: [windows, linux, macos]
|
||||
include:
|
||||
- os: windows
|
||||
runner: windows-latest
|
||||
|
|
@ -75,17 +75,17 @@ jobs:
|
|||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install devel packages
|
||||
if: runner.os == 'Linux'
|
||||
if: ${{ runner.os == 'Linux' }}
|
||||
run: |
|
||||
sudo apt-get -y install libasound2-dev
|
||||
|
||||
- name: Install NASM
|
||||
if: runner.os == 'Windows'
|
||||
shell: pwsh
|
||||
if: ${{ runner.os == 'Windows' }}
|
||||
run: |
|
||||
choco install nasm
|
||||
$Env:PATH += ";$Env:ProgramFiles\NASM"
|
||||
echo "PATH=$Env:PATH" >> $Env:GITHUB_ENV
|
||||
shell: pwsh
|
||||
|
||||
- name: Rust cache
|
||||
uses: Swatinem/rust-cache@v2.7.3
|
||||
|
|
@ -118,8 +118,8 @@ jobs:
|
|||
|
||||
fuzz:
|
||||
name: Fuzzing
|
||||
needs: [formatting]
|
||||
runs-on: ubuntu-latest
|
||||
needs: formatting
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
|
@ -147,8 +147,8 @@ jobs:
|
|||
|
||||
web:
|
||||
name: Web Client
|
||||
needs: [formatting]
|
||||
runs-on: ubuntu-latest
|
||||
needs: formatting
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
|
@ -173,8 +173,8 @@ jobs:
|
|||
|
||||
ffi:
|
||||
name: FFI
|
||||
needs: [formatting]
|
||||
runs-on: ubuntu-latest
|
||||
needs: formatting
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
|
@ -202,20 +202,14 @@ jobs:
|
|||
|
||||
success:
|
||||
name: Success
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ always() }}
|
||||
needs:
|
||||
- formatting
|
||||
- typos
|
||||
- checks
|
||||
- fuzz
|
||||
- web
|
||||
- ffi
|
||||
needs: [formatting, typos, checks, fuzz, web, ffi]
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Check success
|
||||
shell: pwsh
|
||||
run: |
|
||||
$results = '${{ toJSON(needs.*.result) }}' | ConvertFrom-Json
|
||||
$succeeded = $($results | Where { $_ -Ne "success" }).Count -Eq 0
|
||||
exit $(if ($succeeded) { 0 } else { 1 })
|
||||
shell: pwsh
|
||||
|
|
|
|||
12
.github/workflows/coverage.yml
vendored
12
.github/workflows/coverage.yml
vendored
|
|
@ -5,7 +5,7 @@ on:
|
|||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
types: [ opened, synchronize, reopened ]
|
||||
types: [opened, synchronize, reopened]
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
|
|
@ -32,19 +32,19 @@ jobs:
|
|||
run: cargo xtask cov install -v
|
||||
|
||||
- name: Generate PR report
|
||||
if: github.event.number != ''
|
||||
if: ${{ github.event.number != '' }}
|
||||
run: cargo xtask cov report-gh --repo "${{ github.repository }}" --pr "${{ github.event.number }}" -v
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: cargo xtask cov report-gh --repo "${{ github.repository }}" --pr "${{ github.event.number }}" -v
|
||||
|
||||
- name: Configure Git Identity
|
||||
if: github.ref == 'refs/heads/master'
|
||||
if: ${{ github.ref == 'refs/heads/master' }}
|
||||
run: |
|
||||
git config --local user.name "github-actions[bot]"
|
||||
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
- name: Update coverage data
|
||||
if: github.ref == 'refs/heads/master'
|
||||
if: ${{ github.ref == 'refs/heads/master' }}
|
||||
run: cargo xtask cov update -v
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.DEVOLUTIONSBOT_TOKEN }}
|
||||
run: cargo xtask cov update -v
|
||||
|
|
|
|||
18
.github/workflows/fuzz.yml
vendored
18
.github/workflows/fuzz.yml
vendored
|
|
@ -36,12 +36,12 @@ jobs:
|
|||
|
||||
fuzz:
|
||||
name: Fuzzing ${{ matrix.target }}
|
||||
needs: [corpus-download]
|
||||
runs-on: ubuntu-latest
|
||||
needs: corpus-download
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target: [ pdu_decoding, rle_decompression, bitmap_stream, cliprdr_format, channel_processing ]
|
||||
target: [pdu_decoding, rle_decompression, bitmap_stream, cliprdr_format, channel_processing]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
|
@ -108,9 +108,9 @@ jobs:
|
|||
|
||||
corpus-merge:
|
||||
name: Corpus merge artifacts
|
||||
runs-on: ubuntu-latest
|
||||
needs: fuzz
|
||||
if: ${{ always() && !cancelled() }}
|
||||
needs: [fuzz]
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Merge Artifacts
|
||||
|
|
@ -122,9 +122,9 @@ jobs:
|
|||
|
||||
corpus-upload:
|
||||
name: Upload corpus
|
||||
runs-on: ubuntu-latest
|
||||
needs: corpus-merge
|
||||
if: ${{ always() && !cancelled() }}
|
||||
needs: [corpus-merge]
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
AZURE_STORAGE_KEY: ${{ secrets.CORPUS_AZURE_STORAGE_KEY }}
|
||||
|
||||
|
|
@ -156,13 +156,13 @@ jobs:
|
|||
|
||||
notify:
|
||||
name: Notify failure
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ always() && contains(needs.*.result, 'failure') && github.event_name == 'schedule' }}
|
||||
needs:
|
||||
- fuzz
|
||||
needs: [fuzz]
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_ARCHITECTURE }}
|
||||
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
|
||||
|
||||
steps:
|
||||
- name: Send slack notification
|
||||
id: slack
|
||||
|
|
|
|||
52
.github/workflows/npm-publish.yml
vendored
52
.github/workflows/npm-publish.yml
vendored
|
|
@ -21,7 +21,6 @@ jobs:
|
|||
steps:
|
||||
- name: Get dry run
|
||||
id: get-dry-run
|
||||
shell: pwsh
|
||||
run: |
|
||||
$IsDryRun = '${{ github.event.inputs.dry-run }}' -Eq 'true' -Or '${{ github.event_name }}' -Eq 'schedule'
|
||||
|
||||
|
|
@ -30,13 +29,12 @@ jobs:
|
|||
} else {
|
||||
echo "dry-run=false" >> $Env:GITHUB_OUTPUT
|
||||
}
|
||||
shell: pwsh
|
||||
|
||||
build:
|
||||
name: Build package [${{matrix.library}}]
|
||||
needs: [preflight]
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- preflight
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
|
@ -49,18 +47,17 @@ jobs:
|
|||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup wasm-pack
|
||||
shell: bash
|
||||
run: |
|
||||
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||
shell: bash
|
||||
|
||||
- name: Install dependencies
|
||||
shell: pwsh
|
||||
run: |
|
||||
Set-Location -Path "./web-client/${{matrix.library}}/"
|
||||
npm install
|
||||
shell: pwsh
|
||||
|
||||
- name: Build package
|
||||
shell: pwsh
|
||||
run: |
|
||||
Set-PSDebug -Trace 1
|
||||
|
||||
|
|
@ -68,14 +65,15 @@ jobs:
|
|||
npm run build
|
||||
Set-Location -Path ./dist
|
||||
npm pack
|
||||
shell: pwsh
|
||||
|
||||
- name: Harvest package
|
||||
shell: pwsh
|
||||
run: |
|
||||
Set-PSDebug -Trace 1
|
||||
|
||||
New-Item -ItemType "directory" -Path . -Name "npm-packages"
|
||||
Get-ChildItem -Path ./web-client/ -Recurse *.tgz | ForEach { Copy-Item $_ "./npm-packages" }
|
||||
shell: pwsh
|
||||
|
||||
- name: Upload package artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
|
|
@ -85,8 +83,8 @@ jobs:
|
|||
|
||||
npm-merge:
|
||||
name: Merge artifacts
|
||||
needs: [build]
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
|
||||
steps:
|
||||
- name: Merge Artifacts
|
||||
|
|
@ -98,12 +96,13 @@ jobs:
|
|||
|
||||
publish:
|
||||
name: Publish package
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
environment: publish
|
||||
needs:
|
||||
- preflight
|
||||
- npm-merge
|
||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||
needs: [preflight, npm-merge]
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
|
|
@ -117,12 +116,7 @@ jobs:
|
|||
name: npm
|
||||
path: npm-packages
|
||||
|
||||
- name: Prepare npm
|
||||
shell: pwsh
|
||||
run: npm config set "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}"
|
||||
|
||||
- name: Publish
|
||||
shell: pwsh
|
||||
run: |
|
||||
Set-PSDebug -Trace 1
|
||||
|
||||
|
|
@ -168,15 +162,10 @@ jobs:
|
|||
$publishCmd = $publishCmd -Join ' '
|
||||
Invoke-Expression $publishCmd
|
||||
}
|
||||
shell: pwsh
|
||||
|
||||
- name: Create version tags
|
||||
if: ${{ needs.preflight.outputs.dry-run == 'false' }}
|
||||
shell: bash
|
||||
env:
|
||||
GIT_AUTHOR_NAME: github-actions
|
||||
GIT_AUTHOR_EMAIL: github-actions@github.com
|
||||
GIT_COMMITTER_NAME: github-actions
|
||||
GIT_COMMITTER_EMAIL: github-actions@github.com
|
||||
run: |
|
||||
set -e
|
||||
|
||||
|
|
@ -202,6 +191,12 @@ jobs:
|
|||
git tag "$tag" "$GITHUB_SHA"
|
||||
git push origin "$tag"
|
||||
done
|
||||
shell: bash
|
||||
env:
|
||||
GIT_AUTHOR_NAME: github-actions
|
||||
GIT_AUTHOR_EMAIL: github-actions@github.com
|
||||
GIT_COMMITTER_NAME: github-actions
|
||||
GIT_COMMITTER_EMAIL: github-actions@github.com
|
||||
|
||||
- name: Update Artifactory Cache
|
||||
if: ${{ needs.preflight.outputs.dry-run == 'false' }}
|
||||
|
|
@ -213,14 +208,13 @@ jobs:
|
|||
|
||||
notify:
|
||||
name: Notify failure
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ always() && contains(needs.*.result, 'failure') && github.event_name == 'schedule' }}
|
||||
needs:
|
||||
- preflight
|
||||
- build
|
||||
needs: [preflight, build]
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_ARCHITECTURE }}
|
||||
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
|
||||
|
||||
steps:
|
||||
- name: Send slack notification
|
||||
id: slack
|
||||
|
|
|
|||
73
.github/workflows/nuget-publish.yml
vendored
73
.github/workflows/nuget-publish.yml
vendored
|
|
@ -26,7 +26,6 @@ jobs:
|
|||
|
||||
- name: Get dry run
|
||||
id: get-dry-run
|
||||
shell: pwsh
|
||||
run: |
|
||||
$IsDryRun = '${{ github.event.inputs.dry-run }}' -Eq 'true' -Or '${{ github.event_name }}' -Eq 'schedule'
|
||||
|
||||
|
|
@ -35,26 +34,27 @@ jobs:
|
|||
} else {
|
||||
echo "dry-run=false" >> $Env:GITHUB_OUTPUT
|
||||
}
|
||||
shell: pwsh
|
||||
|
||||
- name: Get version
|
||||
id: get-version
|
||||
shell: pwsh
|
||||
run: |
|
||||
$CsprojXml = [Xml] (Get-Content .\ffi\dotnet\Devolutions.IronRdp\Devolutions.IronRdp.csproj)
|
||||
$ProjectVersion = $CsprojXml.Project.PropertyGroup.Version | Select-Object -First 1
|
||||
$PackageVersion = $ProjectVersion -Replace "^(\d+)\.(\d+)\.(\d+).(\d+)$", "`$1.`$2.`$3"
|
||||
echo "project-version=$ProjectVersion" >> $Env:GITHUB_OUTPUT
|
||||
echo "package-version=$PackageVersion" >> $Env:GITHUB_OUTPUT
|
||||
shell: pwsh
|
||||
|
||||
build-native:
|
||||
name: Native build
|
||||
needs: [preflight]
|
||||
runs-on: ${{matrix.runner}}
|
||||
needs: preflight
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ win, osx, linux, ios, android ]
|
||||
arch: [ x86, x64, arm, arm64 ]
|
||||
os: [win, osx, linux, ios, android]
|
||||
arch: [x86, x64, arm, arm64]
|
||||
include:
|
||||
- os: win
|
||||
runner: windows-2022
|
||||
|
|
@ -89,20 +89,20 @@ jobs:
|
|||
uses: actions/checkout@v4
|
||||
|
||||
- name: Configure Android NDK
|
||||
if: ${{ matrix.os == 'android' }}
|
||||
uses: Devolutions/actions-public/cargo-android-ndk@v1
|
||||
if: matrix.os == 'android'
|
||||
with:
|
||||
android_api_level: "21"
|
||||
|
||||
- name: Configure macOS deployement target
|
||||
if: ${{ matrix.os == 'osx' }}
|
||||
shell: pwsh
|
||||
run: Write-Output "MACOSX_DEPLOYMENT_TARGET=10.10" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append
|
||||
shell: pwsh
|
||||
|
||||
- name: Configure iOS deployement target
|
||||
if: ${{ matrix.os == 'ios' }}
|
||||
shell: pwsh
|
||||
run: Write-Output "IPHONEOS_DEPLOYMENT_TARGET=12.1" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append
|
||||
shell: pwsh
|
||||
|
||||
- name: Update runner
|
||||
if: ${{ matrix.os == 'linux' }}
|
||||
|
|
@ -110,12 +110,11 @@ jobs:
|
|||
|
||||
- name: Install dependencies for rustls
|
||||
if: ${{ runner.os == 'Windows' }}
|
||||
shell: pwsh
|
||||
run: |
|
||||
choco install ninja nasm
|
||||
|
||||
# We need to add the NASM binary folder to the PATH manually.
|
||||
# We don’t need to do that for ninja.
|
||||
# We don't need to do that for ninja.
|
||||
Write-Output "PATH=$Env:PATH;$Env:ProgramFiles\NASM" >> $Env:GITHUB_ENV
|
||||
|
||||
# libclang / LLVM is a requirement for AWS LC.
|
||||
|
|
@ -125,6 +124,7 @@ jobs:
|
|||
|
||||
# Install Visual Studio Developer PowerShell Module for cmdlets such as Enter-VsDevShell
|
||||
Install-Module VsDevShell -Force
|
||||
shell: pwsh
|
||||
|
||||
# No pre-generated bindings for Android and iOS.
|
||||
# https://aws.github.io/aws-lc-rs/platform_support.html#pre-generated-bindings
|
||||
|
|
@ -141,19 +141,18 @@ jobs:
|
|||
sudo apt-get install gcc-multilib
|
||||
|
||||
- name: Setup LLVM
|
||||
if: ${{ matrix.os == 'linux' }}
|
||||
uses: Devolutions/actions-public/setup-llvm@v1
|
||||
if: matrix.os == 'linux'
|
||||
with:
|
||||
version: "18.1.8"
|
||||
|
||||
- name: Setup CBake
|
||||
if: ${{ matrix.os == 'linux' }}
|
||||
uses: Devolutions/actions-public/setup-cbake@v1
|
||||
if: matrix.os == 'linux'
|
||||
with:
|
||||
cargo_env_scripts: true
|
||||
|
||||
- name: Build native lib (${{matrix.os}}-${{matrix.arch}})
|
||||
shell: pwsh
|
||||
run: |
|
||||
$DotNetOs = '${{matrix.os}}'
|
||||
$DotNetArch = '${{matrix.arch}}'
|
||||
|
|
@ -210,6 +209,7 @@ jobs:
|
|||
$OutputPath = Join-Path "dependencies" "runtimes" $DotNetRid "native"
|
||||
New-Item -ItemType Directory -Path $OutputPath | Out-Null
|
||||
Copy-Item $OutputLibrary $(Join-Path $OutputPath $RenamedLibraryName)
|
||||
shell: pwsh
|
||||
|
||||
- name: Upload native components
|
||||
uses: actions/upload-artifact@v4
|
||||
|
|
@ -219,8 +219,8 @@ jobs:
|
|||
|
||||
build-universal:
|
||||
name: Universal build
|
||||
needs: [preflight, build-native]
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [ preflight, build-native ]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
|
@ -239,7 +239,6 @@ jobs:
|
|||
path: dependencies/runtimes
|
||||
|
||||
- name: Lipo native components
|
||||
shell: pwsh
|
||||
run: |
|
||||
Set-Location "dependencies/runtimes"
|
||||
# No RID for universal binaries, see: https://github.com/dotnet/runtime/issues/53156
|
||||
|
|
@ -249,9 +248,9 @@ jobs:
|
|||
$LipoCmd = $(@('lipo', '-create', '-output', (Join-Path -Path $OutputPath -ChildPath "libDevolutionsIronRdp.dylib")) + $Libraries) -Join ' '
|
||||
Write-Host $LipoCmd
|
||||
Invoke-Expression $LipoCmd
|
||||
shell: pwsh
|
||||
|
||||
- name: Framework
|
||||
shell: pwsh
|
||||
if: ${{ matrix.os == 'ios' }}
|
||||
run: |
|
||||
$Version = '${{ needs.preflight.outputs.project-version }}'
|
||||
|
|
@ -269,19 +268,19 @@ jobs:
|
|||
|
||||
[xml] $InfoPlistXml = Get-Content (Join-Path "ffi" "dotnet" "Devolutions.IronRdp" "Info.plist")
|
||||
Select-Xml -xml $InfoPlistXml -XPath "/plist/dict/key[. = 'CFBundleIdentifier']/following-sibling::string[1]" |
|
||||
%{
|
||||
%{
|
||||
$_.Node.InnerXml = "com.devolutions.ironrdp"
|
||||
}
|
||||
Select-Xml -xml $InfoPlistXml -XPath "/plist/dict/key[. = 'CFBundleExecutable']/following-sibling::string[1]" |
|
||||
%{
|
||||
%{
|
||||
$_.Node.InnerXml = $BundleName
|
||||
}
|
||||
Select-Xml -xml $InfoPlistXml -XPath "/plist/dict/key[. = 'CFBundleVersion']/following-sibling::string[1]" |
|
||||
%{
|
||||
%{
|
||||
$_.Node.InnerXml = $Version
|
||||
}
|
||||
Select-Xml -xml $InfoPlistXml -XPath "/plist/dict/key[. = 'CFBundleShortVersionString']/following-sibling::string[1]" |
|
||||
%{
|
||||
%{
|
||||
$_.Node.InnerXml = $ShortVersion
|
||||
}
|
||||
|
||||
|
|
@ -294,6 +293,7 @@ jobs:
|
|||
# .NET XML document inserts two square brackets at the end of the DOCTYPE tag
|
||||
# It's perfectly valid XML, but we're dealing with plists here and dyld will not be able to read the file
|
||||
((Get-Content -Path (Join-Path $FrameworkDir "Info.plist") -Raw) -Replace 'PropertyList-1.0.dtd"\[\]', 'PropertyList-1.0.dtd"') | Set-Content -Path (Join-Path $FrameworkDir "Info.plist")
|
||||
shell: pwsh
|
||||
|
||||
- name: Upload native components
|
||||
uses: actions/upload-artifact@v4
|
||||
|
|
@ -303,8 +303,8 @@ jobs:
|
|||
|
||||
build-managed:
|
||||
name: Managed build
|
||||
needs: [build-universal]
|
||||
runs-on: windows-2022
|
||||
needs: build-universal
|
||||
|
||||
steps:
|
||||
- name: Check out ${{ github.repository }}
|
||||
|
|
@ -317,9 +317,9 @@ jobs:
|
|||
run: dotnet workload install ios
|
||||
|
||||
- name: Prepare dependencies
|
||||
shell: pwsh
|
||||
run: |
|
||||
New-Item -ItemType Directory -Path "dependencies/runtimes" | Out-Null
|
||||
shell: pwsh
|
||||
|
||||
- name: Download native components
|
||||
uses: actions/download-artifact@v4
|
||||
|
|
@ -327,19 +327,19 @@ jobs:
|
|||
path: dependencies/runtimes
|
||||
|
||||
- name: Rename dependencies
|
||||
shell: pwsh
|
||||
run: |
|
||||
Set-Location "dependencies/runtimes"
|
||||
$(Get-Item ".\ironrdp-*") | ForEach-Object { Rename-Item $_ $_.Name.Replace("ironrdp-", "") }
|
||||
Get-ChildItem * -Recurse
|
||||
shell: pwsh
|
||||
|
||||
- name: Build Devolutions.IronRdp (managed)
|
||||
shell: pwsh
|
||||
run: |
|
||||
# net8.0 target packaged as Devolutions.IronRdp
|
||||
dotnet build .\ffi\dotnet\Devolutions.IronRdp\Devolutions.IronRdp.csproj -c Release
|
||||
# net8.0-ios target packaged as Devolutions.IronRdp.iOS
|
||||
dotnet build .\ffi\dotnet\Devolutions.IronRdp\Devolutions.IronRdp.csproj -c Release /p:PackageId=Devolutions.IronRdp.iOS
|
||||
shell: pwsh
|
||||
|
||||
- name: Upload managed components
|
||||
uses: actions/upload-artifact@v4
|
||||
|
|
@ -349,12 +349,10 @@ jobs:
|
|||
|
||||
publish:
|
||||
name: Publish NuGet package
|
||||
runs-on: ubuntu-latest
|
||||
environment: nuget-publish
|
||||
if: needs.preflight.outputs.dry-run == 'false'
|
||||
needs:
|
||||
- preflight
|
||||
- build-managed
|
||||
if: ${{ needs.preflight.outputs.dry-run == 'false' }}
|
||||
needs: [preflight, build-managed]
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Download NuGet package artifact
|
||||
|
|
@ -364,15 +362,14 @@ jobs:
|
|||
path: package
|
||||
|
||||
- name: Publish to nuget.org
|
||||
shell: pwsh
|
||||
run: |
|
||||
$Files = Get-ChildItem -Recurse package/*.nupkg
|
||||
|
||||
foreach ($File in $Files) {
|
||||
$PushCmd = @(
|
||||
'dotnet',
|
||||
'nuget',
|
||||
'push',
|
||||
'dotnet',
|
||||
'nuget',
|
||||
'push',
|
||||
"$File",
|
||||
'--api-key',
|
||||
'${{ secrets.NUGET_API_KEY }}',
|
||||
|
|
@ -385,19 +382,17 @@ jobs:
|
|||
$PushCmd = $PushCmd -Join ' '
|
||||
Invoke-Expression $PushCmd
|
||||
}
|
||||
shell: pwsh
|
||||
|
||||
notify:
|
||||
name: Notify failure
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ always() && contains(needs.*.result, 'failure') && github.event_name == 'schedule' }}
|
||||
needs:
|
||||
- preflight
|
||||
- build-native
|
||||
- build-universal
|
||||
- build-managed
|
||||
needs: [preflight, build-native, build-universal, build-managed]
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_ARCHITECTURE }}
|
||||
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
|
||||
|
||||
steps:
|
||||
- name: Send slack notification
|
||||
id: slack
|
||||
|
|
|
|||
7
.github/workflows/release-crates.yml
vendored
7
.github/workflows/release-crates.yml
vendored
|
|
@ -14,9 +14,8 @@ jobs:
|
|||
# Create a PR with the new versions and changelog, preparing the next release.
|
||||
open-pr:
|
||||
name: Open release PR
|
||||
runs-on: ubuntu-latest
|
||||
environment: cratesio-publish
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
concurrency:
|
||||
group: release-plz-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
|
@ -37,7 +36,6 @@ jobs:
|
|||
github-token: ${{ secrets.DEVOLUTIONSBOT_WRITE_TOKEN }}
|
||||
|
||||
- name: Update fuzz/Cargo.lock
|
||||
shell: pwsh
|
||||
if: ${{ steps.release-plz.outputs.did-open-pr == 'true' }}
|
||||
run: |
|
||||
$prRaw = '${{ steps.release-plz.outputs.pr }}'
|
||||
|
|
@ -61,12 +59,13 @@ jobs:
|
|||
|
||||
Write-Host "Update the release pull request"
|
||||
git push --force
|
||||
shell: pwsh
|
||||
|
||||
# Release unpublished packages.
|
||||
release:
|
||||
name: Release crates
|
||||
runs-on: ubuntu-latest
|
||||
environment: cratesio-publish
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
|
|
|
|||
25
Cargo.lock
generated
25
Cargo.lock
generated
|
|
@ -708,9 +708,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.48"
|
||||
version = "4.5.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae"
|
||||
checksum = "0c2cfd7bf8a6017ddaa4e32ffe7403d547790db06bd171c1c53926faab501623"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
|
@ -718,9 +718,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.48"
|
||||
version = "4.5.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9"
|
||||
checksum = "0a4c05b9e80c5ccd3a7ef080ad7b6ba7d6fc00a985b8b157197075677c82c7a0"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
|
|
@ -730,9 +730,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.47"
|
||||
version = "4.5.49"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c"
|
||||
checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
|
|
@ -1527,6 +1527,7 @@ dependencies = [
|
|||
name = "ffi"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"diplomat",
|
||||
"diplomat-runtime",
|
||||
"embed-resource",
|
||||
|
|
@ -1534,6 +1535,7 @@ dependencies = [
|
|||
"ironrdp-cliprdr-native",
|
||||
"ironrdp-core",
|
||||
"ironrdp-dvc-pipe-proxy",
|
||||
"ironrdp-rdcleanpath",
|
||||
"sspi",
|
||||
"thiserror 2.0.17",
|
||||
"tracing",
|
||||
|
|
@ -2597,7 +2599,6 @@ dependencies = [
|
|||
"expect-test",
|
||||
"ironrdp-core",
|
||||
"ironrdp-pdu",
|
||||
"lazy_static",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"yuv",
|
||||
|
|
@ -2643,7 +2644,6 @@ dependencies = [
|
|||
"expect-test",
|
||||
"ironrdp-core",
|
||||
"ironrdp-error",
|
||||
"lazy_static",
|
||||
"md-5",
|
||||
"num-bigint",
|
||||
"num-derive",
|
||||
|
|
@ -2812,7 +2812,6 @@ dependencies = [
|
|||
"ironrdp-rdpfile",
|
||||
"ironrdp-rdpsnd",
|
||||
"ironrdp-session",
|
||||
"lazy_static",
|
||||
"paste",
|
||||
"png",
|
||||
"pretty_assertions",
|
||||
|
|
@ -3712,9 +3711,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "opus2"
|
||||
version = "0.3.2"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8e79f6e5198dfc9ec913fd4ddc8b53b87263d59c500b989f8449bd566552ce3"
|
||||
checksum = "c3a4200c196ebf402d8a7091ce21845e8f2cd2f9c0c00deb73aaa14d024f6e6e"
|
||||
dependencies = [
|
||||
"libopus_sys",
|
||||
]
|
||||
|
|
@ -4440,9 +4439,9 @@ checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2"
|
|||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.12.23"
|
||||
version = "0.12.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb"
|
||||
checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bytes",
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ rstest = "0.25"
|
|||
# Note: we are trying to move away from using these crates.
|
||||
# They are being kept around for now for legacy compatibility,
|
||||
# but new usage should be avoided.
|
||||
lazy_static = "1.4" # Legacy crate; prefer std::sync::LazyLock or LazyCell
|
||||
num-derive = "0.4"
|
||||
num-traits = "0.2"
|
||||
|
||||
|
|
@ -94,7 +93,7 @@ ptr_cast_constness = "warn"
|
|||
|
||||
# == Correctness == #
|
||||
#indexing_slicing = "warn" TODO: enable this lint project wide.
|
||||
#as_conversions = "warn"
|
||||
as_conversions = "warn"
|
||||
cast_lossless = "warn"
|
||||
cast_possible_truncation = "warn"
|
||||
cast_possible_wrap = "warn"
|
||||
|
|
@ -129,6 +128,7 @@ empty_enum_variants_with_brackets = "warn"
|
|||
deref_by_slicing = "warn"
|
||||
multiple_inherent_impl = "warn"
|
||||
map_with_unused_argument_over_ranges = "warn"
|
||||
partial_pub_fields = "warn"
|
||||
trait_duplication_in_bounds = "warn"
|
||||
type_repetition_in_bounds = "warn"
|
||||
checked_conversions = "warn"
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ async fn main() -> Result<(), anyhow::Error> {
|
|||
let mut updates = DisplayUpdates::new(file, DesktopSize { width, height }, fps);
|
||||
while let Some(up) = updates.next_update().await? {
|
||||
if let DisplayUpdate::Bitmap(ref up) = up {
|
||||
total_raw += up.data.len() as u64;
|
||||
total_raw += u64::try_from(up.data.len())?;
|
||||
} else {
|
||||
eprintln!("Invalid update");
|
||||
break;
|
||||
|
|
@ -78,7 +78,7 @@ async fn main() -> Result<(), anyhow::Error> {
|
|||
let Some(frag) = iter.next().await else {
|
||||
break;
|
||||
};
|
||||
let len = frag?.data.len() as u64;
|
||||
let len = u64::try_from(frag?.data.len())?;
|
||||
total_enc += len;
|
||||
}
|
||||
n_updates += 1;
|
||||
|
|
@ -87,6 +87,7 @@ async fn main() -> Result<(), anyhow::Error> {
|
|||
}
|
||||
println!();
|
||||
|
||||
#[expect(clippy::as_conversions, reason = "casting u64 to f64")]
|
||||
let ratio = total_enc as f64 / total_raw as f64;
|
||||
let percent = 100.0 - ratio * 100.0;
|
||||
println!("Encoder: {encoder:?}");
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
msrv = "1.84"
|
||||
msrv = "1.87"
|
||||
semicolon-outside-block-ignore-multiline = true
|
||||
accept-comment-above-statement = true
|
||||
accept-comment-above-attributes = true
|
||||
|
|
|
|||
|
|
@ -713,7 +713,7 @@ impl Sequence for Acceptor {
|
|||
AcceptorState::Accepted {
|
||||
channels,
|
||||
client_capabilities,
|
||||
input_events: finalization.input_events,
|
||||
input_events: finalization.into_input_events(),
|
||||
}
|
||||
} else {
|
||||
AcceptorState::ConnectionFinalization {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ pub struct FinalizationSequence {
|
|||
user_channel_id: u16,
|
||||
io_channel_id: u16,
|
||||
|
||||
pub input_events: Vec<Vec<u8>>,
|
||||
input_events: Vec<Vec<u8>>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
|
|
@ -190,6 +190,10 @@ impl FinalizationSequence {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn into_input_events(self) -> Vec<Vec<u8>> {
|
||||
self.input_events
|
||||
}
|
||||
|
||||
pub fn is_done(&self) -> bool {
|
||||
self.state.is_terminal()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ impl App {
|
|||
let Some((window, _)) = self.window.as_mut() else {
|
||||
return;
|
||||
};
|
||||
#[expect(clippy::as_conversions, reason = "casting f64 to u32")]
|
||||
let scale_factor = (window.scale_factor() * 100.0) as u32;
|
||||
|
||||
let width = u16::try_from(size.width).expect("reasonable width");
|
||||
|
|
@ -222,8 +223,10 @@ impl ApplicationHandler<RdpOutputEvent> for App {
|
|||
}
|
||||
WindowEvent::CursorMoved { position, .. } => {
|
||||
let win_size = window.inner_size();
|
||||
let x = (position.x / win_size.width as f64 * self.buffer_size.0 as f64) as u16;
|
||||
let y = (position.y / win_size.height as f64 * self.buffer_size.1 as f64) as u16;
|
||||
#[expect(clippy::as_conversions, reason = "casting f64 to u16")]
|
||||
let x = (position.x / f64::from(win_size.width) * f64::from(self.buffer_size.0)) as u16;
|
||||
#[expect(clippy::as_conversions, reason = "casting f64 to u16")]
|
||||
let y = (position.y / f64::from(win_size.height) * f64::from(self.buffer_size.1)) as u16;
|
||||
let operation = ironrdp::input::Operation::MouseMove(ironrdp::input::MousePosition { x, y });
|
||||
|
||||
let input_events = self.input_database.apply(core::iter::once(operation));
|
||||
|
|
@ -239,6 +242,7 @@ impl ApplicationHandler<RdpOutputEvent> for App {
|
|||
operations.push(ironrdp::input::Operation::WheelRotations(
|
||||
ironrdp::input::WheelRotations {
|
||||
is_vertical: false,
|
||||
#[expect(clippy::as_conversions, reason = "casting f32 to i16")]
|
||||
rotation_units: (delta_x * 100.) as i16,
|
||||
},
|
||||
));
|
||||
|
|
@ -248,6 +252,7 @@ impl ApplicationHandler<RdpOutputEvent> for App {
|
|||
operations.push(ironrdp::input::Operation::WheelRotations(
|
||||
ironrdp::input::WheelRotations {
|
||||
is_vertical: true,
|
||||
#[expect(clippy::as_conversions, reason = "casting f32 to i16")]
|
||||
rotation_units: (delta_y * 100.) as i16,
|
||||
},
|
||||
));
|
||||
|
|
@ -258,6 +263,7 @@ impl ApplicationHandler<RdpOutputEvent> for App {
|
|||
operations.push(ironrdp::input::Operation::WheelRotations(
|
||||
ironrdp::input::WheelRotations {
|
||||
is_vertical: false,
|
||||
#[expect(clippy::as_conversions, reason = "casting f64 to i16")]
|
||||
rotation_units: delta.x as i16,
|
||||
},
|
||||
));
|
||||
|
|
@ -267,6 +273,7 @@ impl ApplicationHandler<RdpOutputEvent> for App {
|
|||
operations.push(ironrdp::input::Operation::WheelRotations(
|
||||
ironrdp::input::WheelRotations {
|
||||
is_vertical: true,
|
||||
#[expect(clippy::as_conversions, reason = "casting f64 to i16")]
|
||||
rotation_units: delta.y as i16,
|
||||
},
|
||||
));
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ async fn connect(
|
|||
|
||||
let upgraded = ironrdp_tokio::mark_as_upgraded(should_upgrade, &mut connector);
|
||||
|
||||
let erased_stream = Box::new(upgraded_stream) as Box<dyn AsyncReadWrite + Unpin + Send + Sync>;
|
||||
let erased_stream: Box<dyn AsyncReadWrite + Unpin + Send + Sync> = Box::new(upgraded_stream);
|
||||
let mut upgraded_framed = ironrdp_tokio::TokioFramed::new_with_leftover(erased_stream, leftover_bytes);
|
||||
|
||||
let connection_result = ironrdp_tokio::connect_finalize(
|
||||
|
|
@ -336,7 +336,7 @@ async fn connect_ws(
|
|||
.await?;
|
||||
|
||||
let (ws, leftover_bytes) = framed.into_inner();
|
||||
let erased_stream = Box::new(ws) as Box<dyn AsyncReadWrite + Unpin + Send + Sync>;
|
||||
let erased_stream: Box<dyn AsyncReadWrite + Unpin + Send + Sync> = Box::new(ws);
|
||||
let upgraded_framed = ironrdp_tokio::TokioFramed::new_with_leftover(erased_stream, leftover_bytes);
|
||||
|
||||
Ok((connection_result, upgraded_framed))
|
||||
|
|
@ -660,7 +660,7 @@ async fn active_session(
|
|||
desktop_size,
|
||||
enable_server_pointer,
|
||||
pointer_software_rendering,
|
||||
} = connection_activation.state
|
||||
} = connection_activation.connection_activation_state()
|
||||
{
|
||||
debug!(?desktop_size, "Deactivation-Reactivation Sequence completed");
|
||||
// Update image size with the new desktop size.
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ impl<'a> ClipboardDataRef<'a> {
|
|||
};
|
||||
|
||||
// SAFETY: It is safe to call `GlobalLock` on the valid handle.
|
||||
let data = unsafe { GlobalLock(handle) } as *const u8;
|
||||
let data = unsafe { GlobalLock(handle) }.cast::<u8>().cast_const();
|
||||
|
||||
if data.is_null() {
|
||||
// Can't lock data handle, handle is not valid anymore (e.g. clipboard has changed)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use core::ptr::with_exposed_provenance_mut;
|
||||
use core::time::Duration;
|
||||
use std::collections::HashSet;
|
||||
use std::sync::mpsc;
|
||||
|
|
@ -320,17 +321,19 @@ pub(crate) unsafe extern "system" fn clipboard_subproc(
|
|||
|
||||
// SAFETY: `data` is a valid pointer, returned by `Box::into_raw`, transferred to OS earlier
|
||||
// via `SetWindowSubclass` call.
|
||||
let _ = unsafe { Box::from_raw(data as *mut WinClipboardImpl) };
|
||||
let _ = unsafe { Box::from_raw(with_exposed_provenance_mut::<WinClipboardImpl>(data)) };
|
||||
return LRESULT(0);
|
||||
}
|
||||
|
||||
// SAFETY: `data` is a valid pointer, returned by `Box::into_raw`, transferred to OS earlier
|
||||
// via `SetWindowSubclass` call.
|
||||
let ctx = unsafe { &mut *(data as *mut WinClipboardImpl) };
|
||||
let ctx = unsafe { &mut *(with_exposed_provenance_mut::<WinClipboardImpl>(data)) };
|
||||
|
||||
match msg {
|
||||
// We need to keep track of window state to distinguish between local and remote copy
|
||||
WM_ACTIVATE | WM_ACTIVATEAPP => ctx.window_is_active = wparam.0 != WA_INACTIVE as usize, // `as` conversion is fine for constants
|
||||
WM_ACTIVATE | WM_ACTIVATEAPP => {
|
||||
ctx.window_is_active = wparam.0 != usize::try_from(WA_INACTIVE).expect("WA_INACTIVE fits into usize")
|
||||
}
|
||||
// Sent by the OS when OS clipboard content is changed
|
||||
WM_CLIPBOARDUPDATE => {
|
||||
// SAFETY: `GetClipboardOwner` is always safe to call.
|
||||
|
|
@ -347,8 +350,9 @@ pub(crate) unsafe extern "system" fn clipboard_subproc(
|
|||
}
|
||||
// Sent by the OS when delay-rendered data is requested for rendering.
|
||||
WM_RENDERFORMAT => {
|
||||
#[expect(clippy::cast_possible_truncation)] // should never truncate in practice
|
||||
ctx.handle_event(BackendEvent::RenderFormat(ClipboardFormatId::new(wparam.0 as u32)));
|
||||
ctx.handle_event(BackendEvent::RenderFormat(ClipboardFormatId::new(
|
||||
u32::try_from(wparam.0).expect("should never truncate in practice"),
|
||||
)));
|
||||
}
|
||||
// Sent by the OS when all delay-rendered data is requested for rendering.
|
||||
WM_RENDERALLFORMATS => {
|
||||
|
|
|
|||
|
|
@ -200,8 +200,14 @@ impl WinClipboard {
|
|||
//
|
||||
// SAFETY: `window` is a valid window handle, `clipboard_subproc` is in the static memory,
|
||||
// `ctx` is valid and its ownership is transferred to the subclass via `into_raw`.
|
||||
let winapi_result =
|
||||
unsafe { SetWindowSubclass(window, Some(clipboard_subproc), 0, Box::into_raw(ctx) as usize) };
|
||||
let winapi_result = unsafe {
|
||||
SetWindowSubclass(
|
||||
window,
|
||||
Some(clipboard_subproc),
|
||||
0,
|
||||
Box::into_raw(ctx).expose_provenance(),
|
||||
)
|
||||
};
|
||||
|
||||
if winapi_result == FALSE {
|
||||
return Err(WinCliprdrError::WindowSubclass);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ impl GlobalMemoryBuffer {
|
|||
// - `dst` is valid for writes of `data.len()` bytes, we allocated enough above.
|
||||
// - Both `data` and `dst` are properly aligned: u8 alignment is 1
|
||||
// - Memory regions are not overlapping, `dst` was allocated by us just above.
|
||||
unsafe { core::ptr::copy_nonoverlapping(data.as_ptr(), dst as *mut u8, data.len()) };
|
||||
unsafe { core::ptr::copy_nonoverlapping(data.as_ptr(), dst.cast::<u8>(), data.len()) };
|
||||
|
||||
// SAFETY: We called `GlobalLock` on this handle just above.
|
||||
if let Err(error) = unsafe { GlobalUnlock(handle) } {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
#![cfg_attr(doc, doc = include_str!("../README.md"))]
|
||||
#![doc(html_logo_url = "https://cdnweb.devolutions.net/images/projects/devolutions/logos/devolutions-icon-shadow.svg")]
|
||||
#![allow(clippy::arithmetic_side_effects)] // FIXME: remove
|
||||
#![allow(clippy::cast_lossless)] // FIXME: remove
|
||||
#![allow(clippy::cast_possible_truncation)] // FIXME: remove
|
||||
#![allow(clippy::cast_possible_wrap)] // FIXME: remove
|
||||
#![allow(clippy::cast_sign_loss)] // FIXME: remove
|
||||
|
||||
pub mod backend;
|
||||
pub mod pdu;
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ pub struct PackedMetafile<'a> {
|
|||
pub x_ext: u32,
|
||||
pub y_ext: u32,
|
||||
/// The variable sized contents of the metafile as specified in [MS-WMF] section 2
|
||||
data: Cow<'a, [u8]>,
|
||||
pub data: Cow<'a, [u8]>,
|
||||
}
|
||||
|
||||
impl PackedMetafile<'_> {
|
||||
|
|
@ -62,10 +62,6 @@ impl PackedMetafile<'_> {
|
|||
data: data.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn data(&self) -> &[u8] {
|
||||
&self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl Encode for PackedMetafile<'_> {
|
||||
|
|
|
|||
|
|
@ -553,7 +553,7 @@ impl Sequence for ClientConnector {
|
|||
mut connection_activation,
|
||||
} => {
|
||||
let written = connection_activation.step(input, output)?;
|
||||
match connection_activation.state {
|
||||
match connection_activation.connection_activation_state() {
|
||||
ConnectionActivationState::ConnectionFinalization { .. } => (
|
||||
written,
|
||||
ClientConnectorState::ConnectionFinalization { connection_activation },
|
||||
|
|
@ -570,10 +570,10 @@ impl Sequence for ClientConnector {
|
|||
} => {
|
||||
let written = connection_activation.step(input, output)?;
|
||||
|
||||
let next_state = if !connection_activation.state.is_terminal() {
|
||||
let next_state = if !connection_activation.connection_activation_state().is_terminal() {
|
||||
ClientConnectorState::ConnectionFinalization { connection_activation }
|
||||
} else {
|
||||
match connection_activation.state {
|
||||
match connection_activation.connection_activation_state() {
|
||||
ConnectionActivationState::Finalized {
|
||||
io_channel_id,
|
||||
user_channel_id,
|
||||
|
|
@ -699,9 +699,9 @@ fn create_gcc_blocks<'a>(
|
|||
desktop_physical_width: Some(0), // 0 per FreeRDP
|
||||
desktop_physical_height: Some(0), // 0 per FreeRDP
|
||||
desktop_orientation: if config.desktop_size.width > config.desktop_size.height {
|
||||
Some(MonitorOrientation::Landscape as u16)
|
||||
Some(MonitorOrientation::Landscape.as_u16())
|
||||
} else {
|
||||
Some(MonitorOrientation::Portrait as u16)
|
||||
Some(MonitorOrientation::Portrait.as_u16())
|
||||
},
|
||||
desktop_scale_factor: Some(config.desktop_scale_factor),
|
||||
device_scale_factor: if config.desktop_scale_factor >= 100 && config.desktop_scale_factor <= 500 {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ use crate::{
|
|||
/// [Server Deactivate All PDU]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/8a29971a-df3c-48da-add2-8ed9a05edc89
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ConnectionActivationSequence {
|
||||
pub state: ConnectionActivationState,
|
||||
state: ConnectionActivationState,
|
||||
config: Config,
|
||||
}
|
||||
|
||||
|
|
@ -37,6 +37,11 @@ impl ConnectionActivationSequence {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the current state as a district type, rather than `&dyn State` provided by [`Self::state`].
|
||||
pub fn connection_activation_state(&self) -> ConnectionActivationState {
|
||||
self.state
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn reset_clone(&self) -> Self {
|
||||
self.clone().reset()
|
||||
|
|
@ -215,7 +220,7 @@ impl Sequence for ConnectionActivationSequence {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
#[derive(Default, Debug, Copy, Clone)]
|
||||
pub enum ConnectionActivationState {
|
||||
#[default]
|
||||
Consumed,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use tracing::{debug, warn};
|
|||
|
||||
use crate::{general_err, legacy, reason_err, ConnectorResult, Sequence, State, Written};
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
#[derive(Default, Debug, Copy, Clone)]
|
||||
#[non_exhaustive]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
pub enum ConnectionFinalizationState {
|
||||
|
|
@ -48,7 +48,7 @@ impl State for ConnectionFinalizationState {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
pub struct ConnectionFinalizationSequence {
|
||||
pub state: ConnectionFinalizationState,
|
||||
|
|
|
|||
|
|
@ -406,7 +406,7 @@ pub trait ConnectorResultExt {
|
|||
impl<T> ConnectorResultExt for ConnectorResult<T> {
|
||||
fn with_context(self, context: &'static str) -> Self {
|
||||
self.map_err(|mut e| {
|
||||
e.context = context;
|
||||
e.set_context(context);
|
||||
e
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,8 +116,8 @@ impl SvcProcessor for DrdynvcClient {
|
|||
}
|
||||
DrdynvcServerPdu::Create(create_request) => {
|
||||
debug!("Got DVC Create Request PDU: {create_request:?}");
|
||||
let channel_name = create_request.channel_name;
|
||||
let channel_id = create_request.channel_id;
|
||||
let channel_id = create_request.channel_id();
|
||||
let channel_name = create_request.into_channel_name();
|
||||
|
||||
if !self.cap_handshake_done {
|
||||
debug!(
|
||||
|
|
@ -156,9 +156,9 @@ impl SvcProcessor for DrdynvcClient {
|
|||
}
|
||||
DrdynvcServerPdu::Close(close_request) => {
|
||||
debug!("Got DVC Close Request PDU: {close_request:?}");
|
||||
self.dynamic_channels.remove_by_channel_id(close_request.channel_id);
|
||||
self.dynamic_channels.remove_by_channel_id(close_request.channel_id());
|
||||
|
||||
let close_response = DrdynvcClientPdu::Close(ClosePdu::new(close_request.channel_id));
|
||||
let close_response = DrdynvcClientPdu::Close(ClosePdu::new(close_request.channel_id()));
|
||||
|
||||
debug!("Send DVC Close Response PDU: {close_response:?}");
|
||||
responses.push(SvcMessage::from(close_response));
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ impl CompleteData {
|
|||
}
|
||||
|
||||
fn process_data_first_pdu(&mut self, data_first: DataFirstPdu) -> DecodeResult<Option<Vec<u8>>> {
|
||||
let total_data_size: DecodeResult<_> = cast_length!("DataFirstPdu::length", data_first.length);
|
||||
let total_data_size: DecodeResult<_> = cast_length!("DataFirstPdu::length", data_first.length());
|
||||
let total_data_size = total_data_size?;
|
||||
if self.total_size != 0 || !self.data.is_empty() {
|
||||
error!("Incomplete DVC message, it will be skipped");
|
||||
|
|
@ -36,11 +36,11 @@ impl CompleteData {
|
|||
self.data.clear();
|
||||
}
|
||||
|
||||
if total_data_size == data_first.data.len() {
|
||||
Ok(Some(data_first.data))
|
||||
if total_data_size == data_first.data().len() {
|
||||
Ok(Some(data_first.into_data()))
|
||||
} else {
|
||||
self.total_size = total_data_size;
|
||||
self.data = data_first.data;
|
||||
self.data = data_first.into_data();
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
|
@ -49,22 +49,22 @@ impl CompleteData {
|
|||
fn process_data_pdu(&mut self, mut data: DataPdu) -> DecodeResult<Option<Vec<u8>>> {
|
||||
if self.total_size == 0 && self.data.is_empty() {
|
||||
// message is not fragmented
|
||||
return Ok(Some(data.data));
|
||||
return Ok(Some(data.into_data()));
|
||||
}
|
||||
|
||||
// The message is fragmented and needs to be reassembled.
|
||||
match self.data.len().checked_add(data.data.len()) {
|
||||
match self.data.len().checked_add(data.data().len()) {
|
||||
Some(actual_data_length) => {
|
||||
match actual_data_length.cmp(&(self.total_size)) {
|
||||
cmp::Ordering::Less => {
|
||||
// this is one of the fragmented messages, just append it
|
||||
self.data.append(&mut data.data);
|
||||
self.data.append(data.data_mut());
|
||||
Ok(None)
|
||||
}
|
||||
cmp::Ordering::Equal => {
|
||||
// this is the last fragmented message, need to return the whole reassembled message
|
||||
self.total_size = 0;
|
||||
self.data.append(&mut data.data);
|
||||
self.data.append(data.data_mut());
|
||||
Ok(Some(self.data.drain(..).collect()))
|
||||
}
|
||||
cmp::Ordering::Greater => {
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ impl Header {
|
|||
|
||||
fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
|
||||
ensure_fixed_part_size!(in: dst);
|
||||
dst.write_u8(((self.cmd as u8) << 4) | (Into::<u8>::into(self.sp) << 2) | Into::<u8>::into(self.cb_id));
|
||||
dst.write_u8(((self.cmd.as_u8()) << 4) | (Into::<u8>::into(self.sp) << 2) | Into::<u8>::into(self.cb_id));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -235,6 +235,16 @@ enum Cmd {
|
|||
SoftSyncResponse = 0x09,
|
||||
}
|
||||
|
||||
impl Cmd {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn as_u8(self) -> u8 {
|
||||
self as u8
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for Cmd {
|
||||
type Error = DecodeError;
|
||||
|
||||
|
|
@ -282,12 +292,12 @@ impl From<Cmd> for String {
|
|||
#[derive(Debug, PartialEq)]
|
||||
pub struct DataFirstPdu {
|
||||
header: Header,
|
||||
pub channel_id: DynamicChannelId,
|
||||
channel_id: DynamicChannelId,
|
||||
/// Length is the *total* length of the data to be sent, including the length
|
||||
/// of the data that will be sent by subsequent DVC_DATA PDUs.
|
||||
pub length: u32,
|
||||
length: u32,
|
||||
/// Data is just the data to be sent in this PDU.
|
||||
pub data: Vec<u8>,
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl DataFirstPdu {
|
||||
|
|
@ -322,6 +332,18 @@ impl DataFirstPdu {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn length(&self) -> u32 {
|
||||
self.length
|
||||
}
|
||||
|
||||
pub fn data(&self) -> &[u8] {
|
||||
&self.data
|
||||
}
|
||||
|
||||
pub fn into_data(self) -> Vec<u8> {
|
||||
self.data
|
||||
}
|
||||
|
||||
fn decode(header: Header, src: &mut ReadCursor<'_>) -> DecodeResult<Self> {
|
||||
let fixed_part_size = checked_sum(&[header.cb_id.size_of_val(), header.sp.size_of_val()])?;
|
||||
ensure_size!(in: src, size: fixed_part_size);
|
||||
|
|
@ -434,8 +456,8 @@ impl From<FieldType> for u8 {
|
|||
#[derive(Debug, PartialEq)]
|
||||
pub struct DataPdu {
|
||||
header: Header,
|
||||
pub channel_id: DynamicChannelId,
|
||||
pub data: Vec<u8>,
|
||||
channel_id: DynamicChannelId,
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl DataPdu {
|
||||
|
|
@ -447,6 +469,18 @@ impl DataPdu {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn data(&self) -> &[u8] {
|
||||
&self.data
|
||||
}
|
||||
|
||||
pub fn into_data(self) -> Vec<u8> {
|
||||
self.data
|
||||
}
|
||||
|
||||
pub fn data_mut(&mut self) -> &mut Vec<u8> {
|
||||
&mut self.data
|
||||
}
|
||||
|
||||
fn decode(header: Header, src: &mut ReadCursor<'_>) -> DecodeResult<Self> {
|
||||
ensure_size!(in: src, size: header.cb_id.size_of_val());
|
||||
let channel_id = header.cb_id.decode_val(src)?;
|
||||
|
|
@ -485,8 +519,8 @@ impl DataPdu {
|
|||
#[derive(Debug, PartialEq)]
|
||||
pub struct CreateResponsePdu {
|
||||
header: Header,
|
||||
pub channel_id: DynamicChannelId,
|
||||
pub creation_status: CreationStatus,
|
||||
channel_id: DynamicChannelId,
|
||||
creation_status: CreationStatus,
|
||||
}
|
||||
|
||||
impl CreateResponsePdu {
|
||||
|
|
@ -498,6 +532,14 @@ impl CreateResponsePdu {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn channel_id(&self) -> DynamicChannelId {
|
||||
self.channel_id
|
||||
}
|
||||
|
||||
pub fn creation_status(&self) -> CreationStatus {
|
||||
self.creation_status
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
"DYNVC_CREATE_RSP"
|
||||
}
|
||||
|
|
@ -564,7 +606,7 @@ impl From<CreationStatus> for u32 {
|
|||
#[derive(Debug, PartialEq)]
|
||||
pub struct ClosePdu {
|
||||
header: Header,
|
||||
pub channel_id: DynamicChannelId,
|
||||
channel_id: DynamicChannelId,
|
||||
}
|
||||
|
||||
impl ClosePdu {
|
||||
|
|
@ -583,6 +625,10 @@ impl ClosePdu {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn channel_id(&self) -> DynamicChannelId {
|
||||
self.channel_id
|
||||
}
|
||||
|
||||
fn decode(header: Header, src: &mut ReadCursor<'_>) -> DecodeResult<Self> {
|
||||
ensure_size!(in: src, size: Self::headerless_size(&header));
|
||||
let channel_id = header.cb_id.decode_val(src)?;
|
||||
|
|
@ -666,7 +712,7 @@ impl CapsVersion {
|
|||
|
||||
fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
|
||||
ensure_size!(in: dst, size: Self::size());
|
||||
dst.write_u16(*self as u16);
|
||||
dst.write_u16(u16::from(*self));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -689,6 +735,10 @@ impl TryFrom<u16> for CapsVersion {
|
|||
}
|
||||
|
||||
impl From<CapsVersion> for u16 {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn from(version: CapsVersion) -> Self {
|
||||
version as u16
|
||||
}
|
||||
|
|
@ -798,8 +848,8 @@ impl CapabilitiesRequestPdu {
|
|||
#[derive(Debug, PartialEq)]
|
||||
pub struct CreateRequestPdu {
|
||||
header: Header,
|
||||
pub channel_id: DynamicChannelId,
|
||||
pub channel_name: String,
|
||||
channel_id: DynamicChannelId,
|
||||
channel_name: String,
|
||||
}
|
||||
|
||||
impl CreateRequestPdu {
|
||||
|
|
@ -811,6 +861,18 @@ impl CreateRequestPdu {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn channel_id(&self) -> DynamicChannelId {
|
||||
self.channel_id
|
||||
}
|
||||
|
||||
pub fn channel_name(&self) -> &str {
|
||||
&self.channel_name
|
||||
}
|
||||
|
||||
pub fn into_channel_name(self) -> String {
|
||||
self.channel_name
|
||||
}
|
||||
|
||||
fn decode(header: Header, src: &mut ReadCursor<'_>) -> DecodeResult<Self> {
|
||||
ensure_size!(in: src, size: Self::headerless_fixed_part_size(&header));
|
||||
let channel_id = header.cb_id.decode_val(src)?;
|
||||
|
|
|
|||
|
|
@ -139,22 +139,24 @@ impl SvcProcessor for DrdynvcServer {
|
|||
}
|
||||
DrdynvcClientPdu::Create(create_resp) => {
|
||||
debug!("Got DVC Create Response PDU: {create_resp:?}");
|
||||
let id = create_resp.channel_id;
|
||||
let id = create_resp.channel_id();
|
||||
let c = self.channel_by_id(id).map_err(|e| decode_err!(e))?;
|
||||
if c.state != ChannelState::Creation {
|
||||
return Err(pdu_other_err!("invalid channel state"));
|
||||
}
|
||||
if create_resp.creation_status != CreationStatus::OK {
|
||||
c.state = ChannelState::CreationFailed(create_resp.creation_status.into());
|
||||
if create_resp.creation_status() != CreationStatus::OK {
|
||||
c.state = ChannelState::CreationFailed(create_resp.creation_status().into());
|
||||
return Ok(resp);
|
||||
}
|
||||
c.state = ChannelState::Opened;
|
||||
let msg = c.processor.start(create_resp.channel_id)?;
|
||||
let msg = c.processor.start(create_resp.channel_id())?;
|
||||
resp.extend(encode_dvc_messages(id, msg, ChannelFlags::SHOW_PROTOCOL).map_err(|e| encode_err!(e))?);
|
||||
}
|
||||
DrdynvcClientPdu::Close(close_resp) => {
|
||||
debug!("Got DVC Close Response PDU: {close_resp:?}");
|
||||
let c = self.channel_by_id(close_resp.channel_id).map_err(|e| decode_err!(e))?;
|
||||
let c = self
|
||||
.channel_by_id(close_resp.channel_id())
|
||||
.map_err(|e| decode_err!(e))?;
|
||||
if c.state != ChannelState::Opened {
|
||||
return Err(pdu_other_err!("invalid channel state"));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ impl<T> Source for T where T: fmt::Display + fmt::Debug + Send + Sync + 'static
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct Error<Kind> {
|
||||
pub context: &'static str,
|
||||
pub kind: Kind,
|
||||
context: &'static str,
|
||||
kind: Kind,
|
||||
#[cfg(feature = "std")]
|
||||
source: Option<Box<dyn core::error::Error + Sync + Send>>,
|
||||
#[cfg(all(not(feature = "std"), feature = "alloc"))]
|
||||
|
|
@ -80,6 +80,10 @@ impl<Kind> Error<Kind> {
|
|||
&self.kind
|
||||
}
|
||||
|
||||
pub fn set_context(&mut self, context: &'static str) {
|
||||
self.context = context;
|
||||
}
|
||||
|
||||
pub fn report(&self) -> ErrorReport<'_, Kind> {
|
||||
ErrorReport(self)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,8 +114,8 @@ pub fn rdp6_decode_bitmap_stream_to_rgb24(input: &BitmapInput<'_>) {
|
|||
let _ = BitmapStreamDecoder::default().decode_bitmap_stream_to_rgb24(
|
||||
input.src,
|
||||
&mut out,
|
||||
input.width as usize,
|
||||
input.height as usize,
|
||||
usize::from(input.width),
|
||||
usize::from(input.height),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ bitvec = "1.0"
|
|||
ironrdp-core = { path = "../ironrdp-core", version = "0.1" } # public
|
||||
ironrdp-pdu = { path = "../ironrdp-pdu", version = "0.6", features = ["std"] } # public
|
||||
byteorder = "1.5" # TODO: remove
|
||||
lazy_static.workspace = true # Legacy crate; prefer std::sync::LazyLock or LazyCell
|
||||
num-derive.workspace = true # TODO: remove
|
||||
num-traits.workspace = true # TODO: remove
|
||||
yuv = { version = "0.8", features = ["rdp"] }
|
||||
|
|
|
|||
|
|
@ -83,10 +83,15 @@ pub fn to_64x64_ycbcr_tile(
|
|||
/// Convert a 16-bit RDP color to RGB representation. Input value should be represented in
|
||||
/// little-endian format.
|
||||
pub fn rdp_16bit_to_rgb(color: u16) -> [u8; 3] {
|
||||
let r = (((((color >> 11) & 0x1f) * 527) + 23) >> 6) as u8;
|
||||
let g = (((((color >> 5) & 0x3f) * 259) + 33) >> 6) as u8;
|
||||
let b = ((((color & 0x1f) * 527) + 23) >> 6) as u8;
|
||||
[r, g, b]
|
||||
#[expect(clippy::missing_panics_doc, reason = "unreachable panic (checked integer underflow)")]
|
||||
let out = {
|
||||
let r = u8::try_from(((((color >> 11) & 0x1f) * 527) + 23) >> 6).expect("max possible value is 255");
|
||||
let g = u8::try_from(((((color >> 5) & 0x3f) * 259) + 33) >> 6).expect("max possible value is 255");
|
||||
let b = u8::try_from((((color & 0x1f) * 527) + 23) >> 6).expect("max possible value is 255");
|
||||
[r, g, b]
|
||||
};
|
||||
|
||||
out
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
|||
|
|
@ -22,17 +22,21 @@ fn dwt_vertical<const SUBBAND_WIDTH: usize>(buffer: &[i16], dwt: &mut [i16]) {
|
|||
let h_index = l_index + SUBBAND_WIDTH * total_width;
|
||||
let src_index = y * total_width + x;
|
||||
|
||||
dwt[h_index] = ((i32::from(buffer[src_index + total_width])
|
||||
- ((i32::from(buffer[src_index])
|
||||
+ i32::from(buffer[src_index + if n < SUBBAND_WIDTH - 1 { 2 * total_width } else { 0 }]))
|
||||
>> 1))
|
||||
>> 1) as i16;
|
||||
dwt[l_index] = (i32::from(buffer[src_index])
|
||||
+ if n == 0 {
|
||||
i32::from(dwt[h_index])
|
||||
} else {
|
||||
(i32::from(dwt[h_index - total_width]) + i32::from(dwt[h_index])) >> 1
|
||||
}) as i16;
|
||||
dwt[h_index] = i32_to_i16_possible_truncation(
|
||||
(i32::from(buffer[src_index + total_width])
|
||||
- ((i32::from(buffer[src_index])
|
||||
+ i32::from(buffer[src_index + if n < SUBBAND_WIDTH - 1 { 2 * total_width } else { 0 }]))
|
||||
>> 1))
|
||||
>> 1,
|
||||
);
|
||||
dwt[l_index] = i32_to_i16_possible_truncation(
|
||||
i32::from(buffer[src_index])
|
||||
+ if n == 0 {
|
||||
i32::from(dwt[h_index])
|
||||
} else {
|
||||
(i32::from(dwt[h_index - total_width]) + i32::from(dwt[h_index])) >> 1
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -57,16 +61,20 @@ fn dwt_horizontal<const SUBBAND_WIDTH: usize>(mut buffer: &mut [i16], dwt: &[i16
|
|||
let x = n * 2;
|
||||
|
||||
// HL
|
||||
hl[n] = ((i32::from(l_src[x + 1])
|
||||
- ((i32::from(l_src[x]) + i32::from(l_src[if n < SUBBAND_WIDTH - 1 { x + 2 } else { x }])) >> 1))
|
||||
>> 1) as i16;
|
||||
hl[n] = i32_to_i16_possible_truncation(
|
||||
(i32::from(l_src[x + 1])
|
||||
- ((i32::from(l_src[x]) + i32::from(l_src[if n < SUBBAND_WIDTH - 1 { x + 2 } else { x }])) >> 1))
|
||||
>> 1,
|
||||
);
|
||||
// LL
|
||||
ll[n] = (i32::from(l_src[x])
|
||||
+ if n == 0 {
|
||||
i32::from(hl[n])
|
||||
} else {
|
||||
(i32::from(hl[n - 1]) + i32::from(hl[n])) >> 1
|
||||
}) as i16;
|
||||
ll[n] = i32_to_i16_possible_truncation(
|
||||
i32::from(l_src[x])
|
||||
+ if n == 0 {
|
||||
i32::from(hl[n])
|
||||
} else {
|
||||
(i32::from(hl[n - 1]) + i32::from(hl[n])) >> 1
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// H
|
||||
|
|
@ -74,16 +82,20 @@ fn dwt_horizontal<const SUBBAND_WIDTH: usize>(mut buffer: &mut [i16], dwt: &[i16
|
|||
let x = n * 2;
|
||||
|
||||
// HH
|
||||
hh[n] = ((i32::from(h_src[x + 1])
|
||||
- ((i32::from(h_src[x]) + i32::from(h_src[if n < SUBBAND_WIDTH - 1 { x + 2 } else { x }])) >> 1))
|
||||
>> 1) as i16;
|
||||
hh[n] = i32_to_i16_possible_truncation(
|
||||
(i32::from(h_src[x + 1])
|
||||
- ((i32::from(h_src[x]) + i32::from(h_src[if n < SUBBAND_WIDTH - 1 { x + 2 } else { x }])) >> 1))
|
||||
>> 1,
|
||||
);
|
||||
// LH
|
||||
lh[n] = (i32::from(h_src[x])
|
||||
+ if n == 0 {
|
||||
i32::from(hh[n])
|
||||
} else {
|
||||
(i32::from(hh[n - 1]) + i32::from(hh[n])) >> 1
|
||||
}) as i16;
|
||||
lh[n] = i32_to_i16_possible_truncation(
|
||||
i32::from(h_src[x])
|
||||
+ if n == 0 {
|
||||
i32::from(hh[n])
|
||||
} else {
|
||||
(i32::from(hh[n - 1]) + i32::from(hh[n])) >> 1
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
hl = &mut hl[SUBBAND_WIDTH..];
|
||||
|
|
@ -124,24 +136,30 @@ fn inverse_horizontal(mut buffer: &[i16], temp_buffer: &mut [i16], subband_width
|
|||
|
||||
for _ in 0..subband_width {
|
||||
// Even coefficients
|
||||
l_dst[0] = (i32::from(ll[0]) - ((i32::from(hl[0]) + i32::from(hl[0]) + 1) >> 1)) as i16;
|
||||
h_dst[0] = (i32::from(lh[0]) - ((i32::from(hh[0]) + i32::from(hh[0]) + 1) >> 1)) as i16;
|
||||
l_dst[0] = i32_to_i16_possible_truncation(i32::from(ll[0]) - ((i32::from(hl[0]) + i32::from(hl[0]) + 1) >> 1));
|
||||
h_dst[0] = i32_to_i16_possible_truncation(i32::from(lh[0]) - ((i32::from(hh[0]) + i32::from(hh[0]) + 1) >> 1));
|
||||
for n in 1..subband_width {
|
||||
let x = n * 2;
|
||||
l_dst[x] = (i32::from(ll[n]) - ((i32::from(hl[n - 1]) + i32::from(hl[n]) + 1) >> 1)) as i16;
|
||||
h_dst[x] = (i32::from(lh[n]) - ((i32::from(hh[n - 1]) + i32::from(hh[n]) + 1) >> 1)) as i16;
|
||||
l_dst[x] =
|
||||
i32_to_i16_possible_truncation(i32::from(ll[n]) - ((i32::from(hl[n - 1]) + i32::from(hl[n]) + 1) >> 1));
|
||||
h_dst[x] =
|
||||
i32_to_i16_possible_truncation(i32::from(lh[n]) - ((i32::from(hh[n - 1]) + i32::from(hh[n]) + 1) >> 1));
|
||||
}
|
||||
|
||||
// Odd coefficients
|
||||
for n in 0..subband_width - 1 {
|
||||
let x = n * 2;
|
||||
l_dst[x + 1] = (i32::from(hl[n] << 1) + ((i32::from(l_dst[x]) + i32::from(l_dst[x + 2])) >> 1)) as i16;
|
||||
h_dst[x + 1] = (i32::from(hh[n] << 1) + ((i32::from(h_dst[x]) + i32::from(h_dst[x + 2])) >> 1)) as i16;
|
||||
l_dst[x + 1] = i32_to_i16_possible_truncation(
|
||||
i32::from(hl[n] << 1) + ((i32::from(l_dst[x]) + i32::from(l_dst[x + 2])) >> 1),
|
||||
);
|
||||
h_dst[x + 1] = i32_to_i16_possible_truncation(
|
||||
i32::from(hh[n] << 1) + ((i32::from(h_dst[x]) + i32::from(h_dst[x + 2])) >> 1),
|
||||
);
|
||||
}
|
||||
let n = subband_width - 1;
|
||||
let x = n * 2;
|
||||
l_dst[x + 1] = (i32::from(hl[n] << 1) + i32::from(l_dst[x])) as i16;
|
||||
h_dst[x + 1] = (i32::from(hh[n] << 1) + i32::from(h_dst[x])) as i16;
|
||||
l_dst[x + 1] = i32_to_i16_possible_truncation(i32::from(hl[n] << 1) + i32::from(l_dst[x]));
|
||||
h_dst[x + 1] = i32_to_i16_possible_truncation(i32::from(hh[n] << 1) + i32::from(h_dst[x]));
|
||||
|
||||
hl = &hl[subband_width..];
|
||||
lh = &lh[subband_width..];
|
||||
|
|
@ -157,8 +175,9 @@ fn inverse_vertical(mut buffer: &mut [i16], mut temp_buffer: &[i16], subband_wid
|
|||
let total_width = subband_width * 2;
|
||||
|
||||
for _ in 0..total_width {
|
||||
buffer[0] =
|
||||
(i32::from(temp_buffer[0]) - ((i32::from(temp_buffer[subband_width * total_width]) * 2 + 1) >> 1)) as i16;
|
||||
buffer[0] = i32_to_i16_possible_truncation(
|
||||
i32::from(temp_buffer[0]) - ((i32::from(temp_buffer[subband_width * total_width]) * 2 + 1) >> 1),
|
||||
);
|
||||
|
||||
let mut l = temp_buffer;
|
||||
let mut lh = &temp_buffer[(subband_width - 1) * total_width..];
|
||||
|
|
@ -171,18 +190,28 @@ fn inverse_vertical(mut buffer: &mut [i16], mut temp_buffer: &[i16], subband_wid
|
|||
h = &h[total_width..];
|
||||
|
||||
// Even coefficients
|
||||
dst[2 * total_width] = (i32::from(l[0]) - ((i32::from(lh[0]) + i32::from(h[0]) + 1) >> 1)) as i16;
|
||||
dst[2 * total_width] =
|
||||
i32_to_i16_possible_truncation(i32::from(l[0]) - ((i32::from(lh[0]) + i32::from(h[0]) + 1) >> 1));
|
||||
|
||||
// Odd coefficients
|
||||
dst[total_width] =
|
||||
(i32::from(lh[0] << 1) + ((i32::from(dst[0]) + i32::from(dst[2 * total_width])) >> 1)) as i16;
|
||||
dst[total_width] = i32_to_i16_possible_truncation(
|
||||
i32::from(lh[0] << 1) + ((i32::from(dst[0]) + i32::from(dst[2 * total_width])) >> 1),
|
||||
);
|
||||
|
||||
dst = &mut dst[2 * total_width..];
|
||||
}
|
||||
|
||||
dst[total_width] = (i32::from(lh[total_width] << 1) + ((i32::from(dst[0]) + i32::from(dst[0])) >> 1)) as i16;
|
||||
dst[total_width] = i32_to_i16_possible_truncation(
|
||||
i32::from(lh[total_width] << 1) + ((i32::from(dst[0]) + i32::from(dst[0])) >> 1),
|
||||
);
|
||||
|
||||
temp_buffer = &temp_buffer[1..];
|
||||
buffer = &mut buffer[1..];
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(clippy::as_conversions)]
|
||||
#[expect(clippy::cast_possible_truncation)]
|
||||
fn i32_to_i16_possible_truncation(value: i32) -> i16 {
|
||||
value as i16
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
#![cfg_attr(doc, doc = include_str!("../README.md"))]
|
||||
#![doc(html_logo_url = "https://cdnweb.devolutions.net/images/projects/devolutions/logos/devolutions-icon-shadow.svg")]
|
||||
#![allow(clippy::arithmetic_side_effects)] // FIXME: remove
|
||||
#![allow(clippy::cast_lossless)] // FIXME: remove
|
||||
#![allow(clippy::cast_possible_truncation)] // FIXME: remove
|
||||
#![allow(clippy::cast_possible_wrap)] // FIXME: remove
|
||||
#![allow(clippy::cast_sign_loss)] // FIXME: remove
|
||||
|
||||
pub mod color_conversion;
|
||||
pub mod diff;
|
||||
|
|
|
|||
|
|
@ -260,9 +260,12 @@ impl DecodedPointer {
|
|||
} else if target.should_premultiply_alpha() {
|
||||
// Calculate premultiplied alpha via integer arithmetic
|
||||
let with_premultiplied_alpha = [
|
||||
((color[0] as u16 * color[0] as u16) >> 8) as u8,
|
||||
((color[1] as u16 * color[1] as u16) >> 8) as u8,
|
||||
((color[2] as u16 * color[2] as u16) >> 8) as u8,
|
||||
u8::try_from((u16::from(color[0]) * u16::from(color[0])) >> 8)
|
||||
.expect("(u16 >> 8) fits into u8"),
|
||||
u8::try_from((u16::from(color[1]) * u16::from(color[1])) >> 8)
|
||||
.expect("(u16 >> 8) fits into u8"),
|
||||
u8::try_from((u16::from(color[2]) * u16::from(color[2])) >> 8)
|
||||
.expect("(u16 >> 8) fits into u8"),
|
||||
color[3],
|
||||
];
|
||||
bitmap_data.extend_from_slice(&with_premultiplied_alpha);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ pub fn decode(buffer: &mut [i16], quant: &Quant) {
|
|||
let (first_level, buffer) = buffer.split_at_mut(FIRST_LEVEL_SUBBANDS_COUNT * FIRST_LEVEL_SIZE);
|
||||
let (second_level, third_level) = buffer.split_at_mut(SECOND_LEVEL_SUBBANDS_COUNT * SECOND_LEVEL_SIZE);
|
||||
|
||||
let decode_chunk = |a: (&mut [i16], u8)| decode_block(a.0, a.1 as i16 - 1);
|
||||
let decode_chunk = |a: (&mut [i16], u8)| decode_block(a.0, i16::from(a.1) - 1);
|
||||
|
||||
first_level
|
||||
.chunks_mut(FIRST_LEVEL_SIZE)
|
||||
|
|
@ -49,7 +49,7 @@ pub fn encode(buffer: &mut [i16], quant: &Quant) {
|
|||
let (first_level, buffer) = buffer.split_at_mut(FIRST_LEVEL_SUBBANDS_COUNT * FIRST_LEVEL_SIZE);
|
||||
let (second_level, third_level) = buffer.split_at_mut(SECOND_LEVEL_SUBBANDS_COUNT * SECOND_LEVEL_SIZE);
|
||||
|
||||
let encode_chunk = |a: (&mut [i16], u8)| encode_block(a.0, a.1 as i16 - 1);
|
||||
let encode_chunk = |a: (&mut [i16], u8)| encode_block(a.0, i16::from(a.1) - 1);
|
||||
|
||||
first_level
|
||||
.chunks_mut(FIRST_LEVEL_SIZE)
|
||||
|
|
|
|||
|
|
@ -195,8 +195,9 @@ impl<'a> BitmapStreamDecoderImpl<'a> {
|
|||
}
|
||||
|
||||
fn write_aycocg_planes_to_rgb24(&self, params: AYCoCgParams, planes: &[u8], dst: &mut Vec<u8>) {
|
||||
#![allow(clippy::similar_names)] // It’s hard to find better names for co, cg, etc.
|
||||
let sample_shift = params.chroma_subsampling as usize;
|
||||
#![allow(clippy::similar_names, reason = "it’s hard to find better names for co, cg, etc")]
|
||||
|
||||
let sample_shift = usize::from(params.chroma_subsampling);
|
||||
|
||||
let (y_offset, co_offset, cg_offset) = (
|
||||
self.color_plane_offsets[0],
|
||||
|
|
@ -265,12 +266,13 @@ fn ycocg_with_cll_to_rgb(cll: u8, y: u8, co: u8, cg: u8) -> Rgb {
|
|||
// |R| |1 1/2 -1/2| |Y |
|
||||
// |G| = |1 0 1/2| * |Co|
|
||||
// |B| |1 -1/2 -1/2| |Cg|
|
||||
let chroma_shift = (cll - 1) as usize;
|
||||
let chroma_shift = cll - 1;
|
||||
|
||||
let clip_i16 = |v: i16| v.clamp(0, 255) as u8;
|
||||
let clip_i16 =
|
||||
|v: i16| u8::try_from(v.clamp(0, 255)).expect("fits into u8 because the value is clamped to [0..256]");
|
||||
|
||||
let co_signed = (co << chroma_shift) as i8;
|
||||
let cg_signed = (cg << chroma_shift) as i8;
|
||||
let co_signed = (co << chroma_shift).cast_signed();
|
||||
let cg_signed = (cg << chroma_shift).cast_signed();
|
||||
|
||||
let y = i16::from(y);
|
||||
let co = i16::from(co_signed);
|
||||
|
|
|
|||
|
|
@ -93,9 +93,9 @@ impl RlePlaneDecoder {
|
|||
let raw_bytes_field = (control_byte >> 4) & 0x0F;
|
||||
|
||||
let (run_length, raw_bytes_count) = match rle_bytes_field {
|
||||
1 => (16 + raw_bytes_field as usize, 0),
|
||||
2 => (32 + raw_bytes_field as usize, 0),
|
||||
rle_control => (rle_control as usize, raw_bytes_field as usize),
|
||||
1 => (16 + usize::from(raw_bytes_field), 0),
|
||||
2 => (32 + usize::from(raw_bytes_field), 0),
|
||||
rle_control => (usize::from(rle_control), usize::from(raw_bytes_field)),
|
||||
};
|
||||
|
||||
self.decoded_data_len = raw_bytes_count + run_length;
|
||||
|
|
@ -207,7 +207,8 @@ impl<I: Iterator> RleEncoderScanlineIterator<I> {
|
|||
}
|
||||
|
||||
fn delta_value(prev: u8, next: u8) -> u8 {
|
||||
let mut result = (next as i16 - prev as i16) as u8;
|
||||
let mut result = u8::try_from((i16::from(next) - i16::from(prev)) & 0xFF)
|
||||
.expect("masking with 0xFF ensures that the value fits into u8");
|
||||
|
||||
// bit magic from 3.1.9.2.1 of [MS-RDPEGDI].
|
||||
if result < 128 {
|
||||
|
|
@ -326,7 +327,10 @@ impl RlePlaneEncoder {
|
|||
raw = &raw[15..];
|
||||
}
|
||||
|
||||
let control = ((raw.len() as u8) << 4) + cmp::min(run, 15) as u8;
|
||||
let raw_len = u8::try_from(raw.len()).expect("max value is guaranteed to be 15 due to the prior while loop");
|
||||
let run_capped = u8::try_from(cmp::min(run, 15)).expect("max value is guaranteed to be 15");
|
||||
|
||||
let control = (raw_len << 4) + run_capped;
|
||||
|
||||
ensure_size!(dst: dst, size: raw.len() + 1);
|
||||
|
||||
|
|
@ -352,7 +356,8 @@ impl RlePlaneEncoder {
|
|||
while run >= 16 {
|
||||
ensure_size!(dst: dst, size: 1);
|
||||
|
||||
let current = cmp::min(run, MAX_DECODED_SEGMENT_SIZE) as u8;
|
||||
let current = u8::try_from(cmp::min(run, MAX_DECODED_SEGMENT_SIZE))
|
||||
.expect("max value is guaranteed to be MAX_DECODED_SEGMENT_SIZE (47)");
|
||||
|
||||
let c_raw_bytes = cmp::min(current / 16, 2);
|
||||
let n_run_length = current - c_raw_bytes * 16;
|
||||
|
|
@ -361,7 +366,7 @@ impl RlePlaneEncoder {
|
|||
dst.write_u8(control);
|
||||
written += 1;
|
||||
|
||||
run -= current as usize;
|
||||
run -= usize::from(current);
|
||||
}
|
||||
|
||||
if run > 0 {
|
||||
|
|
|
|||
|
|
@ -400,88 +400,86 @@ fn bands_internals_equal(first_band: &[InclusiveRectangle], second_band: &[Inclu
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use lazy_static::lazy_static;
|
||||
use std::sync::LazyLock;
|
||||
|
||||
use super::*;
|
||||
|
||||
lazy_static! {
|
||||
static ref REGION_FOR_RECTANGLES_INTERSECTION: Region = Region {
|
||||
extents: InclusiveRectangle {
|
||||
static REGION_FOR_RECTANGLES_INTERSECTION: LazyLock<Region> = LazyLock::new(|| Region {
|
||||
extents: InclusiveRectangle {
|
||||
left: 1,
|
||||
top: 1,
|
||||
right: 11,
|
||||
bottom: 9,
|
||||
},
|
||||
rectangles: vec![
|
||||
InclusiveRectangle {
|
||||
left: 1,
|
||||
top: 1,
|
||||
right: 5,
|
||||
bottom: 3,
|
||||
},
|
||||
InclusiveRectangle {
|
||||
left: 7,
|
||||
top: 1,
|
||||
right: 8,
|
||||
bottom: 3,
|
||||
},
|
||||
InclusiveRectangle {
|
||||
left: 9,
|
||||
top: 1,
|
||||
right: 11,
|
||||
bottom: 3,
|
||||
},
|
||||
InclusiveRectangle {
|
||||
left: 7,
|
||||
top: 3,
|
||||
right: 11,
|
||||
bottom: 4,
|
||||
},
|
||||
InclusiveRectangle {
|
||||
left: 3,
|
||||
top: 4,
|
||||
right: 6,
|
||||
bottom: 6,
|
||||
},
|
||||
InclusiveRectangle {
|
||||
left: 7,
|
||||
top: 4,
|
||||
right: 11,
|
||||
bottom: 6,
|
||||
},
|
||||
InclusiveRectangle {
|
||||
left: 1,
|
||||
top: 6,
|
||||
right: 3,
|
||||
bottom: 8,
|
||||
},
|
||||
InclusiveRectangle {
|
||||
left: 4,
|
||||
top: 6,
|
||||
right: 5,
|
||||
bottom: 8,
|
||||
},
|
||||
InclusiveRectangle {
|
||||
left: 6,
|
||||
top: 6,
|
||||
right: 10,
|
||||
bottom: 8,
|
||||
},
|
||||
InclusiveRectangle {
|
||||
left: 4,
|
||||
top: 8,
|
||||
right: 5,
|
||||
bottom: 9,
|
||||
},
|
||||
rectangles: vec![
|
||||
InclusiveRectangle {
|
||||
left: 1,
|
||||
top: 1,
|
||||
right: 5,
|
||||
bottom: 3,
|
||||
},
|
||||
InclusiveRectangle {
|
||||
left: 7,
|
||||
top: 1,
|
||||
right: 8,
|
||||
bottom: 3,
|
||||
},
|
||||
InclusiveRectangle {
|
||||
left: 9,
|
||||
top: 1,
|
||||
right: 11,
|
||||
bottom: 3,
|
||||
},
|
||||
InclusiveRectangle {
|
||||
left: 7,
|
||||
top: 3,
|
||||
right: 11,
|
||||
bottom: 4,
|
||||
},
|
||||
InclusiveRectangle {
|
||||
left: 3,
|
||||
top: 4,
|
||||
right: 6,
|
||||
bottom: 6,
|
||||
},
|
||||
InclusiveRectangle {
|
||||
left: 7,
|
||||
top: 4,
|
||||
right: 11,
|
||||
bottom: 6,
|
||||
},
|
||||
InclusiveRectangle {
|
||||
left: 1,
|
||||
top: 6,
|
||||
right: 3,
|
||||
bottom: 8,
|
||||
},
|
||||
InclusiveRectangle {
|
||||
left: 4,
|
||||
top: 6,
|
||||
right: 5,
|
||||
bottom: 8,
|
||||
},
|
||||
InclusiveRectangle {
|
||||
left: 6,
|
||||
top: 6,
|
||||
right: 10,
|
||||
bottom: 8,
|
||||
},
|
||||
InclusiveRectangle {
|
||||
left: 4,
|
||||
top: 8,
|
||||
right: 5,
|
||||
bottom: 9,
|
||||
},
|
||||
InclusiveRectangle {
|
||||
left: 6,
|
||||
top: 8,
|
||||
right: 10,
|
||||
bottom: 9,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
InclusiveRectangle {
|
||||
left: 6,
|
||||
top: 8,
|
||||
right: 10,
|
||||
bottom: 9,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn union_rectangle_sets_extents_and_single_rectangle_for_empty_region() {
|
||||
|
|
|
|||
|
|
@ -63,17 +63,23 @@ impl<'a> BitStream<'a> {
|
|||
}
|
||||
|
||||
pub fn encode(mode: EntropyAlgorithm, input: &[i16], tile: &mut [u8]) -> Result<usize, RlgrError> {
|
||||
let mut k: u32 = 1;
|
||||
let kr: u32 = 1;
|
||||
let mut kp: u32 = k << LS_GR;
|
||||
let mut krp: u32 = kr << LS_GR;
|
||||
#![expect(
|
||||
clippy::as_conversions,
|
||||
reason = "u32-to-usize and usize-to-u32 conversions, mostly fine, and hot loop"
|
||||
)]
|
||||
|
||||
if input.is_empty() {
|
||||
return Err(RlgrError::EmptyTile);
|
||||
}
|
||||
|
||||
let mut k: u32 = 1;
|
||||
let kr: u32 = 1;
|
||||
let mut kp: u32 = k << LS_GR;
|
||||
let mut krp: u32 = kr << LS_GR;
|
||||
let mut bits = BitStream::new(tile);
|
||||
|
||||
let mut input = input.iter().peekable();
|
||||
|
||||
while input.peek().is_some() {
|
||||
match CompressionMode::from(k) {
|
||||
CompressionMode::RunLength => {
|
||||
|
|
@ -98,7 +104,7 @@ pub fn encode(mode: EntropyAlgorithm, input: &[i16], tile: &mut [u8]) -> Result<
|
|||
bits.output_bits(k as usize, nz);
|
||||
|
||||
if let Some(val) = input.next() {
|
||||
let mag = val.unsigned_abs() as u32;
|
||||
let mag = u32::from(val.unsigned_abs());
|
||||
bits.output_bit(1, *val < 0);
|
||||
code_gr(&mut bits, &mut krp, mag - 1);
|
||||
}
|
||||
|
|
@ -152,37 +158,53 @@ pub fn encode(mode: EntropyAlgorithm, input: &[i16], tile: &mut [u8]) -> Result<
|
|||
fn get_2magsign(val: i16) -> u32 {
|
||||
let sign = if val < 0 { 1 } else { 0 };
|
||||
|
||||
(val.unsigned_abs() as u32) * 2 - sign
|
||||
(u32::from(val.unsigned_abs())) * 2 - sign
|
||||
}
|
||||
|
||||
fn code_gr(bits: &mut BitStream<'_>, krp: &mut u32, val: u32) {
|
||||
let kr = (*krp >> LS_GR) as usize;
|
||||
let vk = (val >> kr) as usize;
|
||||
#![expect(
|
||||
clippy::as_conversions,
|
||||
reason = "u32-to-usize and usize-to-u32 conversions, mostly fine, and hot loop"
|
||||
)]
|
||||
|
||||
bits.output_bit(vk, true);
|
||||
let kr = (*krp >> LS_GR) as usize;
|
||||
|
||||
let vk = val >> kr;
|
||||
let vk_usize = vk as usize;
|
||||
|
||||
bits.output_bit(vk_usize, true);
|
||||
bits.output_bit(1, false);
|
||||
|
||||
if kr != 0 {
|
||||
let remainder = val & ((1 << kr) - 1);
|
||||
bits.output_bits(kr, remainder);
|
||||
}
|
||||
|
||||
if vk == 0 {
|
||||
*krp = krp.saturating_sub(2);
|
||||
} else if vk > 1 {
|
||||
*krp = min(*krp + vk as u32, KP_MAX);
|
||||
*krp = min(*krp + vk, KP_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode(mode: EntropyAlgorithm, tile: &[u8], mut output: &mut [i16]) -> Result<(), RlgrError> {
|
||||
let mut k: u32 = 1;
|
||||
let mut kr: u32 = 1;
|
||||
let mut kp: u32 = k << LS_GR;
|
||||
let mut krp: u32 = kr << LS_GR;
|
||||
#![expect(
|
||||
clippy::as_conversions,
|
||||
clippy::cast_possible_truncation,
|
||||
reason = "u32-to-usize and usize-to-u32 conversions, mostly fine, and hot loop"
|
||||
)]
|
||||
|
||||
if tile.is_empty() {
|
||||
return Err(RlgrError::EmptyTile);
|
||||
}
|
||||
|
||||
let mut k: u32 = 1;
|
||||
let mut kr: u32 = 1;
|
||||
let mut kp: u32 = k << LS_GR;
|
||||
let mut krp: u32 = kr << LS_GR;
|
||||
|
||||
let mut bits = Bits::new(BitSlice::from_slice(tile));
|
||||
|
||||
while !bits.is_empty() && !output.is_empty() {
|
||||
match CompressionMode::from(k) {
|
||||
CompressionMode::RunLength => {
|
||||
|
|
@ -201,7 +223,7 @@ pub fn decode(mode: EntropyAlgorithm, tile: &[u8], mut output: &mut [i16]) -> Re
|
|||
kp = kp.saturating_sub(DN_GR);
|
||||
k = kp >> LS_GR;
|
||||
|
||||
let magnitude = compute_rl_magnitude(sign_bit, code_remainder);
|
||||
let magnitude = compute_rl_magnitude(sign_bit, code_remainder)?;
|
||||
|
||||
let size = min(run as usize, output.len());
|
||||
fill(&mut output[..size], 0);
|
||||
|
|
@ -218,7 +240,7 @@ pub fn decode(mode: EntropyAlgorithm, tile: &[u8], mut output: &mut [i16]) -> Re
|
|||
|
||||
match mode {
|
||||
EntropyAlgorithm::Rlgr1 => {
|
||||
let magnitude = compute_rlgr1_magnitude(code_remainder, &mut k, &mut kp);
|
||||
let magnitude = compute_rlgr1_magnitude(code_remainder, &mut k, &mut kp)?;
|
||||
write_byte!(output, magnitude);
|
||||
}
|
||||
EntropyAlgorithm::Rlgr3 => {
|
||||
|
|
@ -234,10 +256,10 @@ pub fn decode(mode: EntropyAlgorithm, tile: &[u8], mut output: &mut [i16]) -> Re
|
|||
k = kp >> LS_GR;
|
||||
}
|
||||
|
||||
let magnitude = compute_rlgr3_magnitude(val1);
|
||||
let magnitude = compute_rlgr3_magnitude(val1)?;
|
||||
write_byte!(output, magnitude);
|
||||
|
||||
let magnitude = compute_rlgr3_magnitude(val2);
|
||||
let magnitude = compute_rlgr3_magnitude(val2)?;
|
||||
write_byte!(output, magnitude);
|
||||
}
|
||||
}
|
||||
|
|
@ -245,7 +267,7 @@ pub fn decode(mode: EntropyAlgorithm, tile: &[u8], mut output: &mut [i16]) -> Re
|
|||
}
|
||||
}
|
||||
|
||||
// fill remaining buffer with zeros
|
||||
// Fill remaining buffer with zeros.
|
||||
fill(output, 0);
|
||||
|
||||
Ok(())
|
||||
|
|
@ -288,37 +310,41 @@ fn count_run(number_of_zeros: usize, k: &mut u32, kp: &mut u32) -> u32 {
|
|||
.sum()
|
||||
}
|
||||
|
||||
fn compute_rl_magnitude(sign_bit: u8, code_remainder: u32) -> i16 {
|
||||
fn compute_rl_magnitude(sign_bit: u8, code_remainder: u32) -> Result<i16, RlgrError> {
|
||||
let rl_magnitude =
|
||||
i16::try_from(code_remainder + 1).map_err(|_| RlgrError::InvalidIntegralConversion("code remainder + 1"))?;
|
||||
|
||||
if sign_bit != 0 {
|
||||
-((code_remainder + 1) as i16)
|
||||
Ok(-rl_magnitude)
|
||||
} else {
|
||||
(code_remainder + 1) as i16
|
||||
Ok(rl_magnitude)
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_rlgr1_magnitude(code_remainder: u32, k: &mut u32, kp: &mut u32) -> i16 {
|
||||
fn compute_rlgr1_magnitude(code_remainder: u32, k: &mut u32, kp: &mut u32) -> Result<i16, RlgrError> {
|
||||
if code_remainder == 0 {
|
||||
*kp = min(*kp + UQ_GR, KP_MAX);
|
||||
*k = *kp >> LS_GR;
|
||||
|
||||
0
|
||||
Ok(0)
|
||||
} else {
|
||||
*kp = kp.saturating_sub(DQ_GR);
|
||||
*k = *kp >> LS_GR;
|
||||
|
||||
if code_remainder % 2 != 0 {
|
||||
-(((code_remainder + 1) >> 1) as i16)
|
||||
Ok(-i16::try_from((code_remainder + 1) >> 1)
|
||||
.map_err(|_| RlgrError::InvalidIntegralConversion("(code remainder + 1) >> 1"))?)
|
||||
} else {
|
||||
(code_remainder >> 1) as i16
|
||||
i16::try_from(code_remainder >> 1).map_err(|_| RlgrError::InvalidIntegralConversion("code remainder >> 1"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_rlgr3_magnitude(val: u32) -> i16 {
|
||||
fn compute_rlgr3_magnitude(val: u32) -> Result<i16, RlgrError> {
|
||||
if val % 2 != 0 {
|
||||
-(((val + 1) >> 1) as i16)
|
||||
Ok(-i16::try_from((val + 1) >> 1).map_err(|_| RlgrError::InvalidIntegralConversion("(val + 1) >> 1"))?)
|
||||
} else {
|
||||
(val >> 1) as i16
|
||||
i16::try_from(val >> 1).map_err(|_| RlgrError::InvalidIntegralConversion("val >> 1"))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -335,11 +361,17 @@ fn compute_n_index(code_remainder: u32) -> usize {
|
|||
}
|
||||
|
||||
fn update_parameters_according_to_number_of_ones(number_of_ones: usize, kr: &mut u32, krp: &mut u32) {
|
||||
#![expect(
|
||||
clippy::as_conversions,
|
||||
clippy::cast_possible_truncation,
|
||||
reason = "usize-to-u32 conversions, hot loop"
|
||||
)]
|
||||
|
||||
if number_of_ones == 0 {
|
||||
*krp = (*krp).saturating_sub(2);
|
||||
*kr = *krp >> LS_GR;
|
||||
} else if number_of_ones > 1 {
|
||||
*krp = min(*krp + number_of_ones as u32, KP_MAX);
|
||||
*krp = min(*krp + (number_of_ones as u32), KP_MAX);
|
||||
*kr = *krp >> LS_GR;
|
||||
}
|
||||
}
|
||||
|
|
@ -365,6 +397,7 @@ pub enum RlgrError {
|
|||
Io(io::Error),
|
||||
Yuv(YuvError),
|
||||
EmptyTile,
|
||||
InvalidIntegralConversion(&'static str),
|
||||
}
|
||||
|
||||
impl core::fmt::Display for RlgrError {
|
||||
|
|
@ -373,6 +406,7 @@ impl core::fmt::Display for RlgrError {
|
|||
Self::Io(_) => write!(f, "IO error"),
|
||||
Self::Yuv(_) => write!(f, "YUV error"),
|
||||
Self::EmptyTile => write!(f, "the input tile is empty"),
|
||||
Self::InvalidIntegralConversion(s) => write!(f, "invalid `{s}`: out of range integral type conversion"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -383,6 +417,7 @@ impl core::error::Error for RlgrError {
|
|||
Self::Io(error) => Some(error),
|
||||
Self::Yuv(error) => Some(error),
|
||||
Self::EmptyTile => None,
|
||||
Self::InvalidIntegralConversion(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,12 +23,14 @@ impl<'a> SegmentedDataPdu<'a> {
|
|||
match descriptor {
|
||||
SegmentedDescriptor::Single => Ok(SegmentedDataPdu::Single(BulkEncodedData::from_buffer(buffer)?)),
|
||||
SegmentedDescriptor::Multipart => {
|
||||
let segment_count = buffer.read_u16::<LittleEndian>()? as usize;
|
||||
let uncompressed_size = buffer.read_u32::<LittleEndian>()? as usize;
|
||||
let segment_count = usize::from(buffer.read_u16::<LittleEndian>()?);
|
||||
let uncompressed_size = usize::try_from(buffer.read_u32::<LittleEndian>()?)
|
||||
.map_err(|_| ZgfxError::InvalidIntegralConversion("segments uncompressed size"))?;
|
||||
|
||||
let mut segments = Vec::with_capacity(segment_count);
|
||||
for _ in 0..segment_count {
|
||||
let size = buffer.read_u32::<LittleEndian>()? as usize;
|
||||
let size = usize::try_from(buffer.read_u32::<LittleEndian>()?)
|
||||
.map_err(|_| ZgfxError::InvalidIntegralConversion("segment data size"))?;
|
||||
let (segment_data, new_buffer) = buffer.split_at(size);
|
||||
buffer = new_buffer;
|
||||
|
||||
|
|
@ -84,7 +86,7 @@ bitflags! {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use lazy_static::lazy_static;
|
||||
use std::sync::LazyLock;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
@ -111,29 +113,30 @@ mod test {
|
|||
0x02, // the third segment: data
|
||||
];
|
||||
|
||||
lazy_static! {
|
||||
static ref SINGLE_SEGMENTED_DATA_PDU: SegmentedDataPdu<'static> = SegmentedDataPdu::Single(BulkEncodedData {
|
||||
static SINGLE_SEGMENTED_DATA_PDU: LazyLock<SegmentedDataPdu<'static>> = LazyLock::new(|| {
|
||||
SegmentedDataPdu::Single(BulkEncodedData {
|
||||
compression_flags: CompressionFlags::COMPRESSED,
|
||||
data: &SINGLE_SEGMENTED_DATA_PDU_BUFFER[2..],
|
||||
});
|
||||
static ref MULTIPART_SEGMENTED_DATA_PDU: SegmentedDataPdu<'static> = SegmentedDataPdu::Multipart {
|
||||
})
|
||||
});
|
||||
static MULTIPART_SEGMENTED_DATA_PDU: LazyLock<SegmentedDataPdu<'static>> =
|
||||
LazyLock::new(|| SegmentedDataPdu::Multipart {
|
||||
uncompressed_size: 0x2B,
|
||||
segments: vec![
|
||||
BulkEncodedData {
|
||||
compression_flags: CompressionFlags::empty(),
|
||||
data: &MULTIPART_SEGMENTED_DATA_PDU_BUFFER[12..12 + 16]
|
||||
data: &MULTIPART_SEGMENTED_DATA_PDU_BUFFER[12..12 + 16],
|
||||
},
|
||||
BulkEncodedData {
|
||||
compression_flags: CompressionFlags::empty(),
|
||||
data: &MULTIPART_SEGMENTED_DATA_PDU_BUFFER[33..33 + 13]
|
||||
data: &MULTIPART_SEGMENTED_DATA_PDU_BUFFER[33..33 + 13],
|
||||
},
|
||||
BulkEncodedData {
|
||||
compression_flags: CompressionFlags::COMPRESSED,
|
||||
data: &MULTIPART_SEGMENTED_DATA_PDU_BUFFER[51..]
|
||||
data: &MULTIPART_SEGMENTED_DATA_PDU_BUFFER[51..],
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn from_buffer_correctly_parses_zgfx_single_segmented_data_pdu() {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ mod circular_buffer;
|
|||
mod control_messages;
|
||||
|
||||
use std::io::{self, Write as _};
|
||||
use std::sync::LazyLock;
|
||||
|
||||
use bitvec::bits;
|
||||
use bitvec::field::BitField as _;
|
||||
|
|
@ -78,8 +79,8 @@ impl Decompressor {
|
|||
let mut bits = BitSlice::from_slice(encoded_data);
|
||||
|
||||
// The value of the last byte indicates the number of unused bits in the final byte
|
||||
bits =
|
||||
&bits[..8 * (encoded_data.len() - 1) - *encoded_data.last().expect("encoded_data is not empty") as usize];
|
||||
bits = &bits
|
||||
[..8 * (encoded_data.len() - 1) - usize::from(*encoded_data.last().expect("encoded_data is not empty"))];
|
||||
let mut bits = Bits::new(bits);
|
||||
let mut bytes_written = 0;
|
||||
|
||||
|
|
@ -134,14 +135,15 @@ fn handle_match(
|
|||
distance_base: u32,
|
||||
history: &mut FixedCircularBuffer,
|
||||
output: &mut Vec<u8>,
|
||||
) -> io::Result<usize> {
|
||||
) -> Result<usize, ZgfxError> {
|
||||
// Each token has been assigned a different base distance
|
||||
// and number of additional value bits to be added to compute the full distance.
|
||||
|
||||
let distance = (distance_base + bits.split_to(distance_value_size).load_be::<u32>()) as usize;
|
||||
let distance = usize::try_from(distance_base + bits.split_to(distance_value_size).load_be::<u32>())
|
||||
.map_err(|_| ZgfxError::InvalidIntegralConversion("token's full distance"))?;
|
||||
|
||||
if distance == 0 {
|
||||
read_unencoded_bytes(bits, history, output)
|
||||
read_unencoded_bytes(bits, history, output).map_err(ZgfxError::from)
|
||||
} else {
|
||||
read_encoded_bytes(bits, distance, history, output)
|
||||
}
|
||||
|
|
@ -155,7 +157,7 @@ fn read_unencoded_bytes(
|
|||
// A match distance of zero is a special case,
|
||||
// which indicates that an unencoded run of bytes follows.
|
||||
// The count of bytes is encoded as a 15-bit value
|
||||
let length = bits.split_to(15).load_be::<u32>() as usize;
|
||||
let length = bits.split_to(15).load_be::<usize>();
|
||||
|
||||
if bits.remaining_bits_of_last_byte() > 0 {
|
||||
let pad_to_byte_boundary = 8 - bits.remaining_bits_of_last_byte();
|
||||
|
|
@ -178,7 +180,7 @@ fn read_encoded_bytes(
|
|||
distance: usize,
|
||||
history: &mut FixedCircularBuffer,
|
||||
output: &mut Vec<u8>,
|
||||
) -> io::Result<usize> {
|
||||
) -> Result<usize, ZgfxError> {
|
||||
// A match length prefix follows the token and indicates
|
||||
// how many additional bits will be needed to get the full length
|
||||
// (the number of bytes to be copied).
|
||||
|
|
@ -191,9 +193,12 @@ fn read_encoded_bytes(
|
|||
|
||||
3
|
||||
} else {
|
||||
let length = bits.split_to(length_token_size + 1).load_be::<u32>() as usize;
|
||||
let length = bits.split_to(length_token_size + 1).load_be::<usize>();
|
||||
|
||||
let base = 2u32.pow(length_token_size as u32 + 1) as usize;
|
||||
let length_token_size = u32::try_from(length_token_size)
|
||||
.map_err(|_| ZgfxError::InvalidIntegralConversion("length of the token size"))?;
|
||||
|
||||
let base = 2usize.pow(length_token_size + 1);
|
||||
|
||||
base + length
|
||||
};
|
||||
|
|
@ -223,8 +228,8 @@ enum TokenType {
|
|||
},
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref TOKEN_TABLE: [Token; 40] = [
|
||||
static TOKEN_TABLE: LazyLock<[Token; 40]> = LazyLock::new(|| {
|
||||
[
|
||||
Token {
|
||||
prefix: bits![static u8, Msb0; 0],
|
||||
ty: TokenType::NullLiteral,
|
||||
|
|
@ -427,8 +432,8 @@ lazy_static::lazy_static! {
|
|||
distance_base: 17_094_304,
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ZgfxError {
|
||||
|
|
@ -440,6 +445,7 @@ pub enum ZgfxError {
|
|||
uncompressed_size: usize,
|
||||
},
|
||||
TokenBitsNotFound,
|
||||
InvalidIntegralConversion(&'static str),
|
||||
}
|
||||
|
||||
impl core::fmt::Display for ZgfxError {
|
||||
|
|
@ -456,6 +462,7 @@ impl core::fmt::Display for ZgfxError {
|
|||
"decompressed size of segments ({decompressed_size}) does not equal to uncompressed size ({uncompressed_size})",
|
||||
),
|
||||
Self::TokenBitsNotFound => write!(f, "token bits not found"),
|
||||
Self::InvalidIntegralConversion(type_name) => write!(f, "invalid `{type_name}`: out of range integral type conversion"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -468,6 +475,7 @@ impl core::error::Error for ZgfxError {
|
|||
Self::InvalidSegmentedDescriptor => None,
|
||||
Self::InvalidDecompressedSize { .. } => None,
|
||||
Self::TokenBitsNotFound => None,
|
||||
Self::InvalidIntegralConversion(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,10 @@ pub enum MouseButton {
|
|||
}
|
||||
|
||||
impl MouseButton {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
pub fn as_idx(self) -> usize {
|
||||
self as usize
|
||||
}
|
||||
|
|
@ -78,7 +82,11 @@ impl Scancode {
|
|||
pub const fn from_u16(scancode: u16) -> Self {
|
||||
let extended = scancode & 0xE000 == 0xE000;
|
||||
|
||||
#[expect(clippy::cast_possible_truncation)] // truncating on purpose
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
clippy::cast_possible_truncation,
|
||||
reason = "truncating on purpose"
|
||||
)]
|
||||
let code = scancode as u8;
|
||||
|
||||
Self { code, extended }
|
||||
|
|
|
|||
|
|
@ -221,7 +221,8 @@ impl GwClient {
|
|||
let mut cur = ReadCursor::new(&msg);
|
||||
let hdr = PktHdr::decode(&mut cur).map_err(|e| custom_err!("Header Decode", e))?;
|
||||
|
||||
assert!(cur.len() >= hdr.length as usize - hdr.size());
|
||||
let header_length = usize::try_from(hdr.length).map_err(|_| Error::new("PktHdr too big", GwErrorKind::Decode))?;
|
||||
assert!(cur.len() >= header_length - hdr.size());
|
||||
match hdr.ty {
|
||||
PktTy::Keepalive => {
|
||||
continue;
|
||||
|
|
@ -287,7 +288,10 @@ impl GwConn {
|
|||
let mut cur = ReadCursor::new(&msg);
|
||||
|
||||
let hdr = PktHdr::decode(&mut cur).map_err(|_| Error::new("PktHdr", GwErrorKind::Decode))?;
|
||||
if cur.len() != hdr.length as usize - hdr.size() {
|
||||
|
||||
let header_length =
|
||||
usize::try_from(hdr.length).map_err(|_| Error::new("PktHdr too big", GwErrorKind::Decode))?;
|
||||
if cur.len() != header_length - hdr.size() {
|
||||
return Err(Error::new("read_packet", GwErrorKind::PacketEof));
|
||||
}
|
||||
|
||||
|
|
@ -315,7 +319,7 @@ impl GwConn {
|
|||
async fn tunnel(&mut self) -> Result<(), Error> {
|
||||
let req = TunnelReqPkt {
|
||||
// Havent seen any server working without this.
|
||||
caps: HttpCapsTy::MessagingConsentSign as u32,
|
||||
caps: HttpCapsTy::MessagingConsentSign.as_u32(),
|
||||
fields_present: 0,
|
||||
..TunnelReqPkt::default()
|
||||
};
|
||||
|
|
@ -350,7 +354,7 @@ impl GwConn {
|
|||
let resp: TunnelAuthRespPkt =
|
||||
TunnelAuthRespPkt::decode(&mut cur).map_err(|_| Error::new("TunnelAuth", GwErrorKind::Decode))?;
|
||||
|
||||
if resp.error_code != 0 {
|
||||
if resp.error_code() != 0 {
|
||||
return Err(Error::new("TunnelAuth", GwErrorKind::Connect));
|
||||
}
|
||||
Ok(())
|
||||
|
|
@ -369,7 +373,7 @@ impl GwConn {
|
|||
let mut cur: ReadCursor<'_> = ReadCursor::new(&bytes);
|
||||
let resp: ChannelResp =
|
||||
ChannelResp::decode(&mut cur).map_err(|_| Error::new("ChannelResp", GwErrorKind::Decode))?;
|
||||
if resp.error_code != 0 {
|
||||
if resp.error_code() != 0 {
|
||||
return Err(Error::new("ChannelCreate", GwErrorKind::Connect));
|
||||
}
|
||||
assert!(cur.eof());
|
||||
|
|
|
|||
|
|
@ -37,6 +37,16 @@ pub(crate) enum PktTy {
|
|||
Keepalive = 0x0D,
|
||||
}
|
||||
|
||||
impl PktTy {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn as_u16(self) -> u16 {
|
||||
self as u16
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u16> for PktTy {
|
||||
type Error = ();
|
||||
|
||||
|
|
@ -66,7 +76,7 @@ impl TryFrom<u16> for PktTy {
|
|||
#[derive(Default, Debug)]
|
||||
pub(crate) struct PktHdr {
|
||||
pub ty: PktTy,
|
||||
_reserved: u16,
|
||||
pub _reserved: u16,
|
||||
pub length: u32,
|
||||
}
|
||||
|
||||
|
|
@ -78,7 +88,7 @@ impl Encode for PktHdr {
|
|||
fn encode(&self, dst: &mut WriteCursor<'_>) -> ironrdp_core::EncodeResult<()> {
|
||||
ensure_size!(in: dst, size: self.size());
|
||||
|
||||
dst.write_u16(self.ty as u16);
|
||||
dst.write_u16(self.ty.as_u16());
|
||||
dst.write_u16(self._reserved);
|
||||
dst.write_u32(self.length);
|
||||
|
||||
|
|
@ -183,7 +193,7 @@ impl Decode<'_> for HandshakeRespPkt {
|
|||
pub(crate) struct TunnelReqPkt {
|
||||
pub caps: u32,
|
||||
pub fields_present: u16,
|
||||
pub(crate) _reserved: u16,
|
||||
pub _reserved: u16,
|
||||
}
|
||||
|
||||
impl Encode for TunnelReqPkt {
|
||||
|
|
@ -215,6 +225,7 @@ impl Encode for TunnelReqPkt {
|
|||
/// 2.2.5.3.9 HTTP_CAPABILITY_TYPE Enumeration
|
||||
#[repr(u32)]
|
||||
#[expect(dead_code)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub(crate) enum HttpCapsTy {
|
||||
QuarSOH = 1,
|
||||
IdleTimeout = 2,
|
||||
|
|
@ -224,8 +235,19 @@ pub(crate) enum HttpCapsTy {
|
|||
UdpTransport = 0x20,
|
||||
}
|
||||
|
||||
impl HttpCapsTy {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
pub(crate) fn as_u32(self) -> u32 {
|
||||
self as u32
|
||||
}
|
||||
}
|
||||
|
||||
/// 2.2.5.3.8 HTTP_TUNNEL_RESPONSE_FIELDS_PRESENT_FLAGS
|
||||
#[repr(u16)]
|
||||
#[derive(Copy, Clone)]
|
||||
enum HttpTunnelResponseFields {
|
||||
TunnelID = 1,
|
||||
Caps = 2,
|
||||
|
|
@ -234,6 +256,16 @@ enum HttpTunnelResponseFields {
|
|||
Consent = 0x10,
|
||||
}
|
||||
|
||||
impl HttpTunnelResponseFields {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn as_u16(self) -> u16 {
|
||||
self as u16
|
||||
}
|
||||
}
|
||||
|
||||
/// 2.2.10.20 HTTP_TUNNEL_RESPONSE Structure
|
||||
#[derive(Debug, Default)]
|
||||
pub(crate) struct TunnelRespPkt {
|
||||
|
|
@ -266,26 +298,26 @@ impl Decode<'_> for TunnelRespPkt {
|
|||
..TunnelRespPkt::default()
|
||||
};
|
||||
|
||||
if pkt.fields_present & (HttpTunnelResponseFields::TunnelID as u16) != 0 {
|
||||
if pkt.fields_present & (HttpTunnelResponseFields::TunnelID.as_u16()) != 0 {
|
||||
ensure_size!(in: src, size: 4);
|
||||
pkt.tunnel_id = Some(src.read_u32());
|
||||
}
|
||||
if pkt.fields_present & (HttpTunnelResponseFields::Caps as u16) != 0 {
|
||||
if pkt.fields_present & (HttpTunnelResponseFields::Caps.as_u16()) != 0 {
|
||||
ensure_size!(in: src, size: 4);
|
||||
pkt.caps_flags = Some(src.read_u32());
|
||||
}
|
||||
if pkt.fields_present & (HttpTunnelResponseFields::Soh as u16) != 0 {
|
||||
if pkt.fields_present & (HttpTunnelResponseFields::Soh.as_u16()) != 0 {
|
||||
ensure_size!(in: src, size: 2 + 2);
|
||||
pkt.nonce = Some(src.read_u16());
|
||||
let len = src.read_u16();
|
||||
ensure_size!(in: src, size: len as usize);
|
||||
pkt.server_cert = src.read_slice(len as usize).to_vec();
|
||||
let len = usize::from(src.read_u16());
|
||||
ensure_size!(in: src, size: len);
|
||||
pkt.server_cert = src.read_slice(len).to_vec();
|
||||
}
|
||||
if pkt.fields_present & (HttpTunnelResponseFields::Consent as u16) != 0 {
|
||||
if pkt.fields_present & (HttpTunnelResponseFields::Consent.as_u16()) != 0 {
|
||||
ensure_size!(in: src, size: 2);
|
||||
let len = src.read_u16();
|
||||
ensure_size!(in: src, size: len as usize);
|
||||
pkt.consent_msg = src.read_slice(len as usize).to_vec();
|
||||
let len = usize::from(src.read_u16());
|
||||
ensure_size!(in: src, size: len);
|
||||
pkt.consent_msg = src.read_slice(len).to_vec();
|
||||
}
|
||||
|
||||
Ok(pkt)
|
||||
|
|
@ -330,12 +362,12 @@ impl Decode<'_> for ExtendedAuthPkt {
|
|||
fn decode(src: &mut ReadCursor<'_>) -> ironrdp_core::DecodeResult<Self> {
|
||||
ensure_size!(in: src, size: 4 + 2);
|
||||
let error_code = src.read_u32();
|
||||
let len = src.read_u16();
|
||||
ensure_size!(in: src, size: len as usize);
|
||||
let len = usize::from(src.read_u16());
|
||||
ensure_size!(in: src, size: len);
|
||||
|
||||
Ok(ExtendedAuthPkt {
|
||||
error_code,
|
||||
blob: src.read_slice(len as usize).to_vec(),
|
||||
blob: src.read_slice(len).to_vec(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -384,13 +416,17 @@ impl Encode for TunnelAuthPkt {
|
|||
/// 2.2.10.16 HTTP_TUNNEL_AUTH_RESPONSE Structure
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct TunnelAuthRespPkt {
|
||||
pub error_code: u32,
|
||||
error_code: u32,
|
||||
_fields_present: u16,
|
||||
_reserved: u16,
|
||||
}
|
||||
|
||||
impl TunnelAuthRespPkt {
|
||||
const FIXED_PART_SIZE: usize = 4 /* error_code */ + 2 /* fields_present */ + 2 /* _reserved */;
|
||||
|
||||
pub(crate) fn error_code(&self) -> u32 {
|
||||
self.error_code
|
||||
}
|
||||
}
|
||||
|
||||
impl Decode<'_> for TunnelAuthRespPkt {
|
||||
|
|
@ -455,7 +491,7 @@ impl Encode for ChannelPkt {
|
|||
/// 2.2.10.4 HTTP_CHANNEL_RESPONSE
|
||||
#[derive(Default, Debug)]
|
||||
pub(crate) struct ChannelResp {
|
||||
pub error_code: u32,
|
||||
error_code: u32,
|
||||
fields_present: u16,
|
||||
_reserved: u16,
|
||||
|
||||
|
|
@ -467,6 +503,10 @@ pub(crate) struct ChannelResp {
|
|||
|
||||
impl ChannelResp {
|
||||
const FIXED_PART_SIZE: usize = 4 /* error_code */ + 2 /* fields_present */ + 2 /* _reserved */;
|
||||
|
||||
pub(crate) fn error_code(&self) -> u32 {
|
||||
self.error_code
|
||||
}
|
||||
}
|
||||
|
||||
impl Decode<'_> for ChannelResp {
|
||||
|
|
@ -489,9 +529,9 @@ impl Decode<'_> for ChannelResp {
|
|||
}
|
||||
if resp.fields_present & 4 != 0 {
|
||||
ensure_size!(in: src, size: 2);
|
||||
let len = src.read_u16();
|
||||
ensure_size!(in: src, size: len as usize);
|
||||
resp.authn_cookie = src.read_slice(len as usize).to_vec();
|
||||
let len = usize::from(src.read_u16());
|
||||
ensure_size!(in: src, size: len);
|
||||
resp.authn_cookie = src.read_slice(len).to_vec();
|
||||
}
|
||||
Ok(resp)
|
||||
}
|
||||
|
|
@ -530,10 +570,10 @@ impl Encode for DataPkt<'_> {
|
|||
impl<'a> Decode<'a> for DataPkt<'a> {
|
||||
fn decode(src: &mut ReadCursor<'a>) -> ironrdp_core::DecodeResult<Self> {
|
||||
ensure_size!(in: src, size: 2);
|
||||
let len = src.read_u16();
|
||||
ensure_size!(in: src, size: len as usize);
|
||||
let len = usize::from(src.read_u16());
|
||||
ensure_size!(in: src, size: len);
|
||||
Ok(DataPkt {
|
||||
data: src.read_slice(len as usize),
|
||||
data: src.read_slice(len),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ pkcs1 = "0.7"
|
|||
|
||||
[dev-dependencies]
|
||||
expect-test.workspace = true
|
||||
lazy_static.workspace = true # TODO: remove in favor of https://doc.rust-lang.org/std/sync/struct.OnceLock.html
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use ironrdp_core::{decode, encode};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
@ -31,31 +32,29 @@ const BITMAP_BUFFER: [u8; 114] = [
|
|||
0x55, 0xad, 0x10, 0x10, 0xa8, 0xd8, 0x60, 0x12,
|
||||
];
|
||||
|
||||
lazy_static! {
|
||||
static ref BITMAP: BitmapUpdateData<'static> = BitmapUpdateData {
|
||||
rectangles: {
|
||||
let vec = vec![BitmapData {
|
||||
rectangle: InclusiveRectangle {
|
||||
left: 1792,
|
||||
top: 1024,
|
||||
right: 1855,
|
||||
bottom: 1079,
|
||||
},
|
||||
width: 64,
|
||||
height: 56,
|
||||
bits_per_pixel: 16,
|
||||
compression_flags: Compression::BITMAP_COMPRESSION,
|
||||
compressed_data_header: Some(CompressedDataHeader {
|
||||
main_body_size: 80,
|
||||
scan_width: 28,
|
||||
uncompressed_size: 4,
|
||||
}),
|
||||
bitmap_data: &BITMAP_BUFFER[30..],
|
||||
}];
|
||||
vec
|
||||
}
|
||||
};
|
||||
}
|
||||
static BITMAP: LazyLock<BitmapUpdateData<'static>> = LazyLock::new(|| BitmapUpdateData {
|
||||
rectangles: {
|
||||
let vec = vec![BitmapData {
|
||||
rectangle: InclusiveRectangle {
|
||||
left: 1792,
|
||||
top: 1024,
|
||||
right: 1855,
|
||||
bottom: 1079,
|
||||
},
|
||||
width: 64,
|
||||
height: 56,
|
||||
bits_per_pixel: 16,
|
||||
compression_flags: Compression::BITMAP_COMPRESSION,
|
||||
compressed_data_header: Some(CompressedDataHeader {
|
||||
main_body_size: 80,
|
||||
scan_width: 28,
|
||||
uncompressed_size: 4,
|
||||
}),
|
||||
bitmap_data: &BITMAP_BUFFER[30..],
|
||||
}];
|
||||
vec
|
||||
},
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn from_buffer_bitmap_data_parsses_correctly() {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@ use crate::rdp::headers::{CompressionFlags, SHARE_DATA_HEADER_COMPRESSION_MASK};
|
|||
|
||||
/// Implements the Fast-Path RDP message header PDU.
|
||||
/// TS_FP_UPDATE_PDU
|
||||
#[expect(
|
||||
clippy::partial_pub_fields,
|
||||
reason = "this structure is used in the match expression in the integration tests"
|
||||
)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct FastPathHeader {
|
||||
pub flags: EncryptionFlags,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use ironrdp_core::{decode, encode};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
@ -29,15 +30,13 @@ const FAST_PATH_HEADER_WITH_FORCED_LONG_LEN_PDU: FastPathHeader = FastPathHeader
|
|||
forced_long_length: true,
|
||||
};
|
||||
|
||||
lazy_static! {
|
||||
static ref FAST_PATH_UPDATE_PDU: FastPathUpdatePdu<'static> = FastPathUpdatePdu {
|
||||
fragmentation: Fragmentation::Single,
|
||||
update_code: UpdateCode::SurfaceCommands,
|
||||
compression_flags: None,
|
||||
compression_type: None,
|
||||
data: &FAST_PATH_UPDATE_PDU_BUFFER[3..],
|
||||
};
|
||||
}
|
||||
static FAST_PATH_UPDATE_PDU: LazyLock<FastPathUpdatePdu<'static>> = LazyLock::new(|| FastPathUpdatePdu {
|
||||
fragmentation: Fragmentation::Single,
|
||||
update_code: UpdateCode::SurfaceCommands,
|
||||
compression_flags: None,
|
||||
compression_type: None,
|
||||
data: &FAST_PATH_UPDATE_PDU_BUFFER[3..],
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn from_buffer_correctly_parses_fast_path_header_with_short_length() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use ironrdp_core::{decode, encode};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
@ -75,8 +76,8 @@ const FRAME_MARKER_PDU: SurfaceCommand<'_> = SurfaceCommand::FrameMarker(FrameMa
|
|||
frame_id: Some(5),
|
||||
});
|
||||
|
||||
lazy_static! {
|
||||
static ref SURFACE_BITS_PDU: SurfaceCommand<'static> = SurfaceCommand::StreamSurfaceBits(SurfaceBitsPdu {
|
||||
static SURFACE_BITS_PDU: LazyLock<SurfaceCommand<'static>> = LazyLock::new(|| {
|
||||
SurfaceCommand::StreamSurfaceBits(SurfaceBitsPdu {
|
||||
destination: ExclusiveRectangle {
|
||||
left: 0,
|
||||
top: 0,
|
||||
|
|
@ -91,8 +92,8 @@ lazy_static! {
|
|||
header: None,
|
||||
data: &SURFACE_BITS_BUFFER[22..],
|
||||
},
|
||||
});
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn from_buffer_correctly_parses_surface_command_frame_marker() {
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ impl Encode for ExtendedMonitorInfo {
|
|||
|
||||
dst.write_u32(self.physical_width);
|
||||
dst.write_u32(self.physical_height);
|
||||
dst.write_u32(self.orientation.as_u32());
|
||||
dst.write_u32(u32::from(self.orientation.as_u16()));
|
||||
dst.write_u32(self.desktop_scale_factor);
|
||||
dst.write_u32(self.device_scale_factor);
|
||||
|
||||
|
|
@ -132,7 +132,7 @@ impl<'de> Decode<'de> for ExtendedMonitorInfo {
|
|||
}
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[repr(u16)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive)]
|
||||
pub enum MonitorOrientation {
|
||||
Landscape = 0,
|
||||
|
|
@ -146,7 +146,7 @@ impl MonitorOrientation {
|
|||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn as_u32(self) -> u32 {
|
||||
self as u32
|
||||
pub fn as_u16(self) -> u16 {
|
||||
self as u16
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use ironrdp_core::{decode, encode_vec};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
@ -19,28 +20,25 @@ const BITMAP_BUFFER: [u8; 24] = [
|
|||
0x00, 0x00, // pad2octetsB
|
||||
];
|
||||
|
||||
lazy_static! {
|
||||
pub static ref BITMAP: Bitmap = Bitmap {
|
||||
pref_bits_per_pix: 24,
|
||||
desktop_width: 1280,
|
||||
desktop_height: 1024,
|
||||
desktop_resize_flag: true,
|
||||
drawing_flags: BitmapDrawingFlags::ALLOW_SKIP_ALPHA,
|
||||
};
|
||||
}
|
||||
static BITMAP: LazyLock<Bitmap> = LazyLock::new(|| Bitmap {
|
||||
pref_bits_per_pix: 24,
|
||||
desktop_width: 1280,
|
||||
desktop_height: 1024,
|
||||
desktop_resize_flag: true,
|
||||
drawing_flags: BitmapDrawingFlags::ALLOW_SKIP_ALPHA,
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn from_buffer_correctly_parses_bitmap_capset() {
|
||||
let buffer = BITMAP_BUFFER.as_ref();
|
||||
|
||||
assert_eq!(*BITMAP, decode(buffer).unwrap());
|
||||
let bitmap = LazyLock::force(&BITMAP);
|
||||
assert_eq!(bitmap, &decode(buffer).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_buffer_correctly_serializes_bitmap_capset() {
|
||||
let capset = BITMAP.clone();
|
||||
|
||||
let buffer = encode_vec(&capset).unwrap();
|
||||
let buffer = encode_vec(LazyLock::force(&BITMAP)).unwrap();
|
||||
|
||||
assert_eq!(buffer, BITMAP_BUFFER.as_ref());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use ironrdp_core::{decode, encode_vec};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
@ -35,58 +36,56 @@ const BITMAP_CACHE_REV2_BUFFER: [u8; 36] = [
|
|||
|
||||
const CELL_INFO_BUFFER: [u8; 4] = [0xfb, 0x09, 0x00, 0x80];
|
||||
|
||||
lazy_static! {
|
||||
pub static ref BITMAP_CACHE: BitmapCache = BitmapCache {
|
||||
caches: [
|
||||
CacheEntry {
|
||||
entries: 200,
|
||||
max_cell_size: 512
|
||||
},
|
||||
CacheEntry {
|
||||
entries: 600,
|
||||
max_cell_size: 2048
|
||||
},
|
||||
CacheEntry {
|
||||
entries: 1000,
|
||||
max_cell_size: 8192
|
||||
}
|
||||
],
|
||||
};
|
||||
pub static ref BITMAP_CACHE_REV2: BitmapCacheRev2 = BitmapCacheRev2 {
|
||||
cache_flags: CacheFlags::PERSISTENT_KEYS_EXPECTED_FLAG | CacheFlags::ALLOW_CACHE_WAITING_LIST_FLAG,
|
||||
num_cell_caches: 3,
|
||||
cache_cell_info: [
|
||||
CellInfo {
|
||||
num_entries: 120,
|
||||
is_cache_persistent: false
|
||||
},
|
||||
CellInfo {
|
||||
num_entries: 120,
|
||||
is_cache_persistent: false
|
||||
},
|
||||
CellInfo {
|
||||
num_entries: 2555,
|
||||
is_cache_persistent: true
|
||||
},
|
||||
CellInfo {
|
||||
num_entries: 0,
|
||||
is_cache_persistent: false
|
||||
},
|
||||
CellInfo {
|
||||
num_entries: 0,
|
||||
is_cache_persistent: false
|
||||
}
|
||||
],
|
||||
};
|
||||
pub static ref CELL_INFO: CellInfo = CellInfo {
|
||||
num_entries: 2555,
|
||||
is_cache_persistent: true
|
||||
};
|
||||
pub static ref CACHE_ENTRY: CacheEntry = CacheEntry {
|
||||
entries: 0x64,
|
||||
max_cell_size: 0x32,
|
||||
};
|
||||
}
|
||||
static BITMAP_CACHE: LazyLock<BitmapCache> = LazyLock::new(|| BitmapCache {
|
||||
caches: [
|
||||
CacheEntry {
|
||||
entries: 200,
|
||||
max_cell_size: 512,
|
||||
},
|
||||
CacheEntry {
|
||||
entries: 600,
|
||||
max_cell_size: 2048,
|
||||
},
|
||||
CacheEntry {
|
||||
entries: 1000,
|
||||
max_cell_size: 8192,
|
||||
},
|
||||
],
|
||||
});
|
||||
static BITMAP_CACHE_REV2: LazyLock<BitmapCacheRev2> = LazyLock::new(|| BitmapCacheRev2 {
|
||||
cache_flags: CacheFlags::PERSISTENT_KEYS_EXPECTED_FLAG | CacheFlags::ALLOW_CACHE_WAITING_LIST_FLAG,
|
||||
num_cell_caches: 3,
|
||||
cache_cell_info: [
|
||||
CellInfo {
|
||||
num_entries: 120,
|
||||
is_cache_persistent: false,
|
||||
},
|
||||
CellInfo {
|
||||
num_entries: 120,
|
||||
is_cache_persistent: false,
|
||||
},
|
||||
CellInfo {
|
||||
num_entries: 2555,
|
||||
is_cache_persistent: true,
|
||||
},
|
||||
CellInfo {
|
||||
num_entries: 0,
|
||||
is_cache_persistent: false,
|
||||
},
|
||||
CellInfo {
|
||||
num_entries: 0,
|
||||
is_cache_persistent: false,
|
||||
},
|
||||
],
|
||||
});
|
||||
static CELL_INFO: LazyLock<CellInfo> = LazyLock::new(|| CellInfo {
|
||||
num_entries: 2555,
|
||||
is_cache_persistent: true,
|
||||
});
|
||||
static CACHE_ENTRY: LazyLock<CacheEntry> = LazyLock::new(|| CacheEntry {
|
||||
entries: 0x64,
|
||||
max_cell_size: 0x32,
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn from_buffer_correctly_parses_bitmap_cache_capset() {
|
||||
|
|
@ -97,9 +96,7 @@ fn from_buffer_correctly_parses_bitmap_cache_capset() {
|
|||
|
||||
#[test]
|
||||
fn to_buffer_correctly_serializes_bitmap_cache_capset() {
|
||||
let bitmap_cache = BITMAP_CACHE.clone();
|
||||
|
||||
let buffer = encode_vec(&bitmap_cache).unwrap();
|
||||
let buffer = encode_vec(&*BITMAP_CACHE).unwrap();
|
||||
|
||||
assert_eq!(buffer, BITMAP_CACHE_BUFFER.as_ref());
|
||||
}
|
||||
|
|
@ -118,9 +115,7 @@ fn from_buffer_correctly_parses_bitmap_cache_rev2_capset() {
|
|||
|
||||
#[test]
|
||||
fn to_buffer_correctly_serializes_bitmap_cache_rev2_capset() {
|
||||
let bitmap_cache = BITMAP_CACHE_REV2.clone();
|
||||
|
||||
let buffer = encode_vec(&bitmap_cache).unwrap();
|
||||
let buffer = encode_vec(&*BITMAP_CACHE_REV2).unwrap();
|
||||
|
||||
assert_eq!(buffer, BITMAP_CACHE_REV2_BUFFER.as_ref());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -637,6 +637,10 @@ pub enum EntropyBits {
|
|||
}
|
||||
|
||||
impl EntropyBits {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn as_u8(self) -> u8 {
|
||||
self as u8
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use ironrdp_core::{decode_cursor, encode_vec, DecodeErrorKind};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
@ -168,14 +169,27 @@ const BITMAP_CODECS_BUFFER: [u8; 91] = [
|
|||
0x03, // color loss level
|
||||
];
|
||||
|
||||
lazy_static! {
|
||||
#[rustfmt::skip]
|
||||
pub static ref GUID: Guid = Guid(0xca8d_1bb9, 0x000f, 0x154f, 0x58, 0x9f, 0xae, 0x2d, 0x1a, 0x87, 0xe2, 0xd6);
|
||||
pub static ref RFX_ICAP: RfxICap = RfxICap {
|
||||
flags: RfxICapFlags::CODEC_MODE,
|
||||
entropy_bits: EntropyBits::Rlgr3,
|
||||
};
|
||||
pub static ref RFX_CAPSET: RfxCapset = RfxCapset(vec![
|
||||
static GUID: LazyLock<Guid> = LazyLock::new(|| {
|
||||
Guid(
|
||||
0xca8d_1bb9,
|
||||
0x000f,
|
||||
0x154f,
|
||||
0x58,
|
||||
0x9f,
|
||||
0xae,
|
||||
0x2d,
|
||||
0x1a,
|
||||
0x87,
|
||||
0xe2,
|
||||
0xd6,
|
||||
)
|
||||
});
|
||||
static RFX_ICAP: LazyLock<RfxICap> = LazyLock::new(|| RfxICap {
|
||||
flags: RfxICapFlags::CODEC_MODE,
|
||||
entropy_bits: EntropyBits::Rlgr3,
|
||||
});
|
||||
static RFX_CAPSET: LazyLock<RfxCapset> = LazyLock::new(|| {
|
||||
RfxCapset(vec![
|
||||
RfxICap {
|
||||
flags: RfxICapFlags::empty(),
|
||||
entropy_bits: EntropyBits::Rlgr1,
|
||||
|
|
@ -183,9 +197,11 @@ lazy_static! {
|
|||
RfxICap {
|
||||
flags: RfxICapFlags::CODEC_MODE,
|
||||
entropy_bits: EntropyBits::Rlgr3,
|
||||
}
|
||||
]);
|
||||
pub static ref RFX_CAPS: RfxCaps = RfxCaps(RfxCapset(vec![
|
||||
},
|
||||
])
|
||||
});
|
||||
static RFX_CAPS: LazyLock<RfxCaps> = LazyLock::new(|| {
|
||||
RfxCaps(RfxCapset(vec![
|
||||
RfxICap {
|
||||
flags: RfxICapFlags::empty(),
|
||||
entropy_bits: EntropyBits::Rlgr1,
|
||||
|
|
@ -193,9 +209,30 @@ lazy_static! {
|
|||
RfxICap {
|
||||
flags: RfxICapFlags::CODEC_MODE,
|
||||
entropy_bits: EntropyBits::Rlgr3,
|
||||
}
|
||||
]));
|
||||
pub static ref RFX_CLIENT_CAPS_CONTAINER: RfxClientCapsContainer = RfxClientCapsContainer {
|
||||
},
|
||||
]))
|
||||
});
|
||||
static RFX_CLIENT_CAPS_CONTAINER: LazyLock<RfxClientCapsContainer> = LazyLock::new(|| RfxClientCapsContainer {
|
||||
capture_flags: CaptureFlags::CARDP_CAPS_CAPTURE_NON_CAC,
|
||||
caps_data: RfxCaps(RfxCapset(vec![
|
||||
RfxICap {
|
||||
flags: RfxICapFlags::empty(),
|
||||
entropy_bits: EntropyBits::Rlgr1,
|
||||
},
|
||||
RfxICap {
|
||||
flags: RfxICapFlags::CODEC_MODE,
|
||||
entropy_bits: EntropyBits::Rlgr3,
|
||||
},
|
||||
])),
|
||||
});
|
||||
static NSCODEC: LazyLock<NsCodec> = LazyLock::new(|| NsCodec {
|
||||
is_dynamic_fidelity_allowed: true,
|
||||
is_subsampling_allowed: true,
|
||||
color_loss_level: 3,
|
||||
});
|
||||
static CODEC: LazyLock<Codec> = LazyLock::new(|| Codec {
|
||||
id: 3,
|
||||
property: CodecProperty::RemoteFx(RemoteFxContainer::ClientContainer(RfxClientCapsContainer {
|
||||
capture_flags: CaptureFlags::CARDP_CAPS_CAPTURE_NON_CAC,
|
||||
caps_data: RfxCaps(RfxCapset(vec![
|
||||
RfxICap {
|
||||
|
|
@ -205,18 +242,19 @@ lazy_static! {
|
|||
RfxICap {
|
||||
flags: RfxICapFlags::CODEC_MODE,
|
||||
entropy_bits: EntropyBits::Rlgr3,
|
||||
}
|
||||
},
|
||||
])),
|
||||
};
|
||||
pub static ref NSCODEC: NsCodec = NsCodec {
|
||||
is_dynamic_fidelity_allowed: true,
|
||||
is_subsampling_allowed: true,
|
||||
color_loss_level: 3,
|
||||
};
|
||||
pub static ref CODEC: Codec = Codec {
|
||||
id: 3,
|
||||
property: CodecProperty::RemoteFx(RemoteFxContainer::ClientContainer(
|
||||
RfxClientCapsContainer {
|
||||
})),
|
||||
});
|
||||
static CODEC_SERVER_MODE: LazyLock<Codec> = LazyLock::new(|| Codec {
|
||||
id: 0,
|
||||
property: CodecProperty::ImageRemoteFx(RemoteFxContainer::ServerContainer(4)),
|
||||
});
|
||||
static BITMAP_CODECS: LazyLock<BitmapCodecs> = LazyLock::new(|| {
|
||||
BitmapCodecs(vec![
|
||||
Codec {
|
||||
id: 3,
|
||||
property: CodecProperty::RemoteFx(RemoteFxContainer::ClientContainer(RfxClientCapsContainer {
|
||||
capture_flags: CaptureFlags::CARDP_CAPS_CAPTURE_NON_CAC,
|
||||
caps_data: RfxCaps(RfxCapset(vec![
|
||||
RfxICap {
|
||||
|
|
@ -226,33 +264,9 @@ lazy_static! {
|
|||
RfxICap {
|
||||
flags: RfxICapFlags::CODEC_MODE,
|
||||
entropy_bits: EntropyBits::Rlgr3,
|
||||
}
|
||||
},
|
||||
])),
|
||||
}
|
||||
)),
|
||||
};
|
||||
pub static ref CODEC_SERVER_MODE: Codec = Codec {
|
||||
id: 0,
|
||||
property: CodecProperty::ImageRemoteFx(RemoteFxContainer::ServerContainer(4)),
|
||||
};
|
||||
pub static ref BITMAP_CODECS: BitmapCodecs = BitmapCodecs(vec![
|
||||
Codec {
|
||||
id: 3,
|
||||
property: CodecProperty::RemoteFx(RemoteFxContainer::ClientContainer(
|
||||
RfxClientCapsContainer {
|
||||
capture_flags: CaptureFlags::CARDP_CAPS_CAPTURE_NON_CAC,
|
||||
caps_data: RfxCaps(RfxCapset(vec![
|
||||
RfxICap {
|
||||
flags: RfxICapFlags::empty(),
|
||||
entropy_bits: EntropyBits::Rlgr1,
|
||||
},
|
||||
RfxICap {
|
||||
flags: RfxICapFlags::CODEC_MODE,
|
||||
entropy_bits: EntropyBits::Rlgr3,
|
||||
}
|
||||
])),
|
||||
}
|
||||
))
|
||||
})),
|
||||
},
|
||||
Codec {
|
||||
id: 1,
|
||||
|
|
@ -260,10 +274,10 @@ lazy_static! {
|
|||
is_dynamic_fidelity_allowed: true,
|
||||
is_subsampling_allowed: true,
|
||||
color_loss_level: 3,
|
||||
})
|
||||
}),
|
||||
},
|
||||
]);
|
||||
}
|
||||
])
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn from_buffer_correctly_parses_guid() {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use ironrdp_core::{decode, encode_vec};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::*;
|
||||
|
||||
const BRUSH_BUFFER: [u8; 4] = [0x01, 0x00, 0x00, 0x00];
|
||||
|
||||
lazy_static! {
|
||||
pub static ref BRUSH: Brush = Brush {
|
||||
support_level: SupportLevel::Color8x8,
|
||||
};
|
||||
}
|
||||
static BRUSH: LazyLock<Brush> = LazyLock::new(|| Brush {
|
||||
support_level: SupportLevel::Color8x8,
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn from_buffer_successfully_parses_brush_capset() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use ironrdp_core::{decode, encode_vec};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
@ -17,20 +18,18 @@ const GENERAL_CAPSET_BUFFER: [u8; 20] = [
|
|||
0x00, // suppressOutputSupport
|
||||
];
|
||||
|
||||
lazy_static! {
|
||||
pub static ref CAPSET_GENERAL: General = General {
|
||||
major_platform_type: MajorPlatformType::WINDOWS,
|
||||
minor_platform_type: MinorPlatformType::WINDOWS_NT,
|
||||
protocol_version: PROTOCOL_VER,
|
||||
extra_flags: GeneralExtraFlags::FASTPATH_OUTPUT_SUPPORTED
|
||||
| GeneralExtraFlags::LONG_CREDENTIALS_SUPPORTED
|
||||
| GeneralExtraFlags::AUTORECONNECT_SUPPORTED
|
||||
| GeneralExtraFlags::ENC_SALTED_CHECKSUM
|
||||
| GeneralExtraFlags::NO_BITMAP_COMPRESSION_HDR,
|
||||
refresh_rect_support: false,
|
||||
suppress_output_support: false,
|
||||
};
|
||||
}
|
||||
static CAPSET_GENERAL: LazyLock<General> = LazyLock::new(|| General {
|
||||
major_platform_type: MajorPlatformType::WINDOWS,
|
||||
minor_platform_type: MinorPlatformType::WINDOWS_NT,
|
||||
protocol_version: PROTOCOL_VER,
|
||||
extra_flags: GeneralExtraFlags::FASTPATH_OUTPUT_SUPPORTED
|
||||
| GeneralExtraFlags::LONG_CREDENTIALS_SUPPORTED
|
||||
| GeneralExtraFlags::AUTORECONNECT_SUPPORTED
|
||||
| GeneralExtraFlags::ENC_SALTED_CHECKSUM
|
||||
| GeneralExtraFlags::NO_BITMAP_COMPRESSION_HDR,
|
||||
refresh_rect_support: false,
|
||||
suppress_output_support: false,
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn from_buffer_correctly_parses_general_capset() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use ironrdp_core::{decode, encode_vec};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
@ -14,61 +15,59 @@ const GLYPH_CACHE_BUFFER: [u8; 48] = [
|
|||
|
||||
const CACHE_DEFINITION_BUFFER: [u8; 4] = [0xfe, 0x00, 0x04, 0x00];
|
||||
|
||||
lazy_static! {
|
||||
pub static ref GLYPH_CACHE: GlyphCache = GlyphCache {
|
||||
glyph_cache: [
|
||||
CacheDefinition {
|
||||
entries: 254,
|
||||
max_cell_size: 4
|
||||
},
|
||||
CacheDefinition {
|
||||
entries: 254,
|
||||
max_cell_size: 4
|
||||
},
|
||||
CacheDefinition {
|
||||
entries: 254,
|
||||
max_cell_size: 8
|
||||
},
|
||||
CacheDefinition {
|
||||
entries: 254,
|
||||
max_cell_size: 8
|
||||
},
|
||||
CacheDefinition {
|
||||
entries: 254,
|
||||
max_cell_size: 16
|
||||
},
|
||||
CacheDefinition {
|
||||
entries: 254,
|
||||
max_cell_size: 32
|
||||
},
|
||||
CacheDefinition {
|
||||
entries: 254,
|
||||
max_cell_size: 64
|
||||
},
|
||||
CacheDefinition {
|
||||
entries: 254,
|
||||
max_cell_size: 128
|
||||
},
|
||||
CacheDefinition {
|
||||
entries: 254,
|
||||
max_cell_size: 256
|
||||
},
|
||||
CacheDefinition {
|
||||
entries: 64,
|
||||
max_cell_size: 2048
|
||||
}
|
||||
],
|
||||
frag_cache: CacheDefinition {
|
||||
entries: 256,
|
||||
static GLYPH_CACHE: LazyLock<GlyphCache> = LazyLock::new(|| GlyphCache {
|
||||
glyph_cache: [
|
||||
CacheDefinition {
|
||||
entries: 254,
|
||||
max_cell_size: 4,
|
||||
},
|
||||
CacheDefinition {
|
||||
entries: 254,
|
||||
max_cell_size: 4,
|
||||
},
|
||||
CacheDefinition {
|
||||
entries: 254,
|
||||
max_cell_size: 8,
|
||||
},
|
||||
CacheDefinition {
|
||||
entries: 254,
|
||||
max_cell_size: 8,
|
||||
},
|
||||
CacheDefinition {
|
||||
entries: 254,
|
||||
max_cell_size: 16,
|
||||
},
|
||||
CacheDefinition {
|
||||
entries: 254,
|
||||
max_cell_size: 32,
|
||||
},
|
||||
CacheDefinition {
|
||||
entries: 254,
|
||||
max_cell_size: 64,
|
||||
},
|
||||
CacheDefinition {
|
||||
entries: 254,
|
||||
max_cell_size: 128,
|
||||
},
|
||||
CacheDefinition {
|
||||
entries: 254,
|
||||
max_cell_size: 256,
|
||||
},
|
||||
glyph_support_level: GlyphSupportLevel::Encode,
|
||||
};
|
||||
pub static ref CACHE_DEFINITION: CacheDefinition = CacheDefinition {
|
||||
entries: 254,
|
||||
max_cell_size: 4,
|
||||
};
|
||||
}
|
||||
CacheDefinition {
|
||||
entries: 64,
|
||||
max_cell_size: 2048,
|
||||
},
|
||||
],
|
||||
frag_cache: CacheDefinition {
|
||||
entries: 256,
|
||||
max_cell_size: 256,
|
||||
},
|
||||
glyph_support_level: GlyphSupportLevel::Encode,
|
||||
});
|
||||
static CACHE_DEFINITION: LazyLock<CacheDefinition> = LazyLock::new(|| CacheDefinition {
|
||||
entries: 254,
|
||||
max_cell_size: 4,
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn from_buffer_correctly_parses_glyph_cache_capset() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use ironrdp_core::{decode, encode_vec};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
@ -16,16 +17,14 @@ const INPUT_BUFFER: [u8; 84] = [
|
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // imeFileName
|
||||
];
|
||||
|
||||
lazy_static! {
|
||||
pub static ref INPUT: Input = Input {
|
||||
input_flags: InputFlags::SCANCODES | InputFlags::UNICODE | InputFlags::MOUSEX,
|
||||
keyboard_layout: 0x409,
|
||||
keyboard_type: Some(KeyboardType::IbmEnhanced),
|
||||
keyboard_subtype: 0,
|
||||
keyboard_function_key: 12,
|
||||
keyboard_ime_filename: String::new(),
|
||||
};
|
||||
}
|
||||
static INPUT: LazyLock<Input> = LazyLock::new(|| Input {
|
||||
input_flags: InputFlags::SCANCODES | InputFlags::UNICODE | InputFlags::MOUSEX,
|
||||
keyboard_layout: 0x409,
|
||||
keyboard_type: Some(KeyboardType::IbmEnhanced),
|
||||
keyboard_subtype: 0,
|
||||
keyboard_function_key: 12,
|
||||
keyboard_ime_filename: String::new(),
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn from_buffer_correctly_parses_input_capset() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use ironrdp_core::{decode, encode_vec};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
@ -8,14 +9,11 @@ const OFFSCREEN_BITMAP_CACHE_BUFFER: [u8; 8] = [
|
|||
0x00, 0x1e, // offscreenCacheSize
|
||||
0x64, 0x00, // offscreenCacheEntries
|
||||
];
|
||||
|
||||
lazy_static! {
|
||||
pub static ref OFFSCREEN_BITMAP_CACHE: OffscreenBitmapCache = OffscreenBitmapCache {
|
||||
is_supported: true,
|
||||
cache_size: 7680,
|
||||
cache_entries: 100,
|
||||
};
|
||||
}
|
||||
static OFFSCREEN_BITMAP_CACHE: LazyLock<OffscreenBitmapCache> = LazyLock::new(|| OffscreenBitmapCache {
|
||||
is_supported: true,
|
||||
cache_size: 7680,
|
||||
cache_entries: 100,
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn from_buffer_correctly_parses_offscreen_bitmap_cache_capset() {
|
||||
|
|
|
|||
|
|
@ -66,11 +66,11 @@ bitflags! {
|
|||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub struct Order {
|
||||
pub order_flags: OrderFlags,
|
||||
order_flags: OrderFlags,
|
||||
order_support: [u8; SUPPORT_ARRAY_LEN],
|
||||
pub order_support_ex_flags: OrderSupportExFlags,
|
||||
pub desktop_save_size: u32,
|
||||
pub text_ansi_code_page: u16,
|
||||
order_support_ex_flags: OrderSupportExFlags,
|
||||
desktop_save_size: u32,
|
||||
text_ansi_code_page: u16,
|
||||
}
|
||||
|
||||
impl Order {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use ironrdp_core::{decode, encode_vec};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
@ -24,42 +25,40 @@ const ORDER_BUFFER: [u8; 84] = [
|
|||
0x00, 0x00, // pad2octetsE
|
||||
];
|
||||
|
||||
lazy_static! {
|
||||
pub static ref ORDER: Order = Order {
|
||||
order_flags: OrderFlags::COLOR_INDEX_SUPPORT | OrderFlags::NEGOTIATE_ORDER_SUPPORT,
|
||||
order_support: {
|
||||
let mut array = [0u8; 32];
|
||||
static ORDER: LazyLock<Order> = LazyLock::new(|| Order {
|
||||
order_flags: OrderFlags::COLOR_INDEX_SUPPORT | OrderFlags::NEGOTIATE_ORDER_SUPPORT,
|
||||
order_support: {
|
||||
let mut array = [0u8; 32];
|
||||
|
||||
array[usize::from(OrderSupportIndex::DstBlt.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::PatBlt.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::ScrBlt.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::MemBlt.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::Mem3Blt.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::DrawnInEGrid.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::LineTo.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::MultiDrawnInEGrid.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::SaveBitmap.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::MultiDstBlt.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::MultiPatBlt.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::MultiScrBlt.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::MultiOpaqueRect.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::Fast.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::PolygonSC.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::PolygonCB.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::Polyline.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::FastGlyph.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::EllipseSC.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::EllipseCB.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::Index.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::DstBlt.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::PatBlt.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::ScrBlt.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::MemBlt.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::Mem3Blt.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::DrawnInEGrid.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::LineTo.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::MultiDrawnInEGrid.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::SaveBitmap.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::MultiDstBlt.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::MultiPatBlt.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::MultiScrBlt.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::MultiOpaqueRect.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::Fast.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::PolygonSC.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::PolygonCB.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::Polyline.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::FastGlyph.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::EllipseSC.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::EllipseCB.as_u8())] = 1;
|
||||
array[usize::from(OrderSupportIndex::Index.as_u8())] = 1;
|
||||
|
||||
array
|
||||
},
|
||||
array
|
||||
},
|
||||
|
||||
order_support_ex_flags: OrderSupportExFlags::CACHE_BITMAP_REV3_SUPPORT,
|
||||
desktop_save_size: 230_400,
|
||||
text_ansi_code_page: 0,
|
||||
};
|
||||
}
|
||||
order_support_ex_flags: OrderSupportExFlags::CACHE_BITMAP_REV3_SUPPORT,
|
||||
desktop_save_size: 230_400,
|
||||
text_ansi_code_page: 0,
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn from_buffer_correctly_parses_order_capset() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use ironrdp_core::{decode, encode_vec};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
@ -9,12 +10,10 @@ const POINTER_BUFFER: [u8; 6] = [
|
|||
0x15, 0x00, // pointerCacheSize
|
||||
];
|
||||
|
||||
lazy_static! {
|
||||
pub static ref POINTER: Pointer = Pointer {
|
||||
color_pointer_cache_size: 20,
|
||||
pointer_cache_size: 21,
|
||||
};
|
||||
}
|
||||
static POINTER: LazyLock<Pointer> = LazyLock::new(|| Pointer {
|
||||
color_pointer_cache_size: 20,
|
||||
pointer_cache_size: 21,
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn from_buffer_correctly_parses_pointer_capset() {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use ironrdp_core::{decode, encode_vec};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::*;
|
||||
|
||||
const SOUND_BUFFER: [u8; 4] = [0x01, 0x00, 0x00, 0x00];
|
||||
|
||||
lazy_static! {
|
||||
pub static ref SOUND: Sound = Sound {
|
||||
flags: SoundFlags::BEEPS,
|
||||
};
|
||||
}
|
||||
static SOUND: LazyLock<Sound> = LazyLock::new(|| Sound {
|
||||
flags: SoundFlags::BEEPS,
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn from_buffer_correctly_parses_sound_capset() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use ironrdp_core::{decode, encode_vec};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
@ -8,11 +9,9 @@ const SURFACE_COMMANDS_BUFFER: [u8; 8] = [
|
|||
0x00, 0x00, 0x00, 0x00, // reserved
|
||||
];
|
||||
|
||||
lazy_static! {
|
||||
pub static ref SURFACE_COMMANDS: SurfaceCommands = SurfaceCommands {
|
||||
flags: CmdFlags::SET_SURFACE_BITS | CmdFlags::FRAME_MARKER | CmdFlags::STREAM_SURFACE_BITS,
|
||||
};
|
||||
}
|
||||
static SURFACE_COMMANDS: LazyLock<SurfaceCommands> = LazyLock::new(|| SurfaceCommands {
|
||||
flags: CmdFlags::SET_SURFACE_BITS | CmdFlags::FRAME_MARKER | CmdFlags::STREAM_SURFACE_BITS,
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn from_buffer_correctly_parses_surface_commands_capset() {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ bitflags! {
|
|||
/// # MSDN
|
||||
///
|
||||
/// * [Virtual Channel Capability Set](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/a8593178-80c0-4b80-876c-cb77e62cecfc)
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||
pub struct VirtualChannel {
|
||||
pub flags: VirtualChannelFlags,
|
||||
pub chunk_size: Option<u32>,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use ironrdp_core::{decode, encode_vec};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
@ -12,16 +13,14 @@ const VIRTUAL_CHANNEL_BUFFER: [u8; 8] = [
|
|||
0x40, 0x06, 0x00, 0x00, // chunk size
|
||||
];
|
||||
|
||||
lazy_static! {
|
||||
pub static ref VIRTUAL_CHANNEL_INCOMPLETE: VirtualChannel = VirtualChannel {
|
||||
flags: VirtualChannelFlags::COMPRESSION_SERVER_TO_CLIENT,
|
||||
chunk_size: None,
|
||||
};
|
||||
pub static ref VIRTUAL_CHANNEL: VirtualChannel = VirtualChannel {
|
||||
flags: VirtualChannelFlags::NO_COMPRESSION,
|
||||
chunk_size: Some(1600),
|
||||
};
|
||||
}
|
||||
static VIRTUAL_CHANNEL_INCOMPLETE: LazyLock<VirtualChannel> = LazyLock::new(|| VirtualChannel {
|
||||
flags: VirtualChannelFlags::COMPRESSION_SERVER_TO_CLIENT,
|
||||
chunk_size: None,
|
||||
});
|
||||
static VIRTUAL_CHANNEL: LazyLock<VirtualChannel> = LazyLock::new(|| VirtualChannel {
|
||||
flags: VirtualChannelFlags::NO_COMPRESSION,
|
||||
chunk_size: Some(1600),
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn from_buffer_correctly_parses_virtual_channel_incomplete_capset() {
|
||||
|
|
@ -38,7 +37,7 @@ fn from_buffer_correctly_parses_virtual_channel_capset() {
|
|||
|
||||
#[test]
|
||||
fn to_buffer_correctly_serializes_virtual_channel_incomplete_capset() {
|
||||
let c = VIRTUAL_CHANNEL_INCOMPLETE.clone();
|
||||
let c = *VIRTUAL_CHANNEL_INCOMPLETE;
|
||||
|
||||
let buffer = encode_vec(&c).unwrap();
|
||||
|
||||
|
|
@ -47,7 +46,7 @@ fn to_buffer_correctly_serializes_virtual_channel_incomplete_capset() {
|
|||
|
||||
#[test]
|
||||
fn to_buffer_correctly_serializes_virtual_channel_capset() {
|
||||
let c = VIRTUAL_CHANNEL.clone();
|
||||
let c = *VIRTUAL_CHANNEL;
|
||||
|
||||
let buffer = encode_vec(&c).unwrap();
|
||||
|
||||
|
|
|
|||
|
|
@ -412,6 +412,10 @@ impl RdpSpecificCode {
|
|||
}
|
||||
}
|
||||
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn as_u32(self) -> u32 {
|
||||
self as u32
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use byteorder::{LittleEndian, WriteBytesExt as _};
|
||||
use ironrdp_core::{decode, encode_vec};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::*;
|
||||
use crate::rdp::server_license::server_license_request::cert::{CertificateType, X509CertificateChain};
|
||||
|
|
@ -59,8 +60,8 @@ const LICENSE_KEY_BUFFER: [u8; 16] = [
|
|||
const CLIENT_USERNAME: &str = "sample-user";
|
||||
const CLIENT_MACHINE_NAME: &str = "sample-machine-name";
|
||||
|
||||
lazy_static! {
|
||||
pub static ref CLIENT_NEW_LICENSE_REQUEST: LicensePdu = ClientNewLicenseRequest {
|
||||
static CLIENT_NEW_LICENSE_REQUEST: LazyLock<LicensePdu> = LazyLock::new(|| {
|
||||
ClientNewLicenseRequest {
|
||||
license_header: LicenseHeader {
|
||||
security_header: BasicSecurityHeader {
|
||||
flags: BasicSecurityHeaderFlags::LICENSE_PKT,
|
||||
|
|
@ -68,212 +69,238 @@ lazy_static! {
|
|||
preamble_message_type: PreambleType::NewLicenseRequest,
|
||||
preamble_flags: PreambleFlags::empty(),
|
||||
preamble_version: PreambleVersion::V3,
|
||||
preamble_message_size: u16::try_from(PREAMBLE_SIZE
|
||||
+ RANDOM_NUMBER_SIZE
|
||||
+ LICENSE_REQUEST_STATIC_FIELDS_SIZE
|
||||
+ ENCRYPTED_PREMASTER_SECRET.len()
|
||||
+ CLIENT_MACHINE_NAME.len()
|
||||
+ UTF8_NULL_TERMINATOR_SIZE
|
||||
+ CLIENT_USERNAME.len()
|
||||
+ UTF8_NULL_TERMINATOR_SIZE).expect("can't panic"),
|
||||
preamble_message_size: u16::try_from(
|
||||
PREAMBLE_SIZE
|
||||
+ RANDOM_NUMBER_SIZE
|
||||
+ LICENSE_REQUEST_STATIC_FIELDS_SIZE
|
||||
+ ENCRYPTED_PREMASTER_SECRET.len()
|
||||
+ CLIENT_MACHINE_NAME.len()
|
||||
+ UTF8_NULL_TERMINATOR_SIZE
|
||||
+ CLIENT_USERNAME.len()
|
||||
+ UTF8_NULL_TERMINATOR_SIZE,
|
||||
)
|
||||
.expect("can't panic"),
|
||||
},
|
||||
client_random: Vec::from(CLIENT_RANDOM_BUFFER.as_ref()),
|
||||
encrypted_premaster_secret: Vec::from(ENCRYPTED_PREMASTER_SECRET.as_ref()),
|
||||
client_username: CLIENT_USERNAME.to_owned(),
|
||||
client_machine_name: CLIENT_MACHINE_NAME.to_owned(),
|
||||
}.into();
|
||||
}
|
||||
.into()
|
||||
});
|
||||
|
||||
pub static ref REQUEST_BUFFER: Vec<u8> = {
|
||||
let username_len = CLIENT_USERNAME.len() + UTF8_NULL_TERMINATOR_SIZE;
|
||||
let mut username_len_buf = Vec::new();
|
||||
username_len_buf.write_u16::<LittleEndian>(u16::try_from(username_len).expect("can't panic")).unwrap();
|
||||
static REQUEST_BUFFER: LazyLock<Vec<u8>> = LazyLock::new(|| {
|
||||
let username_len = CLIENT_USERNAME.len() + UTF8_NULL_TERMINATOR_SIZE;
|
||||
let mut username_len_buf = Vec::new();
|
||||
username_len_buf
|
||||
.write_u16::<LittleEndian>(u16::try_from(username_len).expect("can't panic"))
|
||||
.unwrap();
|
||||
|
||||
let machine_name_len = CLIENT_MACHINE_NAME.len() + UTF8_NULL_TERMINATOR_SIZE;
|
||||
let mut machine_name_len_buf = Vec::new();
|
||||
machine_name_len_buf.write_u16::<LittleEndian>(u16::try_from(machine_name_len).unwrap()).unwrap();
|
||||
let machine_name_len = CLIENT_MACHINE_NAME.len() + UTF8_NULL_TERMINATOR_SIZE;
|
||||
let mut machine_name_len_buf = Vec::new();
|
||||
machine_name_len_buf
|
||||
.write_u16::<LittleEndian>(u16::try_from(machine_name_len).unwrap())
|
||||
.unwrap();
|
||||
|
||||
let buf = [
|
||||
&[0x01u8, 0x00, 0x00, 0x00, // preferred_key_exchange_algorithm
|
||||
0x00, 0x00, 0x01, 0x04], // platform_id
|
||||
CLIENT_RANDOM_BUFFER.as_ref(),
|
||||
&[0x02, 0x00, // blob type
|
||||
0x48, 0x00], // blob len
|
||||
ENCRYPTED_PREMASTER_SECRET.as_ref(),
|
||||
&[0x0f, 0x00], // blob type
|
||||
username_len_buf.as_slice(),
|
||||
CLIENT_USERNAME.as_bytes(),
|
||||
&[0x00, // null
|
||||
0x10, 0x00], // blob type
|
||||
machine_name_len_buf.as_slice(), // blob len
|
||||
CLIENT_MACHINE_NAME.as_bytes(),
|
||||
&[0x00]] // null
|
||||
.concat();
|
||||
let buf = [
|
||||
&[
|
||||
0x01u8, 0x00, 0x00, 0x00, // preferred_key_exchange_algorithm
|
||||
0x00, 0x00, 0x01, 0x04,
|
||||
], // platform_id
|
||||
CLIENT_RANDOM_BUFFER.as_ref(),
|
||||
&[
|
||||
0x02, 0x00, // blob type
|
||||
0x48, 0x00,
|
||||
], // blob len
|
||||
ENCRYPTED_PREMASTER_SECRET.as_ref(),
|
||||
&[0x0f, 0x00], // blob type
|
||||
username_len_buf.as_slice(),
|
||||
CLIENT_USERNAME.as_bytes(),
|
||||
&[
|
||||
0x00, // null
|
||||
0x10, 0x00,
|
||||
], // blob type
|
||||
machine_name_len_buf.as_slice(), // blob len
|
||||
CLIENT_MACHINE_NAME.as_bytes(),
|
||||
&[0x00],
|
||||
] // null
|
||||
.concat();
|
||||
|
||||
let preamble_size_field = u16::try_from(buf.len() + PREAMBLE_SIZE).expect("can't panic");
|
||||
let preamble_size_field = u16::try_from(buf.len() + PREAMBLE_SIZE).expect("can't panic");
|
||||
|
||||
[
|
||||
LICENSE_HEADER_BUFFER_NO_SIZE.as_ref(),
|
||||
&preamble_size_field.to_le_bytes(),
|
||||
buf.as_slice()
|
||||
]
|
||||
.concat()
|
||||
};
|
||||
[
|
||||
LICENSE_HEADER_BUFFER_NO_SIZE.as_ref(),
|
||||
&preamble_size_field.to_le_bytes(),
|
||||
buf.as_slice(),
|
||||
]
|
||||
.concat()
|
||||
});
|
||||
|
||||
pub(crate) static ref SERVER_LICENSE_REQUEST: LicensePdu = {
|
||||
let mut req = ServerLicenseRequest {
|
||||
license_header: LicenseHeader {
|
||||
security_header: BasicSecurityHeader {
|
||||
flags: BasicSecurityHeaderFlags::LICENSE_PKT,
|
||||
},
|
||||
preamble_message_type: PreambleType::LicenseRequest,
|
||||
preamble_flags: PreambleFlags::empty(),
|
||||
preamble_version: PreambleVersion::V3,
|
||||
preamble_message_size: 0,
|
||||
pub(crate) static SERVER_LICENSE_REQUEST: LazyLock<LicensePdu> = LazyLock::new(|| {
|
||||
let mut req = ServerLicenseRequest {
|
||||
license_header: LicenseHeader {
|
||||
security_header: BasicSecurityHeader {
|
||||
flags: BasicSecurityHeaderFlags::LICENSE_PKT,
|
||||
},
|
||||
server_random: Vec::from(SERVER_RANDOM_BUFFER.as_ref()),
|
||||
product_info: ProductInfo {
|
||||
version: 0x60000,
|
||||
company_name: "Microsoft Corporation".to_owned(),
|
||||
product_id: "A02".to_owned(),
|
||||
},
|
||||
server_certificate: Some(ServerCertificate {
|
||||
issued_permanently: true,
|
||||
certificate: CertificateType::X509(X509CertificateChain {
|
||||
certificate_array: vec![
|
||||
vec![0x30, 0x82, 0x03, 0xda, 0x30, 0x82, 0x02, 0xc2, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x13, 0x7f,
|
||||
0x00, 0x00, 0x01, 0x76, 0x00, 0x8f, 0x08, 0x64, 0x08, 0x68, 0xa7, 0x63, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x76, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30,
|
||||
0x1d, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x50, 0x72, 0x6f, 0x64, 0x32,
|
||||
0x4c, 0x53, 0x52, 0x41, 0x73, 0x68, 0x61, 0x32, 0x52, 0x44, 0x53, 0x4c, 0x4d, 0x30, 0x1e, 0x17, 0x0d,
|
||||
0x31, 0x39, 0x31, 0x30, 0x32, 0x36, 0x32, 0x32, 0x35, 0x33, 0x34, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x37,
|
||||
0x30, 0x36, 0x30, 0x36, 0x32, 0x30, 0x34, 0x32, 0x33, 0x38, 0x5a, 0x30, 0x11, 0x31, 0x0f, 0x30, 0x0d,
|
||||
0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x06, 0x42, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x30, 0x82, 0x01, 0x22,
|
||||
0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82,
|
||||
0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa8, 0x6b, 0xda, 0xae, 0x08,
|
||||
0x1d, 0xc5, 0x05, 0x70, 0x7d, 0xa0, 0x41, 0x46, 0xb4, 0x14, 0xcf, 0xfb, 0x8e, 0x09, 0x0b, 0x0a, 0x52,
|
||||
0x8a, 0x7f, 0x7a, 0x35, 0xb6, 0xe3, 0x0d, 0x1c, 0xbe, 0x49, 0x63, 0x41, 0x92, 0x86, 0x00, 0xa2, 0xd3,
|
||||
0xff, 0x5b, 0x08, 0x7d, 0x2b, 0x65, 0xe4, 0xc3, 0x09, 0x68, 0x72, 0x21, 0xc4, 0xd8, 0x0a, 0x21, 0x9e,
|
||||
0x1f, 0xdf, 0xb2, 0xaa, 0x2b, 0x42, 0x68, 0xe7, 0xeb, 0x52, 0xf8, 0x9e, 0xfc, 0x7f, 0x0f, 0x55, 0x26,
|
||||
0x7d, 0x44, 0xfb, 0x35, 0xe5, 0xc2, 0x2c, 0xb6, 0x8d, 0x06, 0xc5, 0xdc, 0xbf, 0x66, 0xf6, 0xb2, 0xf2,
|
||||
0x9b, 0xe2, 0x49, 0xaf, 0xfd, 0x4c, 0x69, 0x46, 0x72, 0xe0, 0x2f, 0x31, 0x77, 0x86, 0x7b, 0x5b, 0x6d,
|
||||
0x49, 0xe6, 0xc7, 0x84, 0xd1, 0xdd, 0x56, 0x89, 0x8d, 0xbd, 0x07, 0x18, 0x01, 0x43, 0x70, 0x9b, 0x00,
|
||||
0x71, 0x16, 0x89, 0x66, 0x2e, 0xb6, 0x5f, 0x62, 0xeb, 0x96, 0xed, 0xf2, 0xdb, 0xdb, 0xcf, 0xdd, 0xa8,
|
||||
0xab, 0xde, 0x93, 0xb3, 0xdb, 0x54, 0xf0, 0x34, 0x4a, 0x28, 0xc3, 0x11, 0xf6, 0xb9, 0xd6, 0x45, 0x3f,
|
||||
0x07, 0xc0, 0x8e, 0x10, 0x7a, 0x2b, 0x56, 0x15, 0xbb, 0x00, 0x9d, 0x82, 0x27, 0xf2, 0x11, 0xa3, 0xda,
|
||||
0x03, 0xaa, 0x51, 0xc0, 0xfd, 0x90, 0xc8, 0x73, 0x81, 0xce, 0x97, 0x30, 0xa2, 0x54, 0x63, 0x6f, 0xfc,
|
||||
0x7f, 0x5b, 0x71, 0xec, 0x11, 0xb0, 0xa0, 0xc8, 0x74, 0x3a, 0xcc, 0x1b, 0x5e, 0xcd, 0x91, 0xa8, 0x18,
|
||||
0x92, 0xeb, 0x33, 0xc4, 0x6d, 0xb8, 0x16, 0x67, 0xe1, 0xc5, 0xa6, 0x26, 0x35, 0x48, 0xc4, 0xe7, 0x94,
|
||||
0xeb, 0xbb, 0xb8, 0xde, 0xd3, 0xe1, 0xc0, 0xcb, 0x00, 0x20, 0xf6, 0xbc, 0xa9, 0xc5, 0x70, 0xc4, 0xda,
|
||||
0x1b, 0x61, 0x0b, 0x9f, 0x0b, 0x19, 0x93, 0xaf, 0x8f, 0x40, 0xbb, 0x26, 0x79, 0x02, 0x03, 0x01, 0x00,
|
||||
0x01, 0xa3, 0x82, 0x01, 0x1d, 0x30, 0x82, 0x01, 0x19, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
|
||||
0x16, 0x04, 0x14, 0xa3, 0xda, 0xe5, 0xef, 0xc3, 0x1c, 0x7a, 0xcf, 0x34, 0x2b, 0xa2, 0x42, 0x2b, 0x77,
|
||||
0xcb, 0x62, 0xfb, 0x4c, 0x28, 0x51, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
|
||||
0x80, 0x14, 0x9c, 0xe1, 0xad, 0x8f, 0xd4, 0x86, 0xd2, 0x1c, 0x7e, 0x48, 0x32, 0xf2, 0x28, 0xfe, 0x87,
|
||||
0x90, 0xe3, 0xb1, 0xc5, 0x8e, 0x30, 0x4a, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x43, 0x30, 0x41, 0x30,
|
||||
0x3f, 0xa0, 0x3d, 0xa0, 0x3b, 0x86, 0x39, 0x66, 0x69, 0x6c, 0x65, 0x3a, 0x2f, 0x2f, 0x2f, 0x2f, 0x52,
|
||||
0x44, 0x32, 0x38, 0x31, 0x38, 0x37, 0x38, 0x30, 0x45, 0x33, 0x45, 0x45, 0x43, 0x2f, 0x43, 0x65, 0x72,
|
||||
0x74, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x50, 0x72, 0x6f, 0x64, 0x32, 0x4c, 0x53, 0x52, 0x41,
|
||||
0x73, 0x68, 0x61, 0x32, 0x52, 0x44, 0x53, 0x4c, 0x4d, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x64, 0x06, 0x08,
|
||||
0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x58, 0x30, 0x56, 0x30, 0x54, 0x06, 0x08, 0x2b,
|
||||
0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x48, 0x66, 0x69, 0x6c, 0x65, 0x3a, 0x2f, 0x2f, 0x2f,
|
||||
0x2f, 0x52, 0x44, 0x32, 0x38, 0x31, 0x38, 0x37, 0x38, 0x30, 0x45, 0x33, 0x45, 0x45, 0x43, 0x2f, 0x43,
|
||||
0x65, 0x72, 0x74, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x52, 0x44, 0x32, 0x38, 0x31, 0x38, 0x37,
|
||||
0x38, 0x30, 0x45, 0x33, 0x45, 0x45, 0x43, 0x5f, 0x50, 0x72, 0x6f, 0x64, 0x32, 0x4c, 0x53, 0x52, 0x41,
|
||||
0x73, 0x68, 0x61, 0x32, 0x52, 0x44, 0x53, 0x4c, 0x4d, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x0c, 0x06, 0x03,
|
||||
0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x17, 0x06, 0x08, 0x2b, 0x06, 0x01,
|
||||
0x04, 0x01, 0x82, 0x37, 0x12, 0x04, 0x0b, 0x16, 0x09, 0x54, 0x4c, 0x53, 0x7e, 0x42, 0x41, 0x53, 0x49,
|
||||
0x43, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03,
|
||||
0x82, 0x01, 0x01, 0x00, 0x55, 0xd5, 0x94, 0x3b, 0x06, 0xef, 0xf2, 0xb0, 0xf9, 0xd7, 0x36, 0x2a, 0x36,
|
||||
0xe0, 0xf1, 0xd9, 0x18, 0xc1, 0x89, 0x7e, 0xa2, 0xcf, 0x01, 0x6f, 0x22, 0x7b, 0x34, 0x81, 0xf0, 0x7a,
|
||||
0x45, 0x11, 0x6e, 0x75, 0x4b, 0x0b, 0xa8, 0xcd, 0x92, 0x57, 0x19, 0x80, 0xb7, 0x6e, 0x1a, 0x4d, 0x12,
|
||||
0x65, 0x91, 0x56, 0x38, 0x17, 0x22, 0xa2, 0x75, 0xae, 0xf9, 0x12, 0x75, 0x38, 0xf3, 0x19, 0x74, 0xea,
|
||||
0x87, 0x46, 0x1f, 0x98, 0x2c, 0x2f, 0xf9, 0xfc, 0xb4, 0xdc, 0x25, 0xa0, 0xd3, 0x34, 0x1b, 0xbc, 0x21,
|
||||
0xbb, 0x3d, 0x82, 0xad, 0x15, 0xc6, 0x3d, 0x02, 0x75, 0x33, 0x70, 0x25, 0x0a, 0x1a, 0xf7, 0x4c, 0xcb,
|
||||
0x84, 0xa3, 0xc1, 0x78, 0xe6, 0xf5, 0xa1, 0x44, 0x54, 0xc8, 0x34, 0xfd, 0xef, 0xbf, 0x86, 0x81, 0x9d,
|
||||
0x9a, 0x7e, 0xb6, 0xad, 0x71, 0x7e, 0xe4, 0xd9, 0x71, 0x6c, 0xb9, 0xe7, 0xf2, 0xd6, 0xd7, 0xbb, 0x66,
|
||||
0x5a, 0x30, 0xf5, 0x29, 0xae, 0x02, 0x39, 0x3d, 0xea, 0x7a, 0x79, 0x1b, 0x53, 0xc5, 0xbe, 0x8d, 0xfb,
|
||||
0xe2, 0xe4, 0x8e, 0xc2, 0x04, 0xb3, 0x0a, 0x94, 0x75, 0xa3, 0xbf, 0xd4, 0x87, 0xd2, 0x74, 0x15, 0x05,
|
||||
0x5e, 0xd5, 0x8f, 0x94, 0x23, 0x41, 0x13, 0x3f, 0xbd, 0xed, 0x21, 0x55, 0x96, 0xe9, 0xc4, 0x93, 0x34,
|
||||
0x7f, 0xaa, 0xea, 0xe7, 0xb1, 0x9a, 0xca, 0x25, 0x91, 0x18, 0xdf, 0x28, 0x05, 0x8e, 0x53, 0xb3, 0x8c,
|
||||
0x8d, 0xcc, 0xf3, 0xf4, 0x78, 0x76, 0x76, 0x7b, 0x82, 0xd6, 0x75, 0x7a, 0x7d, 0xb3, 0x23, 0x2c, 0xc7,
|
||||
0xbe, 0xa6, 0xb0, 0x50, 0x4d, 0x6c, 0xe2, 0x90, 0x85, 0x97, 0x77, 0x0d, 0x2f, 0xf5, 0x7b, 0xb0, 0xc6,
|
||||
0xad, 0xfa, 0x9a, 0x2c, 0xdf, 0xeb, 0x0d, 0x60, 0xd3, 0x0e, 0xa8, 0x5c, 0x43, 0xab, 0x09, 0x85, 0xa3,
|
||||
0xa9, 0x31, 0x66, 0xbd, 0xe4],
|
||||
vec![0x30, 0x82, 0x04, 0x59, 0x30, 0x82, 0x03, 0x45, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x05, 0x01,
|
||||
0x00, 0x00, 0x00, 0x02, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d, 0x05, 0x00, 0x30, 0x11,
|
||||
0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x06, 0x42, 0x65, 0x63, 0x6b, 0x65, 0x72,
|
||||
0x30, 0x1e, 0x17, 0x0d, 0x31, 0x39, 0x31, 0x30, 0x32, 0x36, 0x32, 0x33, 0x32, 0x36, 0x34, 0x35, 0x5a,
|
||||
0x17, 0x0d, 0x33, 0x38, 0x30, 0x31, 0x31, 0x39, 0x30, 0x33, 0x31, 0x34, 0x30, 0x37, 0x5a, 0x30, 0x81,
|
||||
0xa6, 0x31, 0x81, 0xa3, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x1e, 0x20, 0x00, 0x6e, 0x00, 0x63,
|
||||
0x00, 0x61, 0x00, 0x63, 0x00, 0x6e, 0x00, 0x5f, 0x00, 0x69, 0x00, 0x70, 0x00, 0x5f, 0x00, 0x74, 0x00,
|
||||
0x63, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x32, 0x00, 0x37, 0x30, 0x33, 0x06, 0x03, 0x55, 0x04,
|
||||
0x07, 0x1e, 0x2c, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x61, 0x00, 0x63, 0x00, 0x6e, 0x00, 0x5f, 0x00, 0x69,
|
||||
0x00, 0x70, 0x00, 0x5f, 0x00, 0x74, 0x00, 0x63, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x32, 0x00,
|
||||
0x37, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x2e, 0x00, 0x31, 0x30, 0x43, 0x06, 0x03,
|
||||
0x55, 0x04, 0x05, 0x1e, 0x3c, 0x00, 0x31, 0x00, 0x42, 0x00, 0x63, 0x00, 0x4b, 0x00, 0x65, 0x00, 0x56,
|
||||
0x00, 0x33, 0x00, 0x4d, 0x00, 0x67, 0x00, 0x74, 0x00, 0x6a, 0x00, 0x55, 0x00, 0x74, 0x00, 0x6f, 0x00,
|
||||
0x32, 0x00, 0x50, 0x00, 0x49, 0x00, 0x68, 0x00, 0x35, 0x00, 0x52, 0x00, 0x57, 0x00, 0x56, 0x00, 0x36,
|
||||
0x00, 0x42, 0x00, 0x58, 0x00, 0x48, 0x00, 0x77, 0x00, 0x3d, 0x00, 0x0d, 0x00, 0x0a, 0x30, 0x58, 0x30,
|
||||
0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x0f, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41,
|
||||
0x00, 0xab, 0xac, 0x87, 0x11, 0x83, 0xbf, 0xe9, 0x48, 0x25, 0x00, 0x2c, 0x33, 0x31, 0x5e, 0x3d, 0x78,
|
||||
0xc8, 0x5f, 0x82, 0xcb, 0x36, 0x41, 0xf5, 0xb4, 0x65, 0x15, 0xee, 0x04, 0x31, 0xae, 0xe2, 0x48, 0x58,
|
||||
0x99, 0x7f, 0x4f, 0x90, 0x1d, 0xf7, 0x7c, 0xd7, 0xf8, 0x47, 0x93, 0xa0, 0xca, 0x9c, 0xdf, 0x91, 0xb0,
|
||||
0x41, 0xe8, 0x05, 0x4b, 0xdc, 0x24, 0x5b, 0x72, 0xf7, 0x68, 0x91, 0x84, 0xfb, 0x19, 0x02, 0x03, 0x01,
|
||||
0x00, 0x01, 0xa3, 0x82, 0x01, 0xf4, 0x30, 0x82, 0x01, 0xf0, 0x30, 0x14, 0x06, 0x09, 0x2b, 0x06, 0x01,
|
||||
0x04, 0x01, 0x82, 0x37, 0x12, 0x04, 0x01, 0x01, 0xff, 0x04, 0x04, 0x01, 0x00, 0x05, 0x00, 0x30, 0x3c,
|
||||
0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x12, 0x02, 0x01, 0x01, 0xff, 0x04, 0x2c, 0x4d,
|
||||
0x00, 0x69, 0x00, 0x63, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x74, 0x00,
|
||||
0x20, 0x00, 0x43, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x70, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74,
|
||||
0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x30, 0x81, 0xdd, 0x06, 0x09, 0x2b, 0x06, 0x01,
|
||||
0x04, 0x01, 0x82, 0x37, 0x12, 0x05, 0x01, 0x01, 0xff, 0x04, 0x81, 0xcc, 0x00, 0x30, 0x00, 0x00, 0x01,
|
||||
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x22, 0x04, 0x00, 0x00, 0x1c, 0x00, 0x4a, 0x00, 0x66, 0x00,
|
||||
0x4a, 0x00, 0xb0, 0x00, 0x03, 0x00, 0x33, 0x00, 0x64, 0x00, 0x32, 0x00, 0x36, 0x00, 0x37, 0x00, 0x39,
|
||||
0x00, 0x35, 0x00, 0x34, 0x00, 0x2d, 0x00, 0x65, 0x00, 0x65, 0x00, 0x62, 0x00, 0x37, 0x00, 0x2d, 0x00,
|
||||
0x31, 0x00, 0x31, 0x00, 0x64, 0x00, 0x31, 0x00, 0x2d, 0x00, 0x62, 0x00, 0x39, 0x00, 0x34, 0x00, 0x65,
|
||||
0x00, 0x2d, 0x00, 0x30, 0x00, 0x30, 0x00, 0x63, 0x00, 0x30, 0x00, 0x34, 0x00, 0x66, 0x00, 0x61, 0x00,
|
||||
0x33, 0x00, 0x30, 0x00, 0x38, 0x00, 0x30, 0x00, 0x64, 0x00, 0x00, 0x00, 0x33, 0x00, 0x64, 0x00, 0x32,
|
||||
0x00, 0x36, 0x00, 0x37, 0x00, 0x39, 0x00, 0x35, 0x00, 0x34, 0x00, 0x2d, 0x00, 0x65, 0x00, 0x65, 0x00,
|
||||
0x62, 0x00, 0x37, 0x00, 0x2d, 0x00, 0x31, 0x00, 0x31, 0x00, 0x64, 0x00, 0x31, 0x00, 0x2d, 0x00, 0x62,
|
||||
0x00, 0x39, 0x00, 0x34, 0x00, 0x65, 0x00, 0x2d, 0x00, 0x30, 0x00, 0x30, 0x00, 0x63, 0x00, 0x30, 0x00,
|
||||
0x34, 0x00, 0x66, 0x00, 0x61, 0x00, 0x33, 0x00, 0x30, 0x00, 0x38, 0x00, 0x30, 0x00, 0x64, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x80, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x81, 0x80, 0x06, 0x09,
|
||||
0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x12, 0x06, 0x01, 0x01, 0xff, 0x04, 0x70, 0x00, 0x30, 0x00,
|
||||
0x00, 0x00, 0x00, 0x20, 0x00, 0x50, 0x00, 0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x2d, 0x00, 0x34, 0x00,
|
||||
0x4c, 0x00, 0x34, 0x00, 0x4c, 0x00, 0x36, 0x00, 0x41, 0x00, 0x4d, 0x00, 0x42, 0x00, 0x43, 0x00, 0x53,
|
||||
0x00, 0x51, 0x00, 0x00, 0x00, 0x30, 0x00, 0x30, 0x00, 0x34, 0x00, 0x32, 0x00, 0x39, 0x00, 0x2d, 0x00,
|
||||
0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x2d, 0x00, 0x33, 0x00, 0x34, 0x00, 0x39,
|
||||
0x00, 0x37, 0x00, 0x32, 0x00, 0x2d, 0x00, 0x41, 0x00, 0x54, 0x00, 0x33, 0x00, 0x35, 0x00, 0x33, 0x00,
|
||||
0x00, 0x00, 0x57, 0x00, 0x4f, 0x00, 0x52, 0x00, 0x4b, 0x00, 0x47, 0x00, 0x52, 0x00, 0x4f, 0x00, 0x55,
|
||||
0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x37, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x01, 0x01, 0xff,
|
||||
0x04, 0x2d, 0x30, 0x2b, 0xa1, 0x22, 0xa4, 0x20, 0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x2d, 0x00, 0x34,
|
||||
0x00, 0x4c, 0x00, 0x34, 0x00, 0x4c, 0x00, 0x36, 0x00, 0x41, 0x00, 0x4d, 0x00, 0x42, 0x00, 0x43, 0x00,
|
||||
0x53, 0x00, 0x51, 0x00, 0x00, 0x00, 0x82, 0x05, 0x01, 0x00, 0x00, 0x00, 0x02, 0x30, 0x09, 0x06, 0x05,
|
||||
0x2b, 0x0e, 0x03, 0x02, 0x1d, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x3e, 0xd3, 0xd5, 0x61, 0x8a,
|
||||
0x87, 0x7b, 0x98, 0x2c, 0x6d, 0x20, 0x38, 0x12, 0x08, 0xd8, 0xf7, 0x83, 0x08, 0xf8, 0xe6, 0xb2, 0xe1,
|
||||
0x21, 0xe1, 0x30, 0x61, 0x12, 0x19, 0xe8, 0xc1, 0x41, 0xaf, 0x59, 0x7c, 0x1e, 0x3e, 0xc8, 0x40, 0x9e,
|
||||
0x24, 0xe8, 0x8d, 0x0c, 0x41, 0xfd, 0xf8, 0x3e, 0xa1, 0xb3, 0xac, 0x56, 0xac, 0x52, 0x91, 0x5a, 0xf8,
|
||||
0xd0, 0x40, 0x8e, 0x13, 0x47, 0xa9, 0x8a, 0x0a, 0x62, 0x6d, 0x11, 0x89, 0x20, 0x56, 0xe7, 0xd6, 0x5f,
|
||||
0x12, 0x44, 0x94, 0xbf, 0x63, 0x99, 0xa3, 0x42, 0x40, 0xd5, 0xc6, 0x8c, 0x1f, 0x4b, 0xf8, 0xaf, 0x83,
|
||||
0x8e, 0xf6, 0x74, 0xb2, 0x0b, 0x55, 0x13, 0x4a, 0x76, 0xed, 0x37, 0xd8, 0x3d, 0x13, 0xe7, 0xae, 0x43,
|
||||
0x4c, 0x9a, 0x61, 0x6c, 0x7b, 0x1b, 0xd1, 0xaa, 0x00, 0x97, 0xdf, 0x5b, 0x85, 0x9f, 0xc8, 0xee, 0x6c,
|
||||
0xe5, 0xa2, 0x63, 0x76, 0xe4, 0x06, 0xd3, 0x2a, 0xe0, 0x55, 0xe1, 0x92, 0x78, 0xed, 0x03, 0x7b, 0x7d,
|
||||
0x1a, 0x6e, 0xc2, 0x56, 0xdc, 0xad, 0x6e, 0xd7, 0xa9, 0xfe, 0xa7, 0xfd, 0x09, 0x0a, 0xa6, 0xd5, 0x8a,
|
||||
0x99, 0xa4, 0x75, 0x89, 0xad, 0x84, 0xc7, 0x09, 0xf7, 0x4c, 0x6e, 0xd0, 0xe2, 0x80, 0x17, 0x62, 0xfa,
|
||||
0x86, 0xfe, 0x43, 0x51, 0xf2, 0xb4, 0xf6, 0xef, 0x3b, 0xb3, 0x3d, 0x1f, 0xef, 0xa3, 0xcb, 0xa2, 0x57,
|
||||
0x25, 0x7c, 0x02, 0xf2, 0x27, 0x1c, 0x87, 0x70, 0x8e, 0x84, 0x20, 0xfe, 0x1d, 0x4a, 0xc4, 0x87, 0x24,
|
||||
0x3b, 0xba, 0xff, 0x34, 0x1a, 0xe2, 0xff, 0xa2, 0x43, 0x39, 0xd8, 0x19, 0x97, 0xf8, 0xf0, 0xf9, 0x73,
|
||||
0xa6, 0xb6, 0x55, 0x64, 0xa6, 0xca, 0xa3, 0x48, 0x22, 0xb7, 0x1a, 0x9b, 0x98, 0x1a, 0x8e, 0x2f, 0xaa,
|
||||
0xec, 0xc1, 0xfe, 0x25, 0x36, 0x2b, 0x70, 0x97, 0x8c, 0x5b, 0x62, 0x21, 0xc3],
|
||||
preamble_message_type: PreambleType::LicenseRequest,
|
||||
preamble_flags: PreambleFlags::empty(),
|
||||
preamble_version: PreambleVersion::V3,
|
||||
preamble_message_size: 0,
|
||||
},
|
||||
server_random: Vec::from(SERVER_RANDOM_BUFFER.as_ref()),
|
||||
product_info: ProductInfo {
|
||||
version: 0x60000,
|
||||
company_name: "Microsoft Corporation".to_owned(),
|
||||
product_id: "A02".to_owned(),
|
||||
},
|
||||
server_certificate: Some(ServerCertificate {
|
||||
issued_permanently: true,
|
||||
certificate: CertificateType::X509(X509CertificateChain {
|
||||
certificate_array: vec![
|
||||
vec![
|
||||
0x30, 0x82, 0x03, 0xda, 0x30, 0x82, 0x02, 0xc2, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x13, 0x7f,
|
||||
0x00, 0x00, 0x01, 0x76, 0x00, 0x8f, 0x08, 0x64, 0x08, 0x68, 0xa7, 0x63, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x76, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05,
|
||||
0x00, 0x30, 0x1d, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x50, 0x72,
|
||||
0x6f, 0x64, 0x32, 0x4c, 0x53, 0x52, 0x41, 0x73, 0x68, 0x61, 0x32, 0x52, 0x44, 0x53, 0x4c, 0x4d,
|
||||
0x30, 0x1e, 0x17, 0x0d, 0x31, 0x39, 0x31, 0x30, 0x32, 0x36, 0x32, 0x32, 0x35, 0x33, 0x34, 0x30,
|
||||
0x5a, 0x17, 0x0d, 0x32, 0x37, 0x30, 0x36, 0x30, 0x36, 0x32, 0x30, 0x34, 0x32, 0x33, 0x38, 0x5a,
|
||||
0x30, 0x11, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x06, 0x42, 0x65, 0x63,
|
||||
0x6b, 0x65, 0x72, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
|
||||
0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02,
|
||||
0x82, 0x01, 0x01, 0x00, 0xa8, 0x6b, 0xda, 0xae, 0x08, 0x1d, 0xc5, 0x05, 0x70, 0x7d, 0xa0, 0x41,
|
||||
0x46, 0xb4, 0x14, 0xcf, 0xfb, 0x8e, 0x09, 0x0b, 0x0a, 0x52, 0x8a, 0x7f, 0x7a, 0x35, 0xb6, 0xe3,
|
||||
0x0d, 0x1c, 0xbe, 0x49, 0x63, 0x41, 0x92, 0x86, 0x00, 0xa2, 0xd3, 0xff, 0x5b, 0x08, 0x7d, 0x2b,
|
||||
0x65, 0xe4, 0xc3, 0x09, 0x68, 0x72, 0x21, 0xc4, 0xd8, 0x0a, 0x21, 0x9e, 0x1f, 0xdf, 0xb2, 0xaa,
|
||||
0x2b, 0x42, 0x68, 0xe7, 0xeb, 0x52, 0xf8, 0x9e, 0xfc, 0x7f, 0x0f, 0x55, 0x26, 0x7d, 0x44, 0xfb,
|
||||
0x35, 0xe5, 0xc2, 0x2c, 0xb6, 0x8d, 0x06, 0xc5, 0xdc, 0xbf, 0x66, 0xf6, 0xb2, 0xf2, 0x9b, 0xe2,
|
||||
0x49, 0xaf, 0xfd, 0x4c, 0x69, 0x46, 0x72, 0xe0, 0x2f, 0x31, 0x77, 0x86, 0x7b, 0x5b, 0x6d, 0x49,
|
||||
0xe6, 0xc7, 0x84, 0xd1, 0xdd, 0x56, 0x89, 0x8d, 0xbd, 0x07, 0x18, 0x01, 0x43, 0x70, 0x9b, 0x00,
|
||||
0x71, 0x16, 0x89, 0x66, 0x2e, 0xb6, 0x5f, 0x62, 0xeb, 0x96, 0xed, 0xf2, 0xdb, 0xdb, 0xcf, 0xdd,
|
||||
0xa8, 0xab, 0xde, 0x93, 0xb3, 0xdb, 0x54, 0xf0, 0x34, 0x4a, 0x28, 0xc3, 0x11, 0xf6, 0xb9, 0xd6,
|
||||
0x45, 0x3f, 0x07, 0xc0, 0x8e, 0x10, 0x7a, 0x2b, 0x56, 0x15, 0xbb, 0x00, 0x9d, 0x82, 0x27, 0xf2,
|
||||
0x11, 0xa3, 0xda, 0x03, 0xaa, 0x51, 0xc0, 0xfd, 0x90, 0xc8, 0x73, 0x81, 0xce, 0x97, 0x30, 0xa2,
|
||||
0x54, 0x63, 0x6f, 0xfc, 0x7f, 0x5b, 0x71, 0xec, 0x11, 0xb0, 0xa0, 0xc8, 0x74, 0x3a, 0xcc, 0x1b,
|
||||
0x5e, 0xcd, 0x91, 0xa8, 0x18, 0x92, 0xeb, 0x33, 0xc4, 0x6d, 0xb8, 0x16, 0x67, 0xe1, 0xc5, 0xa6,
|
||||
0x26, 0x35, 0x48, 0xc4, 0xe7, 0x94, 0xeb, 0xbb, 0xb8, 0xde, 0xd3, 0xe1, 0xc0, 0xcb, 0x00, 0x20,
|
||||
0xf6, 0xbc, 0xa9, 0xc5, 0x70, 0xc4, 0xda, 0x1b, 0x61, 0x0b, 0x9f, 0x0b, 0x19, 0x93, 0xaf, 0x8f,
|
||||
0x40, 0xbb, 0x26, 0x79, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x1d, 0x30, 0x82, 0x01,
|
||||
0x19, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xa3, 0xda, 0xe5, 0xef,
|
||||
0xc3, 0x1c, 0x7a, 0xcf, 0x34, 0x2b, 0xa2, 0x42, 0x2b, 0x77, 0xcb, 0x62, 0xfb, 0x4c, 0x28, 0x51,
|
||||
0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x9c, 0xe1, 0xad,
|
||||
0x8f, 0xd4, 0x86, 0xd2, 0x1c, 0x7e, 0x48, 0x32, 0xf2, 0x28, 0xfe, 0x87, 0x90, 0xe3, 0xb1, 0xc5,
|
||||
0x8e, 0x30, 0x4a, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x43, 0x30, 0x41, 0x30, 0x3f, 0xa0, 0x3d,
|
||||
0xa0, 0x3b, 0x86, 0x39, 0x66, 0x69, 0x6c, 0x65, 0x3a, 0x2f, 0x2f, 0x2f, 0x2f, 0x52, 0x44, 0x32,
|
||||
0x38, 0x31, 0x38, 0x37, 0x38, 0x30, 0x45, 0x33, 0x45, 0x45, 0x43, 0x2f, 0x43, 0x65, 0x72, 0x74,
|
||||
0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x50, 0x72, 0x6f, 0x64, 0x32, 0x4c, 0x53, 0x52, 0x41,
|
||||
0x73, 0x68, 0x61, 0x32, 0x52, 0x44, 0x53, 0x4c, 0x4d, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x64, 0x06,
|
||||
0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x58, 0x30, 0x56, 0x30, 0x54, 0x06,
|
||||
0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x48, 0x66, 0x69, 0x6c, 0x65, 0x3a,
|
||||
0x2f, 0x2f, 0x2f, 0x2f, 0x52, 0x44, 0x32, 0x38, 0x31, 0x38, 0x37, 0x38, 0x30, 0x45, 0x33, 0x45,
|
||||
0x45, 0x43, 0x2f, 0x43, 0x65, 0x72, 0x74, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x52, 0x44,
|
||||
0x32, 0x38, 0x31, 0x38, 0x37, 0x38, 0x30, 0x45, 0x33, 0x45, 0x45, 0x43, 0x5f, 0x50, 0x72, 0x6f,
|
||||
0x64, 0x32, 0x4c, 0x53, 0x52, 0x41, 0x73, 0x68, 0x61, 0x32, 0x52, 0x44, 0x53, 0x4c, 0x4d, 0x2e,
|
||||
0x63, 0x72, 0x74, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30,
|
||||
0x00, 0x30, 0x17, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x12, 0x04, 0x0b, 0x16,
|
||||
0x09, 0x54, 0x4c, 0x53, 0x7e, 0x42, 0x41, 0x53, 0x49, 0x43, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
|
||||
0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x55, 0xd5,
|
||||
0x94, 0x3b, 0x06, 0xef, 0xf2, 0xb0, 0xf9, 0xd7, 0x36, 0x2a, 0x36, 0xe0, 0xf1, 0xd9, 0x18, 0xc1,
|
||||
0x89, 0x7e, 0xa2, 0xcf, 0x01, 0x6f, 0x22, 0x7b, 0x34, 0x81, 0xf0, 0x7a, 0x45, 0x11, 0x6e, 0x75,
|
||||
0x4b, 0x0b, 0xa8, 0xcd, 0x92, 0x57, 0x19, 0x80, 0xb7, 0x6e, 0x1a, 0x4d, 0x12, 0x65, 0x91, 0x56,
|
||||
0x38, 0x17, 0x22, 0xa2, 0x75, 0xae, 0xf9, 0x12, 0x75, 0x38, 0xf3, 0x19, 0x74, 0xea, 0x87, 0x46,
|
||||
0x1f, 0x98, 0x2c, 0x2f, 0xf9, 0xfc, 0xb4, 0xdc, 0x25, 0xa0, 0xd3, 0x34, 0x1b, 0xbc, 0x21, 0xbb,
|
||||
0x3d, 0x82, 0xad, 0x15, 0xc6, 0x3d, 0x02, 0x75, 0x33, 0x70, 0x25, 0x0a, 0x1a, 0xf7, 0x4c, 0xcb,
|
||||
0x84, 0xa3, 0xc1, 0x78, 0xe6, 0xf5, 0xa1, 0x44, 0x54, 0xc8, 0x34, 0xfd, 0xef, 0xbf, 0x86, 0x81,
|
||||
0x9d, 0x9a, 0x7e, 0xb6, 0xad, 0x71, 0x7e, 0xe4, 0xd9, 0x71, 0x6c, 0xb9, 0xe7, 0xf2, 0xd6, 0xd7,
|
||||
0xbb, 0x66, 0x5a, 0x30, 0xf5, 0x29, 0xae, 0x02, 0x39, 0x3d, 0xea, 0x7a, 0x79, 0x1b, 0x53, 0xc5,
|
||||
0xbe, 0x8d, 0xfb, 0xe2, 0xe4, 0x8e, 0xc2, 0x04, 0xb3, 0x0a, 0x94, 0x75, 0xa3, 0xbf, 0xd4, 0x87,
|
||||
0xd2, 0x74, 0x15, 0x05, 0x5e, 0xd5, 0x8f, 0x94, 0x23, 0x41, 0x13, 0x3f, 0xbd, 0xed, 0x21, 0x55,
|
||||
0x96, 0xe9, 0xc4, 0x93, 0x34, 0x7f, 0xaa, 0xea, 0xe7, 0xb1, 0x9a, 0xca, 0x25, 0x91, 0x18, 0xdf,
|
||||
0x28, 0x05, 0x8e, 0x53, 0xb3, 0x8c, 0x8d, 0xcc, 0xf3, 0xf4, 0x78, 0x76, 0x76, 0x7b, 0x82, 0xd6,
|
||||
0x75, 0x7a, 0x7d, 0xb3, 0x23, 0x2c, 0xc7, 0xbe, 0xa6, 0xb0, 0x50, 0x4d, 0x6c, 0xe2, 0x90, 0x85,
|
||||
0x97, 0x77, 0x0d, 0x2f, 0xf5, 0x7b, 0xb0, 0xc6, 0xad, 0xfa, 0x9a, 0x2c, 0xdf, 0xeb, 0x0d, 0x60,
|
||||
0xd3, 0x0e, 0xa8, 0x5c, 0x43, 0xab, 0x09, 0x85, 0xa3, 0xa9, 0x31, 0x66, 0xbd, 0xe4,
|
||||
],
|
||||
}),
|
||||
vec![
|
||||
0x30, 0x82, 0x04, 0x59, 0x30, 0x82, 0x03, 0x45, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x05, 0x01,
|
||||
0x00, 0x00, 0x00, 0x02, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d, 0x05, 0x00, 0x30,
|
||||
0x11, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x06, 0x42, 0x65, 0x63, 0x6b,
|
||||
0x65, 0x72, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x39, 0x31, 0x30, 0x32, 0x36, 0x32, 0x33, 0x32, 0x36,
|
||||
0x34, 0x35, 0x5a, 0x17, 0x0d, 0x33, 0x38, 0x30, 0x31, 0x31, 0x39, 0x30, 0x33, 0x31, 0x34, 0x30,
|
||||
0x37, 0x5a, 0x30, 0x81, 0xa6, 0x31, 0x81, 0xa3, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x1e,
|
||||
0x20, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x61, 0x00, 0x63, 0x00, 0x6e, 0x00, 0x5f, 0x00, 0x69, 0x00,
|
||||
0x70, 0x00, 0x5f, 0x00, 0x74, 0x00, 0x63, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x32, 0x00,
|
||||
0x37, 0x30, 0x33, 0x06, 0x03, 0x55, 0x04, 0x07, 0x1e, 0x2c, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x61,
|
||||
0x00, 0x63, 0x00, 0x6e, 0x00, 0x5f, 0x00, 0x69, 0x00, 0x70, 0x00, 0x5f, 0x00, 0x74, 0x00, 0x63,
|
||||
0x00, 0x70, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x32, 0x00, 0x37, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x2e,
|
||||
0x00, 0x30, 0x00, 0x2e, 0x00, 0x31, 0x30, 0x43, 0x06, 0x03, 0x55, 0x04, 0x05, 0x1e, 0x3c, 0x00,
|
||||
0x31, 0x00, 0x42, 0x00, 0x63, 0x00, 0x4b, 0x00, 0x65, 0x00, 0x56, 0x00, 0x33, 0x00, 0x4d, 0x00,
|
||||
0x67, 0x00, 0x74, 0x00, 0x6a, 0x00, 0x55, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x32, 0x00, 0x50, 0x00,
|
||||
0x49, 0x00, 0x68, 0x00, 0x35, 0x00, 0x52, 0x00, 0x57, 0x00, 0x56, 0x00, 0x36, 0x00, 0x42, 0x00,
|
||||
0x58, 0x00, 0x48, 0x00, 0x77, 0x00, 0x3d, 0x00, 0x0d, 0x00, 0x0a, 0x30, 0x58, 0x30, 0x09, 0x06,
|
||||
0x05, 0x2b, 0x0e, 0x03, 0x02, 0x0f, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41, 0x00,
|
||||
0xab, 0xac, 0x87, 0x11, 0x83, 0xbf, 0xe9, 0x48, 0x25, 0x00, 0x2c, 0x33, 0x31, 0x5e, 0x3d, 0x78,
|
||||
0xc8, 0x5f, 0x82, 0xcb, 0x36, 0x41, 0xf5, 0xb4, 0x65, 0x15, 0xee, 0x04, 0x31, 0xae, 0xe2, 0x48,
|
||||
0x58, 0x99, 0x7f, 0x4f, 0x90, 0x1d, 0xf7, 0x7c, 0xd7, 0xf8, 0x47, 0x93, 0xa0, 0xca, 0x9c, 0xdf,
|
||||
0x91, 0xb0, 0x41, 0xe8, 0x05, 0x4b, 0xdc, 0x24, 0x5b, 0x72, 0xf7, 0x68, 0x91, 0x84, 0xfb, 0x19,
|
||||
0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0xf4, 0x30, 0x82, 0x01, 0xf0, 0x30, 0x14, 0x06,
|
||||
0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x12, 0x04, 0x01, 0x01, 0xff, 0x04, 0x04, 0x01,
|
||||
0x00, 0x05, 0x00, 0x30, 0x3c, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x12, 0x02,
|
||||
0x01, 0x01, 0xff, 0x04, 0x2c, 0x4d, 0x00, 0x69, 0x00, 0x63, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x73,
|
||||
0x00, 0x6f, 0x00, 0x66, 0x00, 0x74, 0x00, 0x20, 0x00, 0x43, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x70,
|
||||
0x00, 0x6f, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x00,
|
||||
0x00, 0x30, 0x81, 0xdd, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x12, 0x05, 0x01,
|
||||
0x01, 0xff, 0x04, 0x81, 0xcc, 0x00, 0x30, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
|
||||
0x00, 0x22, 0x04, 0x00, 0x00, 0x1c, 0x00, 0x4a, 0x00, 0x66, 0x00, 0x4a, 0x00, 0xb0, 0x00, 0x03,
|
||||
0x00, 0x33, 0x00, 0x64, 0x00, 0x32, 0x00, 0x36, 0x00, 0x37, 0x00, 0x39, 0x00, 0x35, 0x00, 0x34,
|
||||
0x00, 0x2d, 0x00, 0x65, 0x00, 0x65, 0x00, 0x62, 0x00, 0x37, 0x00, 0x2d, 0x00, 0x31, 0x00, 0x31,
|
||||
0x00, 0x64, 0x00, 0x31, 0x00, 0x2d, 0x00, 0x62, 0x00, 0x39, 0x00, 0x34, 0x00, 0x65, 0x00, 0x2d,
|
||||
0x00, 0x30, 0x00, 0x30, 0x00, 0x63, 0x00, 0x30, 0x00, 0x34, 0x00, 0x66, 0x00, 0x61, 0x00, 0x33,
|
||||
0x00, 0x30, 0x00, 0x38, 0x00, 0x30, 0x00, 0x64, 0x00, 0x00, 0x00, 0x33, 0x00, 0x64, 0x00, 0x32,
|
||||
0x00, 0x36, 0x00, 0x37, 0x00, 0x39, 0x00, 0x35, 0x00, 0x34, 0x00, 0x2d, 0x00, 0x65, 0x00, 0x65,
|
||||
0x00, 0x62, 0x00, 0x37, 0x00, 0x2d, 0x00, 0x31, 0x00, 0x31, 0x00, 0x64, 0x00, 0x31, 0x00, 0x2d,
|
||||
0x00, 0x62, 0x00, 0x39, 0x00, 0x34, 0x00, 0x65, 0x00, 0x2d, 0x00, 0x30, 0x00, 0x30, 0x00, 0x63,
|
||||
0x00, 0x30, 0x00, 0x34, 0x00, 0x66, 0x00, 0x61, 0x00, 0x33, 0x00, 0x30, 0x00, 0x38, 0x00, 0x30,
|
||||
0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00,
|
||||
0x10, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x30, 0x81, 0x80, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x12, 0x06, 0x01,
|
||||
0x01, 0xff, 0x04, 0x70, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x50, 0x00, 0x57, 0x00,
|
||||
0x49, 0x00, 0x4e, 0x00, 0x2d, 0x00, 0x34, 0x00, 0x4c, 0x00, 0x34, 0x00, 0x4c, 0x00, 0x36, 0x00,
|
||||
0x41, 0x00, 0x4d, 0x00, 0x42, 0x00, 0x43, 0x00, 0x53, 0x00, 0x51, 0x00, 0x00, 0x00, 0x30, 0x00,
|
||||
0x30, 0x00, 0x34, 0x00, 0x32, 0x00, 0x39, 0x00, 0x2d, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00,
|
||||
0x30, 0x00, 0x30, 0x00, 0x2d, 0x00, 0x33, 0x00, 0x34, 0x00, 0x39, 0x00, 0x37, 0x00, 0x32, 0x00,
|
||||
0x2d, 0x00, 0x41, 0x00, 0x54, 0x00, 0x33, 0x00, 0x35, 0x00, 0x33, 0x00, 0x00, 0x00, 0x57, 0x00,
|
||||
0x4f, 0x00, 0x52, 0x00, 0x4b, 0x00, 0x47, 0x00, 0x52, 0x00, 0x4f, 0x00, 0x55, 0x00, 0x50, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x30, 0x37, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x01, 0x01, 0xff, 0x04, 0x2d,
|
||||
0x30, 0x2b, 0xa1, 0x22, 0xa4, 0x20, 0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x2d, 0x00, 0x34, 0x00,
|
||||
0x4c, 0x00, 0x34, 0x00, 0x4c, 0x00, 0x36, 0x00, 0x41, 0x00, 0x4d, 0x00, 0x42, 0x00, 0x43, 0x00,
|
||||
0x53, 0x00, 0x51, 0x00, 0x00, 0x00, 0x82, 0x05, 0x01, 0x00, 0x00, 0x00, 0x02, 0x30, 0x09, 0x06,
|
||||
0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x3e, 0xd3, 0xd5,
|
||||
0x61, 0x8a, 0x87, 0x7b, 0x98, 0x2c, 0x6d, 0x20, 0x38, 0x12, 0x08, 0xd8, 0xf7, 0x83, 0x08, 0xf8,
|
||||
0xe6, 0xb2, 0xe1, 0x21, 0xe1, 0x30, 0x61, 0x12, 0x19, 0xe8, 0xc1, 0x41, 0xaf, 0x59, 0x7c, 0x1e,
|
||||
0x3e, 0xc8, 0x40, 0x9e, 0x24, 0xe8, 0x8d, 0x0c, 0x41, 0xfd, 0xf8, 0x3e, 0xa1, 0xb3, 0xac, 0x56,
|
||||
0xac, 0x52, 0x91, 0x5a, 0xf8, 0xd0, 0x40, 0x8e, 0x13, 0x47, 0xa9, 0x8a, 0x0a, 0x62, 0x6d, 0x11,
|
||||
0x89, 0x20, 0x56, 0xe7, 0xd6, 0x5f, 0x12, 0x44, 0x94, 0xbf, 0x63, 0x99, 0xa3, 0x42, 0x40, 0xd5,
|
||||
0xc6, 0x8c, 0x1f, 0x4b, 0xf8, 0xaf, 0x83, 0x8e, 0xf6, 0x74, 0xb2, 0x0b, 0x55, 0x13, 0x4a, 0x76,
|
||||
0xed, 0x37, 0xd8, 0x3d, 0x13, 0xe7, 0xae, 0x43, 0x4c, 0x9a, 0x61, 0x6c, 0x7b, 0x1b, 0xd1, 0xaa,
|
||||
0x00, 0x97, 0xdf, 0x5b, 0x85, 0x9f, 0xc8, 0xee, 0x6c, 0xe5, 0xa2, 0x63, 0x76, 0xe4, 0x06, 0xd3,
|
||||
0x2a, 0xe0, 0x55, 0xe1, 0x92, 0x78, 0xed, 0x03, 0x7b, 0x7d, 0x1a, 0x6e, 0xc2, 0x56, 0xdc, 0xad,
|
||||
0x6e, 0xd7, 0xa9, 0xfe, 0xa7, 0xfd, 0x09, 0x0a, 0xa6, 0xd5, 0x8a, 0x99, 0xa4, 0x75, 0x89, 0xad,
|
||||
0x84, 0xc7, 0x09, 0xf7, 0x4c, 0x6e, 0xd0, 0xe2, 0x80, 0x17, 0x62, 0xfa, 0x86, 0xfe, 0x43, 0x51,
|
||||
0xf2, 0xb4, 0xf6, 0xef, 0x3b, 0xb3, 0x3d, 0x1f, 0xef, 0xa3, 0xcb, 0xa2, 0x57, 0x25, 0x7c, 0x02,
|
||||
0xf2, 0x27, 0x1c, 0x87, 0x70, 0x8e, 0x84, 0x20, 0xfe, 0x1d, 0x4a, 0xc4, 0x87, 0x24, 0x3b, 0xba,
|
||||
0xff, 0x34, 0x1a, 0xe2, 0xff, 0xa2, 0x43, 0x39, 0xd8, 0x19, 0x97, 0xf8, 0xf0, 0xf9, 0x73, 0xa6,
|
||||
0xb6, 0x55, 0x64, 0xa6, 0xca, 0xa3, 0x48, 0x22, 0xb7, 0x1a, 0x9b, 0x98, 0x1a, 0x8e, 0x2f, 0xaa,
|
||||
0xec, 0xc1, 0xfe, 0x25, 0x36, 0x2b, 0x70, 0x97, 0x8c, 0x5b, 0x62, 0x21, 0xc3,
|
||||
],
|
||||
],
|
||||
}),
|
||||
scope_list: vec![Scope(String::from("microsoft.com"))],
|
||||
};
|
||||
req.license_header.preamble_message_size = u16::try_from(req.size()).expect("can't panic");
|
||||
req.into()
|
||||
}),
|
||||
scope_list: vec![Scope(String::from("microsoft.com"))],
|
||||
};
|
||||
}
|
||||
req.license_header.preamble_message_size = u16::try_from(req.size()).expect("can't panic");
|
||||
req.into()
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn from_buffer_correctly_parses_client_new_license_request() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use ironrdp_core::{decode, encode_vec};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::*;
|
||||
use crate::rdp::server_license::{LicensePdu, BASIC_SECURITY_HEADER_SIZE};
|
||||
|
|
@ -44,37 +45,37 @@ const DATA_BUFFER: [u8; 16] = [
|
|||
0xf1, 0x59, 0x87, 0x3e, 0xc9, 0xd8, 0x98, 0xaf, 0x24, 0x02, 0xf8, 0xf3, 0x29, 0x3a, 0xf0, 0x26,
|
||||
];
|
||||
|
||||
lazy_static! {
|
||||
pub(crate) static ref RESPONSE: PlatformChallengeResponseData = PlatformChallengeResponseData {
|
||||
client_type: ClientType::Win32,
|
||||
license_detail_level: LicenseDetailLevel::Detail,
|
||||
challenge: Vec::from(CHALLENGE_BUFFER.as_ref()),
|
||||
};
|
||||
pub(crate) static ref CLIENT_HARDWARE_IDENTIFICATION: ClientHardwareIdentification = ClientHardwareIdentification {
|
||||
pub(crate) static RESPONSE: LazyLock<PlatformChallengeResponseData> = LazyLock::new(|| PlatformChallengeResponseData {
|
||||
client_type: ClientType::Win32,
|
||||
license_detail_level: LicenseDetailLevel::Detail,
|
||||
challenge: Vec::from(CHALLENGE_BUFFER.as_ref()),
|
||||
});
|
||||
pub(crate) static CLIENT_HARDWARE_IDENTIFICATION: LazyLock<ClientHardwareIdentification> =
|
||||
LazyLock::new(|| ClientHardwareIdentification {
|
||||
platform_id: HARDWARE_ID,
|
||||
data: Vec::from(DATA_BUFFER.as_ref()),
|
||||
};
|
||||
pub(crate) static ref CLIENT_PLATFORM_CHALLENGE_RESPONSE: LicensePdu =
|
||||
LicensePdu::ClientPlatformChallengeResponse(ClientPlatformChallengeResponse {
|
||||
license_header: LicenseHeader {
|
||||
security_header: BasicSecurityHeader {
|
||||
flags: BasicSecurityHeaderFlags::LICENSE_PKT,
|
||||
},
|
||||
preamble_message_type: PreambleType::PlatformChallengeResponse,
|
||||
preamble_flags: PreambleFlags::empty(),
|
||||
preamble_version: PreambleVersion::V3,
|
||||
preamble_message_size: u16::try_from(
|
||||
CLIENT_PLATFORM_CHALLENGE_RESPONSE_BUFFER.len() - BASIC_SECURITY_HEADER_SIZE
|
||||
)
|
||||
.expect("can't panic"),
|
||||
});
|
||||
pub(crate) static CLIENT_PLATFORM_CHALLENGE_RESPONSE: LazyLock<LicensePdu> = LazyLock::new(|| {
|
||||
LicensePdu::ClientPlatformChallengeResponse(ClientPlatformChallengeResponse {
|
||||
license_header: LicenseHeader {
|
||||
security_header: BasicSecurityHeader {
|
||||
flags: BasicSecurityHeaderFlags::LICENSE_PKT,
|
||||
},
|
||||
encrypted_challenge_response_data: Vec::from(&CLIENT_PLATFORM_CHALLENGE_RESPONSE_BUFFER[12..30]),
|
||||
encrypted_hwid: Vec::from(&CLIENT_PLATFORM_CHALLENGE_RESPONSE_BUFFER[34..54]),
|
||||
mac_data: Vec::from(
|
||||
&CLIENT_PLATFORM_CHALLENGE_RESPONSE_BUFFER[CLIENT_PLATFORM_CHALLENGE_RESPONSE_BUFFER.len() - 16..]
|
||||
),
|
||||
});
|
||||
}
|
||||
preamble_message_type: PreambleType::PlatformChallengeResponse,
|
||||
preamble_flags: PreambleFlags::empty(),
|
||||
preamble_version: PreambleVersion::V3,
|
||||
preamble_message_size: u16::try_from(
|
||||
CLIENT_PLATFORM_CHALLENGE_RESPONSE_BUFFER.len() - BASIC_SECURITY_HEADER_SIZE,
|
||||
)
|
||||
.expect("can't panic"),
|
||||
},
|
||||
encrypted_challenge_response_data: Vec::from(&CLIENT_PLATFORM_CHALLENGE_RESPONSE_BUFFER[12..30]),
|
||||
encrypted_hwid: Vec::from(&CLIENT_PLATFORM_CHALLENGE_RESPONSE_BUFFER[34..54]),
|
||||
mac_data: Vec::from(
|
||||
&CLIENT_PLATFORM_CHALLENGE_RESPONSE_BUFFER[CLIENT_PLATFORM_CHALLENGE_RESPONSE_BUFFER.len() - 16..],
|
||||
),
|
||||
})
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn from_buffer_correctly_parses_platform_challenge_response_data() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use ironrdp_core::{decode, encode_vec};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::*;
|
||||
use crate::rdp::server_license::LicensePdu;
|
||||
|
|
@ -10,26 +11,24 @@ const LICENSE_MESSAGE_BUFFER: [u8; 12] = [
|
|||
0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, // message
|
||||
];
|
||||
|
||||
lazy_static! {
|
||||
pub static ref LICENSING_ERROR_MESSAGE: LicensePdu = {
|
||||
let mut pdu = LicensingErrorMessage {
|
||||
license_header: LicenseHeader {
|
||||
security_header: BasicSecurityHeader {
|
||||
flags: BasicSecurityHeaderFlags::LICENSE_PKT,
|
||||
},
|
||||
preamble_message_type: PreambleType::ErrorAlert,
|
||||
preamble_flags: PreambleFlags::empty(),
|
||||
preamble_version: PreambleVersion::V3,
|
||||
preamble_message_size: 0,
|
||||
static LICENSING_ERROR_MESSAGE: LazyLock<LicensePdu> = LazyLock::new(|| {
|
||||
let mut pdu = LicensingErrorMessage {
|
||||
license_header: LicenseHeader {
|
||||
security_header: BasicSecurityHeader {
|
||||
flags: BasicSecurityHeaderFlags::LICENSE_PKT,
|
||||
},
|
||||
error_code: LicenseErrorCode::StatusValidClient,
|
||||
state_transition: LicensingStateTransition::NoTransition,
|
||||
error_info: Vec::new(),
|
||||
};
|
||||
pdu.license_header.preamble_message_size = u16::try_from(pdu.size()).expect("can't panic");
|
||||
pdu.into()
|
||||
preamble_message_type: PreambleType::ErrorAlert,
|
||||
preamble_flags: PreambleFlags::empty(),
|
||||
preamble_version: PreambleVersion::V3,
|
||||
preamble_message_size: 0,
|
||||
},
|
||||
error_code: LicenseErrorCode::StatusValidClient,
|
||||
state_transition: LicensingStateTransition::NoTransition,
|
||||
error_info: Vec::new(),
|
||||
};
|
||||
}
|
||||
pdu.license_header.preamble_message_size = u16::try_from(pdu.size()).expect("can't panic");
|
||||
pdu.into()
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn from_buffer_correctly_parses_licensing_error_message() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use ironrdp_core::{decode, encode_vec};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::cert::{RsaPublicKey, PROP_CERT_BLOBS_HEADERS_SIZE, PROP_CERT_NO_BLOBS_SIZE, RSA_KEY_SIZE_WITHOUT_MODULUS};
|
||||
use super::*;
|
||||
|
|
@ -210,62 +211,60 @@ const SCOPE_BUFFER: [u8; 18] = [
|
|||
0x00, // scope array
|
||||
];
|
||||
|
||||
lazy_static! {
|
||||
pub static ref PROPRIETARY_CERTIFICATE: ProprietaryCertificate = ProprietaryCertificate {
|
||||
public_key: RsaPublicKey {
|
||||
public_exponent: 0x0001_0001,
|
||||
modulus: Vec::from(MODULUS.as_ref()),
|
||||
},
|
||||
signature: Vec::from(SIGNATURE.as_ref()),
|
||||
};
|
||||
pub static ref PRODUCT_INFO: ProductInfo = ProductInfo {
|
||||
version: 0x60000,
|
||||
company_name: "Microsoft Corporation".to_owned(),
|
||||
product_id: "A02".to_owned(),
|
||||
};
|
||||
pub static ref PUBLIC_KEY: RsaPublicKey = RsaPublicKey {
|
||||
static PROPRIETARY_CERTIFICATE: LazyLock<ProprietaryCertificate> = LazyLock::new(|| ProprietaryCertificate {
|
||||
public_key: RsaPublicKey {
|
||||
public_exponent: 0x0001_0001,
|
||||
modulus: Vec::from(MODULUS.as_ref()),
|
||||
};
|
||||
pub static ref SERVER_LICENSE_REQUEST: LicensePdu = {
|
||||
let mut req = ServerLicenseRequest {
|
||||
license_header: LicenseHeader {
|
||||
security_header: BasicSecurityHeader {
|
||||
flags: BasicSecurityHeaderFlags::LICENSE_PKT,
|
||||
},
|
||||
preamble_message_type: PreambleType::LicenseRequest,
|
||||
preamble_flags: PreambleFlags::empty(),
|
||||
preamble_version: PreambleVersion::V3,
|
||||
preamble_message_size: 0,
|
||||
},
|
||||
signature: Vec::from(SIGNATURE.as_ref()),
|
||||
});
|
||||
static PRODUCT_INFO: LazyLock<ProductInfo> = LazyLock::new(|| ProductInfo {
|
||||
version: 0x60000,
|
||||
company_name: "Microsoft Corporation".to_owned(),
|
||||
product_id: "A02".to_owned(),
|
||||
});
|
||||
static PUBLIC_KEY: LazyLock<RsaPublicKey> = LazyLock::new(|| RsaPublicKey {
|
||||
public_exponent: 0x0001_0001,
|
||||
modulus: Vec::from(MODULUS.as_ref()),
|
||||
});
|
||||
static SERVER_LICENSE_REQUEST: LazyLock<LicensePdu> = LazyLock::new(|| {
|
||||
let mut req = ServerLicenseRequest {
|
||||
license_header: LicenseHeader {
|
||||
security_header: BasicSecurityHeader {
|
||||
flags: BasicSecurityHeaderFlags::LICENSE_PKT,
|
||||
},
|
||||
server_random: Vec::from(SERVER_RANDOM_BUFFER.as_ref()),
|
||||
product_info: ProductInfo {
|
||||
version: 0x60000,
|
||||
company_name: "Microsoft Corporation".to_owned(),
|
||||
product_id: "A02".to_owned(),
|
||||
},
|
||||
server_certificate: Some(ServerCertificate {
|
||||
issued_permanently: true,
|
||||
certificate: CertificateType::X509(X509CertificateChain {
|
||||
certificate_array: vec![Vec::from(CERT_1_BUFFER.as_ref()), Vec::from(CERT_2_BUFFER.as_ref())],
|
||||
}),
|
||||
preamble_message_type: PreambleType::LicenseRequest,
|
||||
preamble_flags: PreambleFlags::empty(),
|
||||
preamble_version: PreambleVersion::V3,
|
||||
preamble_message_size: 0,
|
||||
},
|
||||
server_random: Vec::from(SERVER_RANDOM_BUFFER.as_ref()),
|
||||
product_info: ProductInfo {
|
||||
version: 0x60000,
|
||||
company_name: "Microsoft Corporation".to_owned(),
|
||||
product_id: "A02".to_owned(),
|
||||
},
|
||||
server_certificate: Some(ServerCertificate {
|
||||
issued_permanently: true,
|
||||
certificate: CertificateType::X509(X509CertificateChain {
|
||||
certificate_array: vec![Vec::from(CERT_1_BUFFER.as_ref()), Vec::from(CERT_2_BUFFER.as_ref())],
|
||||
}),
|
||||
scope_list: vec![Scope(String::from("microsoft.com"))],
|
||||
};
|
||||
req.license_header.preamble_message_size = u16::try_from(req.size()).expect("can't panic");
|
||||
req.into()
|
||||
};
|
||||
pub static ref X509_CERTIFICATE: ServerCertificate = ServerCertificate {
|
||||
issued_permanently: true,
|
||||
certificate: CertificateType::X509(X509CertificateChain {
|
||||
certificate_array: vec![Vec::from(CERT_1_BUFFER.as_ref()), Vec::from(CERT_2_BUFFER.as_ref()),],
|
||||
}),
|
||||
scope_list: vec![Scope(String::from("microsoft.com"))],
|
||||
};
|
||||
pub static ref SCOPE: Scope = Scope(String::from("microsoft.com"));
|
||||
static ref CERT_CHAIN: X509CertificateChain = X509CertificateChain {
|
||||
certificate_array: vec![Vec::from(CERT_1_BUFFER.as_ref()), Vec::from(CERT_2_BUFFER.as_ref()),],
|
||||
};
|
||||
}
|
||||
req.license_header.preamble_message_size = u16::try_from(req.size()).expect("can't panic");
|
||||
req.into()
|
||||
});
|
||||
static X509_CERTIFICATE: LazyLock<ServerCertificate> = LazyLock::new(|| ServerCertificate {
|
||||
issued_permanently: true,
|
||||
certificate: CertificateType::X509(X509CertificateChain {
|
||||
certificate_array: vec![Vec::from(CERT_1_BUFFER.as_ref()), Vec::from(CERT_2_BUFFER.as_ref())],
|
||||
}),
|
||||
});
|
||||
static SCOPE: LazyLock<Scope> = LazyLock::new(|| Scope(String::from("microsoft.com")));
|
||||
static CERT_CHAIN: LazyLock<X509CertificateChain> = LazyLock::new(|| X509CertificateChain {
|
||||
certificate_array: vec![Vec::from(CERT_1_BUFFER.as_ref()), Vec::from(CERT_2_BUFFER.as_ref())],
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn from_buffer_correctly_parses_server_license_request() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use ironrdp_core::{decode, encode_vec};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::*;
|
||||
use crate::rdp::server_license::{
|
||||
|
|
@ -26,8 +27,8 @@ const MAC_DATA_BUFFER: [u8; MAC_SIZE] = [
|
|||
0x38, 0x23, 0x62, 0x5d, 0x10, 0x8b, 0x93, 0xc3, 0xf1, 0xe4, 0x67, 0x1f, 0x4a, 0xb6, 0x00, 0x0a, // mac data
|
||||
];
|
||||
|
||||
lazy_static! {
|
||||
pub static ref PLATFORM_CHALLENGE: LicensePdu = ServerPlatformChallenge {
|
||||
static PLATFORM_CHALLENGE: LazyLock<LicensePdu> = LazyLock::new(|| {
|
||||
ServerPlatformChallenge {
|
||||
license_header: LicenseHeader {
|
||||
security_header: BasicSecurityHeader {
|
||||
flags: BasicSecurityHeaderFlags::LICENSE_PKT,
|
||||
|
|
@ -41,8 +42,8 @@ lazy_static! {
|
|||
encrypted_platform_challenge: Vec::from(CHALLENGE_BUFFER.as_ref()),
|
||||
mac_data: Vec::from(MAC_DATA_BUFFER.as_ref()),
|
||||
}
|
||||
.into();
|
||||
}
|
||||
.into()
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn from_buffer_correctly_parses_server_platform_challenge() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use ironrdp_core::{decode, encode_vec};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::*;
|
||||
use crate::rdp::server_license::{
|
||||
|
|
@ -244,15 +245,15 @@ const NEW_LICENSE_INFORMATION_BUFFER: [u8; 2031] = [
|
|||
0xb8, 0x1b, 0xb9, 0xcd, 0xfb, 0x31, 0x00, // license info
|
||||
];
|
||||
|
||||
lazy_static! {
|
||||
pub static ref NEW_LICENSE_INFORMATION: LicenseInformation = LicenseInformation {
|
||||
version: 0x0006_0000,
|
||||
scope: "microsoft.com".to_owned(),
|
||||
company_name: "Microsoft Corporation".to_owned(),
|
||||
product_id: "A02".to_owned(),
|
||||
license_info: Vec::from(&NEW_LICENSE_INFORMATION_BUFFER[NEW_LICENSE_INFORMATION_BUFFER.len() - 0x0799..]),
|
||||
};
|
||||
pub static ref SERVER_UPGRADE_LICENSE: LicensePdu = ServerUpgradeLicense {
|
||||
static NEW_LICENSE_INFORMATION: LazyLock<LicenseInformation> = LazyLock::new(|| LicenseInformation {
|
||||
version: 0x0006_0000,
|
||||
scope: "microsoft.com".to_owned(),
|
||||
company_name: "Microsoft Corporation".to_owned(),
|
||||
product_id: "A02".to_owned(),
|
||||
license_info: Vec::from(&NEW_LICENSE_INFORMATION_BUFFER[NEW_LICENSE_INFORMATION_BUFFER.len() - 0x0799..]),
|
||||
});
|
||||
static SERVER_UPGRADE_LICENSE: LazyLock<LicensePdu> = LazyLock::new(|| {
|
||||
ServerUpgradeLicense {
|
||||
license_header: LicenseHeader {
|
||||
security_header: BasicSecurityHeader {
|
||||
flags: BasicSecurityHeaderFlags::LICENSE_PKT,
|
||||
|
|
@ -264,12 +265,12 @@ lazy_static! {
|
|||
.expect("buffer size is too large"),
|
||||
},
|
||||
encrypted_license_info: Vec::from(
|
||||
&SERVER_UPGRADE_LICENSE_BUFFER[12..SERVER_UPGRADE_LICENSE_BUFFER.len() - MAC_SIZE]
|
||||
&SERVER_UPGRADE_LICENSE_BUFFER[12..SERVER_UPGRADE_LICENSE_BUFFER.len() - MAC_SIZE],
|
||||
),
|
||||
mac_data: Vec::from(MAC_DATA.as_ref()),
|
||||
}
|
||||
.into();
|
||||
}
|
||||
.into()
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn from_buffer_correctly_parses_new_license_information() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use ironrdp_core::{decode, encode_vec};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
@ -35,17 +36,15 @@ const STATUS_VALID_CLIENT_BUFFER: [u8; 20] = [
|
|||
0xff, 0x03, 0x10, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
];
|
||||
|
||||
lazy_static! {
|
||||
pub static ref LICENSE_HEADER: LicenseHeader = LicenseHeader {
|
||||
security_header: BasicSecurityHeader {
|
||||
flags: BasicSecurityHeaderFlags::LICENSE_PKT,
|
||||
},
|
||||
preamble_message_type: PreambleType::ErrorAlert,
|
||||
preamble_flags: PreambleFlags::empty(),
|
||||
preamble_version: PreambleVersion::V3,
|
||||
preamble_message_size: 0x10,
|
||||
};
|
||||
}
|
||||
static LICENSE_HEADER: LazyLock<LicenseHeader> = LazyLock::new(|| LicenseHeader {
|
||||
security_header: BasicSecurityHeader {
|
||||
flags: BasicSecurityHeaderFlags::LICENSE_PKT,
|
||||
},
|
||||
preamble_message_type: PreambleType::ErrorAlert,
|
||||
preamble_flags: PreambleFlags::empty(),
|
||||
preamble_version: PreambleVersion::V3,
|
||||
preamble_message_size: 0x10,
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn read_blob_header_handles_wrong_type_correctly() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use ironrdp_core::{decode, encode_vec, DecodeErrorKind};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
@ -234,39 +235,37 @@ const DOMAIN_NAME: &str = "NTDEV";
|
|||
const USER_NAME: &str = "eltons";
|
||||
const SESSION_ID: u32 = 0x02;
|
||||
|
||||
lazy_static! {
|
||||
static ref LOGON_INFO_V1: LogonInfoVersion1 = LogonInfoVersion1 {
|
||||
logon_info: LogonInfo {
|
||||
domain_name: DOMAIN_NAME.to_owned(),
|
||||
user_name: USER_NAME.to_owned(),
|
||||
session_id: SESSION_ID,
|
||||
},
|
||||
};
|
||||
static ref LOGON_INFO_V2: LogonInfoVersion2 = LogonInfoVersion2 {
|
||||
logon_info: LogonInfo {
|
||||
domain_name: DOMAIN_NAME.to_owned(),
|
||||
user_name: USER_NAME.to_owned(),
|
||||
session_id: SESSION_ID,
|
||||
},
|
||||
};
|
||||
static ref LOGON_EXTENDED: LogonInfoExtended = LogonInfoExtended {
|
||||
present_fields_flags: LogonExFlags::AUTO_RECONNECT_COOKIE | LogonExFlags::LOGON_ERRORS,
|
||||
auto_reconnect: Some(ServerAutoReconnect {
|
||||
logon_id: SESSION_ID,
|
||||
random_bits: [
|
||||
0xa8, 0x02, 0xe7, 0x25, 0xe2, 0x4c, 0x82, 0xb7, 0x52, 0xa5, 0x53, 0x50, 0x34, 0x98, 0xa1, 0xa8
|
||||
],
|
||||
}),
|
||||
errors_info: Some(LogonErrorsInfo {
|
||||
error_type: LogonErrorNotificationType::NoPermission,
|
||||
error_data: LogonErrorNotificationData::ErrorCode(LogonErrorNotificationDataErrorCode::FailedOther),
|
||||
}),
|
||||
};
|
||||
static ref SESSION_PLAIN_NOTIFY: SaveSessionInfoPdu = SaveSessionInfoPdu {
|
||||
info_type: InfoType::PlainNotify,
|
||||
info_data: InfoData::PlainNotify,
|
||||
};
|
||||
}
|
||||
static LOGON_INFO_V1: LazyLock<LogonInfoVersion1> = LazyLock::new(|| LogonInfoVersion1 {
|
||||
logon_info: LogonInfo {
|
||||
domain_name: DOMAIN_NAME.to_owned(),
|
||||
user_name: USER_NAME.to_owned(),
|
||||
session_id: SESSION_ID,
|
||||
},
|
||||
});
|
||||
static LOGON_INFO_V2: LazyLock<LogonInfoVersion2> = LazyLock::new(|| LogonInfoVersion2 {
|
||||
logon_info: LogonInfo {
|
||||
domain_name: DOMAIN_NAME.to_owned(),
|
||||
user_name: USER_NAME.to_owned(),
|
||||
session_id: SESSION_ID,
|
||||
},
|
||||
});
|
||||
static LOGON_EXTENDED: LazyLock<LogonInfoExtended> = LazyLock::new(|| LogonInfoExtended {
|
||||
present_fields_flags: LogonExFlags::AUTO_RECONNECT_COOKIE | LogonExFlags::LOGON_ERRORS,
|
||||
auto_reconnect: Some(ServerAutoReconnect {
|
||||
logon_id: SESSION_ID,
|
||||
random_bits: [
|
||||
0xa8, 0x02, 0xe7, 0x25, 0xe2, 0x4c, 0x82, 0xb7, 0x52, 0xa5, 0x53, 0x50, 0x34, 0x98, 0xa1, 0xa8,
|
||||
],
|
||||
}),
|
||||
errors_info: Some(LogonErrorsInfo {
|
||||
error_type: LogonErrorNotificationType::NoPermission,
|
||||
error_data: LogonErrorNotificationData::ErrorCode(LogonErrorNotificationDataErrorCode::FailedOther),
|
||||
}),
|
||||
});
|
||||
static SESSION_PLAIN_NOTIFY: LazyLock<SaveSessionInfoPdu> = LazyLock::new(|| SaveSessionInfoPdu {
|
||||
info_type: InfoType::PlainNotify,
|
||||
info_data: InfoData::PlainNotify,
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn from_buffer_correct_parses_logon_info_v1() {
|
||||
|
|
|
|||
|
|
@ -976,6 +976,10 @@ pub enum PixelFormat {
|
|||
}
|
||||
|
||||
impl PixelFormat {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn as_u8(self) -> u8 {
|
||||
self as u8
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,16 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use ironrdp_core::{decode, encode_vec};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::*;
|
||||
|
||||
const CHANNEL_CHUNK_LENGTH_DEFAULT: u32 = 1600;
|
||||
const CHANNEL_PDU_HEADER_BUFFER: [u8; CHANNEL_PDU_HEADER_SIZE] = [0x40, 0x06, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00];
|
||||
|
||||
lazy_static! {
|
||||
static ref CHANNEL_PDU_HEADER: ChannelPduHeader = ChannelPduHeader {
|
||||
length: CHANNEL_CHUNK_LENGTH_DEFAULT,
|
||||
flags: ChannelControlFlags::FLAG_FIRST,
|
||||
};
|
||||
}
|
||||
static CHANNEL_PDU_HEADER: LazyLock<ChannelPduHeader> = LazyLock::new(|| ChannelPduHeader {
|
||||
length: CHANNEL_CHUNK_LENGTH_DEFAULT,
|
||||
flags: ChannelControlFlags::FLAG_FIRST,
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn from_buffer_correct_parses_channel_header() {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
#![cfg_attr(doc, doc = include_str!("../README.md"))]
|
||||
#![doc(html_logo_url = "https://cdnweb.devolutions.net/images/projects/devolutions/logos/devolutions-icon-shadow.svg")]
|
||||
#![allow(clippy::arithmetic_side_effects)] // FIXME: remove
|
||||
#![allow(clippy::cast_lossless)] // FIXME: remove
|
||||
#![allow(clippy::cast_possible_truncation)] // FIXME: remove
|
||||
#![allow(clippy::cast_possible_wrap)] // FIXME: remove
|
||||
#![allow(clippy::cast_sign_loss)] // FIXME: remove
|
||||
|
||||
use ironrdp_core::{decode_cursor, impl_as_any, ReadCursor};
|
||||
use ironrdp_pdu::gcc::ChannelName;
|
||||
|
|
|
|||
|
|
@ -154,9 +154,15 @@ impl ClientNameRequest {
|
|||
|
||||
pub fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
|
||||
ensure_size!(in: dst, size: self.size());
|
||||
|
||||
let encoded_computer_name_length = cast_length!(
|
||||
"encoded computer name length",
|
||||
encoded_str_len(self.computer_name(), self.unicode_flag().into(), true)
|
||||
)?;
|
||||
|
||||
dst.write_u32(self.unicode_flag().into());
|
||||
dst.write_u32(0); // // CodePage (4 bytes): it MUST be set to 0
|
||||
dst.write_u32(encoded_str_len(self.computer_name(), self.unicode_flag().into(), true) as u32);
|
||||
dst.write_u32(encoded_computer_name_length);
|
||||
write_string_to_cursor(dst, self.computer_name(), self.unicode_flag().into(), true)
|
||||
}
|
||||
|
||||
|
|
@ -186,6 +192,10 @@ impl From<ClientNameRequestUnicodeFlag> for CharacterSet {
|
|||
}
|
||||
|
||||
impl From<ClientNameRequestUnicodeFlag> for u32 {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn from(val: ClientNameRequestUnicodeFlag) -> Self {
|
||||
val as u32
|
||||
}
|
||||
|
|
@ -431,7 +441,7 @@ impl CapabilityHeader {
|
|||
fn new_general() -> Self {
|
||||
Self {
|
||||
cap_type: CapabilityType::General,
|
||||
length: (Self::SIZE + GeneralCapabilitySet::SIZE) as u16,
|
||||
length: u16::try_from(Self::SIZE + GeneralCapabilitySet::SIZE).expect("value fits into u16"),
|
||||
version: GENERAL_CAPABILITY_VERSION_02,
|
||||
}
|
||||
}
|
||||
|
|
@ -439,7 +449,7 @@ impl CapabilityHeader {
|
|||
fn new_smartcard() -> Self {
|
||||
Self {
|
||||
cap_type: CapabilityType::Smartcard,
|
||||
length: Self::SIZE as u16,
|
||||
length: u16::try_from(Self::SIZE).expect("value fits into u16"),
|
||||
version: SMARTCARD_CAPABILITY_VERSION_01,
|
||||
}
|
||||
}
|
||||
|
|
@ -447,7 +457,7 @@ impl CapabilityHeader {
|
|||
fn new_drive() -> Self {
|
||||
Self {
|
||||
cap_type: CapabilityType::Drive,
|
||||
length: Self::SIZE as u16,
|
||||
length: u16::try_from(Self::SIZE).expect("value fits into u16"),
|
||||
version: DRIVE_CAPABILITY_VERSION_02,
|
||||
}
|
||||
}
|
||||
|
|
@ -490,6 +500,10 @@ enum CapabilityType {
|
|||
}
|
||||
|
||||
impl From<CapabilityType> for u16 {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn from(cap_type: CapabilityType) -> Self {
|
||||
cap_type as u16
|
||||
}
|
||||
|
|
@ -990,6 +1004,10 @@ pub enum DeviceType {
|
|||
}
|
||||
|
||||
impl From<DeviceType> for u32 {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn from(device_type: DeviceType) -> Self {
|
||||
device_type as u32
|
||||
}
|
||||
|
|
@ -1211,6 +1229,10 @@ impl TryFrom<u32> for MajorFunction {
|
|||
}
|
||||
|
||||
impl From<MajorFunction> for u32 {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn from(major_function: MajorFunction) -> Self {
|
||||
major_function as u32
|
||||
}
|
||||
|
|
@ -1253,12 +1275,6 @@ impl From<MinorFunction> for u32 {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<MinorFunction> for u8 {
|
||||
fn from(minor_function: MinorFunction) -> Self {
|
||||
minor_function.0 as u8
|
||||
}
|
||||
}
|
||||
|
||||
/// [2.2.1.4.5] Device Control Request (DR_CONTROL_REQ)
|
||||
///
|
||||
/// [2.2.1.4.5]: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpefs/30662c80-ec6e-4ed1-9004-2e6e367bb59f
|
||||
|
|
|
|||
|
|
@ -574,6 +574,10 @@ impl ReturnCode {
|
|||
}
|
||||
|
||||
impl From<ReturnCode> for u32 {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn from(val: ReturnCode) -> Self {
|
||||
val as u32
|
||||
}
|
||||
|
|
@ -1244,7 +1248,7 @@ impl rpce::HeaderlessDecode for TransmitCall {
|
|||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct SCardIORequest {
|
||||
pub protocol: CardProtocol,
|
||||
pub extra_bytes_length: u32,
|
||||
pub extra_bytes_length: usize,
|
||||
pub extra_bytes: Vec<u8>,
|
||||
}
|
||||
|
||||
|
|
@ -1255,7 +1259,7 @@ impl ndr::Decode for SCardIORequest {
|
|||
{
|
||||
ensure_size!(in: src, size: size_of::<u32>() * 2);
|
||||
let protocol = CardProtocol::from_bits_retain(src.read_u32());
|
||||
let extra_bytes_length = src.read_u32();
|
||||
let extra_bytes_length = cast_length!("SCardIORequest", "extra_bytes_length", src.read_u32())?;
|
||||
let _extra_bytes_ptr = ndr::decode_ptr(src, index)?;
|
||||
let extra_bytes = Vec::new();
|
||||
Ok(Self {
|
||||
|
|
@ -1267,9 +1271,8 @@ impl ndr::Decode for SCardIORequest {
|
|||
|
||||
fn decode_value(&mut self, src: &mut ReadCursor<'_>, charset: Option<CharacterSet>) -> DecodeResult<()> {
|
||||
expect_no_charset(charset)?;
|
||||
let extra_bytes_length: usize = cast_length!("TransmitCall", "extra_bytes_length", self.extra_bytes_length)?;
|
||||
ensure_size!(in: src, size: extra_bytes_length);
|
||||
self.extra_bytes = src.read_slice(extra_bytes_length).to_vec();
|
||||
ensure_size!(in: src, size: self.extra_bytes_length);
|
||||
self.extra_bytes = src.read_slice(self.extra_bytes_length).to_vec();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -1277,8 +1280,11 @@ impl ndr::Decode for SCardIORequest {
|
|||
impl ndr::Encode for SCardIORequest {
|
||||
fn encode_ptr(&self, index: &mut u32, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
|
||||
ensure_size!(in: dst, size: self.size_ptr());
|
||||
|
||||
let extra_bytes_length = cast_length!("SCardIORequest", "extra_bytes_length", self.extra_bytes_length)?;
|
||||
|
||||
dst.write_u32(self.protocol.bits());
|
||||
ndr::encode_ptr(Some(self.extra_bytes_length), index, dst)
|
||||
ndr::encode_ptr(Some(extra_bytes_length), index, dst)
|
||||
}
|
||||
|
||||
fn encode_value(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
|
||||
|
|
@ -1292,7 +1298,7 @@ impl ndr::Encode for SCardIORequest {
|
|||
}
|
||||
|
||||
fn size_value(&self) -> usize {
|
||||
self.extra_bytes_length as usize
|
||||
self.extra_bytes_length
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1485,6 +1491,10 @@ pub enum CardState {
|
|||
}
|
||||
|
||||
impl From<CardState> for u32 {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn from(val: CardState) -> Self {
|
||||
val as u32
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,17 +80,21 @@ pub fn ptr_size(with_length: bool) -> usize {
|
|||
/// offset fields prefixing the string, as well as any extra padding for a 4-byte aligned
|
||||
/// NULL-terminated string.
|
||||
pub fn read_string_from_cursor(cursor: &mut ReadCursor<'_>, charset: CharacterSet) -> DecodeResult<String> {
|
||||
const ALIGNMENT: usize = 4;
|
||||
ensure_size!(ctx: "ndr::read_string_from_cursor", in: cursor, size: size_of::<u32>() * 3);
|
||||
let length = cursor.read_u32();
|
||||
let _length = cursor.read_u32();
|
||||
let _offset = cursor.read_u32();
|
||||
let _length2 = cursor.read_u32();
|
||||
|
||||
let string = utils::read_string_from_cursor(cursor, charset, true)?;
|
||||
|
||||
// Skip padding for 4-byte aligned NULL-terminated string.
|
||||
if length % 2 != 0 {
|
||||
ensure_size!(ctx: "ndr::read_string_from_cursor", in: cursor, size: size_of::<u16>());
|
||||
let _padding = cursor.read_u16();
|
||||
let mut pad = cursor.pos();
|
||||
let size = (pad + ALIGNMENT - 1) & !(ALIGNMENT - 1);
|
||||
pad = size - pad;
|
||||
if pad > 0 {
|
||||
ensure_size!(ctx: "ndr::read_string_from_cursor", in: cursor, size: pad);
|
||||
cursor.advance(pad);
|
||||
}
|
||||
|
||||
Ok(string)
|
||||
|
|
|
|||
|
|
@ -244,6 +244,10 @@ impl TryFrom<u8> for Endianness {
|
|||
}
|
||||
|
||||
impl From<Endianness> for u8 {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn from(endianness: Endianness) -> Self {
|
||||
endianness as u8
|
||||
}
|
||||
|
|
|
|||
|
|
@ -374,6 +374,10 @@ impl TryFrom<u16> for Component {
|
|||
}
|
||||
|
||||
impl From<Component> for u16 {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn from(component: Component) -> Self {
|
||||
component as u16
|
||||
}
|
||||
|
|
@ -454,6 +458,10 @@ impl Display for PacketId {
|
|||
}
|
||||
|
||||
impl From<PacketId> for u16 {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn from(packet_id: PacketId) -> Self {
|
||||
packet_id as u16
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ fn main() -> anyhow::Result<()> {
|
|||
}
|
||||
});
|
||||
|
||||
stream.stream.play()?;
|
||||
stream.stream().play()?;
|
||||
thread::sleep(Duration::from_secs(3));
|
||||
let _ = producer.join();
|
||||
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ impl RdpsndClientHandler for RdpsndBackend {
|
|||
#[doc(hidden)]
|
||||
pub struct DecodeStream {
|
||||
_dec_thread: Option<JoinHandle<()>>,
|
||||
pub stream: Stream,
|
||||
stream: Stream,
|
||||
}
|
||||
|
||||
impl DecodeStream {
|
||||
|
|
@ -160,6 +160,10 @@ impl DecodeStream {
|
|||
}
|
||||
};
|
||||
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "opus::Channels has no conversions to usize implemented"
|
||||
)]
|
||||
let mut pcm = vec![0u8; nb_samples * chan as usize * size_of::<i16>()];
|
||||
if let Err(error) = dec.decode(&pkt, bytemuck::cast_slice_mut(pcm.as_mut_slice()), false) {
|
||||
error!(?error, "Failed to decode an Opus packet");
|
||||
|
|
@ -222,6 +226,10 @@ impl DecodeStream {
|
|||
stream,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn stream(&self) -> &Stream {
|
||||
&self.stream
|
||||
}
|
||||
}
|
||||
|
||||
struct RxBuffer {
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ impl Rdpsnd {
|
|||
|
||||
server_format
|
||||
.formats
|
||||
.get(format_no as usize)
|
||||
.get(usize::from(format_no))
|
||||
.ok_or_else(|| pdu_other_err!("invalid format"))
|
||||
}
|
||||
|
||||
|
|
@ -196,7 +196,7 @@ impl SvcProcessor for Rdpsnd {
|
|||
match pdu {
|
||||
// TODO: handle WaveInfo for < v8
|
||||
pdu::ServerAudioOutputPdu::Wave2(pdu) => {
|
||||
let format_no = pdu.format_no as usize;
|
||||
let format_no = usize::from(pdu.format_no);
|
||||
let ts = pdu.audio_timestamp;
|
||||
self.handler.wave(format_no, ts, pdu.data);
|
||||
return Ok(self.wave_confirm(pdu.timestamp, pdu.block_no)?.into());
|
||||
|
|
|
|||
|
|
@ -51,6 +51,10 @@ impl TryFrom<u16> for Version {
|
|||
}
|
||||
|
||||
impl From<Version> for u16 {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn from(version: Version) -> Self {
|
||||
version as u16
|
||||
}
|
||||
|
|
@ -442,9 +446,8 @@ impl<'de> Decode<'de> for ClientAudioFormatPdu {
|
|||
ensure_fixed_part_size!(in: src);
|
||||
|
||||
let flags = AudioFormatFlags::from_bits_truncate(src.read_u32());
|
||||
let volume = src.read_u32();
|
||||
let volume_left = (volume & 0xFFFF) as u16;
|
||||
let volume_right = (volume >> 16) as u16;
|
||||
let volume_left = src.read_u16();
|
||||
let volume_right = src.read_u16();
|
||||
let pitch = src.read_u32();
|
||||
let dgram_port = src.read_u16_be();
|
||||
let n_formats = usize::from(src.read_u16());
|
||||
|
|
@ -489,6 +492,10 @@ impl TryFrom<u16> for QualityMode {
|
|||
}
|
||||
|
||||
impl From<QualityMode> for u16 {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn from(mode: QualityMode) -> Self {
|
||||
mode as u16
|
||||
}
|
||||
|
|
@ -626,7 +633,7 @@ impl<'de> Decode<'de> for TrainingPdu {
|
|||
ensure_fixed_part_size!(in: src);
|
||||
|
||||
let timestamp = src.read_u16();
|
||||
let len = src.read_u16() as usize;
|
||||
let len = usize::from(src.read_u16());
|
||||
let data = if len != 0 {
|
||||
if len < Self::FIXED_PART_SIZE + ServerAudioOutputPdu::FIXED_PART_SIZE {
|
||||
return Err(invalid_field_err!("TrainingPdu::wPackSize", "too small"));
|
||||
|
|
@ -839,7 +846,7 @@ impl Encode for WavePdu<'_> {
|
|||
impl WavePdu<'_> {
|
||||
fn decode(src: &mut ReadCursor<'_>, body_size: u16) -> DecodeResult<Self> {
|
||||
let info = WaveInfoPdu::decode(src)?;
|
||||
let body_size = body_size as usize;
|
||||
let body_size = usize::from(body_size);
|
||||
let data_len = body_size
|
||||
.checked_sub(info.size())
|
||||
.ok_or_else(|| invalid_field_err!("Length", "WaveInfo body_size is too small"))?;
|
||||
|
|
@ -1090,9 +1097,8 @@ impl<'de> Decode<'de> for VolumePdu {
|
|||
fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
|
||||
ensure_fixed_part_size!(in: src);
|
||||
|
||||
let volume = src.read_u32();
|
||||
let volume_left = (volume & 0xFFFF) as u16;
|
||||
let volume_right = (volume >> 16) as u16;
|
||||
let volume_left = src.read_u16();
|
||||
let volume_right = src.read_u16();
|
||||
|
||||
Ok(Self {
|
||||
volume_left,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ pub(crate) struct BitmapEncoder {
|
|||
impl BitmapEncoder {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
buffer: vec![0; u16::MAX as usize],
|
||||
buffer: vec![0; usize::from(u16::MAX)],
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,10 @@ const FASTPATH_HEADER_SIZE: usize = 6;
|
|||
reason = "Unfortunately, expect attribute doesn't work when above or after visibility::make attribute"
|
||||
)]
|
||||
#[allow(unreachable_pub)]
|
||||
#[expect(
|
||||
clippy::partial_pub_fields,
|
||||
reason = "public field is not a part of the public API and is used by benchmarks"
|
||||
)]
|
||||
#[cfg_attr(feature = "__bench", visibility::make(pub))]
|
||||
pub(crate) struct UpdateFragmenter {
|
||||
code: UpdateCode,
|
||||
|
|
|
|||
|
|
@ -31,6 +31,16 @@ enum CodecId {
|
|||
None = 0x0,
|
||||
}
|
||||
|
||||
impl CodecId {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn as_u8(self) -> u8 {
|
||||
self as u8
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "__bench", visibility::make(pub))]
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct UpdateEncoderCodecs {
|
||||
|
|
@ -389,7 +399,7 @@ impl BitmapUpdateHandler for NoneHandler {
|
|||
for row in bitmap.data.chunks(bitmap.stride.get()).rev() {
|
||||
data.extend_from_slice(&row[..stride]);
|
||||
}
|
||||
set_surface(bitmap, CodecId::None as u8, &data)
|
||||
set_surface(bitmap, CodecId::None.as_u8(), &data)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -97,9 +97,14 @@ impl From<(u16, fast_path::KeyboardFlags)> for KeyboardEvent {
|
|||
}
|
||||
|
||||
impl From<(u16, scan_code::KeyboardFlags)> for KeyboardEvent {
|
||||
#[expect(clippy::cast_possible_truncation)] // we are actually truncating the value
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
clippy::cast_possible_truncation,
|
||||
reason = "we are truncating the value on purpose"
|
||||
)]
|
||||
fn from((key, flags): (u16, scan_code::KeyboardFlags)) -> Self {
|
||||
let extended = flags.contains(scan_code::KeyboardFlags::EXTENDED);
|
||||
|
||||
if flags.contains(scan_code::KeyboardFlags::RELEASE) {
|
||||
KeyboardEvent::Released {
|
||||
code: key as u8,
|
||||
|
|
@ -131,7 +136,11 @@ impl From<SynchronizeFlags> for KeyboardEvent {
|
|||
}
|
||||
|
||||
impl From<SyncToggleFlags> for KeyboardEvent {
|
||||
#[expect(clippy::cast_possible_truncation)] // we are actually truncating the value
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
clippy::cast_possible_truncation,
|
||||
reason = "we are truncating the value on purpose"
|
||||
)]
|
||||
fn from(value: SyncToggleFlags) -> Self {
|
||||
KeyboardEvent::Synchronize(SynchronizeFlags::from_bits_truncate(value.bits() as u8))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -298,7 +298,7 @@ impl Processor {
|
|||
// FIXME: This seems to be a way of special-handling the error case in FastPathUpdate::decode_cursor_with_code
|
||||
// to ignore the unsupported update PDUs, but this is a fragile logic and the rationale behind it is not
|
||||
// obvious.
|
||||
if let DecodeErrorKind::InvalidField { field, reason } = e.kind {
|
||||
if let DecodeErrorKind::InvalidField { field, reason } = e.kind() {
|
||||
warn!(field, reason, "Received invalid Fast-Path update");
|
||||
processor_updates.push(UpdateKind::None);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -72,7 +72,6 @@ struct PointerRenderingState {
|
|||
}
|
||||
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
#[expect(clippy::cast_lossless)] // FIXME
|
||||
fn copy_cursor_data(
|
||||
from: &[u8],
|
||||
from_pos: (usize, usize),
|
||||
|
|
@ -124,11 +123,17 @@ fn copy_cursor_data(
|
|||
continue;
|
||||
}
|
||||
|
||||
// Integer alpha blending, source represented as premultiplied alpha color, calculation in floating point
|
||||
to[to_start + pixel * PIXEL_SIZE] = src_r + (((dest_r as u16) * (255 - src_a) as u16) >> 8) as u8;
|
||||
to[to_start + pixel * PIXEL_SIZE + 1] = src_g + (((dest_g as u16) * (255 - src_a) as u16) >> 8) as u8;
|
||||
to[to_start + pixel * PIXEL_SIZE + 2] = src_b + (((dest_b as u16) * (255 - src_a) as u16) >> 8) as u8;
|
||||
// Framebuffer is always opaque, so we can skip alpha channel change
|
||||
#[expect(clippy::as_conversions, reason = "(u16 >> 8) fits into u8 + hot loop")]
|
||||
{
|
||||
// Integer alpha blending, source represented as premultiplied alpha color, calculation in floating point
|
||||
to[to_start + pixel * PIXEL_SIZE] =
|
||||
src_r + ((u16::from(dest_r) * u16::from(255 - src_a)) >> 8) as u8;
|
||||
to[to_start + pixel * PIXEL_SIZE + 1] =
|
||||
src_g + ((u16::from(dest_g) * u16::from(255 - src_a)) >> 8) as u8;
|
||||
to[to_start + pixel * PIXEL_SIZE + 2] =
|
||||
src_b + ((u16::from(dest_b) * u16::from(255 - src_a)) >> 8) as u8;
|
||||
// Framebuffer is always opaque, so we can skip alpha channel change
|
||||
}
|
||||
}
|
||||
} else {
|
||||
to[to_start..to_start + width * PIXEL_SIZE]
|
||||
|
|
@ -227,6 +232,13 @@ impl DecodedImage {
|
|||
return Ok(None);
|
||||
}
|
||||
|
||||
let pointer_src_rect_width = usize::from(self.pointer_src_rect.width());
|
||||
let pointer_src_rect_height = usize::from(self.pointer_src_rect.height());
|
||||
let pointer_draw_x = usize::from(self.pointer_draw_x);
|
||||
let pointer_draw_y = usize::from(self.pointer_draw_y);
|
||||
let width = usize::from(self.width);
|
||||
let height = usize::from(self.height);
|
||||
|
||||
match &layer {
|
||||
PointerLayer::Background => {
|
||||
if self.pointer_backbuffer.is_empty() {
|
||||
|
|
@ -237,15 +249,12 @@ impl DecodedImage {
|
|||
copy_cursor_data(
|
||||
&self.pointer_backbuffer,
|
||||
(0, 0),
|
||||
self.pointer_src_rect.width() as usize * 4,
|
||||
pointer_src_rect_width * 4,
|
||||
&mut self.data,
|
||||
self.width as usize * 4,
|
||||
(self.pointer_draw_x as usize, self.pointer_draw_y as usize),
|
||||
(
|
||||
self.pointer_src_rect.width() as usize,
|
||||
self.pointer_src_rect.height() as usize,
|
||||
),
|
||||
(self.width as usize, self.height as usize),
|
||||
width * 4,
|
||||
(pointer_draw_x, pointer_draw_y),
|
||||
(pointer_src_rect_width, pointer_src_rect_height),
|
||||
(width, height),
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
|
@ -254,37 +263,34 @@ impl DecodedImage {
|
|||
let buffer_size = self
|
||||
.pointer_backbuffer
|
||||
.len()
|
||||
.max(self.pointer_src_rect.width() as usize * self.pointer_src_rect.height() as usize * 4);
|
||||
.max(pointer_src_rect_width * pointer_src_rect_height * 4);
|
||||
self.pointer_backbuffer.resize(buffer_size, 0);
|
||||
|
||||
copy_cursor_data(
|
||||
&self.data,
|
||||
(self.pointer_draw_x as usize, self.pointer_draw_y as usize),
|
||||
self.width as usize * 4,
|
||||
(pointer_draw_x, pointer_draw_y),
|
||||
width * 4,
|
||||
&mut self.pointer_backbuffer,
|
||||
self.pointer_src_rect.width() as usize * 4,
|
||||
pointer_src_rect_width * 4,
|
||||
(0, 0),
|
||||
(
|
||||
self.pointer_src_rect.width() as usize,
|
||||
self.pointer_src_rect.height() as usize,
|
||||
),
|
||||
(self.width as usize, self.height as usize),
|
||||
(pointer_src_rect_width, pointer_src_rect_height),
|
||||
(width, height),
|
||||
false,
|
||||
);
|
||||
|
||||
// Draw pointer (with compositing)
|
||||
copy_cursor_data(
|
||||
pointer.bitmap_data.as_slice(),
|
||||
(self.pointer_src_rect.left as usize, self.pointer_src_rect.top as usize),
|
||||
(
|
||||
usize::from(self.pointer_src_rect.left),
|
||||
usize::from(self.pointer_src_rect.top),
|
||||
),
|
||||
usize::from(pointer.width) * 4,
|
||||
&mut self.data,
|
||||
self.width as usize * 4,
|
||||
(self.pointer_draw_x as usize, self.pointer_draw_y as usize),
|
||||
(
|
||||
self.pointer_src_rect.width() as usize,
|
||||
self.pointer_src_rect.height() as usize,
|
||||
),
|
||||
(self.width as usize, self.height as usize),
|
||||
width * 4,
|
||||
(pointer_draw_x, pointer_draw_y),
|
||||
(pointer_src_rect_width, pointer_src_rect_height),
|
||||
(width, height),
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
|
@ -312,7 +318,6 @@ impl DecodedImage {
|
|||
}
|
||||
}
|
||||
|
||||
#[expect(clippy::cast_possible_wrap)] // FIXME
|
||||
fn recalculate_pointer_geometry(&mut self) {
|
||||
let x = self.pointer_x;
|
||||
let y = self.pointer_y;
|
||||
|
|
@ -322,10 +327,10 @@ impl DecodedImage {
|
|||
_ => return,
|
||||
};
|
||||
|
||||
let left_virtual = x as i16 - pointer.hotspot_x as i16;
|
||||
let top_virtual = y as i16 - pointer.hotspot_y as i16;
|
||||
let right_virtual = left_virtual + pointer.width as i16 - 1;
|
||||
let bottom_virtual = top_virtual + pointer.height as i16 - 1;
|
||||
let left_virtual = i32::from(x) - i32::from(pointer.hotspot_x);
|
||||
let top_virtual = i32::from(y) - i32::from(pointer.hotspot_y);
|
||||
let right_virtual = left_virtual + i32::from(pointer.width) - 1;
|
||||
let bottom_virtual = top_virtual + i32::from(pointer.height) - 1;
|
||||
|
||||
let (left, draw_x) = if left_virtual < 0 {
|
||||
// Cut left side if required
|
||||
|
|
@ -342,7 +347,7 @@ impl DecodedImage {
|
|||
};
|
||||
|
||||
// Cut right side if required
|
||||
let right = if right_virtual >= (self.width - 1) as i16 {
|
||||
let right = if right_virtual >= i32::from(self.width - 1) {
|
||||
if draw_x + 1 >= self.width {
|
||||
// Pointer is completely out of bounds horizontally
|
||||
self.pointer_visible_on_screen = false;
|
||||
|
|
@ -355,7 +360,7 @@ impl DecodedImage {
|
|||
};
|
||||
|
||||
// Cut bottom side if required
|
||||
let bottom = if bottom_virtual >= (self.height - 1) as i16 {
|
||||
let bottom = if bottom_virtual >= i32::from(self.height - 1) {
|
||||
if (draw_y + 1) >= self.height {
|
||||
// Pointer is completely out of bounds vertically
|
||||
self.pointer_visible_on_screen = false;
|
||||
|
|
@ -539,7 +544,7 @@ impl DecodedImage {
|
|||
const SRC_COLOR_DEPTH: usize = 2;
|
||||
const DST_COLOR_DEPTH: usize = 4;
|
||||
|
||||
let image_width = self.width as usize;
|
||||
let image_width = usize::from(self.width);
|
||||
let rectangle_width = usize::from(update_rectangle.width());
|
||||
let top = usize::from(update_rectangle.top);
|
||||
let left = usize::from(update_rectangle.left);
|
||||
|
|
@ -586,7 +591,7 @@ impl DecodedImage {
|
|||
const SRC_COLOR_DEPTH: usize = 3;
|
||||
const DST_COLOR_DEPTH: usize = 4;
|
||||
|
||||
let image_width = self.width as usize;
|
||||
let image_width = usize::from(self.width);
|
||||
let top = usize::from(update_rectangle.top);
|
||||
let left = usize::from(update_rectangle.left);
|
||||
|
||||
|
|
@ -636,7 +641,7 @@ impl DecodedImage {
|
|||
const SRC_COLOR_DEPTH: usize = 4;
|
||||
const DST_COLOR_DEPTH: usize = 4;
|
||||
|
||||
let image_width = self.width as usize;
|
||||
let image_width = usize::from(self.width);
|
||||
let rectangle_width = usize::from(update_rectangle.width());
|
||||
let top = usize::from(update_rectangle.top);
|
||||
let left = usize::from(update_rectangle.left);
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ pub trait SessionResultExt {
|
|||
impl<T> SessionResultExt for SessionResult<T> {
|
||||
fn with_context(self, context: &'static str) -> Self {
|
||||
self.map_err(|mut e| {
|
||||
e.context = context;
|
||||
e.set_context(context);
|
||||
e
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -187,10 +187,11 @@ struct DecodingTileContext {
|
|||
|
||||
impl DecodingTileContext {
|
||||
fn new() -> Self {
|
||||
let tile_size = usize::from(TILE_SIZE);
|
||||
Self {
|
||||
tile_output: vec![0; TILE_SIZE as usize * TILE_SIZE as usize * 4],
|
||||
ycbcr_buffer: vec![vec![0; TILE_SIZE as usize * TILE_SIZE as usize]; 3],
|
||||
ycbcr_temp_buffer: vec![0; TILE_SIZE as usize * TILE_SIZE as usize],
|
||||
tile_output: vec![0; tile_size * tile_size * 4],
|
||||
ycbcr_buffer: vec![vec![0; tile_size * tile_size]; 3],
|
||||
ycbcr_temp_buffer: vec![0; tile_size * tile_size],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ array-concat = "0.5"
|
|||
expect-test = "1"
|
||||
ironrdp-core.path = "../ironrdp-core"
|
||||
ironrdp-pdu.path = "../ironrdp-pdu"
|
||||
lazy_static.workspace = true # TODO: remove in favor of https://doc.rust-lang.org/std/sync/struct.OnceLock.html
|
||||
paste = "1"
|
||||
visibility = { version = "0.1", optional = true }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use ironrdp_core::decode;
|
||||
use ironrdp_pdu::rdp::capability_sets::{
|
||||
CapabilitySet, ClientConfirmActive, DemandActive, ServerDemandActive, SERVER_CHANNEL_ID,
|
||||
};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
pub const SERVER_DEMAND_ACTIVE_BUFFER: [u8; 357] = [
|
||||
0x04, 0x00, // source descriptor length
|
||||
|
|
@ -264,28 +265,29 @@ pub const CLIENT_MULTI_FRAGMENT_UPDATE_CAPABILITY_SET: [u8; 4] = [0x0, 0x0, 0x0,
|
|||
|
||||
pub const CLIENT_WINDOW_LIST_CAPABILITY_SET: [u8; 7] = [0x1, 0x0, 0x0, 0x0, 0x3, 0xc, 0x0];
|
||||
|
||||
lazy_static! {
|
||||
pub static ref SERVER_DEMAND_ACTIVE: ServerDemandActive = ServerDemandActive {
|
||||
pdu: DemandActive {
|
||||
source_descriptor: String::from("RDP"),
|
||||
capability_sets: vec![
|
||||
CapabilitySet::Share(SERVER_SHARE_CAPABILITY_SET.to_vec()),
|
||||
CapabilitySet::General(decode(SERVER_GENERAL_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::VirtualChannel(decode(SERVER_VIRTUAL_CHANNEL_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::DrawGdiPlus(SERVER_DRAW_GDI_PLUS_CAPABILITY_SET.to_vec()),
|
||||
CapabilitySet::Font(SERVER_FONT_CAPABILITY_SET.to_vec()),
|
||||
CapabilitySet::Bitmap(decode(SERVER_BITMAP_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::Order(decode(SERVER_ORDER_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::ColorCache(SERVER_COLOR_CACHE_CAPABILITY_SET.to_vec()),
|
||||
CapabilitySet::BitmapCacheHostSupport(SERVER_BITMAP_CACHE_HOST_SUPPORT_CAPABILITY_SET.to_vec()),
|
||||
CapabilitySet::Pointer(decode(SERVER_POINTER_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::Input(decode(SERVER_INPUT_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::Rail(SERVER_RAIL_CAPABILITY_SET.to_vec()),
|
||||
CapabilitySet::WindowList(SERVER_WINDOW_LIST_CAPABILITY_SET.to_vec()),
|
||||
],
|
||||
}
|
||||
};
|
||||
pub static ref CLIENT_DEMAND_ACTIVE_WITH_INCOMPLETE_CAPABILITY_SET: ClientConfirmActive = ClientConfirmActive {
|
||||
pub static SERVER_DEMAND_ACTIVE: LazyLock<ServerDemandActive> = LazyLock::new(|| ServerDemandActive {
|
||||
pdu: DemandActive {
|
||||
source_descriptor: String::from("RDP"),
|
||||
capability_sets: vec![
|
||||
CapabilitySet::Share(SERVER_SHARE_CAPABILITY_SET.to_vec()),
|
||||
CapabilitySet::General(decode(SERVER_GENERAL_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::VirtualChannel(decode(SERVER_VIRTUAL_CHANNEL_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::DrawGdiPlus(SERVER_DRAW_GDI_PLUS_CAPABILITY_SET.to_vec()),
|
||||
CapabilitySet::Font(SERVER_FONT_CAPABILITY_SET.to_vec()),
|
||||
CapabilitySet::Bitmap(decode(SERVER_BITMAP_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::Order(decode(SERVER_ORDER_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::ColorCache(SERVER_COLOR_CACHE_CAPABILITY_SET.to_vec()),
|
||||
CapabilitySet::BitmapCacheHostSupport(SERVER_BITMAP_CACHE_HOST_SUPPORT_CAPABILITY_SET.to_vec()),
|
||||
CapabilitySet::Pointer(decode(SERVER_POINTER_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::Input(decode(SERVER_INPUT_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::Rail(SERVER_RAIL_CAPABILITY_SET.to_vec()),
|
||||
CapabilitySet::WindowList(SERVER_WINDOW_LIST_CAPABILITY_SET.to_vec()),
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
pub static CLIENT_DEMAND_ACTIVE_WITH_INCOMPLETE_CAPABILITY_SET: LazyLock<ClientConfirmActive> =
|
||||
LazyLock::new(|| ClientConfirmActive {
|
||||
originator_id: SERVER_CHANNEL_ID,
|
||||
pdu: DemandActive {
|
||||
source_descriptor: String::from("MSTSC"),
|
||||
|
|
@ -306,41 +308,41 @@ lazy_static! {
|
|||
CapabilitySet::Brush(decode(CLIENT_BRUSH_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::OffscreenBitmapCache(decode(CLIENT_OFFSCREEN_BITMAP_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::VirtualChannel(
|
||||
decode(CLIENT_VIRTUAL_CHANNEL_CAPABILITY_SET_INCOMPLETE.as_ref()).unwrap()
|
||||
decode(CLIENT_VIRTUAL_CHANNEL_CAPABILITY_SET_INCOMPLETE.as_ref()).unwrap(),
|
||||
),
|
||||
CapabilitySet::DrawNineGridCache(CLIENT_DRAW_NINE_GRID_CACHE_CAPABILITY_SET.to_vec()),
|
||||
CapabilitySet::DrawGdiPlus(CLIENT_DRAW_GDI_PLUS_CAPABILITY_SET.to_vec()),
|
||||
CapabilitySet::MultiFragmentUpdate(
|
||||
decode(CLIENT_MULTI_FRAGMENT_UPDATE_CAPABILITY_SET.as_ref()).unwrap()
|
||||
decode(CLIENT_MULTI_FRAGMENT_UPDATE_CAPABILITY_SET.as_ref()).unwrap(),
|
||||
),
|
||||
CapabilitySet::WindowList(CLIENT_WINDOW_LIST_CAPABILITY_SET.to_vec()),
|
||||
],
|
||||
}
|
||||
};
|
||||
pub static ref CLIENT_DEMAND_ACTIVE: ClientConfirmActive = ClientConfirmActive {
|
||||
originator_id: SERVER_CHANNEL_ID,
|
||||
pdu: DemandActive {
|
||||
source_descriptor: String::from("MSTSC"),
|
||||
capability_sets: vec![
|
||||
CapabilitySet::General(decode(CLIENT_GENERAL_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::Bitmap(decode(CLIENT_BITMAP_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::Order(decode(CLIENT_ORDER_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::BitmapCacheRev2(decode(CLIENT_BITMAP_CACHE_REV_2_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::ColorCache(CLIENT_COLOR_CACHE_CAPABILITY_SET.to_vec()),
|
||||
CapabilitySet::WindowActivation(CLIENT_WINDOW_ACTIVATION_CAPABILITY_SET.to_vec()),
|
||||
CapabilitySet::Control(CLIENT_CONTROL_CAPABILITY_SET.to_vec()),
|
||||
CapabilitySet::Pointer(decode(CLIENT_POINTER_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::Share(CLIENT_SHARE_CAPABILITY_SET.to_vec()),
|
||||
CapabilitySet::Input(decode(CLIENT_INPUT_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::Sound(decode(CLIENT_SOUND_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::Font(CLIENT_FONT_CAPABILITY_SET.to_vec()),
|
||||
CapabilitySet::GlyphCache(decode(CLIENT_GLYPH_CACHE_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::Brush(decode(CLIENT_BRUSH_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::OffscreenBitmapCache(decode(CLIENT_OFFSCREEN_BITMAP_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::VirtualChannel(decode(CLIENT_VIRTUAL_CHANNEL_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::DrawNineGridCache(CLIENT_DRAW_NINE_GRID_CACHE_CAPABILITY_SET.to_vec()),
|
||||
CapabilitySet::DrawGdiPlus(CLIENT_DRAW_GDI_PLUS_CAPABILITY_SET.to_vec()),
|
||||
],
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
pub static CLIENT_DEMAND_ACTIVE: LazyLock<ClientConfirmActive> = LazyLock::new(|| ClientConfirmActive {
|
||||
originator_id: SERVER_CHANNEL_ID,
|
||||
pdu: DemandActive {
|
||||
source_descriptor: String::from("MSTSC"),
|
||||
capability_sets: vec![
|
||||
CapabilitySet::General(decode(CLIENT_GENERAL_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::Bitmap(decode(CLIENT_BITMAP_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::Order(decode(CLIENT_ORDER_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::BitmapCacheRev2(decode(CLIENT_BITMAP_CACHE_REV_2_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::ColorCache(CLIENT_COLOR_CACHE_CAPABILITY_SET.to_vec()),
|
||||
CapabilitySet::WindowActivation(CLIENT_WINDOW_ACTIVATION_CAPABILITY_SET.to_vec()),
|
||||
CapabilitySet::Control(CLIENT_CONTROL_CAPABILITY_SET.to_vec()),
|
||||
CapabilitySet::Pointer(decode(CLIENT_POINTER_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::Share(CLIENT_SHARE_CAPABILITY_SET.to_vec()),
|
||||
CapabilitySet::Input(decode(CLIENT_INPUT_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::Sound(decode(CLIENT_SOUND_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::Font(CLIENT_FONT_CAPABILITY_SET.to_vec()),
|
||||
CapabilitySet::GlyphCache(decode(CLIENT_GLYPH_CACHE_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::Brush(decode(CLIENT_BRUSH_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::OffscreenBitmapCache(decode(CLIENT_OFFSCREEN_BITMAP_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::VirtualChannel(decode(CLIENT_VIRTUAL_CHANNEL_CAPABILITY_SET.as_ref()).unwrap()),
|
||||
CapabilitySet::DrawNineGridCache(CLIENT_DRAW_NINE_GRID_CACHE_CAPABILITY_SET.to_vec()),
|
||||
CapabilitySet::DrawGdiPlus(CLIENT_DRAW_GDI_PLUS_CAPABILITY_SET.to_vec()),
|
||||
],
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use ironrdp_pdu::rdp::client_info::{
|
||||
AddressFamily, ClientInfo, ClientInfoFlags, CompressionType, Credentials, DayOfWeek, DayOfWeekOccurrence,
|
||||
ExtendedClientInfo, ExtendedClientOptionalInfo, Month, OptionalSystemTime, PerformanceFlags, SystemTime,
|
||||
|
|
@ -81,75 +83,73 @@ pub const CLIENT_INFO_BUFFER_ANSI: [u8; 301] = [
|
|||
0x01, 0x00, 0x00, 0x00, // performance flags
|
||||
];
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref CLIENT_INFO_UNICODE: ClientInfo = ClientInfo {
|
||||
code_page: 0x0409_0409,
|
||||
flags: ClientInfoFlags::MOUSE
|
||||
| ClientInfoFlags::DISABLE_CTRL_ALT_DEL
|
||||
| ClientInfoFlags::UNICODE
|
||||
| ClientInfoFlags::MAXIMIZE_SHELL
|
||||
| ClientInfoFlags::COMPRESSION
|
||||
| ClientInfoFlags::ENABLE_WINDOWS_KEY
|
||||
| ClientInfoFlags::FORCE_ENCRYPTED_CS_PDU,
|
||||
compression_type: CompressionType::K64,
|
||||
credentials: Credentials {
|
||||
username: String::from("eltons"),
|
||||
password: String::from(""),
|
||||
domain: Some(String::from("NTDEV"))
|
||||
},
|
||||
alternate_shell: String::from(""),
|
||||
work_dir: String::from(""),
|
||||
extra_info: ExtendedClientInfo {
|
||||
address_family: AddressFamily::INET,
|
||||
address: String::from("157.59.242.156"),
|
||||
dir: String::from("C:\\depots\\w2k3_1\\termsrv\\newclient\\lib\\win32\\obj\\i386\\mstscax.dll"),
|
||||
optional_data: ExtendedClientOptionalInfo::builder()
|
||||
.timezone(TimezoneInfo {
|
||||
bias: 480,
|
||||
standard_name: String::from("Pacific Standard Time"),
|
||||
standard_date: OptionalSystemTime(Some(SystemTime {
|
||||
month: Month::October,
|
||||
day_of_week: DayOfWeek::Sunday,
|
||||
day: DayOfWeekOccurrence::Last,
|
||||
hour: 2,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
milliseconds: 0,
|
||||
})),
|
||||
standard_bias: 0,
|
||||
daylight_name: String::from("Pacific Daylight Time"),
|
||||
daylight_date: OptionalSystemTime(Some(SystemTime {
|
||||
month: Month::April,
|
||||
day_of_week: DayOfWeek::Sunday,
|
||||
day: DayOfWeekOccurrence::First,
|
||||
hour: 2,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
milliseconds: 0,
|
||||
})),
|
||||
daylight_bias: -60,
|
||||
})
|
||||
.session_id(0)
|
||||
.performance_flags(PerformanceFlags::DISABLE_WALLPAPER)
|
||||
.build(),
|
||||
},
|
||||
};
|
||||
pub static CLIENT_INFO_UNICODE: LazyLock<ClientInfo> = LazyLock::new(|| ClientInfo {
|
||||
code_page: 0x0409_0409,
|
||||
flags: ClientInfoFlags::MOUSE
|
||||
| ClientInfoFlags::DISABLE_CTRL_ALT_DEL
|
||||
| ClientInfoFlags::UNICODE
|
||||
| ClientInfoFlags::MAXIMIZE_SHELL
|
||||
| ClientInfoFlags::COMPRESSION
|
||||
| ClientInfoFlags::ENABLE_WINDOWS_KEY
|
||||
| ClientInfoFlags::FORCE_ENCRYPTED_CS_PDU,
|
||||
compression_type: CompressionType::K64,
|
||||
credentials: Credentials {
|
||||
username: String::from("eltons"),
|
||||
password: String::from(""),
|
||||
domain: Some(String::from("NTDEV")),
|
||||
},
|
||||
alternate_shell: String::from(""),
|
||||
work_dir: String::from(""),
|
||||
extra_info: ExtendedClientInfo {
|
||||
address_family: AddressFamily::INET,
|
||||
address: String::from("157.59.242.156"),
|
||||
dir: String::from("C:\\depots\\w2k3_1\\termsrv\\newclient\\lib\\win32\\obj\\i386\\mstscax.dll"),
|
||||
optional_data: ExtendedClientOptionalInfo::builder()
|
||||
.timezone(TimezoneInfo {
|
||||
bias: 480,
|
||||
standard_name: String::from("Pacific Standard Time"),
|
||||
standard_date: OptionalSystemTime(Some(SystemTime {
|
||||
month: Month::October,
|
||||
day_of_week: DayOfWeek::Sunday,
|
||||
day: DayOfWeekOccurrence::Last,
|
||||
hour: 2,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
milliseconds: 0,
|
||||
})),
|
||||
standard_bias: 0,
|
||||
daylight_name: String::from("Pacific Daylight Time"),
|
||||
daylight_date: OptionalSystemTime(Some(SystemTime {
|
||||
month: Month::April,
|
||||
day_of_week: DayOfWeek::Sunday,
|
||||
day: DayOfWeekOccurrence::First,
|
||||
hour: 2,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
milliseconds: 0,
|
||||
})),
|
||||
daylight_bias: -60,
|
||||
})
|
||||
.session_id(0)
|
||||
.performance_flags(PerformanceFlags::DISABLE_WALLPAPER)
|
||||
.build(),
|
||||
},
|
||||
});
|
||||
|
||||
pub static ref CLIENT_INFO_ANSI: ClientInfo = {
|
||||
let mut client_info = CLIENT_INFO_UNICODE.clone();
|
||||
client_info.flags -= ClientInfoFlags::UNICODE;
|
||||
client_info
|
||||
};
|
||||
pub static CLIENT_INFO_ANSI: LazyLock<ClientInfo> = LazyLock::new(|| {
|
||||
let mut client_info = CLIENT_INFO_UNICODE.clone();
|
||||
client_info.flags -= ClientInfoFlags::UNICODE;
|
||||
client_info
|
||||
});
|
||||
|
||||
pub static ref CLIENT_INFO_UNICODE_WITHOUT_OPTIONAL_FIELDS: ClientInfo = {
|
||||
let mut client_info = CLIENT_INFO_UNICODE.clone();
|
||||
client_info.extra_info.optional_data = ExtendedClientOptionalInfo::default();
|
||||
client_info
|
||||
};
|
||||
pub static CLIENT_INFO_UNICODE_WITHOUT_OPTIONAL_FIELDS: LazyLock<ClientInfo> = LazyLock::new(|| {
|
||||
let mut client_info = CLIENT_INFO_UNICODE.clone();
|
||||
client_info.extra_info.optional_data = ExtendedClientOptionalInfo::default();
|
||||
client_info
|
||||
});
|
||||
|
||||
pub static ref CLIENT_INFO_BUFFER_UNICODE_WITHOUT_OPTIONAL_FIELDS: Vec<u8> = {
|
||||
let mut buffer = CLIENT_INFO_BUFFER_UNICODE.to_vec();
|
||||
buffer.truncate(CLIENT_INFO_BUFFER_UNICODE_WITHOUT_OPTIONAL_FIELDS_LEN);
|
||||
buffer
|
||||
};
|
||||
}
|
||||
pub static CLIENT_INFO_BUFFER_UNICODE_WITHOUT_OPTIONAL_FIELDS: LazyLock<Vec<u8>> = LazyLock::new(|| {
|
||||
let mut buffer = CLIENT_INFO_BUFFER_UNICODE.to_vec();
|
||||
buffer.truncate(CLIENT_INFO_BUFFER_UNICODE_WITHOUT_OPTIONAL_FIELDS_LEN);
|
||||
buffer
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use ironrdp_pdu::gcc::{ClientClusterData, RedirectionFlags, RedirectionVersion};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
pub const CLUSTER_DATA_BUFFER: [u8; 8] = [0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
|
||||
|
||||
lazy_static! {
|
||||
pub static ref CLUSTER_DATA: ClientClusterData = ClientClusterData {
|
||||
flags: RedirectionFlags::REDIRECTION_SUPPORTED,
|
||||
redirection_version: RedirectionVersion::V4,
|
||||
redirected_session_id: 0,
|
||||
};
|
||||
}
|
||||
pub static CLUSTER_DATA: LazyLock<ClientClusterData> = LazyLock::new(|| ClientClusterData {
|
||||
flags: RedirectionFlags::REDIRECTION_SUPPORTED,
|
||||
redirection_version: RedirectionVersion::V4,
|
||||
redirected_session_id: 0,
|
||||
});
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue