|
|
|
@ -2,7 +2,7 @@ from typing import Any, Generic as G, TypeVar, Union as U, Optional as O, Sequen |
|
|
|
|
import os |
|
|
|
|
import errno |
|
|
|
|
from ..core.base import Type, Context, PossibleDynamic, PathElement, to_type |
|
|
|
|
from ..core.io import Stream, Segment, Pos, add_sizes |
|
|
|
|
from ..core.io import Stream, Segment, Pos, PosInfo, add_sizes |
|
|
|
|
from ..core.meta import Wrapper |
|
|
|
|
from ..core.util import stretch, seeking, find_overlap |
|
|
|
|
|
|
|
|
@ -86,12 +86,12 @@ class Sized(G[T], Wrapper[T]): |
|
|
|
|
size = stream.tell() - start |
|
|
|
|
context.put(self.limit, size) |
|
|
|
|
|
|
|
|
|
def sizeof(self, context: Context, value: O[T]) -> O[Pos]: |
|
|
|
|
def sizeof(self, context: Context, start: PosInfo, value: O[T]) -> O[Pos]: |
|
|
|
|
hard = context.peek(self.hard) |
|
|
|
|
if hard: |
|
|
|
|
return context.peek(self.limit) |
|
|
|
|
else: |
|
|
|
|
return super().sizeof(context, value) |
|
|
|
|
return super().sizeof(context, start, value) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TerminatedStream: |
|
|
|
@ -219,13 +219,13 @@ class Terminated(G[T], Wrapper[T]): |
|
|
|
|
if required and not included: |
|
|
|
|
stream.write(terminator) |
|
|
|
|
|
|
|
|
|
def sizeof(self, context: Context, value: O[T]) -> O[Pos]: |
|
|
|
|
def sizeof(self, context: Context, start: PosInfo, value: O[T]) -> O[Pos]: |
|
|
|
|
terminator = context.peek(self.terminator) |
|
|
|
|
required = context.peek(self.required) |
|
|
|
|
included = context.peek(self.included) |
|
|
|
|
if not required: |
|
|
|
|
return None |
|
|
|
|
size = super().sizeof(context, value) |
|
|
|
|
size = super().sizeof(context, start, value) |
|
|
|
|
if size is None: |
|
|
|
|
return None |
|
|
|
|
if not included: |
|
|
|
@ -263,15 +263,15 @@ class Ref(G[T], Wrapper[T]): |
|
|
|
|
|
|
|
|
|
context.put(self.pos, pos) |
|
|
|
|
|
|
|
|
|
def sizeof(self, context: Context, value: O[T]) -> O[Pos]: |
|
|
|
|
def sizeof(self, context: Context, start: PosInfo, value: O[T]) -> O[PosInfo]: |
|
|
|
|
segment = context.peek(self.segment) or context.params.segments['refs'] |
|
|
|
|
with context.enter_segment(segment): |
|
|
|
|
return super().sizeof(context, value) |
|
|
|
|
return super().sizeof(context, start, value) |
|
|
|
|
|
|
|
|
|
def offsetof(self, context: Context, path: Sequence[PathElement], value: O[T]) -> O[Pos]: |
|
|
|
|
def offsetof(self, context: Context, start: PosInfo, path: Sequence[PathElement], value: O[T]) -> O[PosInfo]: |
|
|
|
|
segment = context.peek(self.segment) or context.params.segments['refs'] |
|
|
|
|
with context.enter_segment(segment): |
|
|
|
|
return super().offsetof(context, path, value) |
|
|
|
|
return super().offsetof(context, start, path, value) |
|
|
|
|
|
|
|
|
|
def __str__(self) -> str: |
|
|
|
|
indicator = {os.SEEK_SET: '', os.SEEK_CUR: '+', os.SEEK_END: '-'}.get(self.whence, self.whence) |
|
|
|
@ -325,7 +325,7 @@ class Lazy(G[T], Type[LazyEntry[T]]): |
|
|
|
|
self.type = type |
|
|
|
|
|
|
|
|
|
def parse(self, context: Context, stream: Stream) -> LazyEntry[T]: |
|
|
|
|
sizes = context.to_size(self.sizeof(context, None)) |
|
|
|
|
sizes = context.to_size(self.sizeof(context, context.pos_info(), None)) |
|
|
|
|
pos = {} |
|
|
|
|
|
|
|
|
|
base_size = sizes.pop(context.segment) |
|
|
|
@ -346,11 +346,11 @@ class Lazy(G[T], Type[LazyEntry[T]]): |
|
|
|
|
def dump(self, context: Context, stream: Stream, value: LazyEntry[T]) -> None: |
|
|
|
|
return context.dump(to_type(self.type), stream, value()) |
|
|
|
|
|
|
|
|
|
def sizeof(self, context: Context, value: O[LazyEntry[T]]) -> O[Pos]: |
|
|
|
|
return context.sizeof(to_type(self.type), value() if value is not None else value) |
|
|
|
|
def sizeof(self, context: Context, start: PosInfo, value: O[LazyEntry[T]]) -> O[Pos]: |
|
|
|
|
return context.sizeof(to_type(self.type), start, value() if value is not None else value) |
|
|
|
|
|
|
|
|
|
def offsetof(self, context: Context, path: Sequence[PathElement], value: O[LazyEntry[T]]) -> O[Pos]: |
|
|
|
|
return context.offsetof(to_type(self.type), path, value() if value is not None else value) |
|
|
|
|
def offsetof(self, context: Context, start: PosInfo, path: Sequence[PathElement], value: O[LazyEntry[T]]) -> O[Pos]: |
|
|
|
|
return context.offsetof(to_type(self.type), start, path, value() if value is not None else value) |
|
|
|
|
|
|
|
|
|
def default(self, context: Context) -> LazyEntry[T]: |
|
|
|
|
return LazyEntry(self.type, context, None, {}, value=context.default(to_type(self.type))) |
|
|
|
@ -363,34 +363,58 @@ class Lazy(G[T], Type[LazyEntry[T]]): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AlignTo(G[T], Wrapper[T]): |
|
|
|
|
__slots__ = ('alignment', 'value') |
|
|
|
|
__slots__ = ('alignment', 'value', 'offset') |
|
|
|
|
|
|
|
|
|
def __init__(self, child: Type[T], alignment: U[PossibleDynamic, Pos], value: U[PossibleDynamic, bytes] = b'\x00') -> None: |
|
|
|
|
def __init__(self, child: Type[T], alignment: U[PossibleDynamic, Pos], value: U[PossibleDynamic, bytes] = b'\x00', offset: U[PossibleDynamic, Pos, None] = 0) -> None: |
|
|
|
|
super().__init__(child) |
|
|
|
|
self.alignment = alignment |
|
|
|
|
self.value = value |
|
|
|
|
self.offset = offset |
|
|
|
|
|
|
|
|
|
def parse(self, context: Context, stream: Stream) -> T: |
|
|
|
|
start = stream.tell() |
|
|
|
|
value = super().parse(context, stream) |
|
|
|
|
|
|
|
|
|
align = context.get(self.alignment) |
|
|
|
|
adjustment = stream.tell() % align |
|
|
|
|
pos = stream.tell() |
|
|
|
|
offset = context.get(self.offset) |
|
|
|
|
if offset is None: |
|
|
|
|
pos -= start |
|
|
|
|
else: |
|
|
|
|
pos -= offset |
|
|
|
|
|
|
|
|
|
adjustment = pos % align |
|
|
|
|
if adjustment: |
|
|
|
|
stream.seek(align - adjustment, os.SEEK_CUR) |
|
|
|
|
return value |
|
|
|
|
|
|
|
|
|
def dump(self, context: Context, stream: Stream, value: T) -> None: |
|
|
|
|
start = stream.tell() |
|
|
|
|
super().dump(context, stream, value) |
|
|
|
|
|
|
|
|
|
align = context.get(self.alignment) |
|
|
|
|
adjustment = stream.tell() % align |
|
|
|
|
pos = stream.tell() |
|
|
|
|
offset = context.get(self.offset) |
|
|
|
|
if offset is None: |
|
|
|
|
pos -= start |
|
|
|
|
else: |
|
|
|
|
pos -= offset |
|
|
|
|
|
|
|
|
|
adjustment = pos % align |
|
|
|
|
if adjustment: |
|
|
|
|
padding = stretch(context.get(self.value), align - adjustment) |
|
|
|
|
stream.write(padding) |
|
|
|
|
|
|
|
|
|
def sizeof(self, context: Context, value: O[T]) -> O[Pos]: |
|
|
|
|
# TODO |
|
|
|
|
return None |
|
|
|
|
def sizeof(self, context: Context, start: PosInfo, value: O[T]) -> O[Pos]: |
|
|
|
|
align = context.peek(self.alignment) |
|
|
|
|
offset = context.peek(self.offset) |
|
|
|
|
|
|
|
|
|
size = super().sizeof(context, start, value) |
|
|
|
|
pos = add_sizes(start, size).get(context.segment, 0) |
|
|
|
|
adjustment = (pos - offset) % align |
|
|
|
|
if adjustment: |
|
|
|
|
size = add_sizes(adjustment, size) |
|
|
|
|
return size |
|
|
|
|
|
|
|
|
|
def __str__(self) -> str: |
|
|
|
|
return f'{super().__str__()}%{self.align}' |
|
|
|
@ -400,35 +424,50 @@ class AlignTo(G[T], Wrapper[T]): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AlignedTo(G[T], Wrapper[T]): |
|
|
|
|
__slots__ = ('alignment', 'value') |
|
|
|
|
__slots__ = ('alignment', 'value', 'offset') |
|
|
|
|
|
|
|
|
|
def __init__(self, child: Type[T], alignment: U[PossibleDynamic, Pos], value: U[PossibleDynamic, bytes] = b'\x00') -> None: |
|
|
|
|
def __init__(self, child: Type[T], alignment: U[PossibleDynamic, Pos], value: U[PossibleDynamic, bytes] = b'\x00', offset: U[PossibleDynamic, Pos] = 0) -> None: |
|
|
|
|
super().__init__(child) |
|
|
|
|
self.alignment = alignment |
|
|
|
|
self.value = value |
|
|
|
|
self.offset = offset |
|
|
|
|
|
|
|
|
|
def parse(self, context: Context, stream: Stream) -> T: |
|
|
|
|
align = context.get(self.alignment) |
|
|
|
|
adjustment = stream.tell() % align |
|
|
|
|
adjustment = (stream.tell() - context.get(self.offset)) % align |
|
|
|
|
if adjustment: |
|
|
|
|
stream.seek(align - adjustment, os.SEEK_CUR) |
|
|
|
|
return super().parse(context, stream) |
|
|
|
|
|
|
|
|
|
def dump(self, context: Context, stream: Stream, value: T) -> None: |
|
|
|
|
align = context.get(self.alignment) |
|
|
|
|
adjustment = stream.tell() % align |
|
|
|
|
adjustment = (stream.tell() - context.get(self.offset)) % align |
|
|
|
|
if adjustment: |
|
|
|
|
padding = stretch(context.get(self.value), align - adjustment) |
|
|
|
|
stream.write(padding) |
|
|
|
|
super().dump(context, stream, value) |
|
|
|
|
|
|
|
|
|
def sizeof(self, context: Context, value: O[T]) -> O[Pos]: |
|
|
|
|
# TODO |
|
|
|
|
return None |
|
|
|
|
def sizeof(self, context: Context, start: PosInfo, value: O[T]) -> O[Pos]: |
|
|
|
|
currstart = start.get(context.segment, 0) |
|
|
|
|
align = context.peek(self.alignment) |
|
|
|
|
adjustment = (currstart - context.peek(self.offset)) % align |
|
|
|
|
if adjustment: |
|
|
|
|
size = context.to_size(align - adjustment) |
|
|
|
|
start = add_sizes(start, size) |
|
|
|
|
else: |
|
|
|
|
size = context.to_size(0) |
|
|
|
|
return add_sizes(size, super().sizeof(context, start, value)) |
|
|
|
|
|
|
|
|
|
def offsetof(self, context: Context, path: Sequence[PathElement], value: O[T]) -> O[Pos]: |
|
|
|
|
# TODO |
|
|
|
|
return None |
|
|
|
|
def offsetof(self, context: Context, start: PosInfo, path: Sequence[PathElement], value: O[T]) -> O[Pos]: |
|
|
|
|
currstart = start.get(context.segment, 0) |
|
|
|
|
align = context.peek(self.alignment) |
|
|
|
|
adjustment = (currstart - context.peek(self.offset)) % align |
|
|
|
|
if adjustment: |
|
|
|
|
size = context.to_size(align - adjustment) |
|
|
|
|
start = add_sizes(start, size) |
|
|
|
|
else: |
|
|
|
|
size = context.to_size(0) |
|
|
|
|
return add_sizes(size, super().offsetof(context, start, path, value)) |
|
|
|
|
|
|
|
|
|
def __str__(self) -> str: |
|
|
|
|
return f'{super().__str__()}%{self.align}' |
|
|
|
@ -447,7 +486,7 @@ class Tell(Type[Pos]): |
|
|
|
|
def dump(self, context: Context, stream: Stream, value: Pos) -> None: |
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
def sizeof(self, context: Context, value: O[Pos]) -> Pos: |
|
|
|
|
def sizeof(self, context: Context, start: PosInfo, value: O[Pos]) -> Pos: |
|
|
|
|
return 0 |
|
|
|
|
|
|
|
|
|
def __str__(self) -> str: |
|
|
|
|