PowerShell 读取 MSZIP 压缩的 mszyml

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 | 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 | # 错误强制停止 $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 # 检查文件头是否为 MSZIP 格式 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 { # Write-Warning "解压错误: chunkIndex: $chunkIndex, $_" break } $chunkIndex++ } } end { # 在所有输入处理完毕后执行清理工作 $decompressed.Position = 0 $reader = [System.IO.StreamReader]::new($decompressed) $reader.ReadToEnd() } } |
示例
例1
1 | $buffer = [System.IO.File]::ReadAllBytes(".\versionData.mszyml") $decompressedData = ConvertFrom-MSZIP -buffer $buffer $decompressedData |
例2
1 | $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