koro 2.0.0rc2__py3-none-any.whl → 2.0.1__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
koro/__init__.py CHANGED
@@ -1,8 +1,8 @@
1
- from .slot import *
2
- from .slot.bin import *
3
- from .slot.file import *
4
- from .slot.save import *
5
- from .slot.xml import *
6
- from .stage import *
7
- from .stage.model import *
8
- from .stage.part import *
1
+ from .slot import *
2
+ from .slot.bin import *
3
+ from .slot.file import *
4
+ from .slot.save import *
5
+ from .slot.xml import *
6
+ from .stage import *
7
+ from .stage.model import *
8
+ from .stage.part import *
koro/slot/__init__.py CHANGED
@@ -1,21 +1,21 @@
1
- from abc import ABC, abstractmethod
2
-
3
- from ..stage import Stage
4
-
5
- __all__ = ["Slot"]
6
-
7
-
8
- class Slot(ABC):
9
- __slots__ = ()
10
-
11
- def __bool__(self) -> bool:
12
- """Return whether this slot is filled."""
13
- return self.load() is not None
14
-
15
- @abstractmethod
16
- def load(self) -> Stage | None:
17
- pass
18
-
19
- @abstractmethod
20
- def save(self, data: Stage | None, /) -> None:
21
- pass
1
+ from abc import ABC, abstractmethod
2
+
3
+ from ..stage import Stage
4
+
5
+ __all__ = ["Slot"]
6
+
7
+
8
+ class Slot(ABC):
9
+ __slots__ = ()
10
+
11
+ def __bool__(self) -> bool:
12
+ """Return whether this slot is filled."""
13
+ return self.load() is not None
14
+
15
+ @abstractmethod
16
+ def load(self) -> Stage | None:
17
+ pass
18
+
19
+ @abstractmethod
20
+ def save(self, data: Stage | None, /) -> None:
21
+ pass
koro/slot/bin.py CHANGED
@@ -1,155 +1,158 @@
1
- from itertools import chain
2
- from typing import Final
3
-
4
- from ..stage import Stage
5
- from .file import FileSlot
6
- from .xml import XmlSlot
7
-
8
-
9
- class BinSlot(FileSlot):
10
- __slots__ = ()
11
-
12
- @staticmethod
13
- def compress(data: bytes, /) -> bytes:
14
- buffer: bytearray = bytearray(1024)
15
- buffer_index: int = 958
16
- chunk: bytearray
17
- data_index: int = 0
18
- output: Final[bytearray] = bytearray(
19
- b"\x00\x00\x00\x01\x00\x00\x00\x08"
20
- + len(data).to_bytes(4, byteorder="big")
21
- + b"\x00\x00\x00\x01"
22
- )
23
- reference_indices: list[int]
24
- test_buffer: bytearray
25
- test_length: int
26
- test_reference_indicies: list[int]
27
- while data_index < len(data):
28
- chunk = bytearray(b"\x00")
29
- for bit in range(8):
30
- if data_index >= len(data):
31
- chunk[0] >>= 8 - bit
32
- output.extend(chunk)
33
- return output + b"\x00" * (len(output) & 1)
34
- if len(data) - data_index <= 2:
35
- buffer[buffer_index] = data[data_index]
36
- buffer_index = buffer_index + 1 & 1023
37
- chunk[0] = chunk[0] >> 1 | 128
38
- chunk.append(data[data_index])
39
- data_index += 1
40
- continue
41
- reference_indices = []
42
- for i in chain(range(buffer_index, 1024), range(buffer_index)):
43
- if data[data_index] == buffer[i]:
44
- reference_indices.append(i)
45
- if not reference_indices:
46
- buffer[buffer_index] = data[data_index]
47
- buffer_index = buffer_index + 1 & 1023
48
- chunk[0] = chunk[0] >> 1 | 128
49
- chunk.append(data[data_index])
50
- data_index += 1
51
- continue
52
- test_buffer = buffer.copy()
53
- test_buffer[buffer_index] = data[data_index]
54
- for i in reference_indices.copy():
55
- if data[data_index + 1] != test_buffer[i - 1023]:
56
- reference_indices.remove(i)
57
- if not reference_indices:
58
- buffer[buffer_index] = data[data_index]
59
- buffer_index = buffer_index + 1 & 1023
60
- chunk[0] = chunk[0] >> 1 | 128
61
- chunk.append(data[data_index])
62
- data_index += 1
63
- continue
64
- test_buffer[buffer_index - 1023] = data[data_index + 1]
65
- for i in reference_indices.copy():
66
- if data[data_index + 2] != test_buffer[i - 1022]:
67
- reference_indices.remove(i)
68
- if not reference_indices:
69
- buffer[buffer_index] = data[data_index]
70
- buffer_index = buffer_index + 1 & 1023
71
- chunk[0] = chunk[0] >> 1 | 128
72
- chunk.append(data[data_index])
73
- data_index += 1
74
- continue
75
- test_length = 4
76
- test_reference_indicies = reference_indices.copy()
77
- while test_length <= min(66, len(data) - data_index):
78
- test_buffer[buffer_index + test_length - 1026] = data[
79
- data_index + test_length - 2
80
- ]
81
- for i in test_reference_indicies.copy():
82
- if (
83
- data[data_index + test_length - 1]
84
- != test_buffer[i + test_length - 1025]
85
- ):
86
- test_reference_indicies.remove(i)
87
- if test_reference_indicies:
88
- reference_indices = test_reference_indicies.copy()
89
- else:
90
- break
91
- test_length += 1
92
- chunk[0] >>= 1
93
- test_length -= 1
94
- if buffer_index + test_length >= 1024:
95
- buffer[buffer_index:] = data[
96
- data_index : data_index + 1024 - buffer_index
97
- ]
98
- buffer[: buffer_index + test_length - 1024] = data[
99
- data_index + 1024 - buffer_index : data_index + test_length
100
- ]
101
- else:
102
- buffer[buffer_index : buffer_index + test_length] = data[
103
- data_index : data_index + test_length
104
- ]
105
- buffer_index = buffer_index + test_length & 1023
106
- chunk.extend(
107
- (
108
- reference_indices[0] & 255,
109
- reference_indices[0] >> 2 & 192 | test_length - 3,
110
- )
111
- )
112
- data_index += test_length
113
- output.extend(chunk)
114
- return bytes(output)
115
-
116
- @staticmethod
117
- def decompress(data: bytes, /) -> bytes:
118
- buffer: Final[bytearray] = bytearray(1024)
119
- buffer_index: int = 958
120
- handle: int | bytearray
121
- flags: int
122
- offset: int
123
- raw: Final[bytearray] = bytearray(data[:15:-1])
124
- ref: bytes
125
- result: Final[bytearray] = bytearray()
126
- result_size: Final[int] = int.from_bytes(data[8:12], byteorder="big")
127
- while len(result) < result_size:
128
- flags = raw.pop()
129
- for _ in range(8):
130
- if flags & 1:
131
- handle = raw.pop()
132
- buffer[buffer_index] = handle
133
- buffer_index = buffer_index + 1 & 1023
134
- result.append(handle)
135
- else:
136
- if len(raw) < 2:
137
- return result
138
- ref = bytes((raw.pop() for _ in range(2)))
139
- offset = (ref[1] << 2 & 768) + ref[0]
140
- handle = bytearray()
141
- for i in range((ref[1] & 63) + 3):
142
- handle.append(buffer[offset + i - 1024])
143
- buffer[buffer_index] = handle[-1]
144
- buffer_index = buffer_index + 1 & 1023
145
- result.extend(handle)
146
- flags >>= 1
147
- return bytes(result)
148
-
149
- @staticmethod
150
- def deserialize(data: bytes, /) -> Stage:
151
- return XmlSlot.deserialize(BinSlot.decompress(data))
152
-
153
- @staticmethod
154
- def serialize(level: Stage, /) -> bytes:
155
- return BinSlot.compress(XmlSlot.serialize(level))
1
+ from itertools import chain
2
+ from typing import Final
3
+
4
+ from ..stage import Stage
5
+ from .file import FileSlot
6
+ from .xml import XmlSlot
7
+
8
+
9
+ __all__ = ["BinSlot"]
10
+
11
+
12
+ class BinSlot(FileSlot):
13
+ __slots__ = ()
14
+
15
+ @staticmethod
16
+ def compress(data: bytes, /) -> bytes:
17
+ buffer: bytearray = bytearray(1024)
18
+ buffer_index: int = 958
19
+ chunk: bytearray
20
+ data_index: int = 0
21
+ output: Final[bytearray] = bytearray(
22
+ b"\x00\x00\x00\x01\x00\x00\x00\x08"
23
+ + len(data).to_bytes(4, byteorder="big")
24
+ + b"\x00\x00\x00\x01"
25
+ )
26
+ reference_indices: list[int]
27
+ test_buffer: bytearray
28
+ test_length: int
29
+ test_reference_indicies: list[int]
30
+ while data_index < len(data):
31
+ chunk = bytearray(b"\x00")
32
+ for bit in range(8):
33
+ if data_index >= len(data):
34
+ chunk[0] >>= 8 - bit
35
+ output.extend(chunk)
36
+ return output + b"\x00" * (len(output) & 1)
37
+ if len(data) - data_index <= 2:
38
+ buffer[buffer_index] = data[data_index]
39
+ buffer_index = buffer_index + 1 & 1023
40
+ chunk[0] = chunk[0] >> 1 | 128
41
+ chunk.append(data[data_index])
42
+ data_index += 1
43
+ continue
44
+ reference_indices = []
45
+ for i in chain(range(buffer_index, 1024), range(buffer_index)):
46
+ if data[data_index] == buffer[i]:
47
+ reference_indices.append(i)
48
+ if not reference_indices:
49
+ buffer[buffer_index] = data[data_index]
50
+ buffer_index = buffer_index + 1 & 1023
51
+ chunk[0] = chunk[0] >> 1 | 128
52
+ chunk.append(data[data_index])
53
+ data_index += 1
54
+ continue
55
+ test_buffer = buffer.copy()
56
+ test_buffer[buffer_index] = data[data_index]
57
+ for i in reference_indices.copy():
58
+ if data[data_index + 1] != test_buffer[i - 1023]:
59
+ reference_indices.remove(i)
60
+ if not reference_indices:
61
+ buffer[buffer_index] = data[data_index]
62
+ buffer_index = buffer_index + 1 & 1023
63
+ chunk[0] = chunk[0] >> 1 | 128
64
+ chunk.append(data[data_index])
65
+ data_index += 1
66
+ continue
67
+ test_buffer[buffer_index - 1023] = data[data_index + 1]
68
+ for i in reference_indices.copy():
69
+ if data[data_index + 2] != test_buffer[i - 1022]:
70
+ reference_indices.remove(i)
71
+ if not reference_indices:
72
+ buffer[buffer_index] = data[data_index]
73
+ buffer_index = buffer_index + 1 & 1023
74
+ chunk[0] = chunk[0] >> 1 | 128
75
+ chunk.append(data[data_index])
76
+ data_index += 1
77
+ continue
78
+ test_length = 4
79
+ test_reference_indicies = reference_indices.copy()
80
+ while test_length <= min(66, len(data) - data_index):
81
+ test_buffer[buffer_index + test_length - 1026] = data[
82
+ data_index + test_length - 2
83
+ ]
84
+ for i in test_reference_indicies.copy():
85
+ if (
86
+ data[data_index + test_length - 1]
87
+ != test_buffer[i + test_length - 1025]
88
+ ):
89
+ test_reference_indicies.remove(i)
90
+ if test_reference_indicies:
91
+ reference_indices = test_reference_indicies.copy()
92
+ else:
93
+ break
94
+ test_length += 1
95
+ chunk[0] >>= 1
96
+ test_length -= 1
97
+ if buffer_index + test_length >= 1024:
98
+ buffer[buffer_index:] = data[
99
+ data_index : data_index + 1024 - buffer_index
100
+ ]
101
+ buffer[: buffer_index + test_length - 1024] = data[
102
+ data_index + 1024 - buffer_index : data_index + test_length
103
+ ]
104
+ else:
105
+ buffer[buffer_index : buffer_index + test_length] = data[
106
+ data_index : data_index + test_length
107
+ ]
108
+ buffer_index = buffer_index + test_length & 1023
109
+ chunk.extend(
110
+ (
111
+ reference_indices[0] & 255,
112
+ reference_indices[0] >> 2 & 192 | test_length - 3,
113
+ )
114
+ )
115
+ data_index += test_length
116
+ output.extend(chunk)
117
+ return bytes(output)
118
+
119
+ @staticmethod
120
+ def decompress(data: bytes, /) -> bytes:
121
+ buffer: Final[bytearray] = bytearray(1024)
122
+ buffer_index: int = 958
123
+ handle: int | bytearray
124
+ flags: int
125
+ offset: int
126
+ raw: Final[bytearray] = bytearray(data[:15:-1])
127
+ ref: bytes
128
+ result: Final[bytearray] = bytearray()
129
+ result_size: Final[int] = int.from_bytes(data[8:12], byteorder="big")
130
+ while len(result) < result_size:
131
+ flags = raw.pop()
132
+ for _ in range(8):
133
+ if flags & 1:
134
+ handle = raw.pop()
135
+ buffer[buffer_index] = handle
136
+ buffer_index = buffer_index + 1 & 1023
137
+ result.append(handle)
138
+ else:
139
+ if len(raw) < 2:
140
+ return result
141
+ ref = bytes((raw.pop() for _ in range(2)))
142
+ offset = (ref[1] << 2 & 768) + ref[0]
143
+ handle = bytearray()
144
+ for i in range((ref[1] & 63) + 3):
145
+ handle.append(buffer[offset + i - 1024])
146
+ buffer[buffer_index] = handle[-1]
147
+ buffer_index = buffer_index + 1 & 1023
148
+ result.extend(handle)
149
+ flags >>= 1
150
+ return bytes(result)
151
+
152
+ @staticmethod
153
+ def deserialize(data: bytes, /) -> Stage:
154
+ return XmlSlot.deserialize(BinSlot.decompress(data))
155
+
156
+ @staticmethod
157
+ def serialize(stage: Stage, /) -> bytes:
158
+ return BinSlot.compress(XmlSlot.serialize(stage))
koro/slot/file.py CHANGED
@@ -1,67 +1,70 @@
1
- from abc import ABC, abstractmethod
2
- from os import remove
3
- from os.path import isfile
4
- from typing import TYPE_CHECKING, Any
5
-
6
- from ..stage import Stage
7
- from . import Slot
8
-
9
- if TYPE_CHECKING:
10
- from _typeshed import StrOrBytesPath
11
- else:
12
- StrOrBytesPath = Any
13
-
14
-
15
- class FileSlot(Slot, ABC):
16
- __match_args__ = ("path",)
17
- __slots__ = ("_path",)
18
-
19
- _path: StrOrBytesPath
20
-
21
- def __init__(self, path: StrOrBytesPath, /) -> None:
22
- self._path = path
23
-
24
- def __bool__(self) -> bool:
25
- return isfile(self.path)
26
-
27
- @staticmethod
28
- @abstractmethod
29
- def deserialize(data: bytes, /) -> Stage:
30
- pass
31
-
32
- def __eq__(self, other: object, /) -> bool:
33
- if isinstance(other, FileSlot) and (
34
- isinstance(other, type(self)) or isinstance(self, type(other))
35
- ):
36
- return self.path == other.path
37
- else:
38
- return NotImplemented
39
-
40
- def __hash__(self) -> int:
41
- return hash(self.path)
42
-
43
- def load(self) -> Stage | None:
44
- try:
45
- with open(self.path, "rb") as f:
46
- return self.deserialize(f.read())
47
- except FileNotFoundError:
48
- return None
49
-
50
- @property
51
- def path(self) -> StrOrBytesPath:
52
- return self._path
53
-
54
- def __repr__(self) -> str:
55
- return f"{type(self).__name__}({self.path!r})"
56
-
57
- def save(self, data: Stage | None) -> None:
58
- if data is None:
59
- remove(self.path)
60
- else:
61
- with open(self.path, "wb") as f:
62
- f.write(self.serialize(data))
63
-
64
- @staticmethod
65
- @abstractmethod
66
- def serialize(stage: Stage, /) -> bytes:
67
- pass
1
+ from abc import ABC, abstractmethod
2
+ from os import remove
3
+ from os.path import isfile
4
+ from typing import TYPE_CHECKING, Any
5
+
6
+ from ..stage import Stage
7
+ from . import Slot
8
+
9
+ if TYPE_CHECKING:
10
+ from _typeshed import StrOrBytesPath
11
+ else:
12
+ StrOrBytesPath = Any
13
+
14
+
15
+ __all__ = ["FileSlot"]
16
+
17
+
18
+ class FileSlot(Slot, ABC):
19
+ __match_args__ = ("path",)
20
+ __slots__ = ("_path",)
21
+
22
+ _path: StrOrBytesPath
23
+
24
+ def __init__(self, path: StrOrBytesPath, /) -> None:
25
+ self._path = path
26
+
27
+ def __bool__(self) -> bool:
28
+ return isfile(self.path)
29
+
30
+ @staticmethod
31
+ @abstractmethod
32
+ def deserialize(data: bytes, /) -> Stage:
33
+ pass
34
+
35
+ def __eq__(self, other: object, /) -> bool:
36
+ if isinstance(other, FileSlot) and (
37
+ isinstance(other, type(self)) or isinstance(self, type(other))
38
+ ):
39
+ return self.path == other.path
40
+ else:
41
+ return NotImplemented
42
+
43
+ def __hash__(self) -> int:
44
+ return hash(self.path)
45
+
46
+ def load(self) -> Stage | None:
47
+ try:
48
+ with open(self.path, "rb") as f:
49
+ return self.deserialize(f.read())
50
+ except FileNotFoundError:
51
+ return None
52
+
53
+ @property
54
+ def path(self) -> StrOrBytesPath:
55
+ return self._path
56
+
57
+ def __repr__(self) -> str:
58
+ return f"{type(self).__name__}({self.path!r})"
59
+
60
+ def save(self, data: Stage | None) -> None:
61
+ if data is None:
62
+ remove(self.path)
63
+ else:
64
+ with open(self.path, "wb") as f:
65
+ f.write(self.serialize(data))
66
+
67
+ @staticmethod
68
+ @abstractmethod
69
+ def serialize(stage: Stage, /) -> bytes:
70
+ pass