- コードのメモ用
- PowerQuery勉強中で適当にコード遊びをしていたときの産物
- PowerQueryのシンタックスハイライトがなかったので色付く部分が多めのJSを採用
- 処理はRFC1952を参考にPowerQuery用の調整をしている
- PowerQuery版は300KB程度のファイルでも少しぐるぐるするくらい速度は終わっているのでこのままだと実用性はなさそう
power query
(data as binary) => let
crcTable = List.Transform(
List.Numbers(0, 256),
(n as number) => List.Accumulate(
List.Numbers(0, 8), n, (seed as number, notUse) =>
if Number.IsOdd(seed)
then Number.BitwiseXor(0xedb88320, Number.BitwiseShiftRight(seed, 1))
else Number.BitwiseShiftRight(seed, 1)
)
)
in
Number.BitwiseXor(
List.Accumulate(
Binary.ToList(data),
Number.BitwiseXor(0, 0xffffffff),
(seed as number, byte as number) => Number.BitwiseXor(
crcTable{Number.BitwiseAnd(Number.BitwiseXor(seed, byte), 0xff)},
Number.BitwiseShiftRight(seed, 8)
)
),
0xffffffff
)
VBA版(64bit専用)
- オーバーフローを起こしたり負数になったりしていい感じにそのまま移せなかったのでLongLongを使ったので64bit専用
- どうせ他で使うこともなさそうなのでテーブルを普段使う機会のないstatic変数で持つようにしてある
- わかりにくい部分補足
- バックスラッシュに見える部分はVBAでは「¥」
- LongLongのリテラルは末尾に「^」
- &HはVBAの16進数リテラルの0x的な部分(Hexから来てそう)
vba(64bit専用)
Public Function Crc32(ByRef Bytes() As Byte) As LongLong
Static Table(0 To 255) As LongLong
If Table(255) = 0 Then
Dim i As Long
For i = 0 To 255
Dim c As LongLong
c = i
Dim j As Long
For j = 1 To 8
If c And 1 Then
c = &HEDB88320^ Xor (c \ 2^)
Else
c = c \ 2
End If
Next
Table(i) = c
Next
End If
Dim Crc As LongLong
Crc = 0 Xor &HFFFFFFFF^
Dim ByteItem As Variant
For Each ByteItem In Bytes
Dim Temp As LongLong
Temp = Crc Xor CLngLng(ByteItem)
Dim Index As Long
Index = CLng("&H" & Right("00" & Hex(Temp), 2))
Crc = Table(Index) Xor (Crc \ 256^)
Next
Crc32 = Crc Xor &HFFFFFFFF^
End Function
Python版
- 参考にしたコードやVBA版と違ってテーブル部分も含めて一体化させればインポートとワンライナーの無名関数でCRCの計算処理が作れる
- やり方的には無名関数やreduceを使ってる点でPowerQuery版とほぼ一緒
crc32(python、reduce利用)
from functools import reduce
crc_table = tuple(
reduce(
lambda x, _: 0xEDB88320 ^ (x >> 1) if x & 1 else x >> 1,
range(8),
i
)
for i in range(256)
)
crc32 = lambda data: (
reduce(
lambda c, b, t=crc_table:
t[(c ^ b) & 0xFF] ^ (c >> 8),
data,
0 ^ 0xFFFF_FFFF,
) ^ 0xFFFF_FFFF
)