You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

PBS文件头CRC16校验不匹配求助:计算值与文件存储值不一致

PBS文件头CRC16校验不匹配求助:计算值与文件存储值不一致

问题描述

我正在开发一个C#项目,用于解析KRK系统使用的专有.pbs归档格式。文件头包含一个CRC16校验和,但我计算出的值始终和文件中存储的不匹配。

读取有效.pbs文件时,代码输出:

CRC check failed. Expected: 0xE3A2, Actual: 0x0506

文件头结构说明

.pbs文件以66字节的头部开头,具体布局如下:

  • 0x00-0x01:签名(固定为"PB")
  • 0x02-0x03:CRC16(uint16类型,存储的校验值)
  • 0x04-0x41:元数据(包含版本、程序数量、各部分大小等,共62字节)

根据格式定义,CRC16应该是对**整个头部(排除CRC16字段本身)**计算得到的。

现有代码实现

主逻辑代码

var crc16 = new PBSTCRC16Calculator();
byte[] headerBytes = new byte[66];
stream.Read(headerBytes, 0, 66);

// 提取排除CRC字段的头部数据(总长度64字节:2字节签名+62字节元数据)
byte[] headerBytesWithoutCRC = new byte[64];
Array.Copy(headerBytes, 2, headerBytesWithoutCRC, 0, 64);

crc16.Append(headerBytesWithoutCRC);

ushort expected = BitConverter.ToUInt16(headerBytes, 2);
ushort actual = (ushort)crc16.CRC;

Console.WriteLine($"Expected: 0x{expected:X4}, Actual: 0x{actual:X4}");

初始CRC计算器类

public class PBSCRC16Calculator
{
    private const ushort POLY = 0xA001;
    private ushort crc = 0xFFFF;

    public ushort CRC => crc;

    public void Append(byte[] data)
    {
        foreach (byte b in data)
        {
            crc ^= b;
            for (int i = 0; i < 8; i++)
            {
                if ((crc & 1) != 0)
                    crc = (ushort)((crc >> 1) ^ POLY);
                else
                    crc >>= 1;
            }
        }
    }
}

尝试的查表版CRC计算器(含测试逻辑)

public class PBSCRC16Calculator
{
    public short CRC { get; private set; }
    private readonly short[] crcTable = new short[256];
    private readonly short cnCrc16 = -32763;

    public PBSCRC16Calculator()
    {
        for (short i = 0; (i & 0xFFFF) < 256; i++)
        {
            short data = (short)((i & 0xFFFF) << 8);
            short accum = 0;
            for (short j = 0; (j & 0xFFFF) < 8; j++)
            {
                if ((((data & 0xFFFF) ^ (accum & 0xFFFF)) & 0x8000) != 0)
                    accum = (short)(((accum & 0xFFFF) << 1) ^ (cnCrc16 & 0xFFFF));
                else
                    accum = (short)((accum & 0xFFFF) << 1);
                data = (short)((data & 0xFFFF) << 1);
            }
            crcTable[i & 0xFF] = accum;
        }
    }

    public void Append(byte[] data)
    {
        short accum = 0;
        foreach (byte b in data)
            accum = (short)(crcTable[(b ^ (accum >> 8)) & 0xFF] ^ (accum << 8));
        CRC = accum;
    }
}

class Program
{
    static void Main()
    {
        var crc16 = new PBSCRC16Calculator();
        byte[] headerBytes = new byte[66];
        
        // 模拟示例头部数据
        for (int i = 0; i < headerBytes.Length; i++)
            headerBytes[i] = (byte)(i + 1);

        // 提取排除CRC字段的头部数据
        byte[] headerBytesWithoutCRC = new byte[64];
        Array.Copy(headerBytes, 2, headerBytesWithoutCRC, 0, 64);

        crc16.Append(headerBytesWithoutCRC);

        ushort expected = BitConverter.ToUInt16(headerBytes, 2);
        ushort actual = (ushort)crc16.CRC;

        Console.WriteLine($"Expected: 0x{expected:X4}, Actual: 0x{actual:X4}");
    }
}

已尝试的排查方向

  • 验证了字节序(通过BitConverter.IsLittleEndian确认本地环境的字节序)
  • 尝试将CRC初始值改为0x00000xFFFF两种情况
  • 尝试反转整个头部的字节顺序后再计算
  • 尝试过包含/排除CRC字段进行计算
    但所有尝试得到的结果都和文件中存储的CRC值不匹配,希望能得到大家的排查思路或解决建议。

火山引擎 最新活动