技术笔记PowerShell 读取 MSZIP 压缩的 mszyml
狂犬主子PowerShell 读取 MSZIP 压缩的 mszyml
由于本人在研究 winget-cli 的过程中发现了一种格式(.mszyml
,application/x-ms-zip-yaml
),显而易见为 MSZIP 算法压缩的 YAML 格式。
经过查询资料,MSZIP 的压缩块与 RFC1951(DEFLATE)类似,并且这背后貌似有一些早在DOS时代的历史原因导致没解决方案,不过目前这个问题早就得以解决,可以使用 .NET System.IO.Compression
命名空间的 DeflateStream
类来实现,除了C++直接调用 Win32 API 外,其它编程语言也有通过 Zlib
来实现。
PowerShell 暂时没有合适的解压代码,这里就让能工智人参考着搓了一个,并且根据实际需要做了一些修改。代码可能没处理周到,对输入内容的要求会有点高。
本文编写时的环境如下,不保证支持老版本的 PowerShell:
1 2 3 4 5 6 7 8 9 10 11 12 13
| PS D:\> $PSVersionTable
Name Value ---- ----- PSVersion 7.4.5 PSEdition Core GitCommitId 7.4.5 OS Microsoft Windows 10.0.22631 Platform Win32NT PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…} PSRemotingProtocolVersion 2.3 SerializationVersion 1.1.0.1 WSManStackVersion 3.0
|
函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| $ErrorActionPreference = "Stop"
Add-Type -AssemblyName System.IO.Compression.FileSystem
function ConvertFrom-MSZIP { param ( [Parameter(ValueFromPipeline=$true)] [byte[]]$buffer )
begin { $magicHeader = [byte[]](0, 0, 0x43, 0x4b) $decompressed = [System.IO.MemoryStream]::new() }
process { Add-Type -AssemblyName System.IO.Compression.FileSystem if (-not ($buffer[26..29] -join ',') -eq ($magicHeader -join ',')) { throw "Invalid MSZIP format" }
$chunkIndex = 26
$bufferStream = [System.IO.MemoryStream]::new($buffer)
while ($chunkIndex -lt $buffer.Length) { $chunkIndex += $magicHeader.Length $bufferStream.Position = $chunkIndex try { $decompressedChunk = New-Object System.IO.Compression.DeflateStream($bufferStream, [System.IO.Compression.CompressionMode]::Decompress) $decompressedChunk.CopyTo($decompressed) } catch { break } $chunkIndex++ } }
end { $decompressed.Position = 0 $reader = [System.IO.StreamReader]::new($decompressed) $reader.ReadToEnd() } }
|
示例
例1
1 2 3
| $buffer = [System.IO.File]::ReadAllBytes(".\versionData.mszyml") $decompressedData = ConvertFrom-MSZIP -buffer $buffer $decompressedData
|
例2
1 2 3 4 5
| $buffer = (Invoke-WebRequest "https://cdn.winget.microsoft.com/cache/packages/Seewo.EasiNote/3e5b908d/versionData.mszyml").Content $versionData = (ConvertFrom-MSZIP -buffer $buffer | ConvertFrom-Yaml).vD[0] Write-Host "RelativePath: " $versionData.rP Write-Host "Version: " $versionData.v Write-Host "Sha256Hash: " $versionData.s256H
|
参考
https://learn.microsoft.com/zh-cn/windows/win32/cmpapi/using-the-compression-api
https://learn.microsoft.com/zh-cn/windows/win32/api/compressapi/nf-compressapi-createcompressor
https://learn.microsoft.com/zh-cn/dotnet/api/system.io.compression.deflatestream
https://github.com/frereit/pymszip
https://github.com/masihyeganeh/mszip
https://github.com/ustclug/ustcmirror-images/blob/master/winget-source/utilities.js
https://stackoverflow.com/questions/19370304/how-to-decompress-mszip-files-with-c