Public/Validation/Test-AssFile.ps1
|
function Test-AssFile { <# .SYNOPSIS Validates the structure and content of an ASS/SSA file or SubtitleFile object. .DESCRIPTION Checks: mandatory sections present, ScriptType field, styles exist, event timestamps valid, no unclosed override tags. .PARAMETER Path Path to an ASS or SSA file. .PARAMETER InputObject A SubtitleFile object. .EXAMPLE Test-AssFile -Path 'anime.ass' #> [CmdletBinding(DefaultParameterSetName = 'Path')] [OutputType('ValidationResult')] param( [Parameter(Mandatory, ParameterSetName = 'Path')] [string] $Path, [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'Object')] [SubtitleFile] $InputObject ) process { if ($PSCmdlet.ParameterSetName -eq 'Path') { $InputObject = Import-SubtitleFile -Path $Path } $result = [ValidationResult]::new() $result.FilePath = $InputObject.Path $result.Format = $InputObject.Format # Must have a Header if (-not $InputObject.Header) { $result.AddError(0, 'Structure', 'Missing [Script Info] section — Header is null.') return $result } # Must have at least one style if ($InputObject.Header.Styles.Count -eq 0) { $result.AddError(0, 'Styles', 'No styles defined in [V4+ Styles] section.') } # Parser warnings foreach ($key in $InputObject.ParserWarnings.Keys) { $result.AddWarning($key, 'Parse', $InputObject.ParserWarnings[$key]) } $prevEnd = [TimeSpan]::Zero foreach ($entry in $InputObject.Entries) { $i = $entry.Index # Timestamp validity if ($entry.End -le $entry.Start) { $result.AddError($i, 'Timestamp', "End ($($entry.End)) is not after Start ($($entry.Start)).") } if ($entry.Start -lt [TimeSpan]::Zero) { $result.AddError($i, 'Timestamp', "Negative start time: $($entry.Start).") } # Unclosed override tags (odd number of braces is a sign of malformation) $rawText = $entry.RawText if ($rawText -match '\{[^}]*$') { $result.AddWarning($i, 'OverrideTag', "Possible unclosed override tag in: '$rawText'") } # Style reference exists if ($entry -is [AssEntry]) { $styleName = $entry.Style $styleExists = $InputObject.Header.Styles | Where-Object { $_.Name -eq $styleName } if (-not $styleExists) { $result.AddWarning($i, 'Style', "Entry references undefined style '$styleName'.") } } # Overlap if ($entry.Start -lt $prevEnd) { $result.AddWarning($i, 'Overlap', "Entry $i starts ($($entry.Start)) before previous ends ($prevEnd).") } $prevEnd = $entry.End } return $result } } |