Java 使用掩蔽读取int的未知方法

Java 使用掩蔽读取int的未知方法,java,android,c,image-processing,Java,Android,C,Image Processing,我试图绕过Android的各种限制,但我对如何解释以下代码感到困惑 static bool read_mbf(SkStream* stream, int* value) { int n = 0; uint8_t data; do { if (!read_byte(stream, &data)) { return false; } n = (n << 7) | (data &

我试图绕过Android的各种限制,但我对如何解释以下代码感到困惑

static bool read_mbf(SkStream* stream, int* value)
{
    int n = 0;
    uint8_t data;
    do {
        if (!read_byte(stream, &data)) {
            return false;
        }
        n = (n << 7) | (data & 0x7F); // Appends lower 7 bits
    } while (data & 0x80); // Handles upper bit as flag!?

    *value = n;
    return true;
}
有人能证实或指出我做错了什么吗

编辑:


更新了Java代码以反映Daniel Fischer的更正

您的实现几乎正确,但由于太累,您将错误的值移向了错误的方向:

array[offset + 0] = (byte)((value & (0x7F << 21)) | 0x80);
你想要

array[offset + 0] = (byte)(((value >> 21) & 0x7F) | 0x80);
等等

以及你的例外情况

if( (value & 0xF0000000) == 0xF0000000 )
这是不对的。只有在设置了所有四个最高有效位时才会抛出。如果只设置了其中的一部分,则编码将丢弃它们。情况可能是这样的

if( (value & 0xF0000000) != 0 )
检查是否设置了这些位中的任何一位

但你真的想要那个例外吗?C代码中没有理由存在这种限制(但是,有理由不允许负
int
s,因为这会导致溢出,从而导致上次左移时的未定义行为)

如果要使用编码允许的最小字节数对任何非负
int
进行编码,则代码会变得更复杂,因为使用的字节数随编码值的大小而变化

private int encode( byte[] array, int offset, int value ) {
    if (value < 0)
        throw new InvalidParameterException("Value " + value + " is negative and cannot safely be decoded.");
    byte temp;
    int shift = 28;
    // find highest set septet
    while(shift > 0 && (value >> shift) == 0) {
        shift -= 7;
    }
    // encode parts that have a successor
    while(shift > 0) {
        array[offset++] = (byte)(((value >> shift) & 0x7F) | 0x80);
        shift -= 7;
    }
    // last septet
    array[offset++] = (byte)(value & 0x7F);
    // return offset for next value
    return offset;
}
也可以写

array[offset++] = (byte)((value >> shift) | 0x80);
因为转换到
字节
会丢弃所有其他位


(我省略了对
偏移量
的检查,因为这不是算法的一部分,为了安全起见,应该添加它们。)

您的实现几乎是正确的,但由于太累,您将错误的值移到了错误的方向:

array[offset + 0] = (byte)((value & (0x7F << 21)) | 0x80);
你想要

array[offset + 0] = (byte)(((value >> 21) & 0x7F) | 0x80);
等等

以及你的例外情况

if( (value & 0xF0000000) == 0xF0000000 )
这是不对的。只有在设置了所有四个最高有效位时才会抛出。如果只设置了其中的一部分,则编码将丢弃它们。情况可能是这样的

if( (value & 0xF0000000) != 0 )
检查是否设置了这些位中的任何一位

但你真的想要那个例外吗?C代码中没有理由存在这种限制(但是,有理由不允许负
int
s,因为这会导致溢出,从而导致上次左移时的未定义行为)

如果要使用编码允许的最小字节数对任何非负
int
进行编码,则代码会变得更复杂,因为使用的字节数随编码值的大小而变化

private int encode( byte[] array, int offset, int value ) {
    if (value < 0)
        throw new InvalidParameterException("Value " + value + " is negative and cannot safely be decoded.");
    byte temp;
    int shift = 28;
    // find highest set septet
    while(shift > 0 && (value >> shift) == 0) {
        shift -= 7;
    }
    // encode parts that have a successor
    while(shift > 0) {
        array[offset++] = (byte)(((value >> shift) & 0x7F) | 0x80);
        shift -= 7;
    }
    // last septet
    array[offset++] = (byte)(value & 0x7F);
    // return offset for next value
    return offset;
}
也可以写

array[offset++] = (byte)((value >> shift) | 0x80);
因为转换到
字节
会丢弃所有其他位


(我省略了对
偏移量
的检查,因为这不是算法的一部分,为了安全起见,应该添加它们。)

您对C代码的解释听起来很合理。在Java中,你必须小心,因为所有的整数类型都是有符号的,这是行不通的。c函数读取被编码为尽可能少的字节数的整数以节省空间。例如,0到127取一个字节。不管发生什么,您总是输出四个字节。在这种情况下,c函数需要一个字节,当再次调用时,它会将以下内容读入其他数字。@DiegoBasch我真的不明白你在说什么。如果您有
10000000
,则七个
0
将向左移动,并且根本没有效果。当然,我可以钳制不必要的空字节,但在我看来它应该可以工作。如果将127编码为四个字节,它将只消耗这四个字节中的一个。下次它将读取四个字节中的第二个字节,并认为这是一个新的数字。我认为这会起作用,因为设置了
0x80
(continue)位。但也许我太累了。明天我们再来看看。你对C代码的解释听起来很合理。在Java中,你必须小心,因为所有的整数类型都是有符号的,这是行不通的。c函数读取被编码为尽可能少的字节数的整数以节省空间。例如,0到127取一个字节。不管发生什么,您总是输出四个字节。在这种情况下,c函数需要一个字节,当再次调用时,它会将以下内容读入其他数字。@DiegoBasch我真的不明白你在说什么。如果您有
10000000
,则七个
0
将向左移动,并且根本没有效果。当然,我可以钳制不必要的空字节,但在我看来它应该可以工作。如果将127编码为四个字节,它将只消耗这四个字节中的一个。下次它将读取四个字节中的第二个字节,并认为这是一个新的数字。我认为这会起作用,因为设置了
0x80
(continue)位。但也许我太累了。我明天再来看看。太好了。谢谢。把变化纳入我的问题。在我看来,我的天真方法更容易阅读/理解。哦,当然。固定长度编码提供了更简单的代码。但是它可以占用更多的空间,参见UTF-n。谢谢。把变化纳入我的问题。在我看来,我的天真方法更容易阅读/理解。哦,当然。固定长度编码提供了更简单的代码。但它可能会占用更多空间,请参见UTF-n。