需要帮助为特定值格式编写二进制 reader 扩展方法:6 位然后 7 位结构
Need help writing a binary reader extension method for a specific value format: 6 bit then 7 bits structure
好的,就这样吧。
我目前需要为 System.IO.BinaryReader class 编写一个能够读取特定格式的扩展方法。
我不知道这种格式叫什么,但我确实知道它是如何工作的,所以我将在下面描述它。
组成该值的每个字节都被标记以指示 reader 接下来需要如何表现。
第一个字节有 2 个标志,值的任何后续字节只有 1 个标志。
First byte:
01000111
^^^^^^^^
|||____|_ 6 bit value
||_______ flag: next byte required
|________ flag: signed value
Next bytes:
00000011
^^^^^^^^
||_____|_ 7 bit value
|________ flag: next byte required
值的第一个字节有两个标志位,第一位表示值是正数还是负数。
第二位是是否需要读取另一个字节。
剩下的 6 位是目前的值,需要保留以备后用。
如果不需要读取更多字节,那么您只需 return 具有第一个位标志指示的正确符号的 6 位值。
如果需要读取另一个字节,则读取该字节的第一位,这将指示是否需要读取另一个字节。
剩下的 7 位就是这里的值。
该值需要与第一个字节的 6 位值相结合。
所以在上面的例子中:
第一个值是:01000111。
即为正,需要再读一个字节,目前的值为000111。
读取了另一个字节,它是:00000011
因此不需要读取新字节,这里的值是:0000011
到目前为止,它像这样连接到值的前面:0000011000111
因此这就是最终值:0000011000111 或 199
0100011100000011 变成这样:0000011000111
这是另一个例子:
011001111000110100000001
^^^^^^^^^^^^^^^^^^^^^^^^
| || ||______|_____ Third Byte (1 flag)
| ||______|_____________ Second Byte (1 flag)
|______|_____________________ First Byte (2 flags)
First Byte:
0 - Positive
1 - Next Needed
100111 - Value
Second Byte:
1 - Next Needed
0001101 - Value
Third Byte:
0 - Next Not Needed
0000001 - Value
Value:
00000010001101100111 = 9063
希望我的解释很清楚:)
现在我需要能够为 System.IO.BinaryReader 编写一个清晰、简单且最重要的快速扩展方法来从流中读取这样的值。
到目前为止,我的尝试有点糟糕,而且涉及布尔数组和位数组的不必要的复杂。
因此,我真的需要有人帮助我编写这样的方法,我将不胜感激!
感谢阅读。
根据评论中的描述,我想到了这个,异常读取有符号字节,因为它使继续标志更容易检查:(未测试)
static int ReadVLQInt32(this BinaryReader r)
{
sbyte b0 = r.ReadSByte();
// the first byte has 6 bits of the raw value
int shift = 6;
int raw = b0 & 0x3F;
// first continue flag is the second bit from the top, shift it into the sign
sbyte cont = (sbyte)(b0 << 1);
while (cont < 0)
{
sbyte b = r.ReadSByte();
// these bytes have 7 bits of the raw value
raw |= (b & 0x7F) << shift;
shift += 7;
// continue flag is already in the sign
cont = b;
}
return b0 < 0 ? -raw : raw;
}
它也可以很容易地扩展为读取 long
,只需确保使用 b & 0x7FL
否则该值将被转换为 int
并且位会被丢弃。
检查非法值的版本(例如 0xFF、0xFF... 的超长序列,plus 与 C# 的 checked
数学一起工作(C# 编译器中有一个选项使用 cheched 数学来检查溢出)
public static int ReadVlqInt32(this BinaryReader r)
{
byte b = r.ReadByte();
// the first byte has 6 bits of the raw value
uint raw = (uint)(b & 0x3F);
bool negative = (b & 0x80) != 0;
// first continue flag is the second bit from the top, shift it into the sign
bool cont = (b & 0x40) != 0;
if (cont)
{
int shift = 6;
while (true)
{
b = r.ReadByte();
cont = (b & 0x80) != 0;
b &= 0x7F;
if (shift == 27)
{
if (negative)
{
// minumum value abs(int.MinValue)
if (b > 0x10 || (b == 0x10 && raw != 0))
{
throw new Exception();
}
}
else
{
// maximum value int.MaxValue
if (b > 0xF)
{
throw new Exception();
}
}
}
// these bytes have 7 bits of the raw value
raw |= ((uint)b) << shift;
if (!cont)
{
break;
}
if (shift == 27)
{
throw new Exception();
}
shift += 7;
}
}
// We use unchecked here to handle int.MinValue
return negative ? unchecked(-(int)raw) : (int)raw;
}
好的,就这样吧。
我目前需要为 System.IO.BinaryReader class 编写一个能够读取特定格式的扩展方法。 我不知道这种格式叫什么,但我确实知道它是如何工作的,所以我将在下面描述它。
组成该值的每个字节都被标记以指示 reader 接下来需要如何表现。 第一个字节有 2 个标志,值的任何后续字节只有 1 个标志。
First byte:
01000111
^^^^^^^^
|||____|_ 6 bit value
||_______ flag: next byte required
|________ flag: signed value
Next bytes:
00000011
^^^^^^^^
||_____|_ 7 bit value
|________ flag: next byte required
值的第一个字节有两个标志位,第一位表示值是正数还是负数。 第二位是是否需要读取另一个字节。 剩下的 6 位是目前的值,需要保留以备后用。
如果不需要读取更多字节,那么您只需 return 具有第一个位标志指示的正确符号的 6 位值。
如果需要读取另一个字节,则读取该字节的第一位,这将指示是否需要读取另一个字节。 剩下的 7 位就是这里的值。 该值需要与第一个字节的 6 位值相结合。
所以在上面的例子中:
第一个值是:01000111。 即为正,需要再读一个字节,目前的值为000111。
读取了另一个字节,它是:00000011 因此不需要读取新字节,这里的值是:0000011 到目前为止,它像这样连接到值的前面:0000011000111
因此这就是最终值:0000011000111 或 199
0100011100000011 变成这样:0000011000111
这是另一个例子:
011001111000110100000001
^^^^^^^^^^^^^^^^^^^^^^^^
| || ||______|_____ Third Byte (1 flag)
| ||______|_____________ Second Byte (1 flag)
|______|_____________________ First Byte (2 flags)
First Byte:
0 - Positive
1 - Next Needed
100111 - Value
Second Byte:
1 - Next Needed
0001101 - Value
Third Byte:
0 - Next Not Needed
0000001 - Value
Value:
00000010001101100111 = 9063
希望我的解释很清楚:)
现在我需要能够为 System.IO.BinaryReader 编写一个清晰、简单且最重要的快速扩展方法来从流中读取这样的值。 到目前为止,我的尝试有点糟糕,而且涉及布尔数组和位数组的不必要的复杂。
因此,我真的需要有人帮助我编写这样的方法,我将不胜感激!
感谢阅读。
根据评论中的描述,我想到了这个,异常读取有符号字节,因为它使继续标志更容易检查:(未测试)
static int ReadVLQInt32(this BinaryReader r)
{
sbyte b0 = r.ReadSByte();
// the first byte has 6 bits of the raw value
int shift = 6;
int raw = b0 & 0x3F;
// first continue flag is the second bit from the top, shift it into the sign
sbyte cont = (sbyte)(b0 << 1);
while (cont < 0)
{
sbyte b = r.ReadSByte();
// these bytes have 7 bits of the raw value
raw |= (b & 0x7F) << shift;
shift += 7;
// continue flag is already in the sign
cont = b;
}
return b0 < 0 ? -raw : raw;
}
它也可以很容易地扩展为读取 long
,只需确保使用 b & 0x7FL
否则该值将被转换为 int
并且位会被丢弃。
检查非法值的版本(例如 0xFF、0xFF... 的超长序列,plus 与 C# 的 checked
数学一起工作(C# 编译器中有一个选项使用 cheched 数学来检查溢出)
public static int ReadVlqInt32(this BinaryReader r)
{
byte b = r.ReadByte();
// the first byte has 6 bits of the raw value
uint raw = (uint)(b & 0x3F);
bool negative = (b & 0x80) != 0;
// first continue flag is the second bit from the top, shift it into the sign
bool cont = (b & 0x40) != 0;
if (cont)
{
int shift = 6;
while (true)
{
b = r.ReadByte();
cont = (b & 0x80) != 0;
b &= 0x7F;
if (shift == 27)
{
if (negative)
{
// minumum value abs(int.MinValue)
if (b > 0x10 || (b == 0x10 && raw != 0))
{
throw new Exception();
}
}
else
{
// maximum value int.MaxValue
if (b > 0xF)
{
throw new Exception();
}
}
}
// these bytes have 7 bits of the raw value
raw |= ((uint)b) << shift;
if (!cont)
{
break;
}
if (shift == 27)
{
throw new Exception();
}
shift += 7;
}
}
// We use unchecked here to handle int.MinValue
return negative ? unchecked(-(int)raw) : (int)raw;
}