Private/Test-NSPScanBridgePdfStructure.ps1

function Test-NSPScanBridgePdfStructure {
    <#
    .SYNOPSIS
        Checks for a PDF header near the start and an end-of-file marker near the end.
    .DESCRIPTION
        A structural completeness heuristic, not a parser: it does not prove the document renders.
        Reads at most two 1024-byte windows from a caller-owned seekable stream and leaves it open.
    #>

    [CmdletBinding()]
    param([Parameter(Mandatory)][IO.Stream]$Stream)
    $window = 1024
    $length = $Stream.Length
    $headLength = [int][math]::Min([long]$window, $length)
    $head = New-Object byte[] $headLength
    [void]$Stream.Seek(0, [IO.SeekOrigin]::Begin)
    $read = 0
    while ($read -lt $headLength) { $n = $Stream.Read($head, $read, $headLength - $read); if ($n -le 0) { break }; $read += $n }
    $tailLength = [int][math]::Min([long]$window, $length)
    $tail = New-Object byte[] $tailLength
    [void]$Stream.Seek($length - $tailLength, [IO.SeekOrigin]::Begin)
    $read = 0
    while ($read -lt $tailLength) { $n = $Stream.Read($tail, $read, $tailLength - $read); if ($n -le 0) { break }; $read += $n }
    # Latin-1 maps every byte to one character, so offsets survive binary content.
    $latin1 = [Text.Encoding]::GetEncoding(28591)
    $hasHeader = $latin1.GetString($head).Contains('%PDF-')
    $hasTrailer = $latin1.GetString($tail).Contains('%%EOF')
    $reasons = @()
    if (-not $hasHeader) { $reasons += 'MissingHeader' }
    if (-not $hasTrailer) { $reasons += 'MissingEndOfFile' }
    [pscustomobject]@{ Complete = ($reasons.Count -eq 0); HasHeader = $hasHeader; HasEndOfFile = $hasTrailer; Reasons = $reasons }
}