我正试图将一个用C#制作的CRC 32生成器的特定实现转换为静态网站的JavaScript.

它将两个字符串合并为一个,将其转换为一个,生成CRC,并将其转换为十六进制输出.

问题是,JavaScript版本(CF 2 F4221)的输出与C#版本(67 CDF980)不匹配.

C#代码:

using System;
using System.Text;

namespace CRC32.Generator
{
    internal class CRC
    {
        public static readonly uint[] Table;

        private uint _value = 0xFFFFFFFF;

        static CRC()
        {
            Table = new uint[256];
            const uint kPoly = 0xEDB88320;
            for (uint i = 0; i < 256; i++)
            {
                uint r = i;
                for (int j = 0; j < 8; j++)
                    if ((r & 1) != 0)
                        r = (r >> 1) ^ kPoly;
                    else
                        r >>= 1;
                Table[i] = r;
            }
        }

        public void Init()
        {
            _value = 0xFFFFFFFF;
        }

        public void UpdateByte(byte b)
        {
            _value = Table[(((byte) (_value)) ^ b)] ^ (_value >> 8);
        }

        public void Update(byte[] data, uint offset, uint size)
        {
            for (uint i = 0; i < size; i++)
                _value = Table[(((byte) (_value)) ^ data[offset + i])] ^ (_value >> 8);
        }

        public uint GetDigest()
        {
            return _value ^ 0xFFFFFFFF;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            string string1 = "TestString1";
            string string2 = "TestString2";

            string stringData = string1 + string2;
            byte[] data = Encoding.Unicode.GetBytes(stringData);

            CRC crc = new CRC();
            crc.Update(data, 0, (uint)data.Length);
            uint crc32Value = crc.GetDigest();

            byte[] bytes = BitConverter.GetBytes(crc32Value);
            Array.Reverse(bytes);
            uint reversedCrc32Value = BitConverter.ToUInt32(bytes, 0);

            Console.WriteLine(reversedCrc32Value.ToString("X"));
        }
    }
}

JavaScript代码:

// CRC32 Table
const crc32Table = new Array(256);
for (let i = 0; i < 256; i++) {
    let crc = i;
    for (let j = 0; j < 8; j++) {
        crc = (crc & 1) ? (crc >>> 1) ^ 0xEDB88320 : crc >>> 1;
    }
    crc32Table[i] = crc;
}

// CRC32 Function
function crc32(data) {
    let crc = 0xFFFFFFFF;
    for (let i = 0; i < data.length; i++) {
        crc = (crc >>> 8) ^ crc32Table[(crc ^ data[i]) & 0xFF];
    }
    return (crc ^ 0xFFFFFFFF) >>> 0;  // Unsigned right shift
}

// Generate CRC
function generateCRC() {
    let string1 = document.getElementById('string1').value;
    let string2 = document.getElementById('string2').value;
    let stringData = string1 + string2;

    // Convert the string to a UTF-16LE byte array
    let encoder = new TextEncoder('utf-16le');
    let data = encoder.encode(stringData);

    let crc32Value = crc32(new Uint8Array(data.buffer));
    document.getElementById('output').textContent = crc32Value.toString(16).toUpperCase();  // Convert to hexadecimal
}

从我所做的研究中,我了解到C#和JavaScript输出之间的差异很可能是由于这两种语言在处理逐位操作、字节顺序以及字符编码方面的差异所致.

我希望那些对这些事情有更多了解的人能给我指明正确的方向,因为无可否认这超出了我的理解范围.

推荐答案

C#代码在字符串的小端UTF—16表示上计算CRC—32,字符串中的ASCII字节后面跟着一个零字节,总共44个字节.CRC是0x80f9cd67.C#代码反转这些字节以显示结果0x67CDF980.

JavaScript代码正确地计算CRC—32,但直接在22个ASCII或UTF—8字节上进行计算,即得到0xcf2f4221个字节(注意没有字节反转).

我找不到证据证明TextEncoder()支持'utf-16le'的论点,或任何论点.据我所知,它只支持UTF—8编码,这就是它在本例中所做的.最不幸的是,TextEncoder()确实报告了一个错误,无论它的论点是什么.

您可以使用charCodeAt()直接从字符串中获取每个UTF—16值,然后手动将它们按小字节顺序放置在字节数组中,每个字符两个字节,以便复制C#代码提供给CRC计算的内容.

这将直接在字符串上计算CRC,给出C#代码的结果:

// CRC32 Function
function crc32(string) {
    let crc = 0xFFFFFFFF;
    for (let i = 0; i < string.length; i++) {
        crc ^= string.charCodeAt(i);
        crc = (crc >>> 8) ^ crc32Table[crc & 0xFF];
        crc = (crc >>> 8) ^ crc32Table[crc & 0xFF];
    }
    return (crc ^ 0xFFFFFFFF) >>> 0;  // Unsigned right shift
}

它返回字符串"TestString1TestString2"的整数2163854695或0x80f9cd67.然后,您可以将数字转换为十六进制,并根据需要反转字节.

Javascript相关问答推荐

在JS中获取名字和姓氏的首字母

如何将拖放功能添加到我已自定义为图像的文件输入HTML标签中?

如何将连续的十六进制字符串拆分为以空间分隔的十六进制块,每个十六进制块包含32个二元组?

如何从JSON数组添加Google Maps标记—或者如何为数组添加参数到标记构造器

拖放仅通过 Select 上传

如何在不创建新键的情况下动态更改 map 中的项目?

Next.js(react)使用moment或不使用日期和时间格式

函数返回与输入对象具有相同键的对象

显示图—如何在图例项上添加删除线效果?

更改预请求脚本中重用的JSON主体变量- Postman

第三方包不需要NODE_MODULES文件夹就可以工作吗?

如何在HTMX提示符中设置默认值?

我想使用GAS和HTML将从Electron 表格中获得的信息插入到文本字段的初始值中

JavaScript:如果字符串不是A或B,则

FindByIdAndUpdate在嵌套对象中创建_id

P5play SecurityError:无法从';窗口';读取命名属性';Add';:阻止具有源的帧访问跨源帧

计算对象数组中属性的滚动增量

将匿名函数附加到链接的onClick属性

错误400:当我试图在React中使用put方法时,该字段是必需的

已在EventListener中更新/更改异步的React.js状态对象,但不会导致组件重新呈现