Private/Threat.Text.ps1

function New-OIUnicodeScalarMap {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [AllowEmptyString()]
        [string]$Text
    )

    $pairStarts = New-Object 'System.Collections.Generic.List[System.Int32]'
    $index = 0
    while ($index -lt $Text.Length) {
        if ([char]::IsHighSurrogate($Text[$index]) -and
            ($index + 1) -lt $Text.Length -and
            [char]::IsLowSurrogate($Text[$index + 1])) {
            $pairStarts.Add($index)
            $index += 2
        }
        else {
            $index++
        }
    }

    return [pscustomobject]@{
        TextLength       = [int]$Text.Length
        SurrogatePairs   = $pairStarts.ToArray()
        UnicodeScalarCount = [int64]$Text.Length - [int64]$pairStarts.Count
    }
}

function Get-OISurrogatePairCountBefore {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [AllowEmptyCollection()]
        [int[]]$PairStarts,

        [Parameter(Mandatory = $true)]
        [ValidateScript({ $_ -ge 0 })]
        [int]$Utf16PrefixLength
    )

    $low = 0
    $high = $PairStarts.Length
    while ($low -lt $high) {
        $midpoint = $low + [int][Math]::Floor(($high - $low) / 2)
        if ($PairStarts[$midpoint] -lt $Utf16PrefixLength) {
            $low = $midpoint + 1
        }
        else {
            $high = $midpoint
        }
    }

    return $low
}

function ConvertTo-OIUtf16PrefixLength {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [object]$ScalarMap,

        [Parameter(Mandatory = $true)]
        [ValidateScript({ $_ -ge 0 })]
        [int64]$UnicodeScalarPrefixLength
    )

    if ($UnicodeScalarPrefixLength -gt $ScalarMap.UnicodeScalarCount) {
        throw "Unicode scalar prefix length $UnicodeScalarPrefixLength exceeds content length $($ScalarMap.UnicodeScalarCount)."
    }

    if ($UnicodeScalarPrefixLength -eq 0) { return 0 }

    $pairStarts = [int[]]$ScalarMap.SurrogatePairs
    $low = [int]$UnicodeScalarPrefixLength
    $high = [int]($UnicodeScalarPrefixLength + $pairStarts.Length)

    while ($low -lt $high) {
        $midpoint = $low + [int][Math]::Floor(($high - $low) / 2)
        $pairCount = Get-OISurrogatePairCountBefore -PairStarts $pairStarts -Utf16PrefixLength $midpoint
        $scalarCount = $midpoint - $pairCount

        if ($scalarCount -ge $UnicodeScalarPrefixLength) {
            $high = $midpoint
        }
        else {
            $low = $midpoint + 1
        }
    }

    return $low
}

function Get-OIStrictEncoding {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [System.Text.Encoding]$Encoding
    )

    return [System.Text.Encoding]::GetEncoding(
        $Encoding.CodePage,
        [System.Text.EncoderFallback]::ExceptionFallback,
        [System.Text.DecoderFallback]::ExceptionFallback
    )
}