PyLibMS 3.3.1__tar.gz → 3.3.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-3.3.1 → pylibms-3.3.2}/PKG-INFO +3 -3
- {pylibms-3.3.1 → pylibms-3.3.2}/PyLibMS.egg-info/PKG-INFO +3 -3
- {pylibms-3.3.1 → pylibms-3.3.2}/README.md +2 -2
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/common/lms_datatype.py +1 -1
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/message/definitions/field/lms_field.py +9 -6
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/message/msbt.py +7 -11
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/message/section/atr1.py +1 -1
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/message/section/txt2.py +5 -5
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/project/msbpread.py +1 -1
- {pylibms-3.3.1 → pylibms-3.3.2}/pyproject.toml +1 -1
- {pylibms-3.3.1 → pylibms-3.3.2}/LICENSE +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/MANIFEST.in +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/PyLibMS.egg-info/SOURCES.txt +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/PyLibMS.egg-info/dependency_links.txt +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/PyLibMS.egg-info/requires.txt +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/PyLibMS.egg-info/top_level.txt +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/__init__.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/common/__init__.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/common/lms_exceptions.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/common/lms_fileinfo.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/common/stream/fileinfo.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/common/stream/hashtable.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/common/stream/section.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/fileio/encoding.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/fileio/io.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/message/__init__.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/message/definitions/__init__.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/message/definitions/field/__init__.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/message/definitions/field/io.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/message/definitions/lms_messagetext.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/message/msbtentry.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/message/msbtio.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/message/section/__init__.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/message/section/nli1.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/message/section/tsy1.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/message/tag/__init__.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/message/tag/io/param_io.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/message/tag/io/tag_io.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/message/tag/lms_tag.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/message/tag/lms_tagexceptions.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/project/__init__.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/project/definitions/__init__.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/project/definitions/attribute.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/project/definitions/color.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/project/definitions/style.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/project/definitions/tag.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/project/msbp.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/project/section/ali2.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/project/section/ati2.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/project/section/clr1.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/project/section/string.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/project/section/syl3.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/project/section/tag2.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/project/section/tgg2.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/project/section/tgp2.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/titleconfig/__init__.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/titleconfig/config.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/titleconfig/definitions/__init__.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/titleconfig/definitions/attribute.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/titleconfig/definitions/tags.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/titleconfig/definitions/value.py +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/titleconfig/presets/Badge Arcade.yaml +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/titleconfig/presets/Brain Age Concentration Training.yaml +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/titleconfig/presets/Kirby Planet Robobot.yaml +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/titleconfig/presets/Super Mario 3D Land.yaml +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/titleconfig/presets/Super Mario 3D World + Bowsers Fury.yaml +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/titleconfig/presets/Super Mario Odyssey.yaml +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/titleconfig/presets/The Legend of Zelda Echos of Wisdom.yaml +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/titleconfig/presets/The Legend of Zelda a Link Between Worlds.yaml +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/lms/titleconfig/presets/Tomodachi Life.yaml +0 -0
- {pylibms-3.3.1 → pylibms-3.3.2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyLibMS
|
|
3
|
-
Version: 3.3.
|
|
3
|
+
Version: 3.3.2
|
|
4
4
|
Summary: Python library built for the libMessageStudio (LMS) proprietary file formats from Nintendo. Supports MSBT, MSBP, and soon to be MSBF.
|
|
5
5
|
Author: AbdyyEee
|
|
6
6
|
License: Copyright 2025 AbdyyEee
|
|
@@ -20,7 +20,7 @@ Requires-Dist: PyYAML>=6.0.1
|
|
|
20
20
|
Dynamic: license-file
|
|
21
21
|
|
|
22
22
|
# PylibMS
|
|
23
|
-
PylibMS is a library built in Python 3.
|
|
23
|
+
PylibMS is a library built in Python 3.12+ for the libMessageStudio (LMS) proprietary file formats (`msbt`, `msbp`, `msbf`) from Nintendo. It supports the following:
|
|
24
24
|
|
|
25
25
|
* Full reading and writing of MSBT files.
|
|
26
26
|
* Full reading of MSBP files.
|
|
@@ -35,7 +35,7 @@ This library is designed to support LMS revision 3.0 and above, with the associa
|
|
|
35
35
|
* Mobile (Specific titles only)
|
|
36
36
|
* Nintendo Switch
|
|
37
37
|
|
|
38
|
-
MSBF is
|
|
38
|
+
MSBF is currently in the works.
|
|
39
39
|
|
|
40
40
|
# Features and Usage
|
|
41
41
|
Simple preview of the library is below. See [the wiki](https://github.com/AbdyyEee/PylibMS/wiki) for more explanations and examples.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyLibMS
|
|
3
|
-
Version: 3.3.
|
|
3
|
+
Version: 3.3.2
|
|
4
4
|
Summary: Python library built for the libMessageStudio (LMS) proprietary file formats from Nintendo. Supports MSBT, MSBP, and soon to be MSBF.
|
|
5
5
|
Author: AbdyyEee
|
|
6
6
|
License: Copyright 2025 AbdyyEee
|
|
@@ -20,7 +20,7 @@ Requires-Dist: PyYAML>=6.0.1
|
|
|
20
20
|
Dynamic: license-file
|
|
21
21
|
|
|
22
22
|
# PylibMS
|
|
23
|
-
PylibMS is a library built in Python 3.
|
|
23
|
+
PylibMS is a library built in Python 3.12+ for the libMessageStudio (LMS) proprietary file formats (`msbt`, `msbp`, `msbf`) from Nintendo. It supports the following:
|
|
24
24
|
|
|
25
25
|
* Full reading and writing of MSBT files.
|
|
26
26
|
* Full reading of MSBP files.
|
|
@@ -35,7 +35,7 @@ This library is designed to support LMS revision 3.0 and above, with the associa
|
|
|
35
35
|
* Mobile (Specific titles only)
|
|
36
36
|
* Nintendo Switch
|
|
37
37
|
|
|
38
|
-
MSBF is
|
|
38
|
+
MSBF is currently in the works.
|
|
39
39
|
|
|
40
40
|
# Features and Usage
|
|
41
41
|
Simple preview of the library is below. See [the wiki](https://github.com/AbdyyEee/PylibMS/wiki) for more explanations and examples.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# PylibMS
|
|
2
|
-
PylibMS is a library built in Python 3.
|
|
2
|
+
PylibMS is a library built in Python 3.12+ for the libMessageStudio (LMS) proprietary file formats (`msbt`, `msbp`, `msbf`) from Nintendo. It supports the following:
|
|
3
3
|
|
|
4
4
|
* Full reading and writing of MSBT files.
|
|
5
5
|
* Full reading of MSBP files.
|
|
@@ -14,7 +14,7 @@ This library is designed to support LMS revision 3.0 and above, with the associa
|
|
|
14
14
|
* Mobile (Specific titles only)
|
|
15
15
|
* Nintendo Switch
|
|
16
16
|
|
|
17
|
-
MSBF is
|
|
17
|
+
MSBF is currently in the works.
|
|
18
18
|
|
|
19
19
|
# Features and Usage
|
|
20
20
|
Simple preview of the library is below. See [the wiki](https://github.com/AbdyyEee/PylibMS/wiki) for more explanations and examples.
|
|
@@ -25,7 +25,7 @@ def is_number_datatype(value: object, datatype: LMS_DataType) -> TypeGuard[int |
|
|
|
25
25
|
LMS_DataType.INT16,
|
|
26
26
|
LMS_DataType.INT32,
|
|
27
27
|
LMS_DataType.FLOAT32,
|
|
28
|
-
) and isinstance(value,
|
|
28
|
+
) and isinstance(value, int)
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
def is_list_datatype(value: object, datatype: LMS_DataType) -> TypeGuard[str]:
|
|
@@ -15,8 +15,7 @@ type FieldValue = int | str | float | bool | bytes
|
|
|
15
15
|
@dataclass(frozen=True)
|
|
16
16
|
class LMS_FieldMap:
|
|
17
17
|
"""
|
|
18
|
-
A wrapper for a
|
|
19
|
-
and abstraction from the dict object.
|
|
18
|
+
A wrapper for a basic ``dict[str, LMS_Field]``. Difference is validation upon modification of a field.
|
|
20
19
|
"""
|
|
21
20
|
|
|
22
21
|
fields: dict[str, LMS_Field]
|
|
@@ -52,8 +51,10 @@ class LMS_FieldMap:
|
|
|
52
51
|
@classmethod
|
|
53
52
|
def from_string_dict(cls, data: dict[str, str], definitions: list[ValueDefinition]):
|
|
54
53
|
fields = {}
|
|
54
|
+
casted_value = None
|
|
55
55
|
|
|
56
56
|
for definition in definitions:
|
|
57
|
+
# These datatypes do not require any casting
|
|
57
58
|
if definition.datatype in (LMS_DataType.STRING, LMS_DataType.LIST):
|
|
58
59
|
fields[definition.name] = LMS_Field(data[definition.name], definition)
|
|
59
60
|
continue
|
|
@@ -64,7 +65,7 @@ class LMS_FieldMap:
|
|
|
64
65
|
casted_value = bytes.fromhex(value)
|
|
65
66
|
case LMS_DataType.BOOL:
|
|
66
67
|
if value not in ("false", "true"):
|
|
67
|
-
raise ValueError("
|
|
68
|
+
raise ValueError("Invalid boolean value!")
|
|
68
69
|
casted_value = value.strip().lower() == "true"
|
|
69
70
|
case LMS_DataType.FLOAT32:
|
|
70
71
|
casted_value = float(value)
|
|
@@ -115,7 +116,7 @@ class LMS_Field:
|
|
|
115
116
|
|
|
116
117
|
@property
|
|
117
118
|
def list_items(self) -> list[str]:
|
|
118
|
-
"""The list items bound to the field instance. Only is valid for
|
|
119
|
+
"""The list items bound to the field instance. Only is valid for ``LMS_Datatype.LIST`` values."""
|
|
119
120
|
return self._definition.list_items
|
|
120
121
|
|
|
121
122
|
@value.setter
|
|
@@ -141,7 +142,8 @@ def _verify_value(
|
|
|
141
142
|
case LMS_DataType.LIST if isinstance(value, str):
|
|
142
143
|
if value not in definition.list_items:
|
|
143
144
|
raise ValueError(
|
|
144
|
-
f"The value of '{value}' provided for field '{definition.name}' is not
|
|
145
|
+
f"""The value of '{value}' provided for field '{definition.name}' is not a
|
|
146
|
+
valid item in the list {definition.list_items}."""
|
|
145
147
|
)
|
|
146
148
|
else:
|
|
147
149
|
return
|
|
@@ -172,5 +174,6 @@ def _verify_number_is_in_range(
|
|
|
172
174
|
):
|
|
173
175
|
if not min_value <= value <= max_value:
|
|
174
176
|
raise ValueError(
|
|
175
|
-
f"The value '{value}' of type '{definition.datatype}' provided for field '{definition.name}'
|
|
177
|
+
f"""The value '{value}' of type '{definition.datatype}' provided for field '{definition.name}'
|
|
178
|
+
is out of range of ({min_value}, {max_value})"""
|
|
176
179
|
)
|
|
@@ -43,19 +43,15 @@ class MSBT:
|
|
|
43
43
|
|
|
44
44
|
self.size_per_attribute = 0
|
|
45
45
|
|
|
46
|
-
self.
|
|
46
|
+
self.slot_count = MSBT.DEFAULT_SLOT_COUNT
|
|
47
47
|
|
|
48
48
|
self.uses_encoded_attributes = True
|
|
49
49
|
self.attr_string_table: bytes | None = None
|
|
50
50
|
|
|
51
51
|
self._unsupported_section_map = unsupported_section_map or {}
|
|
52
52
|
|
|
53
|
-
# Some MSBTs store labels with NLI1 over LBL1
|
|
54
|
-
# This flag creates a MSBT instance with NLI1 preferred over LBL1
|
|
55
|
-
self.uses_nli1 = uses_nli1
|
|
56
|
-
|
|
57
53
|
# Store the section list so that the order of any and all sections is preserved when writing
|
|
58
|
-
self._section_list: list[str] = section_list or ["LBL1" if not
|
|
54
|
+
self._section_list: list[str] = section_list or ["LBL1" if not uses_nli1 else "NLI1"]
|
|
59
55
|
|
|
60
56
|
self._attribute_config = attribute_config
|
|
61
57
|
self._tag_config = tag_config
|
|
@@ -103,11 +99,6 @@ class MSBT:
|
|
|
103
99
|
"""Tuple of all the MSBT entries."""
|
|
104
100
|
return tuple(self._entries)
|
|
105
101
|
|
|
106
|
-
@property
|
|
107
|
-
def slot_count(self) -> int:
|
|
108
|
-
"""The slot count for the MSBT instance."""
|
|
109
|
-
return self._slot_count
|
|
110
|
-
|
|
111
102
|
@property
|
|
112
103
|
def section_list(self) -> tuple[str, ...]:
|
|
113
104
|
"""The list of sections with order preserved."""
|
|
@@ -118,6 +109,11 @@ class MSBT:
|
|
|
118
109
|
"""The list of unsupported sections."""
|
|
119
110
|
return tuple(self._unsupported_section_map.keys())
|
|
120
111
|
|
|
112
|
+
@property
|
|
113
|
+
def uses_nli1(self) -> bool:
|
|
114
|
+
"""If the MSBT contains the NLI1 section."""
|
|
115
|
+
return self.section_exists("NLI1")
|
|
116
|
+
|
|
121
117
|
@property
|
|
122
118
|
def contains_attributes(self) -> bool:
|
|
123
119
|
"""If the MSBT contains attributes."""
|
|
@@ -39,7 +39,7 @@ def read_encoded_atr1(reader: FileReader, section_size: int) -> ATR1Data:
|
|
|
39
39
|
|
|
40
40
|
def read_decoded_atr1(reader: FileReader, config: AttributeConfig) -> ATR1Data:
|
|
41
41
|
# String table as a list is not necessary for decoded attributes
|
|
42
|
-
# It is easier to save all changes from the user
|
|
42
|
+
# It is easier to save all changes from the user when writing
|
|
43
43
|
# to recreate the table from all the string parameters in every attribute
|
|
44
44
|
string_table = None
|
|
45
45
|
|
|
@@ -19,23 +19,23 @@ def read_txt2(
|
|
|
19
19
|
for offset in reader.read_offset_array(message_count):
|
|
20
20
|
reader.seek(offset)
|
|
21
21
|
|
|
22
|
-
text,
|
|
22
|
+
text, text_segments = b"", []
|
|
23
23
|
while (data := reader.read_bytes(encoding.width)) != encoding.terminator:
|
|
24
24
|
is_closing_tag = data == tag_close
|
|
25
25
|
|
|
26
26
|
if data == tag_start or is_closing_tag:
|
|
27
|
-
|
|
27
|
+
text_segments.append(text.decode(encoding_format))
|
|
28
28
|
tag = read_tag(reader, config, is_closing_tag, suppress_tag_errors)
|
|
29
|
-
|
|
29
|
+
text_segments.append(tag)
|
|
30
30
|
text = b""
|
|
31
31
|
else:
|
|
32
32
|
text += data
|
|
33
33
|
|
|
34
34
|
# Add the remaining text in case there were no control tags
|
|
35
35
|
if text:
|
|
36
|
-
|
|
36
|
+
text_segments.append(text.decode(encoding_format))
|
|
37
37
|
|
|
38
|
-
message = LMS_MessageText(
|
|
38
|
+
message = LMS_MessageText(text_segments, config)
|
|
39
39
|
messages.append(message)
|
|
40
40
|
|
|
41
41
|
return messages
|
|
@@ -62,7 +62,7 @@ def read_msbp(stream: BinaryIO | bytes) -> MSBP:
|
|
|
62
62
|
for magic, _ in read_section_data(reader, file_info.section_count):
|
|
63
63
|
match magic:
|
|
64
64
|
case "CLB1" | "ALB1" | "SLB1":
|
|
65
|
-
# Set the name
|
|
65
|
+
# Set the name attribute of last read item
|
|
66
66
|
labels, _ = read_labels(reader)
|
|
67
67
|
for i in labels:
|
|
68
68
|
items[i].name = labels[i]
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "PyLibMS"
|
|
7
|
-
version = "3.3.
|
|
7
|
+
version = "3.3.2"
|
|
8
8
|
requires-python = ">=3.12"
|
|
9
9
|
description = "Python library built for the libMessageStudio (LMS) proprietary file formats from Nintendo. Supports MSBT, MSBP, and soon to be MSBF."
|
|
10
10
|
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
|
|
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-3.3.1 → pylibms-3.3.2}/lms/titleconfig/presets/Brain Age Concentration Training.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pylibms-3.3.1 → pylibms-3.3.2}/lms/titleconfig/presets/Super Mario 3D World + Bowsers Fury.yaml
RENAMED
|
File without changes
|
|
File without changes
|
{pylibms-3.3.1 → pylibms-3.3.2}/lms/titleconfig/presets/The Legend of Zelda Echos of Wisdom.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|