tasd 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tasd-1.0.0/LICENSE +21 -0
- tasd-1.0.0/PKG-INFO +78 -0
- tasd-1.0.0/README.md +63 -0
- tasd-1.0.0/pyproject.toml +23 -0
- tasd-1.0.0/setup.cfg +4 -0
- tasd-1.0.0/tasd/__init__.py +4 -0
- tasd-1.0.0/tasd/constants.py +56 -0
- tasd-1.0.0/tasd/file.py +57 -0
- tasd-1.0.0/tasd/packet.py +304 -0
- tasd-1.0.0/tasd/packets/__init__.py +6 -0
- tasd-1.0.0/tasd/packets/extra.py +38 -0
- tasd-1.0.0/tasd/packets/general.py +406 -0
- tasd-1.0.0/tasd/packets/genesis.py +18 -0
- tasd-1.0.0/tasd/packets/input.py +106 -0
- tasd-1.0.0/tasd/packets/nes.py +38 -0
- tasd-1.0.0/tasd/packets/snes.py +50 -0
- tasd-1.0.0/tasd/utils.py +128 -0
- tasd-1.0.0/tasd.egg-info/PKG-INFO +78 -0
- tasd-1.0.0/tasd.egg-info/SOURCES.txt +19 -0
- tasd-1.0.0/tasd.egg-info/dependency_links.txt +1 -0
- tasd-1.0.0/tasd.egg-info/top_level.txt +1 -0
tasd-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 TheMas3212
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
tasd-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tasd
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: TASD file serializer and deserializer
|
|
5
|
+
Author-email: TheMas3212 <mas3212@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/themas3212/tasd-py
|
|
8
|
+
Project-URL: Issues, https://github.com/themas3212/tasd-py/issues
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.10
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Dynamic: license-file
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# TASD
|
|
18
|
+
|
|
19
|
+
This is a python library for the serialization and deserialization of tasd files using the [tasd file specfication](https://tasd.io/)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
Install tasd with pip
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install tasd
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Usage/Examples
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
Read a file in a print all the packets in it
|
|
34
|
+
```py
|
|
35
|
+
from tasd import TASD
|
|
36
|
+
|
|
37
|
+
with open("example.tasd", "rb") as f:
|
|
38
|
+
file = TASD.from_bytes(f.read())
|
|
39
|
+
|
|
40
|
+
print(file)
|
|
41
|
+
for packet in file. packets:
|
|
42
|
+
print(packet)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Create a tasd file from scratch and add packets to it
|
|
46
|
+
```py
|
|
47
|
+
from tasd import TASD, packets
|
|
48
|
+
|
|
49
|
+
file = TASD()
|
|
50
|
+
file.packets.append(packets.extra.Comment(comment="This is a comment"))
|
|
51
|
+
file.packets.append(packets.general.Attribution(type=packets.general.Attribution.ATTRIBUTION_TYPE.TASD_FILE_CREATOR, name="Me"))
|
|
52
|
+
|
|
53
|
+
for packet in file. packets:
|
|
54
|
+
print(packet)
|
|
55
|
+
|
|
56
|
+
print(file.to_bytes())
|
|
57
|
+
```
|
|
58
|
+
## Brief API Reference
|
|
59
|
+
|
|
60
|
+
Not an exhaustive list
|
|
61
|
+
|
|
62
|
+
`tasd.TASD`
|
|
63
|
+
|
|
64
|
+
Class holding properties of the tasd file itself: Version and KeyLength
|
|
65
|
+
|
|
66
|
+
`tasd.constants.PACKET_TYPES`
|
|
67
|
+
|
|
68
|
+
Enumlike class containing the different packet type indentifiers
|
|
69
|
+
|
|
70
|
+
`tasd.packets`
|
|
71
|
+
|
|
72
|
+
Submodule containing all the different packet classes
|
|
73
|
+
|
|
74
|
+
For details about the different packet types i suggest reading the specification document to determine what packets you need to consider for your use case
|
|
75
|
+
## Appendix
|
|
76
|
+
|
|
77
|
+
Any additional information goes here
|
|
78
|
+
|
tasd-1.0.0/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
|
|
2
|
+
# TASD
|
|
3
|
+
|
|
4
|
+
This is a python library for the serialization and deserialization of tasd files using the [tasd file specfication](https://tasd.io/)
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
Install tasd with pip
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install tasd
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage/Examples
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
Read a file in a print all the packets in it
|
|
19
|
+
```py
|
|
20
|
+
from tasd import TASD
|
|
21
|
+
|
|
22
|
+
with open("example.tasd", "rb") as f:
|
|
23
|
+
file = TASD.from_bytes(f.read())
|
|
24
|
+
|
|
25
|
+
print(file)
|
|
26
|
+
for packet in file. packets:
|
|
27
|
+
print(packet)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Create a tasd file from scratch and add packets to it
|
|
31
|
+
```py
|
|
32
|
+
from tasd import TASD, packets
|
|
33
|
+
|
|
34
|
+
file = TASD()
|
|
35
|
+
file.packets.append(packets.extra.Comment(comment="This is a comment"))
|
|
36
|
+
file.packets.append(packets.general.Attribution(type=packets.general.Attribution.ATTRIBUTION_TYPE.TASD_FILE_CREATOR, name="Me"))
|
|
37
|
+
|
|
38
|
+
for packet in file. packets:
|
|
39
|
+
print(packet)
|
|
40
|
+
|
|
41
|
+
print(file.to_bytes())
|
|
42
|
+
```
|
|
43
|
+
## Brief API Reference
|
|
44
|
+
|
|
45
|
+
Not an exhaustive list
|
|
46
|
+
|
|
47
|
+
`tasd.TASD`
|
|
48
|
+
|
|
49
|
+
Class holding properties of the tasd file itself: Version and KeyLength
|
|
50
|
+
|
|
51
|
+
`tasd.constants.PACKET_TYPES`
|
|
52
|
+
|
|
53
|
+
Enumlike class containing the different packet type indentifiers
|
|
54
|
+
|
|
55
|
+
`tasd.packets`
|
|
56
|
+
|
|
57
|
+
Submodule containing all the different packet classes
|
|
58
|
+
|
|
59
|
+
For details about the different packet types i suggest reading the specification document to determine what packets you need to consider for your use case
|
|
60
|
+
## Appendix
|
|
61
|
+
|
|
62
|
+
Any additional information goes here
|
|
63
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "tasd"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
authors = [
|
|
5
|
+
{ name="TheMas3212", email="mas3212@gmail.com" },
|
|
6
|
+
]
|
|
7
|
+
description = "TASD file serializer and deserializer"
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
requires-python = ">=3.10"
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Programming Language :: Python :: 3",
|
|
12
|
+
"Operating System :: OS Independent",
|
|
13
|
+
]
|
|
14
|
+
license = "MIT"
|
|
15
|
+
license-files = ["LICEN[CS]E*"]
|
|
16
|
+
|
|
17
|
+
[project.urls]
|
|
18
|
+
Homepage = "https://github.com/themas3212/tasd-py"
|
|
19
|
+
Issues = "https://github.com/themas3212/tasd-py/issues"
|
|
20
|
+
|
|
21
|
+
[build-system]
|
|
22
|
+
requires = ["setuptools >= 77.0.3"]
|
|
23
|
+
build-backend = "setuptools.build_meta"
|
tasd-1.0.0/setup.cfg
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
class _MetaPacketType():
|
|
2
|
+
def __init_subclass__(self):
|
|
3
|
+
keys = [key for key in self.__dict__.keys() if type(self.__dict__[key]) == int]
|
|
4
|
+
self._key2name = dict()
|
|
5
|
+
for key in keys:
|
|
6
|
+
self._key2name[self.__dict__[key]] = key
|
|
7
|
+
|
|
8
|
+
class PacketType(_MetaPacketType):
|
|
9
|
+
# General Keys
|
|
10
|
+
CONSOLE_TYPE = 0x0001
|
|
11
|
+
CONSOLE_REGION = 0x0002
|
|
12
|
+
GAME_TITLE = 0x0003
|
|
13
|
+
ROM_NAME = 0x0004
|
|
14
|
+
ATTRIBUTION = 0x0005
|
|
15
|
+
CATEGORY = 0x0006
|
|
16
|
+
EMULATOR_NAME = 0x0007
|
|
17
|
+
EMULATOR_VERSION = 0x0008
|
|
18
|
+
EMULATOR_CORE = 0x0009
|
|
19
|
+
TAS_LAST_MODIFIED = 0x000A
|
|
20
|
+
DUMP_CREATED = 0x000B
|
|
21
|
+
DUMP_LAST_MODIFIED = 0x000C
|
|
22
|
+
TOTAL_FRAMES = 0x000D
|
|
23
|
+
RERECORDS = 0x000E
|
|
24
|
+
SOURCE_LINK = 0x000F
|
|
25
|
+
BLANK_FRAMES = 0x0010
|
|
26
|
+
VERIFIED = 0x0011
|
|
27
|
+
MEMORY_INIT = 0x0012
|
|
28
|
+
GAME_IDENTIFIER = 0x0013
|
|
29
|
+
MOVIE_LICENSE = 0x0014
|
|
30
|
+
MOVIE_FILE = 0x0015
|
|
31
|
+
PORT_CONTROLLER = 0x00F0
|
|
32
|
+
PORT_OVERREAD = 0x00F1
|
|
33
|
+
# NES Specific Keys
|
|
34
|
+
NES_LATCH_FILTER = 0x0101
|
|
35
|
+
NES_CLOCK_FILTER = 0x0102
|
|
36
|
+
NES_GAME_GENIE_CODE = 0x0104
|
|
37
|
+
# SNES Specific Keys
|
|
38
|
+
SNES_LATCH_FILTER = 0x0201
|
|
39
|
+
SNES_CLOCK_FILTER = 0x0202
|
|
40
|
+
SNES_GAME_GENIE_CODE = 0x0204
|
|
41
|
+
SNES_LATCH_TRAIN = 0x0205
|
|
42
|
+
# Genesis Specific Keys
|
|
43
|
+
GENESIS_GAME_GENIE_CODE = 0x0804
|
|
44
|
+
# Input Frame/Timing Keys
|
|
45
|
+
INPUT_CHUNK = 0xFE01
|
|
46
|
+
INPUT_MOMENT = 0xFE02
|
|
47
|
+
TRANSITION = 0xFE03
|
|
48
|
+
LAG_FRAME_CHUNK = 0xFE04
|
|
49
|
+
MOVIE_TRANSITION = 0xFE05
|
|
50
|
+
# Extraneous Keys
|
|
51
|
+
COMMENT = 0xFF01
|
|
52
|
+
EXPERIMENTAL = 0xFFFE
|
|
53
|
+
UNSPECIFIED = 0xFFFF
|
|
54
|
+
@classmethod
|
|
55
|
+
def lookup(cls, key):
|
|
56
|
+
return cls._key2name.get(key, f'UNKNOWN_PACKET_{key:04X}')
|
tasd-1.0.0/tasd/file.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import tasd.packets as packets
|
|
2
|
+
import tasd.constants as constants
|
|
3
|
+
import tasd.utils as utils
|
|
4
|
+
from tasd.packet import lookup_packet, _TASDPacket
|
|
5
|
+
from typing import List
|
|
6
|
+
|
|
7
|
+
class TASD():
|
|
8
|
+
MAGIC = b"TASD"
|
|
9
|
+
def __init__(self, version = 1, g_keylen = 2):
|
|
10
|
+
self.version = version
|
|
11
|
+
self.g_keylen = g_keylen
|
|
12
|
+
self.packets: List[_TASDPacket] = []
|
|
13
|
+
@classmethod
|
|
14
|
+
def from_bytes(cls, buffer: bytes, *, bypass_errors = False):
|
|
15
|
+
magic = utils.readBytes(buffer, 0, 4)
|
|
16
|
+
if magic != cls.MAGIC:
|
|
17
|
+
raise ValueError("Invalid TASD File, Missing Magic")
|
|
18
|
+
version = utils.readUint16(buffer, 4)
|
|
19
|
+
if version != 1 and not bypass_errors:
|
|
20
|
+
raise ValueError("Unsupported TASD File, Version Unsupported", version)
|
|
21
|
+
g_keylen = utils.readUint8(buffer, 6)
|
|
22
|
+
if g_keylen != 2:
|
|
23
|
+
raise ValueError("Unsupported TASD File, Unknown G_KEYLEN", g_keylen)
|
|
24
|
+
self = cls(version, g_keylen)
|
|
25
|
+
index = 7
|
|
26
|
+
while index < len(buffer):
|
|
27
|
+
key = utils.readUintN(buffer, index, self.g_keylen)
|
|
28
|
+
index += self.g_keylen
|
|
29
|
+
packet_cls = lookup_packet(key)
|
|
30
|
+
pexp = utils.readUint8(buffer, index)
|
|
31
|
+
index += 1
|
|
32
|
+
plen = utils.readUintN(buffer, index, pexp)
|
|
33
|
+
index += pexp
|
|
34
|
+
data = utils.readBytes(buffer, index, plen)
|
|
35
|
+
index += plen
|
|
36
|
+
packet = packet_cls.from_bytes(data)
|
|
37
|
+
self.packets.append(packet)
|
|
38
|
+
return self
|
|
39
|
+
def to_bytes(self):
|
|
40
|
+
header = bytearray(7)
|
|
41
|
+
header[0:4] = self.MAGIC
|
|
42
|
+
utils.writeUint16(self.version, header, 4)
|
|
43
|
+
utils.writeUint8(self.g_keylen, header, 6)
|
|
44
|
+
packets = [ header ]
|
|
45
|
+
for packet in self.packets:
|
|
46
|
+
plen = packet.size()
|
|
47
|
+
pexp = utils.minUint(plen)
|
|
48
|
+
size = self.g_keylen + 1 + pexp
|
|
49
|
+
buffer = bytearray(size)
|
|
50
|
+
utils.writeUintN(packet._key, buffer, 0, self.g_keylen)
|
|
51
|
+
utils.writeUint8(pexp, buffer, self.g_keylen)
|
|
52
|
+
utils.writeUintN(plen, buffer, self.g_keylen + 1, pexp)
|
|
53
|
+
payload = packet.to_bytes()
|
|
54
|
+
packets.append(buffer + payload)
|
|
55
|
+
return b"".join(packets)
|
|
56
|
+
def __repr__(self):
|
|
57
|
+
return f"TASD(version={self.version}, g_keylen={self.g_keylen})"
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
from typing import NamedTuple, List, Any
|
|
2
|
+
from enum import Enum
|
|
3
|
+
|
|
4
|
+
from tasd.constants import PacketType
|
|
5
|
+
from tasd.utils import *
|
|
6
|
+
|
|
7
|
+
class _VariableType(Enum):
|
|
8
|
+
STRING_EOP = 0x00
|
|
9
|
+
STRING_PLEN = 0x01
|
|
10
|
+
STRING_PEXP = 0x02
|
|
11
|
+
BYTES_EOP = 0x10
|
|
12
|
+
BYTES_PLEN = 0x11
|
|
13
|
+
BYTES_PEXP = 0x12
|
|
14
|
+
INT_8 = 0x20
|
|
15
|
+
INT_16 = 0x21
|
|
16
|
+
INT_24 = 0x22
|
|
17
|
+
INT_32 = 0x23
|
|
18
|
+
INT_64 = 0x24
|
|
19
|
+
INT_N = 0x25
|
|
20
|
+
UINT_8 = 0x30
|
|
21
|
+
UINT_16 = 0x31
|
|
22
|
+
UINT_24 = 0x32
|
|
23
|
+
UINT_32 = 0x33
|
|
24
|
+
UINT_64 = 0x34
|
|
25
|
+
UINT_N = 0x35
|
|
26
|
+
BOOL = 0x40
|
|
27
|
+
LIST_UINT_64 = 0x50
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class _VariableDefinition(NamedTuple):
|
|
31
|
+
name: str
|
|
32
|
+
type: _VariableType
|
|
33
|
+
default: Any
|
|
34
|
+
|
|
35
|
+
class _EnumDefinition(NamedTuple):
|
|
36
|
+
name: str
|
|
37
|
+
enum: Enum
|
|
38
|
+
|
|
39
|
+
class _TASDPacket():
|
|
40
|
+
@classmethod
|
|
41
|
+
def from_bytes(cls, buffer: bytes):
|
|
42
|
+
self = cls()
|
|
43
|
+
index = 0
|
|
44
|
+
for variable in cls._variables:
|
|
45
|
+
match variable.type:
|
|
46
|
+
case _VariableType.STRING_EOP:
|
|
47
|
+
setattr(self, variable.name, readString(buffer, index, len(buffer) - index))
|
|
48
|
+
index = len(buffer)
|
|
49
|
+
case _VariableType.STRING_PLEN:
|
|
50
|
+
plen = readInt8(buffer, index)
|
|
51
|
+
index += 1
|
|
52
|
+
setattr(self, variable.name, readString(buffer, index, plen))
|
|
53
|
+
index += plen
|
|
54
|
+
case _VariableType.STRING_PEXP:
|
|
55
|
+
pexp = readInt8(buffer, index)
|
|
56
|
+
index += 1
|
|
57
|
+
plen = readIntN(buffer, index, pexp)
|
|
58
|
+
index += pexp
|
|
59
|
+
setattr(self, variable.name, readString(buffer, index, plen))
|
|
60
|
+
index += plen
|
|
61
|
+
case _VariableType.BYTES_EOP:
|
|
62
|
+
setattr(self, variable.name, readBytes(buffer, index, len(buffer)))
|
|
63
|
+
index = len(buffer)
|
|
64
|
+
case _VariableType.BYTES_PLEN:
|
|
65
|
+
plen = readInt8(buffer, index)
|
|
66
|
+
index += 1
|
|
67
|
+
setattr(self, variable.name, readBytes(buffer, index, plen))
|
|
68
|
+
index += plen
|
|
69
|
+
case _VariableType.BYTES_PEXP:
|
|
70
|
+
pexp = readInt8(buffer, index)
|
|
71
|
+
index += 1
|
|
72
|
+
plen = readIntN(buffer, index, pexp)
|
|
73
|
+
index += pexp
|
|
74
|
+
setattr(self, variable.name, readBytes(buffer, index, plen))
|
|
75
|
+
index += plen
|
|
76
|
+
case _VariableType.INT_8:
|
|
77
|
+
setattr(self, variable.name, readInt8(buffer, index))
|
|
78
|
+
index += 1
|
|
79
|
+
case _VariableType.INT_16:
|
|
80
|
+
setattr(self, variable.name, readInt16(buffer, index))
|
|
81
|
+
index += 2
|
|
82
|
+
case _VariableType.INT_24:
|
|
83
|
+
setattr(self, variable.name, readInt24(buffer, index))
|
|
84
|
+
index += 3
|
|
85
|
+
case _VariableType.INT_32:
|
|
86
|
+
setattr(self, variable.name, readInt32(buffer, index))
|
|
87
|
+
index += 4
|
|
88
|
+
case _VariableType.INT_64:
|
|
89
|
+
setattr(self, variable.name, readInt64(buffer, index))
|
|
90
|
+
index += 8
|
|
91
|
+
case _VariableType.INT_N:
|
|
92
|
+
pexp = readInt8(buffer, index)
|
|
93
|
+
index += 1
|
|
94
|
+
setattr(self, variable.name, readIntN(buffer, index, pexp))
|
|
95
|
+
index += pexp
|
|
96
|
+
case _VariableType.UINT_8:
|
|
97
|
+
setattr(self, variable.name, readUint8(buffer, index))
|
|
98
|
+
index += 1
|
|
99
|
+
case _VariableType.UINT_16:
|
|
100
|
+
setattr(self, variable.name, readUint16(buffer, index))
|
|
101
|
+
index += 2
|
|
102
|
+
case _VariableType.UINT_24:
|
|
103
|
+
setattr(self, variable.name, readUint24(buffer, index))
|
|
104
|
+
index += 3
|
|
105
|
+
case _VariableType.UINT_32:
|
|
106
|
+
setattr(self, variable.name, readUint32(buffer, index))
|
|
107
|
+
index += 4
|
|
108
|
+
case _VariableType.UINT_64:
|
|
109
|
+
setattr(self, variable.name, readUint64(buffer, index))
|
|
110
|
+
index += 8
|
|
111
|
+
case _VariableType.UINT_N:
|
|
112
|
+
pexp = readUint8(buffer, index)
|
|
113
|
+
index += 1
|
|
114
|
+
setattr(self, variable.name, readUintN(buffer, index, pexp))
|
|
115
|
+
index += pexp
|
|
116
|
+
case _VariableType.BOOL:
|
|
117
|
+
setattr(self, variable.name, readBoolean(buffer, index))
|
|
118
|
+
index += 1
|
|
119
|
+
case _VariableType.LIST_UINT_64:
|
|
120
|
+
l = list()
|
|
121
|
+
while index < len(buffer):
|
|
122
|
+
l.append(readUint64(buffer, index))
|
|
123
|
+
index += 8
|
|
124
|
+
setattr(self, variable.name, l)
|
|
125
|
+
case _:
|
|
126
|
+
raise ValueError("Unknown Variable Type", variable)
|
|
127
|
+
return self
|
|
128
|
+
def size(self):
|
|
129
|
+
size = 0
|
|
130
|
+
for variable in self._variables:
|
|
131
|
+
value = getattr(self, variable.name)
|
|
132
|
+
match variable.type:
|
|
133
|
+
case _VariableType.STRING_EOP:
|
|
134
|
+
size += sizeString(value)
|
|
135
|
+
case _VariableType.STRING_PLEN:
|
|
136
|
+
size += ( 1 + sizeString(value) )
|
|
137
|
+
case _VariableType.STRING_PEXP:
|
|
138
|
+
vsize = sizeString(value)
|
|
139
|
+
size += ( 1 + minUint(vsize) + vsize )
|
|
140
|
+
case _VariableType.BYTES_EOP:
|
|
141
|
+
size += len(value)
|
|
142
|
+
case _VariableType.BYTES_PLEN:
|
|
143
|
+
size += ( 1 + len(value) )
|
|
144
|
+
case _VariableType.BYTES_PEXP:
|
|
145
|
+
vsize = len(value)
|
|
146
|
+
size += ( 1 + minUint(vsize) + vsize )
|
|
147
|
+
case _VariableType.INT_8:
|
|
148
|
+
size += 1
|
|
149
|
+
case _VariableType.INT_16:
|
|
150
|
+
size += 2
|
|
151
|
+
case _VariableType.INT_24:
|
|
152
|
+
size += 3
|
|
153
|
+
case _VariableType.INT_32:
|
|
154
|
+
size += 4
|
|
155
|
+
case _VariableType.INT_64:
|
|
156
|
+
size += 8
|
|
157
|
+
case _VariableType.INT_N:
|
|
158
|
+
size += minInt(value)
|
|
159
|
+
case _VariableType.UINT_8:
|
|
160
|
+
size += 1
|
|
161
|
+
case _VariableType.UINT_16:
|
|
162
|
+
size += 2
|
|
163
|
+
case _VariableType.UINT_24:
|
|
164
|
+
size += 3
|
|
165
|
+
case _VariableType.UINT_32:
|
|
166
|
+
size += 4
|
|
167
|
+
case _VariableType.UINT_64:
|
|
168
|
+
size += 8
|
|
169
|
+
case _VariableType.UINT_N:
|
|
170
|
+
size += minUint(value)
|
|
171
|
+
case _VariableType.BOOL:
|
|
172
|
+
size += 1
|
|
173
|
+
case _VariableType.LIST_UINT_64:
|
|
174
|
+
size += ( 8 * len(value) )
|
|
175
|
+
case _:
|
|
176
|
+
raise ValueError("Unknown Variable Type", variable)
|
|
177
|
+
return size
|
|
178
|
+
def to_bytes(self):
|
|
179
|
+
buffer = bytearray(self.size())
|
|
180
|
+
index = 0
|
|
181
|
+
for variable in self._variables:
|
|
182
|
+
value = getattr(self, variable.name)
|
|
183
|
+
match variable.type:
|
|
184
|
+
case _VariableType.STRING_EOP:
|
|
185
|
+
writeString(value, buffer, index)
|
|
186
|
+
index += sizeString(value)
|
|
187
|
+
case _VariableType.STRING_PLEN:
|
|
188
|
+
plen = sizeString(value)
|
|
189
|
+
writeUint8(plen, buffer, index)
|
|
190
|
+
index += 1
|
|
191
|
+
writeString(value, buffer, index)
|
|
192
|
+
index += plen
|
|
193
|
+
case _VariableType.STRING_PEXP:
|
|
194
|
+
plen = sizeString(value)
|
|
195
|
+
pexp = minUint(plen)
|
|
196
|
+
writeUint8(pexp, buffer, index)
|
|
197
|
+
index += 1
|
|
198
|
+
writeUintN(plen, buffer, index, pexp)
|
|
199
|
+
index += pexp
|
|
200
|
+
writeString(value, buffer, index)
|
|
201
|
+
index += plen
|
|
202
|
+
case _VariableType.BYTES_EOP:
|
|
203
|
+
writeBytes(value, buffer, index)
|
|
204
|
+
index += len(value)
|
|
205
|
+
case _VariableType.BYTES_PLEN:
|
|
206
|
+
plen = len(value)
|
|
207
|
+
writeUint8(plen, buffer, index)
|
|
208
|
+
index += 1
|
|
209
|
+
writeBytes(value, buffer, index)
|
|
210
|
+
index += plen
|
|
211
|
+
case _VariableType.BYTES_PEXP:
|
|
212
|
+
plen = len(value)
|
|
213
|
+
pexp = minUint(plen)
|
|
214
|
+
writeUint8(pexp, buffer, index)
|
|
215
|
+
index += 1
|
|
216
|
+
writeUintN(plen, buffer, index, pexp)
|
|
217
|
+
index += pexp
|
|
218
|
+
writeBytes(value, buffer, index)
|
|
219
|
+
index += plen
|
|
220
|
+
case _VariableType.INT_8:
|
|
221
|
+
writeInt8(value, buffer, index)
|
|
222
|
+
index += 1
|
|
223
|
+
case _VariableType.INT_16:
|
|
224
|
+
writeInt16(value, buffer, index)
|
|
225
|
+
index += 2
|
|
226
|
+
case _VariableType.INT_24:
|
|
227
|
+
writeInt24(value, buffer, index)
|
|
228
|
+
index += 3
|
|
229
|
+
case _VariableType.INT_32:
|
|
230
|
+
writeInt32(value, buffer, index)
|
|
231
|
+
index += 4
|
|
232
|
+
case _VariableType.INT_64:
|
|
233
|
+
writeInt64(value, buffer, index)
|
|
234
|
+
index += 8
|
|
235
|
+
case _VariableType.INT_N:
|
|
236
|
+
pexp = minInt(value)
|
|
237
|
+
writeUint8(pexp, buffer, index)
|
|
238
|
+
index += 1
|
|
239
|
+
writeIntN(value, buffer, index, pexp)
|
|
240
|
+
index += pexp
|
|
241
|
+
case _VariableType.UINT_8:
|
|
242
|
+
writeUint8(value, buffer, index)
|
|
243
|
+
index += 1
|
|
244
|
+
case _VariableType.UINT_16:
|
|
245
|
+
writeUint16(value, buffer, index)
|
|
246
|
+
index += 2
|
|
247
|
+
case _VariableType.UINT_24:
|
|
248
|
+
writeUint24(value, buffer, index)
|
|
249
|
+
index += 3
|
|
250
|
+
case _VariableType.UINT_32:
|
|
251
|
+
writeUint32(value, buffer, index)
|
|
252
|
+
index += 4
|
|
253
|
+
case _VariableType.UINT_64:
|
|
254
|
+
writeUint64(value, buffer, index)
|
|
255
|
+
index += 8
|
|
256
|
+
case _VariableType.UINT_N:
|
|
257
|
+
pexp = minInt(value)
|
|
258
|
+
writeUint8(pexp, buffer, index)
|
|
259
|
+
index += 1
|
|
260
|
+
writeUintN(value, buffer, index, pexp)
|
|
261
|
+
index += pexp
|
|
262
|
+
case _VariableType.BOOL:
|
|
263
|
+
writeBoolean(value, buffer, index)
|
|
264
|
+
index += 1
|
|
265
|
+
case _VariableType.LIST_UINT_64:
|
|
266
|
+
for val in value:
|
|
267
|
+
writeUint64(val, buffer, index)
|
|
268
|
+
index += 8
|
|
269
|
+
case _:
|
|
270
|
+
raise ValueError("Unknown Variable Type", variable)
|
|
271
|
+
return buffer
|
|
272
|
+
def __repr__(self):
|
|
273
|
+
return f"{self._name}({', '.join(f'{var.name}={getattr(self, var.name)}' for var in self._variables)})"
|
|
274
|
+
|
|
275
|
+
_lookup_table = dict()
|
|
276
|
+
|
|
277
|
+
def _TASDPacketFactory(name: str, key: int, variables: List[_VariableDefinition] = [], enums: List[_EnumDefinition] = []):
|
|
278
|
+
class Packet(_TASDPacket):
|
|
279
|
+
_variables = variables
|
|
280
|
+
_key = key
|
|
281
|
+
_name = name
|
|
282
|
+
def __init__(self, **kwargs):
|
|
283
|
+
for variable in Packet._variables:
|
|
284
|
+
setattr(self, variable.name, kwargs.get(variable.name, variable.default))
|
|
285
|
+
|
|
286
|
+
for enum in enums:
|
|
287
|
+
setattr(Packet, enum.name, enum.enum)
|
|
288
|
+
|
|
289
|
+
_lookup_table[key] = Packet
|
|
290
|
+
|
|
291
|
+
Packet.__name__ = name
|
|
292
|
+
Packet.__qualname__ = name
|
|
293
|
+
return Packet
|
|
294
|
+
|
|
295
|
+
def _build_unknown_packet(key):
|
|
296
|
+
_UnknownPacket = _TASDPacketFactory(f"UnknownPacket_{key:04x}", key, [ _VariableDefinition("data", _VariableType.BYTES_EOP, b"") ])
|
|
297
|
+
return _UnknownPacket
|
|
298
|
+
|
|
299
|
+
def lookup_packet(key: int) -> _TASDPacket:
|
|
300
|
+
packet = _lookup_table.get(key, None)
|
|
301
|
+
if packet == None:
|
|
302
|
+
packet = _build_unknown_packet(key)
|
|
303
|
+
return packet
|
|
304
|
+
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from tasd.packet import _TASDPacketFactory as _TASD_PF, _VariableType as _VType, _VariableDefinition as _VDef, _EnumDefinition as _EDef
|
|
2
|
+
from tasd.constants import PacketType
|
|
3
|
+
|
|
4
|
+
'''
|
|
5
|
+
4.3.6.1. COMMENT Packet
|
|
6
|
+
'''
|
|
7
|
+
|
|
8
|
+
Comment = _TASD_PF(
|
|
9
|
+
"Comment",
|
|
10
|
+
PacketType.COMMENT,
|
|
11
|
+
[
|
|
12
|
+
_VDef("comment", _VType.STRING_EOP, "")
|
|
13
|
+
]
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
'''
|
|
17
|
+
4.3.6.2. EXPERIMENTAL Packet
|
|
18
|
+
'''
|
|
19
|
+
|
|
20
|
+
Experimental = _TASD_PF(
|
|
21
|
+
"Experimental",
|
|
22
|
+
PacketType.EXPERIMENTAL,
|
|
23
|
+
[
|
|
24
|
+
_VDef("experimental", _VType.BOOL, False)
|
|
25
|
+
]
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
'''
|
|
29
|
+
4.3.6.3. UNSPECIFIED Packet
|
|
30
|
+
'''
|
|
31
|
+
|
|
32
|
+
Unspecified = _TASD_PF(
|
|
33
|
+
"Unspecified",
|
|
34
|
+
PacketType.UNSPECIFIED,
|
|
35
|
+
[
|
|
36
|
+
_VDef("data", _VType.BYTES_EOP, b"")
|
|
37
|
+
]
|
|
38
|
+
)
|