Source code for harmonize.utils.reader
# Original https://github.com/devoxin/Lavalink.py/blob/development/lavalink/source_decoders.py
import struct
from base64 import b64decode
from io import BytesIO
from typing import Optional
from harmonize.utils.utfm_codec import read_utfm
__all__ = (
"DataReader",
"read_utfm"
)
[docs]
class DataReader:
"""
A utility class for reading binary data from a base 64 track.
`Original <https://github.com/devoxin/Lavalink.py/blob/development/lavalink/dataio.py>`_
"""
def __init__(self, base64_str: str):
self._buf = BytesIO(b64decode(base64_str))
@property
def remaining(self) -> int:
""" The amount of bytes left to be read. """
return self._buf.getbuffer().nbytes - self._buf.tell()
def _read(self, count: int):
return self._buf.read(count)
[docs]
def read_byte(self) -> bytes:
"""
Reads a single byte from the stream.
Returns
-------
:class:`bytes`
"""
return self._read(1)
[docs]
def read_boolean(self) -> bool:
"""
Reads a bool from the stream.
Returns
-------
:class:`bool`
"""
result, = struct.unpack('B', self.read_byte())
return result != 0
[docs]
def read_unsigned_short(self) -> int:
"""
Reads an unsigned short from the stream.
Returns
-------
:class:`int`
"""
result, = struct.unpack('>H', self._read(2))
return result
[docs]
def read_int(self) -> int:
"""
Reads an int from the stream.
Returns
-------
:class:`int`
"""
result, = struct.unpack('>i', self._read(4))
return result
[docs]
def read_long(self) -> int:
"""
Reads a long from the stream.
Returns
-------
:class:`int`
"""
result, = struct.unpack('>Q', self._read(8))
return result
[docs]
def read_nullable_utf(self, utfm: bool = False) -> Optional[str]:
"""
.. _modified UTF: https://en.wikipedia.org/wiki/UTF-8#Modified_UTF-8
Reads an optional UTF string from the stream.
Internally, this just reads a bool and then a string if the bool is ``True``.
Parameters
----------
utfm: :class:`bool`
Whether to read the string as `modified UTF`_.
Returns
-------
Optional[:class:`str`]
"""
exists = self.read_boolean()
if not exists:
return None
return self.read_utfm() if utfm else self.read_utf().decode()
[docs]
def read_utf(self) -> bytes:
"""
Reads a UTF string from the stream.
Returns
-------
:class:`bytes`
"""
text_length = self.read_unsigned_short()
return self._read(text_length)
[docs]
def read_utfm(self) -> str:
"""
.. _modified UTF: https://en.wikipedia.org/wiki/UTF-8#Modified_UTF-8
Reads a UTF string from the stream.
This method is different to :func:`read_utf` as it accounts for
different encoding methods utilised by Java's streams, which uses `modified UTF`_
for character encoding.
Returns
-------
:class:`str`
"""
text_length = self.read_unsigned_short()
utf_string = self._read(text_length)
return read_utfm(text_length, utf_string)