Utils/sum.ps1

Register-GnuUtil @{
    Name         = 'sum'
    Category     = 'Checksums'
    Synopsis     = 'Checksum and count the blocks in a file.'
    Usage        = @('sum [OPTION]... [FILE]...')
    Description  = @('Print or check BSD (16-bit) checksums.', '', 'With no FILE, or when FILE is -, read standard input.')
    FileOperands = $true
    Options      = @(
        @{ Short = 'r'; Key = 'algorithm'; Value = 'bsd'; Help = 'use BSD sum algorithm (the default), use 1K blocks' }
        @{ Short = 's'; Long = 'sysv'; Key = 'algorithm'; Value = 'sysv'; Help = 'use System V sum algorithm, use 512 bytes blocks' }
    )
}



function script:Get-GnuSumLine {
    <#
    .SYNOPSIS
    "CHECKSUM BLOCKS" as printed by sum -r (BSD) or sum -s (System V), without the file name.
    #>

    param([Parameter(Mandatory)][AllowEmptyCollection()][byte[]]$Bytes, [switch]$SysV)

    if ($SysV) {
        $total = [long]0
        foreach ($byte in $Bytes) { $total = ($total + $byte) -band 0xFFFFFFFFL }
        $folded = ($total -band 0xFFFF) + (($total -shr 16) -band 0xFFFF)
        return "$(($folded -band 0xFFFF) + ($folded -shr 16)) $([long][Math]::Ceiling($Bytes.Length / 512))"
    }
    $checksum = 0
    foreach ($byte in $Bytes) { $checksum = (($checksum -shr 1) + (($checksum -band 1) -shl 15) + $byte) -band 0xFFFF }
    ([string]$checksum).PadLeft(5, '0') + ' ' + ([string][long][Math]::Ceiling($Bytes.Length / 1024)).PadLeft(5)
}