Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions src/Convert/Public/ConvertFrom-Base64ToString.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,19 @@ function ConvertFrom-Base64ToString {
$ptr = [ConvertCoreInterop]::base64_to_string($s, $Encoding)

if ($ptr -eq $nullPtr) {
$errorMsg = GetRustError -DefaultMessage "Base64 decoding failed for encoding '$Encoding'"
throw $errorMsg
$rustError = GetRustError -DefaultMessage ''
if ($rustError -match 'Invalid UTF-8|Invalid ASCII|Invalid UTF-16|Invalid UTF-32') {
# Binary data - fall back to Latin-1 which can represent any byte
$bytes = [System.Convert]::FromBase64String($s)
[System.Text.Encoding]::GetEncoding('ISO-8859-1').GetString($bytes)
} elseif ($rustError) {
throw $rustError
} else {
throw "Base64 decoding failed for encoding '$Encoding'"
}
} else {
ConvertPtrToString -Ptr $ptr
}

ConvertPtrToString -Ptr $ptr
} finally {
if ($ptr -ne $nullPtr) {
[ConvertCoreInterop]::free_string($ptr)
Expand Down
39 changes: 22 additions & 17 deletions src/Convert/Public/ConvertTo-String.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -133,33 +133,38 @@ function ConvertTo-String {
}

process {
$splat = @{}
switch ($PSCmdlet.ParameterSetName) {
'Base64String' {
$InputObject = $Base64EncodedString
$Function = 'ConvertFrom-Base64ToString'
$splat.Add('Encoding', $Encoding)
if ($Decompress) {
$splat.Add('Decompress', $true)
foreach ($b64 in $Base64EncodedString) {
try {
if ($Decompress) {
$b64 | ConvertFrom-Base64ToString -Encoding $Encoding -Decompress -ErrorAction Stop
} else {
try {
ConvertFrom-Base64ToString -String $b64 -Encoding $Encoding -ErrorAction Stop
} catch {
if ($_.Exception.Message -match 'does not represent valid .+ text') {
# Binary data - fall back to Latin-1 which can represent any byte
$bytes = [System.Convert]::FromBase64String($b64)
[System.Text.Encoding]::GetEncoding('ISO-8859-1').GetString($bytes)
} else {
throw
}
}
}
} catch {
Write-Error -ErrorRecord $_ -ErrorAction $userErrorActionPreference
}
}
break
}

'MemoryStream' {
$InputObject = $MemoryStream
$Function = 'ConvertFrom-MemoryStreamToString'
break
$MemoryStream | ConvertFrom-MemoryStreamToString -ErrorAction $userErrorActionPreference
}

'Stream' {
$InputObject = $Stream
$Function = 'ConvertFrom-MemoryStreamToString'
break
$Stream | ConvertFrom-MemoryStreamToString -ErrorAction $userErrorActionPreference
}
}

if ($InputObject) {
$InputObject | & $Function @splat -ErrorAction $userErrorActionPreference
}
}
}
20 changes: 20 additions & 0 deletions src/Tests/Unit/ConvertFrom-Base64ToString.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,26 @@ Describe -Name $function -Fixture {
$base64 = 'SGVsbG8'
{ ConvertFrom-Base64ToString -String $base64 -Encoding 'UTF8' -ErrorAction Stop } | Should -Throw
}

It -Name 'Converts binary data (non-UTF8) without error' -Test {
$binaryBytes = [byte[]](0xA1, 0x59, 0xC0, 0xA5, 0xE4, 0x94, 0xFF, 0x00, 0x80)
$base64 = [System.Convert]::ToBase64String($binaryBytes)

$result = ConvertFrom-Base64ToString -String $base64

$result | Should -Not -BeNullOrEmpty
$result | Should -BeOfType [string]
}

It -Name 'Round-trips binary data through Latin-1 fallback' -Test {
$binaryBytes = [byte[]](0xA1, 0x59, 0xC0, 0xA5, 0xE4, 0x94, 0xFF, 0x00, 0x80)
$base64 = [System.Convert]::ToBase64String($binaryBytes)

$resultString = ConvertFrom-Base64ToString -String $base64
$resultBytes = [System.Text.Encoding]::GetEncoding('ISO-8859-1').GetBytes($resultString)

$resultBytes | Should -Be $binaryBytes
}
}

Context -Name 'Error Handling' -Fixture {
Expand Down
21 changes: 21 additions & 0 deletions src/Tests/Unit/ConvertTo-String.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,27 @@ Describe -Name $function -Fixture {

$assertion | Should -BeExactly $String
}

It -Name 'Converts binary data (non-UTF8) without error' -Test {
# Binary data that is not valid UTF-8 (e.g., certificate/image data)
$binaryBytes = [byte[]](0xA1, 0x59, 0xC0, 0xA5, 0xE4, 0x94, 0xFF, 0x00, 0x80)
$base64 = [System.Convert]::ToBase64String($binaryBytes)

$assertion = ConvertTo-String -Base64EncodedString $base64

$assertion | Should -Not -BeNullOrEmpty
$assertion | Should -BeOfType [string]
}

It -Name 'Round-trips binary data through Latin-1 fallback' -Test {
$binaryBytes = [byte[]](0xA1, 0x59, 0xC0, 0xA5, 0xE4, 0x94, 0xFF, 0x00, 0x80)
$base64 = [System.Convert]::ToBase64String($binaryBytes)

$resultString = ConvertTo-String -Base64EncodedString $base64
$resultBytes = [System.Text.Encoding]::GetEncoding('ISO-8859-1').GetBytes($resultString)

$resultBytes | Should -Be $binaryBytes
}
}

Context -Name 'MemoryStream input' -Fixture {
Expand Down