How to efficiently read bits out of bytes?

前端 未结 4 1943
野的像风
野的像风 2021-01-02 02:24

I\'m working on a project that includes WebSockets, and data between the server (Node.js) and the client (Chrome) is sent using a custom (very simple) format for data exchan

4条回答
  •  悲哀的现实
    2021-01-02 03:00

    We can get value we need by getting appropriate 16-bits integer and then bitshift it.

    It is clear, that to get i-th value we should get 16-bits integer with offset in bytes that fits (bits * (i + 1) - 16)/8 <= offset <= (bits * i)/8.

    Lets take M=bits*i/8, so we have M + bits/8 - 2<= offset <= M. Then we get minimal offset as ceil(M + bits/8 - 2) and calculate position of i-th value in the 16-bit integer by offsets. I have just wrote the following function

    function getDataFromStream(buffer, bitsPerValue, endianness) {
        var valuesCount = Math.floor(buffer.length * 8 / bitsPerValue);
        var ret = new Buffer(valuesCount);
    
        if (valuesCount > 0) {
            for (var i = 0; i < valuesCount; i++) {
                var offsetMin = Math.ceil(bitsPerValue * i / 8. + bitsPerValue / 8. - 2);
                if (offsetMin < 0) {
                    offsetMin = 0;
                }
                if(endianness == 'BE')
                    var wordWithValue = buffer.readUInt16BE(offsetMin, true);
                else
                    var wordWithValue = buffer.readUInt16LE(offsetMin, true); 
                var offsetInWord = bitsPerValue * i - offsetMin * 8;
                var leftInWord = 16 - bitsPerValue - offsetInWord;
    
                // then get value in the word by shifting and then remove other bits by "%"
                ret[i] = (wordWithValue >> (endianness == 'BE' ? leftInWord : offsetInWord ))  % Math.pow(2, bitsPerValue);
            }
        }
        return ret;
    }
    

    And the following example to read 8 5-bit values off the Buffer with 5 bytes length.

    // buffer with 5 bytes
    var xx = new Buffer(5);
    xx[0] = 255;
    xx[1] = 255;
    xx[2] = 255;
    xx[3] = 255;
    xx[4] = 250;
    
    // get data, 5bits per value.
    var yy = getDataFromStream(xx, 5, 'BE');
    console.log('got buffer with length='+ yy.length);
    for(i = 0; i < yy.length; i++){
        console.log(i+'-'+yy[i]);
    }
    

    When I launch node test.js I got

    got buffer with length=8
    0-31
    1-31
    2-31
    3-31
    4-31
    5-31
    6-31
    7-26
    

提交回复
热议问题