Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python equivalent for JavaScript's DataView

I load a byte array from a base-64 encoded string and I'd like to parse it.

However values are encoded in different ways and I'd like to replicate DataView's behavior.

Example:

function parse(data){
    view = new DataView(data.buffer);

    return {
        headerSize : view.getUint8(0),
        numberOfPlanes : view.getUint16(1, true),
        width: view.getUint16(3, true),
        height: view.getUint16(5, true),
        offset: view.getUint16(7, true)
    };
}

Usage:

data = new Uint8Array([8, 96, 0, 0, 2, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
parse(data)

Returns {headerSize: 8, numberOfPlanes: 96, width: 512, height: 256, offset: 8}

Later on I'll need to use DataView.getFloat32.

Right now I have something like this:

def get_bin(a):
    ba = bin(a)[2:]
    return "0" * (8 - len(ba)) + ba


def getUInt16(arr, ind):
    a = arr[ind]
    b = arr[ind + 1]
    return int(get_bin(b) + get_bin(a), 2)

def getFloat32(arr, ind):
    return bin_to_float("".join(get(i) for i in arr[ind : ind + 4][::-1]))


def bin_to_float(binary):
    return struct.unpack("!f", struct.pack("!I", int(binary, 2)))[0]

But a library could be more efficient and versatile

Float example: [111, 62, 163, 36] should yield 7.079574826789837e-17

like image 728
ted Avatar asked Mar 20 '26 08:03

ted


1 Answers

This should cover enough of your use cases or at least get you to the point where you can make minor changes. Hopefully you can somewhat follow what I am doing but feel free to ask questions.

from functools import reduce
import struct
class DataView:
    def __init__(self, array, bytes_per_element=1):
        """
        bytes_per_element is the size of each element in bytes.
        By default we are assume the array is one byte per element.
        """
        self.array = array
        self.bytes_per_element = 1

    def __get_binary(self, start_index, byte_count, signed=False):
        integers = [self.array[start_index + x] for x in range(byte_count)]
        bytes = [integer.to_bytes(self.bytes_per_element, byteorder='little', signed=signed) for integer in integers]
        return reduce(lambda a, b: a + b, bytes)

    def get_uint_16(self, start_index):
        bytes_to_read = 2
        return int.from_bytes(self.__get_binary(start_index, bytes_to_read), byteorder='little')

    def get_uint_8(self, start_index):
        bytes_to_read = 1
        return int.from_bytes(self.__get_binary(start_index, bytes_to_read), byteorder='little')

    def get_float_32(self, start_index):
        bytes_to_read = 4
        binary = self.__get_binary(start_index, bytes_to_read)
        return struct.unpack('<f', binary)[0] # <f for little endian


def parse(byte_array):
    d = DataView(byte_array)
    return {
        "headerSize": d.get_uint_8(0),
        "numverOfPlanes": d.get_uint_16(1),
        "width": d.get_uint_16(3),
        "hieght": d.get_uint_16(5),
        "offset": d.get_uint_16(7),
    }

result = parse([8, 96, 0, 0, 2, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
import json
print(json.dumps(result, indent=2))

d = DataView([111, 62, 163, 36])
d.get_float_32(0)

Output:

{
  "headerSize": 8,
  "numverOfPlanes": 96,
  "width": 512,
  "hieght": 256,
  "offset": 8
}
7.079574826789837e-17
like image 163
Error - Syntactical Remorse Avatar answered Mar 21 '26 21:03

Error - Syntactical Remorse