Source code for malduck.string.bin

# Copyright (C) 2018 Jurriaan Bremer.
# This file is part of Roach - https://github.com/jbremer/roach.
# See the file 'docs/LICENSE.txt' for copying permission.
import struct
import warnings
from typing import Optional

from ..ints import Int8, Int16, Int32, Int64, UInt8, UInt16, UInt32, UInt64
from ..string.ops import Padding, enhex, unhex

__all__ = [
    "uint64",
    "uint32",
    "uint16",
    "uint8",
    "uint64be",
    "uint32be",
    "uint16be",
    "uint8be",
    "u64",
    "u32",
    "u16",
    "u8",
    "u64be",
    "u32be",
    "u16be",
    "u8be",
    "int64",
    "int32",
    "int16",
    "int8",
    "int64be",
    "int32be",
    "int16be",
    "int8be",
    "i64",
    "i32",
    "i16",
    "i8",
    "i64be",
    "i32be",
    "i16be",
    "i8be",
    "p64",
    "p32",
    "p16",
    "p8",
    "p64be",
    "p32be",
    "p16be",
    "p8be",
    "bigint",
    "unpack",
    "pack",
]


class Bigint:
    def unpack(self, other: bytes, size: Optional[int] = None) -> int:
        """
        Unpacks bigint value from provided buffer with little-endian order

        .. versionadded:: 4.0.0
            Use bigint.unpack instead of bigint() method

        :param other: Buffer object containing value to unpack
        :type other: bytes
        :param size: Size of bigint in bytes
        :type size: bytes, optional
        :rtype: int
        """
        if size:
            if len(other) < size:
                raise ValueError(f"Buffer is trimmed: {len(other)} < {size}")
            other = other[:size]
        return int(enhex(other[::-1]), 16)

    def pack(self, other: int, size: Optional[int] = None) -> bytes:
        """
        Packs bigint value into bytes with little-endian order

        .. versionadded:: 4.0.0
            Use bigint.pack instead of bigint() method

        :param other: Value to be packed
        :type other: int
        :param size: Size of bigint in bytes
        :type size: bytes, optional
        :rtype: bytes
        """
        if size is None:
            size = (other.bit_length() + 7) // 8
        return other.to_bytes(size, byteorder="little")

    def unpack_be(self, other: bytes, size: Optional[int] = None) -> int:
        """
        Unpacks bigint value from provided buffer with big-endian order

        :param other: Buffer object containing value to unpack
        :type other: bytes
        :param size: Size of bigint in bytes
        :type size: bytes, optional
        :rtype: int
        """
        if size:
            if len(other) < size:
                raise ValueError(f"Buffer is trimmed: {len(other)} < {size}")
            other = other[:size]
        return int(enhex(other), 16)

    def pack_be(self, other: int, size: Optional[int] = None) -> bytes:
        """
        Packs bigint value into bytes with big-endian order

        .. versionadded:: 4.0.0
            Use bigint.pack instead of bigint() method

        :param other: Value to be packed
        :type other: int
        :param size: Size of bigint in bytes
        :type size: bytes, optional
        :rtype: bytes
        """
        if size is None:
            size = (other.bit_length() + 7) // 8
        return other.to_bytes(size, byteorder="big")

    def __call__(self, s, bitsize):
        warnings.warn(
            "malduck.bigint() is deprecated, use malduck.bigint.unpack/pack methods",
            DeprecationWarning,
        )
        if isinstance(s, int):
            return Padding.null(unhex("%x" % s)[::-1], bitsize // 8)

        if len(s) < bitsize // 8:
            raise ValueError(f"Buffer is trimmed: {len(s) * 8} < {bitsize}")

        return int(enhex(s[: bitsize // 8][::-1]), 16)


bigint = Bigint()

# Shortcuts for mostly used unpack methods
uint64 = u64 = UInt64.unpack
uint32 = u32 = UInt32.unpack
uint16 = u16 = UInt16.unpack
uint8 = u8 = UInt8.unpack

uint64be = u64be = UInt64.unpack_be
uint32be = u32be = UInt32.unpack_be
uint16be = u16be = UInt16.unpack_be
uint8be = u8be = UInt8.unpack_be

int64 = i64 = Int64.unpack
int32 = i32 = Int32.unpack
int16 = i16 = Int16.unpack
int8 = i8 = Int8.unpack

int64be = i64be = Int64.unpack_be
int32be = i32be = Int32.unpack_be
int16be = i16be = Int16.unpack_be
int8be = i8be = Int8.unpack_be


# Shortcuts for mostly used pack methods
[docs]def p64(v): return UInt64(v).pack()
[docs]def p32(v): return UInt32(v).pack()
[docs]def p16(v): return UInt16(v).pack()
[docs]def p8(v): return UInt8(v).pack()
def p64be(v): return UInt64(v).pack_be() def p32be(v): return UInt32(v).pack_be() def p16be(v): return UInt16(v).pack_be() def p8be(v): return UInt8(v).pack_be() unpack = struct.unpack pack = struct.pack