Private/Get-ExtensionByContent.ps1
|
function Test-FoBufferBytes { param( [byte[]]$Buffer, [int]$Offset, [byte[]]$Pattern ) if ($null -eq $Buffer -or $null -eq $Pattern) { return $false } if ($Offset -lt 0 -or $Pattern.Length -eq 0) { return $false } if ($Buffer.Length -lt ($Offset + $Pattern.Length)) { return $false } for ($i = 0; $i -lt $Pattern.Length; $i++) { if ($Buffer[$Offset + $i] -ne $Pattern[$i]) { return $false } } return $true } function Test-FoBufferAscii { param( [byte[]]$Buffer, [int]$Offset, [string]$Text ) $pattern = [System.Text.Encoding]::ASCII.GetBytes($Text) return Test-FoBufferBytes -Buffer $Buffer -Offset $Offset -Pattern $pattern } function Get-ExtensionByContent { [CmdletBinding()] [OutputType([string])] param( [Parameter(Mandatory)] [string]$Path, [string]$Extension, [switch]$Force, [hashtable]$Settings ) $ext = if ($Extension) { $Extension.ToLowerInvariant() } else { '' } $mapPath = if ($script:FoModuleRoot) { Join-Path $script:FoModuleRoot 'Data\ExtensionMap.psd1' } else { $null } $allExts = @() if ($mapPath -and (Test-Path -LiteralPath $mapPath)) { $allExts = @((Import-FoPsd1File -Path $mapPath).Keys) } if ($Settings -and $Settings.JSAdditionalExtensions) { foreach ($token in ($Settings.JSAdditionalExtensions.Split(',') | ForEach-Object { $_.Trim() } | Where-Object { $_ })) { $normalized = if ($token.StartsWith('.')) { $token.ToLowerInvariant() } else { ('.' + $token).ToLowerInvariant() } if ($normalized -notin $allExts) { $allExts += $normalized } } } $needsDetect = $Force -or -not $ext -or ($ext -notin $allExts) if (-not $needsDetect) { return $ext } if (-not (Test-Path -LiteralPath $Path)) { return $ext } $fs = [System.IO.File]::OpenRead($Path) try { $head = New-Object byte[] 512 $read = $fs.Read($head, 0, 512) if ($read -lt 4) { return '' } $tail = New-Object byte[] 512 $tailRead = 0 if ($fs.Length -gt 0) { $fs.Seek([math]::Max(0, $fs.Length - 512), [System.IO.SeekOrigin]::Begin) | Out-Null $tailRead = $fs.Read($tail, 0, 512) } if (Test-FoBufferAscii -Buffer $head -Offset 4 -Text 'ftyp') { return '.avif' } if (Test-FoBufferAscii -Buffer $head -Offset 0 -Text 'BM') { return '.bmp' } if (Test-FoBufferAscii -Buffer $head -Offset 0 -Text 'BA') { return '.bmp' } if (Test-FoBufferAscii -Buffer $head -Offset 0 -Text 'CI') { return '.bmp' } if (Test-FoBufferAscii -Buffer $head -Offset 0 -Text 'CP') { return '.bmp' } if (Test-FoBufferAscii -Buffer $head -Offset 0 -Text 'IC') { return '.bmp' } if (Test-FoBufferAscii -Buffer $head -Offset 0 -Text 'PT') { return '.bmp' } if (Test-FoBufferAscii -Buffer $head -Offset 0 -Text 'MZ') { return '.dll' } if (Test-FoBufferAscii -Buffer $head -Offset 0 -Text 'ZM') { return '.dll' } if (Test-FoBufferAscii -Buffer $head -Offset 0 -Text 'fLaC') { return '.flac' } if (Test-FoBufferAscii -Buffer $head -Offset 0 -Text 'GIF8') { return '.gif' } if (Test-FoBufferBytes -Buffer $head -Offset 0 -Pattern ([byte[]](0x1F, 0x8B, 0x08))) { return '.gz' } if (Test-FoBufferBytes -Buffer $head -Offset 0 -Pattern ([byte[]](0x00, 0x00, 0x01, 0x00))) { return '.ico' } if (Test-FoBufferAscii -Buffer $head -Offset 4 -Text 'jP') { return '.jp2' } if (Test-FoBufferBytes -Buffer $head -Offset 0 -Pattern ([byte[]](0xFF, 0xD8, 0xFF))) { return '.jpg' } if (Test-FoBufferBytes -Buffer $head -Offset 0 -Pattern ([byte[]](0x00, 0x00, 0x00, 0x0C, 0x4A, 0x58, 0x4C, 0x20, 0x0D, 0x0A, 0x87, 0x0A))) { return '.jxl' } if (Test-FoBufferAscii -Buffer $head -Offset 0 -Text '.RTS') { return '.mkv' } if (Test-FoBufferBytes -Buffer $head -Offset 0 -Pattern ([byte[]](0x8A, 0x4D, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A))) { return '.mng' } if (Test-FoBufferAscii -Buffer $head -Offset 0 -Text 'ID3') { return '.mp3' } if (Test-FoBufferAscii -Buffer $head -Offset 3 -Text 'ftyp') { return '.mp4' } if (Test-FoBufferBytes -Buffer $head -Offset 0 -Pattern ([byte[]](0x4C, 0x01))) { return '.obj' } if ($head[0] -eq 0x80) { return '.obj' } if (Test-FoBufferAscii -Buffer $head -Offset 0 -Text 'OggS') { return '.ogg' } if (Test-FoBufferBytes -Buffer $head -Offset 0 -Pattern ([byte[]](0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1))) { return '.ole' } if (Test-FoBufferBytes -Buffer $head -Offset 0 -Pattern ([byte[]](0x0E, 0x11, 0xFC, 0x0D, 0xD0, 0xCF, 0x11, 0x0E))) { return '.ole' } if ($read -ge 75 -and $head[0] -eq 10 -and $head[2] -eq 1 -and $head[64] -eq 0 -and $head[74] -eq 0) { return '.pcx' } if (Test-FoBufferAscii -Buffer $head -Offset 0 -Text '%PDF-') { return '.pdf' } if (Test-FoBufferBytes -Buffer $head -Offset 0 -Pattern ([byte[]](0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A))) { return '.png' } if (Test-FoBufferAscii -Buffer $head -Offset 0 -Text 'SQLite format 3') { return '.sqlite' } if (Test-FoBufferAscii -Buffer $head -Offset 0 -Text 'FWS') { return '.swf' } if (Test-FoBufferAscii -Buffer $head -Offset 0 -Text 'CWS') { return '.swf' } if (Test-FoBufferAscii -Buffer $head -Offset 0 -Text 'ZWS') { return '.swf' } if ($read -ge 262 -and (Test-FoBufferBytes -Buffer $head -Offset 257 -Pattern ([byte[]](0x75, 0x73, 0x74, 0x61, 0x72)))) { return '.tar' } if ($tailRead -ge 504 -and (Test-FoBufferAscii -Buffer $tail -Offset 494 -Text 'TRUEVISION')) { return '.tga' } if (Test-FoBufferBytes -Buffer $head -Offset 0 -Pattern ([byte[]](0x0C, 0xED))) { return '.tif' } if (Test-FoBufferBytes -Buffer $head -Offset 0 -Pattern ([byte[]](0x49, 0x20, 0x49))) { return '.tif' } if (Test-FoBufferBytes -Buffer $head -Offset 0 -Pattern ([byte[]](0x49, 0x49, 0x2A, 0x00))) { return '.tif' } if (Test-FoBufferBytes -Buffer $head -Offset 0 -Pattern ([byte[]](0x4D, 0x4D, 0x00, 0x2B))) { return '.tif' } if (Test-FoBufferAscii -Buffer $head -Offset 0 -Text 'RIFF') { return '.wav' } if (Test-FoBufferAscii -Buffer $head -Offset 7 -Text 'WEBP') { return '.webp' } if (Test-FoBufferBytes -Buffer $head -Offset 0 -Pattern ([byte[]](0x50, 0x4B, 0x03, 0x04))) { return '.zip' } if (Test-FoBufferAscii -Buffer $head -Offset 0 -Text 'MSCF') { return '.cab' } if (Test-FoBufferBytes -Buffer $head -Offset 0 -Pattern ([byte[]](0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C))) { return '.7z' } } finally { $fs.Dispose() } return '' } function Get-FoExtensionMap { if (-not $script:FoExtensionMap) { $path = Join-Path $script:FoModuleRoot 'Data\ExtensionMap.psd1' $script:FoExtensionMap = Import-FoPsd1File -Path $path } return $script:FoExtensionMap } function Get-FoPipelineGroupsForFile { param( [string]$Path, [hashtable]$Settings ) $pathExt = [System.IO.Path]::GetExtension($Path) $ext = Get-ExtensionByContent -Path $Path -Extension $pathExt -Settings $Settings if (-not $ext) { return @() } $map = Get-FoExtensionMap if ($map -and $map.ContainsKey($ext)) { return @($map[$ext]) } if ($Settings -and $Settings.JSAdditionalExtensions) { foreach ($token in ($Settings.JSAdditionalExtensions.Split(',') | ForEach-Object { $_.Trim() } | Where-Object { $_ })) { $normalized = if ($token.StartsWith('.')) { $token.ToLowerInvariant() } else { ('.' + $token).ToLowerInvariant() } if ($ext -eq $normalized) { return @('JS') } } } return @() } |