internal/functions/parse-font.ps1
<# .SYNOPSIS Parses data from a FIGlet font file and stores it in the global FIGlet fonts hashtable. .DESCRIPTION This function processes the raw data of a FIGlet font file, normalizes its line endings, and extracts metadata such as height, baseline, layout, and smushing rules. The parsed font data is stored in the global `$Script:FigFonts` hashtable under the specified font name. It also validates the header data to ensure the font file is correctly formatted. .PARAMETER FontName The name of the FIGlet font being parsed. This is used as the key in the `$Script:FigFonts` hashtable. .PARAMETER FontData The raw data of the FIGlet font file as a string. This data is parsed to extract font metadata and options. .EXAMPLE $FontName = "Standard" $FontData = Get-Content -Path "C:\Fonts\Standard.flf" -Raw Parse-Font -FontName $FontName -FontData $FontData This example parses the "Standard" FIGlet font file and stores its metadata and options in the global `$Script:FigFonts` hashtable. .NOTES This function relies on the `Get-SmushingRules` helper function to calculate smushing rules based on the font's layout values. It validates the header data to ensure the font file is properly formatted. Author: Oleksandr Nikolaiev (@onikolaiev) #> function Parse-Font { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] param ( [string]$FontName, # Name of the font [string]$FontData # Data from the FIGlet font file ) # Normalize line endings $FontData = "$FontData" -replace "`r`n", "`n" -replace "`r", "`n" $Script:FigFonts[$FontName] = @{} $lines = $FontData -split "`n" $headerData = ($lines[0] -split " ") $lines = $lines[1..($lines.Count - 1)] $figFont = $Script:FigFonts[$FontName] $opts = @{} # Parse header data $opts.hardBlank = $headerData[0].Substring(5, 1) $opts.height = [int]$headerData[1] $opts.baseline = [int]$headerData[2] $opts.maxLength = [int]$headerData[3] $opts.oldLayout = if([int]$headerData[4] -eq 0) { -1 } else { [int]$headerData[4] } $opts.numCommentLines = [int]$headerData[5] $opts.printDirection = if ($headerData.Count -ge 7) { [int]$headerData[6] } else { 0 } $opts.fullLayout = if ($headerData.Count -ge 8) { [int]$headerData[7] } else { $null } $opts.codeTagCount = if ($headerData.Count -ge 9) { [int]$headerData[8] } else { $null } $opts.fittingRules = Get-SmushingRules -oldLayout $opts.oldLayout -fullLayout $opts.fullLayout $figFont.options = $opts # Error check if ( $opts.hardBlank.Length -ne 1 -or -not $opts.height -or -not $opts.baseline -or -not $opts.maxLength -or -not $opts.oldLayout -or -not $opts.numCommentLines ) { throw "FIGlet header contains invalid values." } # Define required character codes $charNums = @(32..126) + @(196, 214, 220, 228, 246, 252, 223) # Error check - validate that there are enough lines in the file if ($lines.Count -lt ($opts.numCommentLines + $opts.height * $charNums.Count)) { throw "FIGlet file is missing data." } # Parse the font data $figFont.comment = ($lines[0..($opts.numCommentLines - 1)] -join "`n") $lines = $lines[$opts.numCommentLines..($lines.Count - 1)] $figFont.numChars = 0 while ($lines.Count -gt 0 -and $figFont.numChars -lt $charNums.Count) { $cNum = $charNums[$figFont.numChars] $figFont[$cNum] = $lines[0..($opts.height - 1)] $lines = $lines[$opts.height..($lines.Count - 1)] # Remove end sub-chars for ($ii = 0; $ii -lt $opts.height; $ii++) { if (-not $figFont[$cNum][$ii]) { $figFont[$cNum][$ii] = "" } else { $endChar = [regex]::Escape($figFont[$cNum][$ii].Substring($figFont[$cNum][$ii].Length - 1, 1)) $figFont[$cNum][$ii] = $figFont[$cNum][$ii] -replace "$endChar+$", "" } } $figFont.numChars++ } # Parse additional characters $parseError = $false while ($lines.Count -gt 0) { $cNum = ($lines[0] -split " ")[0] $lines = $lines[1..($lines.Count - 1)] if ($cNum -match "^0[xX][0-9a-fA-F]+$") { $cNum = [int]::Parse($cNum.Substring(2), [System.Globalization.NumberStyles]::HexNumber) } elseif ($cNum -match "^0[0-7]+$") { $cNum = [int]::Parse($cNum, [System.Globalization.NumberStyles]::None) } elseif ($cNum -match "^[0-9]+$") { $cNum = [int]$cNum } elseif ($cNum -match "^-0[xX][0-9a-fA-F]+$") { $cNum = -[int]::Parse($cNum.Substring(3), [System.Globalization.NumberStyles]::HexNumber) } else { if ($cNum -eq "") { break } Write-PSFMessage -Level Host -Message "Invalid data: $cNum" -ForegroundColor Red $parseError = $true break } $figFont[$cNum] = $lines[0..($opts.height - 1)] $lines = $lines[$opts.height..($lines.Count - 1)] # Remove end sub-chars for ($ii = 0; $ii -lt $opts.height; $ii++) { if (-not $figFont[$cNum][$ii]) { $figFont[$cNum][$ii] = "" } else { $endChar = [regex]::Escape($figFont[$cNum][$ii].Substring($figFont[$cNum][$ii].Length - 1, 1)) $figFont[$cNum][$ii] = $figFont[$cNum][$ii] -replace "$endChar+$", "" } } $figFont.numChars++ } # Error check if ($parseError) { throw "Error parsing data." } return $figFont } |