用屏蔽读取int的未知方式

时间:2013-01-04 00:03:02

标签: 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 & 0x7F); // Appends lower 7 bits
    } while (data & 0x80); // Handles upper bit as flag!?

    *value = n;
    return true;
}

在我看来,高位是数据继续的标志。当它丢失时,读取int停止。这是对的吗?

用Java正确编码(参见Daniel的答案):

private void encode( byte[] array, int offset, int value ) {
    if( (value & 0xF0000000) != 0 )
        throw new InvalidParameterException("Value " + value + "is too big to be encoded (max: " + 0x0FFFFFFF + ")");

    // | 0x80 makes sure, upper most bit is set so next byte is processed
    // & 0x7F makes sure, upper most bit is NOT set to end processing
    array[offset + 0] = (byte)((value >> 21) | 0x80);
    array[offset + 1] = (byte)((value >> 14) | 0x80);
    array[offset + 2] = (byte)((value >>  7) | 0x80);
    array[offset + 3] = (byte)((value >>  0) & 0x7F);
}

有人可以确认或指出我做错了吗?

编辑:

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

1 个答案:

答案 0 :(得分:1)

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

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

因此,除了来自value的位置21到27中的所有位,然后按位 - 或者用0x80屏蔽掉所有位。然后将结果转换为byte,这意味着丢弃除最不重要的8位之外的所有内容。离开

array[offset + 0] = (byte)0x80;

你想要

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

你的异常情况,

if( (value & 0xF0000000) == 0xF0000000 )

不正确。只有在设置了所有四个最高有效位时才会抛出。如果只设置了其中一些,则编码只会丢弃它们。条件可能是

if( (value & 0xF0000000) != 0 )

检查是否设置了这些位。

但你真的想要那个例外吗? C代码中没有理由说明该限制(但是,有一个理由不允许使用负int s,因为这会导致溢出,因此在最后一次左移时会导致未定义的行为。) p>

如果要编码具有编码允许的最小字节数的任何非负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) & 0x7F) | 0x80);

也可以写

array[offset++] = (byte)((value >> shift) | 0x80);

因为转换为byte会丢弃所有其他位。

(我省略了对offset < array.length的检查,因为这不是算法的一部分,为了安全起见,应加上它们。)