PyLibMS 5.0.1__tar.gz → 5.0.2__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.
- {pylibms-5.0.1 → pylibms-5.0.2}/PKG-INFO +4 -11
- {pylibms-5.0.1 → pylibms-5.0.2}/PyLibMS.egg-info/PKG-INFO +4 -11
- {pylibms-5.0.1 → pylibms-5.0.2}/PyLibMS.egg-info/SOURCES.txt +0 -1
- {pylibms-5.0.1 → pylibms-5.0.2}/README.md +3 -10
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/common/field/io.py +0 -3
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/common/field/lms_datatype.py +5 -3
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/common/field/lms_field.py +2 -2
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/message/lms_messagetext.py +7 -3
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/message/msbt.py +20 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/message/tag/io/param_io.py +2 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/message/tag/io/tag_io.py +4 -4
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/message/tag/lms_tag.py +27 -23
- {pylibms-5.0.1 → pylibms-5.0.2}/pyproject.toml +1 -1
- pylibms-5.0.1/lms/titleconfig/definitions/__init__.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/LICENSE +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/MANIFEST.in +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/PyLibMS.egg-info/dependency_links.txt +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/PyLibMS.egg-info/requires.txt +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/PyLibMS.egg-info/top_level.txt +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/__init__.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/common/__init__.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/common/field/__init__.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/common/lms_constants.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/common/lms_exceptions.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/common/lms_fileinfo.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/common/stream/fileinfo.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/common/stream/hashtable.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/common/stream/section.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/fileio/encoding.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/fileio/io.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/flowchart/__init__.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/flowchart/definitions/__init__.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/flowchart/definitions/lms_nodeexceptions.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/flowchart/definitions/node.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/flowchart/definitions/node_type.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/flowchart/flw3.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/flowchart/msbf.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/flowchart/msbfio.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/message/__init__.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/message/definitions/__init__.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/message/msbtentry.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/message/msbtio.py +0 -0
- {pylibms-5.0.1/lms/message/definitions/field → pylibms-5.0.2/lms/message/section}/__init__.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/message/section/atr1.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/message/section/nli1.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/message/section/tsy1.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/message/section/txt2.py +0 -0
- {pylibms-5.0.1/lms/message/section → pylibms-5.0.2/lms/message/tag}/__init__.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/message/tag/lms_tagexceptions.py +0 -0
- {pylibms-5.0.1/lms/message/tag → pylibms-5.0.2/lms/project}/__init__.py +0 -0
- {pylibms-5.0.1/lms/project → pylibms-5.0.2/lms/project/definitions}/__init__.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/project/definitions/attribute.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/project/definitions/color.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/project/definitions/style.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/project/definitions/tag.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/project/msbp.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/project/msbpread.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/project/section/ali2.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/project/section/ati2.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/project/section/clr1.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/project/section/string.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/project/section/syl3.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/project/section/tag2.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/project/section/tgg2.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/project/section/tgp2.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/py.typed +0 -0
- {pylibms-5.0.1/lms/project/definitions → pylibms-5.0.2/lms/titleconfig}/__init__.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/titleconfig/config.py +0 -0
- {pylibms-5.0.1/lms/titleconfig → pylibms-5.0.2/lms/titleconfig/definitions}/__init__.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/titleconfig/definitions/attribute.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/titleconfig/definitions/field.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/titleconfig/definitions/nodes.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/titleconfig/definitions/tags.py +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/titleconfig/presets/Badge Arcade.yaml +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/titleconfig/presets/Brain Age Concentration Training.yaml +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/titleconfig/presets/Kirby Planet Robobot.yaml +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/titleconfig/presets/Super Mario 3D Land.yaml +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/titleconfig/presets/Super Mario 3D World + Bowsers Fury.yaml +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/titleconfig/presets/Super Mario Odyssey.yaml +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/titleconfig/presets/The Legend of Zelda Echos of Wisdom.yaml +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/titleconfig/presets/The Legend of Zelda a Link Between Worlds.yaml +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/lms/titleconfig/presets/Tomodachi Life Living The Dream.yaml +0 -0
- {pylibms-5.0.1 → pylibms-5.0.2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyLibMS
|
|
3
|
-
Version: 5.0.
|
|
3
|
+
Version: 5.0.2
|
|
4
4
|
Summary: Python library built for the libMessageStudio (LMS) proprietary file formats from Nintendo. Supports MSBT, MSBP, and MSBF.
|
|
5
5
|
Author: AbdyyEee
|
|
6
6
|
License-Expression: MIT
|
|
@@ -23,6 +23,7 @@ Dynamic: license-file
|
|
|
23
23
|
[](https://pypi.org/project/PyLibMS/)
|
|
24
24
|

|
|
25
25
|
[](https://badge.fury.io/py/PyLibMS)
|
|
26
|
+

|
|
26
27
|
|
|
27
28
|
PyLibMS is a library built in Python 3.11 and above for reading and writing of libMessageStudio (LMS) proprietary file
|
|
28
29
|
formats from Nintendo.
|
|
@@ -90,7 +91,7 @@ pip install PyLibMS
|
|
|
90
91
|
|
|
91
92
|
# Build Instructions
|
|
92
93
|
|
|
93
|
-
Python version must be `3.
|
|
94
|
+
Python version must be `3.11` or higher.
|
|
94
95
|
|
|
95
96
|
Clone the repository, then run `pip install` (venv recommended)
|
|
96
97
|
|
|
@@ -102,15 +103,7 @@ pip install -e .
|
|
|
102
103
|
|
|
103
104
|
# AI Disclaimer
|
|
104
105
|
|
|
105
|
-
Code in this library was written by me. AI was utilized occasionally when
|
|
106
|
-
|
|
107
|
-
`MSBT`: Only usage of AI was for control tag regex formats and for understanding implementing string importing with
|
|
108
|
-
`re`.
|
|
109
|
-
|
|
110
|
-
`MSBP`: AI was not utilized anywhere.
|
|
111
|
-
|
|
112
|
-
`MSBF`: AI was only utilized for the `LMS_BaseNode.get_descendents` function and for consultation for ways to improve
|
|
113
|
-
the API.
|
|
106
|
+
Code in this library was written by me. AI was utilized occasionally when developing MSBT (specifically tag string importing) , MSBF and assisting in creating unit tests.
|
|
114
107
|
|
|
115
108
|
# Credits & Sources
|
|
116
109
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyLibMS
|
|
3
|
-
Version: 5.0.
|
|
3
|
+
Version: 5.0.2
|
|
4
4
|
Summary: Python library built for the libMessageStudio (LMS) proprietary file formats from Nintendo. Supports MSBT, MSBP, and MSBF.
|
|
5
5
|
Author: AbdyyEee
|
|
6
6
|
License-Expression: MIT
|
|
@@ -23,6 +23,7 @@ Dynamic: license-file
|
|
|
23
23
|
[](https://pypi.org/project/PyLibMS/)
|
|
24
24
|

|
|
25
25
|
[](https://badge.fury.io/py/PyLibMS)
|
|
26
|
+

|
|
26
27
|
|
|
27
28
|
PyLibMS is a library built in Python 3.11 and above for reading and writing of libMessageStudio (LMS) proprietary file
|
|
28
29
|
formats from Nintendo.
|
|
@@ -90,7 +91,7 @@ pip install PyLibMS
|
|
|
90
91
|
|
|
91
92
|
# Build Instructions
|
|
92
93
|
|
|
93
|
-
Python version must be `3.
|
|
94
|
+
Python version must be `3.11` or higher.
|
|
94
95
|
|
|
95
96
|
Clone the repository, then run `pip install` (venv recommended)
|
|
96
97
|
|
|
@@ -102,15 +103,7 @@ pip install -e .
|
|
|
102
103
|
|
|
103
104
|
# AI Disclaimer
|
|
104
105
|
|
|
105
|
-
Code in this library was written by me. AI was utilized occasionally when
|
|
106
|
-
|
|
107
|
-
`MSBT`: Only usage of AI was for control tag regex formats and for understanding implementing string importing with
|
|
108
|
-
`re`.
|
|
109
|
-
|
|
110
|
-
`MSBP`: AI was not utilized anywhere.
|
|
111
|
-
|
|
112
|
-
`MSBF`: AI was only utilized for the `LMS_BaseNode.get_descendents` function and for consultation for ways to improve
|
|
113
|
-
the API.
|
|
106
|
+
Code in this library was written by me. AI was utilized occasionally when developing MSBT (specifically tag string importing) , MSBF and assisting in creating unit tests.
|
|
114
107
|
|
|
115
108
|
# Credits & Sources
|
|
116
109
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
[](https://pypi.org/project/PyLibMS/)
|
|
4
4
|

|
|
5
5
|
[](https://badge.fury.io/py/PyLibMS)
|
|
6
|
+

|
|
6
7
|
|
|
7
8
|
PyLibMS is a library built in Python 3.11 and above for reading and writing of libMessageStudio (LMS) proprietary file
|
|
8
9
|
formats from Nintendo.
|
|
@@ -70,7 +71,7 @@ pip install PyLibMS
|
|
|
70
71
|
|
|
71
72
|
# Build Instructions
|
|
72
73
|
|
|
73
|
-
Python version must be `3.
|
|
74
|
+
Python version must be `3.11` or higher.
|
|
74
75
|
|
|
75
76
|
Clone the repository, then run `pip install` (venv recommended)
|
|
76
77
|
|
|
@@ -82,15 +83,7 @@ pip install -e .
|
|
|
82
83
|
|
|
83
84
|
# AI Disclaimer
|
|
84
85
|
|
|
85
|
-
Code in this library was written by me. AI was utilized occasionally when
|
|
86
|
-
|
|
87
|
-
`MSBT`: Only usage of AI was for control tag regex formats and for understanding implementing string importing with
|
|
88
|
-
`re`.
|
|
89
|
-
|
|
90
|
-
`MSBP`: AI was not utilized anywhere.
|
|
91
|
-
|
|
92
|
-
`MSBF`: AI was only utilized for the `LMS_BaseNode.get_descendents` function and for consultation for ways to improve
|
|
93
|
-
the API.
|
|
86
|
+
Code in this library was written by me. AI was utilized occasionally when developing MSBT (specifically tag string importing) , MSBF and assisting in creating unit tests.
|
|
94
87
|
|
|
95
88
|
# Credits & Sources
|
|
96
89
|
|
|
@@ -3,7 +3,6 @@ from typing import Callable
|
|
|
3
3
|
from lms.common.field.lms_datatype import (
|
|
4
4
|
LMS_DataType,
|
|
5
5
|
is_bool_datatype,
|
|
6
|
-
is_bytes_datatype,
|
|
7
6
|
is_enum_datatype,
|
|
8
7
|
is_number_datatype,
|
|
9
8
|
)
|
|
@@ -72,8 +71,6 @@ def write_field(
|
|
|
72
71
|
write_variable_width_value(value)
|
|
73
72
|
else:
|
|
74
73
|
writer.write_uint8(value)
|
|
75
|
-
elif is_bytes_datatype(field.value, field.datatype):
|
|
76
|
-
writer.write_bytes(field.value)
|
|
77
74
|
elif is_bool_datatype(field.value, field.datatype):
|
|
78
75
|
if write_variable_width_value is not None:
|
|
79
76
|
write_variable_width_value(bool(field.value))
|
|
@@ -22,6 +22,9 @@ ALIAS_MAP = {
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
def is_number_datatype(value: object, datatype: LMS_DataType) -> TypeGuard[int | float]:
|
|
25
|
+
if isinstance(value, float) and datatype is LMS_DataType.FLOAT32:
|
|
26
|
+
return True
|
|
27
|
+
|
|
25
28
|
return datatype in (
|
|
26
29
|
LMS_DataType.UINT8,
|
|
27
30
|
LMS_DataType.UINT16,
|
|
@@ -29,7 +32,6 @@ def is_number_datatype(value: object, datatype: LMS_DataType) -> TypeGuard[int |
|
|
|
29
32
|
LMS_DataType.INT8,
|
|
30
33
|
LMS_DataType.INT16,
|
|
31
34
|
LMS_DataType.INT32,
|
|
32
|
-
LMS_DataType.FLOAT32,
|
|
33
35
|
) and isinstance(value, int)
|
|
34
36
|
|
|
35
37
|
|
|
@@ -138,8 +140,8 @@ def verify_number_from_datatype(
|
|
|
138
140
|
else:
|
|
139
141
|
bits = datatype.stream_size * 8
|
|
140
142
|
if datatype.signed:
|
|
141
|
-
|
|
142
|
-
|
|
143
|
+
min_value = -(2 ** (bits - 1))
|
|
144
|
+
max_value = (2 ** (bits - 1)) - 1
|
|
143
145
|
else:
|
|
144
146
|
min_value, max_value = 0, (2 ** bits) - 1
|
|
145
147
|
|
|
@@ -93,7 +93,7 @@ class LMS_FieldMap:
|
|
|
93
93
|
value = data[definition.name]
|
|
94
94
|
match definition.datatype:
|
|
95
95
|
case LMS_DataType.BOOL:
|
|
96
|
-
if value not in ("false", "true"):
|
|
96
|
+
if value.lower() not in ("false", "true"):
|
|
97
97
|
raise ValueError("Invalid boolean value!")
|
|
98
98
|
casted_value = value.strip().lower() == "true"
|
|
99
99
|
case LMS_DataType.FLOAT32:
|
|
@@ -174,7 +174,7 @@ def _verify_value_from_definition(
|
|
|
174
174
|
)
|
|
175
175
|
else:
|
|
176
176
|
return
|
|
177
|
-
case _ if isinstance(value, int):
|
|
177
|
+
case _ if isinstance(value, (int, float)):
|
|
178
178
|
verify_number_from_datatype(value, definition.datatype)
|
|
179
179
|
return
|
|
180
180
|
|
|
@@ -7,7 +7,7 @@ from lms.message.tag.lms_tag import (
|
|
|
7
7
|
LMS_ControlTag,
|
|
8
8
|
LMS_DecodedTag,
|
|
9
9
|
LMS_EncodedTag,
|
|
10
|
-
is_tag,
|
|
10
|
+
is_tag, TAG_PADDING_VALUE,
|
|
11
11
|
)
|
|
12
12
|
from lms.message.tag.lms_tagexceptions import LMS_TagForbiddenParametersError
|
|
13
13
|
from lms.titleconfig.config import TagConfig
|
|
@@ -90,8 +90,12 @@ class LMS_MessageText:
|
|
|
90
90
|
|
|
91
91
|
tag = LMS_EncodedTag(group_id, tag_index, is_closing=True)
|
|
92
92
|
else:
|
|
93
|
+
list_parameters = list(parameters)
|
|
94
|
+
if len(list_parameters) % 2 == 1:
|
|
95
|
+
list_parameters.append(TAG_PADDING_VALUE)
|
|
96
|
+
|
|
93
97
|
tag = LMS_EncodedTag(
|
|
94
|
-
group_id, tag_index, None if not parameters else
|
|
98
|
+
group_id, tag_index, None if not parameters else list_parameters
|
|
95
99
|
)
|
|
96
100
|
|
|
97
101
|
self._segments.append(tag)
|
|
@@ -121,7 +125,7 @@ class LMS_MessageText:
|
|
|
121
125
|
if self._tag_config is None:
|
|
122
126
|
raise ValueError("A TitleConfig is required to append decoded tags.")
|
|
123
127
|
|
|
124
|
-
definition = self._tag_config
|
|
128
|
+
definition = self._tag_config[group_name][tag_name]
|
|
125
129
|
|
|
126
130
|
if is_closing:
|
|
127
131
|
if parameters:
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
from typing import overload
|
|
2
2
|
|
|
3
|
+
from lms.common.field.lms_field import LMS_FieldMap
|
|
3
4
|
from lms.common.lms_fileinfo import LMS_FileInfo
|
|
4
5
|
from lms.fileio.encoding import FileEncoding
|
|
6
|
+
from lms.message.lms_messagetext import LMS_MessageText
|
|
5
7
|
from lms.message.msbtentry import MSBTEntry
|
|
6
8
|
from lms.titleconfig.definitions.attribute import AttributeConfig
|
|
7
9
|
from lms.titleconfig.definitions.tags import TagConfig
|
|
@@ -219,6 +221,24 @@ class MSBT:
|
|
|
219
221
|
self._entries.append(entry)
|
|
220
222
|
self._label_map[entry.name] = entry
|
|
221
223
|
|
|
224
|
+
def create_entry(self, name: str,
|
|
225
|
+
message: str = None,
|
|
226
|
+
attribute: LMS_FieldMap | bytes | None = None,
|
|
227
|
+
style_index: int = None) -> MSBTEntry:
|
|
228
|
+
"""
|
|
229
|
+
Creates an MSBT Entry and adds it to the file.
|
|
230
|
+
|
|
231
|
+
param name: the name of the entry.
|
|
232
|
+
param message: the message of the entry.
|
|
233
|
+
param attribute: the attribute of the entry.
|
|
234
|
+
param style_index: the style of the entry.
|
|
235
|
+
"""
|
|
236
|
+
self.add_entry(entry := MSBTEntry(name,
|
|
237
|
+
message=LMS_MessageText(message, self._tag_config),
|
|
238
|
+
attribute=attribute,
|
|
239
|
+
style_index=style_index))
|
|
240
|
+
return entry
|
|
241
|
+
|
|
222
242
|
def delete_entry(self, entry: MSBTEntry) -> None:
|
|
223
243
|
"""
|
|
224
244
|
Deletes an entry from the MSBT instance.
|
|
@@ -37,7 +37,7 @@ def read_tag(
|
|
|
37
37
|
return _read_encoded_tag(reader, group_id, tag_index, is_closing)
|
|
38
38
|
|
|
39
39
|
definition = tag_config[group_id][tag_index]
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
# Tags not defined in the config are not considered fallback tags
|
|
42
42
|
# Not all configs will define every tag, so this is simply a measure to still read tags that aren't defined
|
|
43
43
|
if definition is None:
|
|
@@ -79,15 +79,15 @@ def _read_encoded_tag(
|
|
|
79
79
|
def _read_decoded_tag(
|
|
80
80
|
reader: FileReader, definition: TagDefinition, is_closing: bool = False
|
|
81
81
|
) -> LMS_DecodedTag:
|
|
82
|
+
if is_closing:
|
|
83
|
+
return LMS_DecodedTag(definition, is_closing=True)
|
|
84
|
+
|
|
82
85
|
parameter_size = reader.read_uint16()
|
|
83
86
|
end = reader.tell() + parameter_size
|
|
84
87
|
|
|
85
88
|
if not parameter_size:
|
|
86
89
|
return LMS_DecodedTag(definition)
|
|
87
90
|
|
|
88
|
-
if is_closing:
|
|
89
|
-
return LMS_DecodedTag(definition, is_closing=True)
|
|
90
|
-
|
|
91
91
|
parameters = read_decoded_parameters(reader, definition)
|
|
92
92
|
reader.seek(end)
|
|
93
93
|
return LMS_DecodedTag(definition, parameters)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import re
|
|
4
|
-
from typing import TypeGuard, TypeAlias
|
|
4
|
+
from typing import TypeGuard, TypeAlias, Sequence
|
|
5
5
|
|
|
6
6
|
from lms.common.field.lms_field import LMS_FieldMap
|
|
7
7
|
from lms.message.tag.lms_tagexceptions import (
|
|
@@ -29,44 +29,48 @@ class LMS_EncodedTag:
|
|
|
29
29
|
is_fallback: bool = False,
|
|
30
30
|
is_closing: bool = False,
|
|
31
31
|
):
|
|
32
|
-
self.
|
|
33
|
-
self.
|
|
32
|
+
self.group_id = group_id
|
|
33
|
+
self.tag_index = tag_index
|
|
34
|
+
self.is_closing = is_closing
|
|
35
|
+
|
|
34
36
|
self._parameters = parameters
|
|
35
37
|
|
|
36
38
|
self._is_fallback = is_fallback
|
|
37
|
-
self._is_closing = is_closing
|
|
38
39
|
|
|
39
40
|
def __len__(self) -> int:
|
|
40
41
|
return len(self.to_text())
|
|
41
42
|
|
|
42
43
|
@property
|
|
43
|
-
def
|
|
44
|
-
"""The
|
|
45
|
-
return self.
|
|
44
|
+
def parameters(self) -> tuple[int, ...]:
|
|
45
|
+
"""The list of parameters."""
|
|
46
|
+
return () if self._parameters is None else tuple(self._parameters)
|
|
46
47
|
|
|
47
|
-
@
|
|
48
|
-
def
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
@parameters.setter
|
|
49
|
+
def parameters(self, parameters: Sequence[int] | None) -> None:
|
|
50
|
+
if parameters is None:
|
|
51
|
+
self._parameters = None
|
|
52
|
+
return
|
|
51
53
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
for value in parameters:
|
|
55
|
+
if type(value) is not int:
|
|
56
|
+
raise TypeError("Each parameter must be an integer.")
|
|
57
|
+
if not 0 <= value <= 0xFF:
|
|
58
|
+
raise ValueError("Each parameter must be between 0 and 255.")
|
|
59
|
+
|
|
60
|
+
new = list(parameters)
|
|
61
|
+
if len(new) % 2 == 1:
|
|
62
|
+
new.append(TAG_PADDING_VALUE)
|
|
63
|
+
|
|
64
|
+
self._parameters = tuple(new)
|
|
56
65
|
|
|
57
66
|
@property
|
|
58
67
|
def is_fallback(self) -> bool:
|
|
59
68
|
"""Determines if the tag is a fallback tag. Fallback tags have a '!' prefix before the group index."""
|
|
60
69
|
return self._is_fallback
|
|
61
70
|
|
|
62
|
-
@property
|
|
63
|
-
def is_closing(self) -> bool:
|
|
64
|
-
"""Determines if the tag is a closing tag."""
|
|
65
|
-
return self._is_closing
|
|
66
|
-
|
|
67
71
|
def to_text(self) -> str:
|
|
68
|
-
if self.
|
|
69
|
-
return f"[/{self.
|
|
72
|
+
if self.is_closing:
|
|
73
|
+
return f"[/{self.group_id}:{self.tag_index}]"
|
|
70
74
|
|
|
71
75
|
fallback_prefix = "!" if self._is_fallback else ""
|
|
72
76
|
|
|
@@ -134,7 +138,7 @@ class LMS_DecodedTag:
|
|
|
134
138
|
"""
|
|
135
139
|
|
|
136
140
|
TAG_FORMAT = re.compile(
|
|
137
|
-
r"\[\s*(/)?\s*([A-Za-z]\w*)\s*:\s*([A-Za-z]
|
|
141
|
+
r"\[\s*(/)?\s*([A-Za-z]\w*)\s*:\s*([A-Za-z]\w*)(?:\s+[^]]*)?\s*]"
|
|
138
142
|
)
|
|
139
143
|
PARAMETER_FORMAT = re.compile(r'(\w+)="([^"]*)"')
|
|
140
144
|
|
|
@@ -7,7 +7,7 @@ include = ["lms*"]
|
|
|
7
7
|
|
|
8
8
|
[project]
|
|
9
9
|
name = "PyLibMS"
|
|
10
|
-
version = "5.0.
|
|
10
|
+
version = "5.0.2"
|
|
11
11
|
requires-python = ">=3.11"
|
|
12
12
|
description = "Python library built for the libMessageStudio (LMS) proprietary file formats from Nintendo. Supports MSBT, MSBP, and MSBF."
|
|
13
13
|
readme = "README.md"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pylibms-5.0.1/lms/message/definitions/field → pylibms-5.0.2/lms/message/section}/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pylibms-5.0.1 → pylibms-5.0.2}/lms/titleconfig/presets/Brain Age Concentration Training.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pylibms-5.0.1 → pylibms-5.0.2}/lms/titleconfig/presets/Super Mario 3D World + Bowsers Fury.yaml
RENAMED
|
File without changes
|
|
File without changes
|
{pylibms-5.0.1 → pylibms-5.0.2}/lms/titleconfig/presets/The Legend of Zelda Echos of Wisdom.yaml
RENAMED
|
File without changes
|
|
File without changes
|
{pylibms-5.0.1 → pylibms-5.0.2}/lms/titleconfig/presets/Tomodachi Life Living The Dream.yaml
RENAMED
|
File without changes
|
|
File without changes
|