How do I convert the last 4 bytes of an array to an integer?

If I have an array Uint8Array

in JavaScript, how can I get the last four bytes and then convert it to int? With C #, I would do something like this:

int count = BitConverter.ToInt32(array, array.Length - 4);

      

Is there a non-equivalent way to do this using JavaScript?

+4


source to share


7 replies


Open the base one ArrayBuffer

and create a new one TypedArray

with a chunk of its bytes:

var u8 = new Uint8Array([1,2,3,4,5,6]); // original array
var u32bytes = u8.buffer.slice(-4); // last four bytes as a new `ArrayBuffer`
var uint = new Uint32Array(u32bytes)[0];

      

If it TypedArray

doesn't cover the entire buffer, you need a little more complex, but not much:

var startbyte = u8.byteOffset + u8.byteLength - Uint32Array.BYTES_PER_ELEMENT;
var u32bytes = u8.buffer.slice(startbyte, startbyte + Uint32Array.BYTES_PER_ELEMENT);

      

This works in both cases.



If the bytes you want to fit into the alignment boundary of your base buffer for the data type (for example, you want a 32 bit byte value 4-8 of the base buffer), you can avoid copying the bytes with slice()

and just supply byteoffset to a constructor like in the answer @Bergi.

Below is a very easily tested function that should get a scalar value of whatever offset you want. This will avoid copying if possible.

function InvalidArgument(msg) {
    this.message = msg | null;
}

function scalarValue(buf_or_view, byteOffset, type) {
    var buffer, bufslice, view, sliceLength = type.BYTES_PER_ELEMENT;
    if (buf_or_view instanceof ArrayBuffer) {
        buffer = buf_or_view;
        if (byteOffset < 0) {
            byteOffset = buffer.byteLength - byteOffset;
        }
    } else if (buf_or_view.buffer instanceof ArrayBuffer) {
        view = buf_or_view;
        buffer = view.buffer;
        if (byteOffset < 0) {
            byteOffset = view.byteOffset + view.byteLength + byteOffset;
        } else {
            byteOffset = view.byteOffset + byteOffset;
        }
        return scalarValue(buffer, view.byteOffset + byteOffset, type);
    } else {
        throw new InvalidArgument('buf_or_view must be ArrayBuffer or have a .buffer property');
    }
    // assert buffer instanceof ArrayBuffer
    // assert byteOffset > 0
    // assert byteOffset relative to entire buffer
    try {
        // try in-place first
        // only works if byteOffset % slicelength === 0
        return (new type(buffer, byteOffset, 1))[0]
    } catch (e) {
        // if this doesn't work, we need to copy the bytes (slice them out)
        bufslice = buffer.slice(byteOffset, byteOffset + sliceLength);
        return (new type(bufslice, 0, 1))[0]
    }
}

      

You would use it like this:

// positive or negative byte offset
// relative to beginning or end *of a view*
100992003 === scalarValueAs(u8, -4, Uint32Array)
// positive or negative byte offset
// relative to the beginning or end *of a buffer*
100992003 === scalarValue(u8.buffer, -4, Uint32Array)

      

+7


source


Do you have an example? I think this would do it:



var result = ((array[array.length - 1]) | 
              (array[array.length - 2] << 8) | 
              (array[array.length - 3] << 16) | 
              (array[array.length - 4] << 24));

      

+5


source


A bit inelegant, but if you can do it manually based on the entianna.

Little horse:

var count = 0;
// assuming the array has at least four elements
for(var i = array.length - 1; i >= array.length - 4; i--)
{
    count = count << 8 + array[i];
}

      

Big endian:

var count = 0;
// assuming the array has at least four elements
for(var i = array.length - 4; i <= array.length - 1 ; i++)
{
    count = count << 8 + array[i];
}

      

This can be extended to other data lengths

Edit: thanks to David for pointing out my typos

+3


source


Your best bet is to create a view in the same ArrayBuffer and access the 32-bit number directly:Uint32Array

var uint8array = new Uint8Array([1,2,3,4,5,6,7,8]);
var uint32array = new Uint32Array(
                    uint8array.buffer,
                    uint8array.byteOffset + uint8array.byteLength - 4,
                    1 // 4Bytes long
                  );
return uint32array[0];

      

+1


source


Nowadays, if you can live with IE 11+ / Chrome 49+ / Firefox 50+ , then you can use DataView to make your life almost as simple as in C #:

var u8array = new Uint8Array([0xFF, 0xFF, 0xFF, 0xFF]); // -1
var view = new DataView(u8array.buffer)
console.log("result:" + view.getInt32());

      

Test it out here: https://jsfiddle.net/3udtek18/1/

+1


source


var a = Uint8Array(6)
a.set([1,2,8,0,0,1])

 i1 = a[a.length-4];
 i2 = a[a.length-3];
 i3 = a[a.length-2];
 i4 = a[a.length-1];

console.log(i1<<24 | i2<<16 | i3<<8 | i4);

      

0


source


Too bad there are no ways to do this. I needed to read variables of variable sizes, so based on Imortenson's answer, I wrote this little function where p

is the read position and s

is the number of bytes to read:

function readUInt(arr, p, s) {
    var r = 0;
    for (var i = s-1; i >= 0; i--) {
        r |= arr[p + i] << (i * 8);
    } return r >>> 0;
} 

var iable = readUint(arr, arr.length - 4, 4);

      

0


source







All Articles