82 lines
2.6 KiB
Python
82 lines
2.6 KiB
Python
import enum
|
|
from typing import Optional as O, Union as U
|
|
from ..core.base import PossibleDynamic as D, Type, Context
|
|
from ..core.io import Stream, PosInfo
|
|
from .io import Terminated
|
|
|
|
|
|
class Str(Type[str]):
|
|
def __init__(self, length: U[D, O[int]] = None, encoding: U[D, str] = 'utf-8', char_size: U[D, int] = 1) -> None:
|
|
self.length = length
|
|
self.encoding = encoding
|
|
self.char_size = char_size
|
|
|
|
def parse(self, context: Context, stream: Stream) -> str:
|
|
length = context.get(self.length)
|
|
encoding = context.get(self.encoding)
|
|
char_size = context.get(self.char_size)
|
|
|
|
if length is None:
|
|
data = stream.read()
|
|
else:
|
|
data = stream.read(length * char_size)
|
|
|
|
return data.decode(encoding)
|
|
|
|
def dump(self, context: Context, stream: Stream, value: str) -> None:
|
|
encoding = context.get(self.encoding)
|
|
char_size = context.get(self.char_size)
|
|
|
|
bs = value.encode(encoding)
|
|
length = len(bs) // char_size
|
|
stream.write(bs)
|
|
|
|
context.put(self.length, length)
|
|
|
|
def default(self, context: Context) -> str:
|
|
return ''
|
|
|
|
def sizeof(self, context: Context, start: PosInfo, value: O[str]) -> O[PosInfo]:
|
|
if value is not None:
|
|
return len(value.encode(context.peek(self.encoding)))
|
|
return None
|
|
|
|
def __str__(self) -> str:
|
|
if self.length is not None:
|
|
length = f'({self.length})'
|
|
else:
|
|
length = ''
|
|
if self.encoding != 'utf-8':
|
|
encoding = f'.{self.encoding}'
|
|
else:
|
|
encoding = ''
|
|
return f'str{self.encoding}{length}'
|
|
|
|
def __repr__(self) -> str:
|
|
return f'{__name__}.Str(length={self.length!r}, encoding={self.encoding!r}, char_size={self.char_size!r})'
|
|
|
|
|
|
class CStr(Terminated[str]):
|
|
def __init__(self, *args, terminator_required=True, **kwargs) -> None:
|
|
terminator = '\x00'.encode(kwargs.get('encoding', 'utf-8'))
|
|
super().__init__(Str(*args, **kwargs), terminator, required=terminator_required, align=len(terminator), blocksize=16)
|
|
|
|
def __str__(self) -> str:
|
|
if self.child.encoding == 'utf-8':
|
|
return 'cstr'
|
|
if self.child.encoding == 'utf-16le':
|
|
return 'wcstr'
|
|
if self.child.encoding == 'sjis':
|
|
return 'jcstr'
|
|
return str(self.child)
|
|
|
|
def __repr__(self) -> str:
|
|
return f'<{__name__}.CStr({self.child!r})>'
|
|
|
|
cstr = \
|
|
utf8cstr = CStr()
|
|
wcstr = \
|
|
utf16cstr = CStr(encoding='utf-16le', char_size=2)
|
|
jcstr = \
|
|
sjiscstr = CStr(encoding='sjis')
|