位 reader 在连续非 8 的倍数读取时失败

Bit reader fails on consecutive non-multiple of 8 reads

过去两天我一直在为此苦苦挣扎,此时我可能已经修复了至少 20 个不同的错误。

基本上这个错误是如果你调用 ReadBits() 并请求任何不是 8 的倍数的东西,它第一次会工作,但如果你再次调用它,另一个非 8 的倍数,它会赢't.

我第一次使用 61 位,第二次使用 33 位。

这是请求 61 位的输出:0x1FFFFFFFFFFFFFFFF 从 33 开始:0x1FFFFFFF8

33位输出的最后一个字节应该是FF,但不知为什么是F8?如果我将它移到 3 个空位上,它只有 30 位长,而不是应该的 33 位。

struct BitIO {
    FILE                           *InputFP;
    fpos_t                     *InputOffset;
    uint64_t                    InputFPSize;
    uint8_t  InputBuffer[BufferSizeInBytes];
    uint64_t                  InputBitIndex;
} BitIO;

static const uint8_t ByteMask[2][8] = {
    {0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01},
    {0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE}
};

static const uint8_t ShiftTable[8] = {
    0, 7, 6, 5, 4, 3, 2, 1
};


uint64_t Bits2Bytes(uint64_t Bits) {
    return (Bits + 7) >> 3;
};

uint64_t ReadBits(int8_t Bits2Read) {
    uint64_t OutputData = 0;

    uint64_t StartByte      = Bits2Bytes(BitIO.InputBitIndex - (BitIO.InputBitIndex % 8));
    uint64_t EndByte        = Bits2Bytes((BitIO.InputBitIndex + Bits2Read));
    uint64_t BufferShift    = ShiftTable[BitIO.InputBitIndex % 8];
    uint64_t Bits2ReadShift = ShiftTable[Bits2Read % 8];
    uint64_t ByteMaskStart  = ByteMask[0][~(BitIO.InputBitIndex % 8)];

    for (uint64_t Byte = StartByte; Byte < EndByte; Byte++) {
        if (EndByte == StartByte + 1) {
            OutputData +=  BitIO.InputBuffer[Byte] & ByteMask[1][(BitIO.InputBitIndex + Bits2Read) % 8];
            OutputData >>= ShiftTable[(BitIO.InputBitIndex + Bits2Read) % 8];
        } else if (Byte == StartByte) {
            OutputData +=  BitIO.InputBuffer[Byte] & ByteMask[1][Bits2Read % 8];
            OutputData >>= Bits2ReadShift;
            OutputData <<= 8;
        } else if (Byte == EndByte - 1) {
            OutputData +=  BitIO.InputBuffer[Byte] & ByteMask[1][(BitIO.InputBitIndex % 8)];
        } else if (Byte != StartByte && Byte != EndByte) {
            OutputData +=  BitIO.InputBuffer[Byte];
            OutputData <<= 8;
        }
    }
    BitIO.InputBitIndex += Bits2Read;
    return OutputData;
};

试试这个:

static const uint8_t ByteMask[2][8] = {
    {0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01},
    {0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE}
};

第一个条目是错误的,虽然下面没有使用它。

// assume 0 <= n <= 64
uint64_t ReadBits (int n)
{
    uint64_t r = 0;
    uint64_t byte = BitIO.InputBitIndex / 8;
    uint64_t bit = BitIO.InputBitIndex % 8;
    while (n > 0) {
        int count = (n >= 8) ? 8 : n;
        n -= count;
        uint64_t tmp;
        // We make sure not to look at two bytes if we don't have to
        // to avoid a buffer overrun.
        if (bit == 0) {
            tmp = BitIO.InputBuffer[byte];
        }
        else {
            uint64_t x = BitIO.InputBuffer[byte] & ByteMask[0][bit];
            uint64_t y = BitIO.InputBuffer[byte + 1] & ByteMask[1][bit];
            tmp = ((x << 8) | y) >> (8 - bit);
        }
        tmp >>= (8 - count);
        BitIO.InputBitIndex += count;
        byte++;
        r = (r << count) | tmp;
    }
    return r;
}