我试图将以下C++函数移植到C#:
QString Engine::FDigest(const QString & input)
{
if(input.size() != 32) return "";
int idx[] = {0xe, 0x3, 0x6, 0x8, 0x2},
mul[] = {2, 2, 5, 4, 3},
add[] = {0x0, 0xd, 0x10, 0xb, 0x5},
a, m, i, t, v;
QString b;
char tmp[2] = { 0, 0 };
for(int j = 0; j <= 4; j++)
{
a = add[j];
m = mul[j];
i = idx[j];
tmp[0] = input[i].toAscii();
t = a + (int)(strtol(tmp, NULL, 16));
v = (int)(strtol(input.mid(t, 2).toLocal8Bit(), NULL, 16));
snprintf(tmp, 2, "%x", (v * m) % 0x10);
b += tmp;
}
return b;
}
Run Code Online (Sandbox Code Playgroud)
有些代码很容易移植但是我遇到了这个部分的问题:
tmp[0] = input[i].toAscii();
t = a + (int)(strtol(tmp, NULL, 16));
v = (int)(strtol(input.mid(t, 2).toLocal8Bit(), NULL, 16));
snprintf(tmp, 2, "%x", (v * m) % 0x10);
Run Code Online (Sandbox Code Playgroud)
我发现,(int)strtol(tmp, NULL, 16)
等于int.Parse(tmp, "x")
在C#和snprintf
是String.Format
,但我不知道它的其余部分.
如何将此片段移植到C#?
编辑我怀疑你的代码实际上是输入数据的MD5摘要.请参阅下面的基于该假设的代码段.
一些应该运作良好的提示1
问:
tmp[0] = input[i].toAscii();
bytes[] ascii = ASCIIEncoding.GetBytes(input);
tmp[0] = ascii[i];
Run Code Online (Sandbox Code Playgroud)
问:
t = a + (int)(strtol(tmp, NULL, 16));
t = a + int.Parse(string.Format("{0}{1}", tmp[0], tmp[1]),
System.Globalization.NumberStyles.HexNumber);
Run Code Online (Sandbox Code Playgroud)
问:
v = (int)(strtol(input.mid(t, 2).toLocal8Bit(), NULL, 16));
没有关于toLocal8bit的线索,需要阅读Qt文档......
问:
snprintf(tmp, 2, "%x", (v * m) % 0x10);
{
string tmptext = ((v*m % 16)).ToString("X2");
tmp[0] = tmptext[0];
tmp[1] = tmptext[1];
}
Run Code Online (Sandbox Code Playgroud)
您可以直接尝试这一点,看看它是否达到了您的需求:
using System;
public string FDigest(string input)
{
MD5 md5 = System.Security.Cryptography.MD5.Create();
byte[] ascii = System.Text.Encoding.ASCII.GetBytes (input);
byte[] hash = md5.ComputeHash (ascii);
// Convert the byte array to hexadecimal string
StringBuilder sb = new StringBuilder();
for (int i = 0; i < hash.Length; i++)
sb.Append (hash[i].ToString ("X2")); // "x2" for lowercase
return sb.ToString();
}
Run Code Online (Sandbox Code Playgroud)
1显式未优化,旨在作为快速提示; 根据需要进行优化
还有一些提示:
t 是一个两字节缓冲区,您只能写入第一个字节,留下尾随 nul。因此 t 始终是只有一个字符的字符串,并且您一次处理一个十六进制数字。所以我认为
tmp[0] = input[i].toAscii();
t = a + (int)(strtol(tmp, NULL, 16));
Run Code Online (Sandbox Code Playgroud)
这大致是int t = a + Convert.ToInt32(input.substring(i, 1), 16);
- 从输入中取出一位数字并将其十六进制值添加到您从表中查找到的值中。(我假设 toAscii 只是将已经是十六进制数字的 QString 字符映射到 strtol 的 ASCII 中,所以如果你已经有一串十六进制数字就可以了。)
下一个
v = (int)(strtol(input.mid(t, 2).toLocal8Bit(), NULL, 16));
Run Code Online (Sandbox Code Playgroud)
这意味着从偏移量 t 处的输入中查找两个字符,即input.substring(t, 2)
,然后再次将它们转换为十六进制整数。v = Convert.ToInt32(input.substring(t, 2), 16);
现在,碰巧的是,我想你实际上只会在这里使用第二个数字,因为计算是(v * a) % 0x10
,但是嘿。如果我们再次使用十六进制数字的 QString,那么 toLocal8Bit 应该与 toAscii 具有相同的转换 - 我不清楚为什么你的代码在这里有两个不同的函数。
最后将这些值转换为 tmp 中的单个数字,然后将其附加到 b
snprintf(tmp, 2, "%x", (v * m) % 0x10);
b += tmp;
Run Code Online (Sandbox Code Playgroud)
(2 是缓冲区的长度,并且由于我们需要尾随 nul,因此仅写入 1)即
int digit = (v * m) % 0x10;
b += digit.ToString("x");
Run Code Online (Sandbox Code Playgroud)
应该做。我个人会将 mod 16 写为逻辑 and, & 0xf
,因为它的目的是将值缩减为一位数。
另请注意,在您的代码中i
从未设置 - 我猜这是一个循环或您为了简洁而省略的内容?
所以,总而言之
int t = a + Convert.ToInt32(input.substring(i, 1), 16);
int v = Convert.ToInt32(input.substring(t, 2), 16);
int nextDigit = (v * m) & 0xf;
b += nextDigit.ToString("x");
Run Code Online (Sandbox Code Playgroud)