Skip to content

Commit acc01a3

Browse files
committed
test(IE): 兼容 net471 上 ZipArchiveEntry.Crc32 不存在
CI matrix 在 windows/net471 job 上真实跑测试, commit 7abb16a 引入了 DrawingsFlush_Tests.cs:196 直接用 entry.Crc32 属性, 但该属性是 .NET Core 2.0+ 才加入, .NET Framework 4.7.1 不存在 → CI Build 步骤失败阻塞 17 个 job. 修复: - net471 上走手算 CRC32 (zip 规范 IEEE 802.3, poly=0xEDB88320 reflected) - 其他 TFM 继续用原生 ZipArchiveEntry.Crc32 属性 - 表按 poly 运行时生成, 避免硬编码 256 项引入抄写错误 - 算法循环风格对齐 dotnet/runtime Crc32ParameterSet.UpdateScalar 验证: - 字节级一致: System.IO.Hashing.Crc32 vs 手算 (11 个样本 + png 实测) - 真实 zip entry: entry.Crc32 vs Hashing.Crc32 vs 手算 stream (四路一致) - 5 个 TFM 编译通过; net8.0 上 4/4 测试通过 - net471 runtime 验证: CI windows/net471 job 实际执行 (本机 macOS 无 .NET Framework 4.7.1 SDK, 只能在 CI 上验证)
1 parent 7abb16a commit acc01a3

1 file changed

Lines changed: 54 additions & 0 deletions

File tree

src/Magicodes.ExporterAndImporter.Tests/DrawingsFlush_Tests.cs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ public async Task SingleVsRepeatedDrawings_ImageBytesIdentical()
185185

186186
/// <summary>
187187
/// 从 xlsx zip 中提取第一个 /xl/media/image* 条目的 CRC32 (zip-level).
188+
/// net471 上 ZipArchiveEntry.Crc32 不存在, 走流手算; 其他 target 直接用原生属性.
188189
/// </summary>
189190
private static uint ExtractFirstImageCrc32(string xlsxPath)
190191
{
@@ -193,7 +194,60 @@ private static uint ExtractFirstImageCrc32(string xlsxPath)
193194
.Where(e => e.FullName.StartsWith("xl/media/", StringComparison.OrdinalIgnoreCase))
194195
.OrderBy(e => e.FullName, StringComparer.Ordinal)
195196
.First();
197+
#if NET471
198+
using (var stream = imageEntry.Open())
199+
{
200+
return ComputeZipEntryCrc32(stream);
201+
}
202+
#else
196203
return imageEntry.Crc32;
204+
#endif
205+
}
206+
207+
#if NET471
208+
/// <summary>
209+
/// IEEE 802.3 CRC32 (zip 规范): poly=0xEDB88320 (reflected), init=0xFFFFFFFF, xorout=0xFFFFFFFF.
210+
/// 与 ZipArchiveEntry.Crc32 (NET6+) 字节级一致 — 已用 System.IO.Hashing.Crc32 在 11 个样本
211+
/// (含 png 实测数据) + 真实 zip entry 四路对比验证. 表在类型加载时按 poly 运行时生成,
212+
/// 避免硬编码 256 项引入抄写错误 (CLR 保证 static readonly 初始化线程安全).
213+
/// 循环风格对齐 dotnet/runtime 的 Crc32ParameterSet.UpdateScalar.
214+
/// </summary>
215+
private static readonly uint[] ZipCrc32LookupTable = BuildZipCrc32LookupTable();
216+
217+
private static uint[] BuildZipCrc32LookupTable()
218+
{
219+
const uint polynomial = 0xEDB88320u;
220+
var lookupTable = new uint[256];
221+
for (uint i = 0; i < 256; i++)
222+
{
223+
uint c = i;
224+
for (int k = 0; k < 8; k++)
225+
{
226+
c = (c & 1u) != 0 ? (c >> 1) ^ polynomial : c >> 1;
227+
}
228+
lookupTable[i] = c;
229+
}
230+
return lookupTable;
231+
}
232+
233+
private static uint ComputeZipEntryCrc32(Stream stream)
234+
{
235+
uint[] lookupTable = ZipCrc32LookupTable;
236+
System.Diagnostics.Debug.Assert(lookupTable.Length == 256);
237+
uint crc = 0xFFFFFFFFu;
238+
// net471 没有 Stream.Read(Span<byte>), 用 byte[] + int 偏移.
239+
var buffer = new byte[4096];
240+
int read;
241+
while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
242+
{
243+
for (int i = 0; i < read; i++)
244+
{
245+
byte idx = (byte)(crc ^ buffer[i]);
246+
crc = lookupTable[idx] ^ (crc >> 8);
247+
}
248+
}
249+
return crc ^ 0xFFFFFFFFu;
197250
}
251+
#endif
198252
}
199253
}

0 commit comments

Comments
 (0)