mapfile-parser 2.9.3__tar.gz → 2.10.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.
Files changed (42) hide show
  1. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/CHANGELOG.md +25 -0
  2. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/Cargo.lock +1 -1
  3. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/Cargo.toml +1 -1
  4. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/PKG-INFO +3 -7
  5. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/README.md +2 -2
  6. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/pyproject.toml +1 -1
  7. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/mapfile_parser/__init__.py +1 -1
  8. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/mapfile_parser/frontends/bss_check.py +40 -8
  9. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/mapfile_parser/frontends/first_diff.py +38 -7
  10. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/mapfile_parser/frontends/jsonify.py +26 -4
  11. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/mapfile_parser/frontends/objdiff_report.py +20 -2
  12. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/mapfile_parser/frontends/pj64_syms.py +25 -4
  13. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/mapfile_parser/frontends/progress.py +44 -11
  14. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/mapfile_parser/frontends/sym_info.py +28 -4
  15. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/mapfile_parser/frontends/symbol_sizes_csv.py +28 -4
  16. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/mapfile_parser/frontends/upload_frogress.py +31 -3
  17. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/mapfile_parser/mapfile.py +99 -19
  18. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/rs/lib.rs +1 -1
  19. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/rs/mapfile.rs +112 -9
  20. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/rs/parser.rs +115 -32
  21. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/rs/section.rs +11 -45
  22. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/rs/segment.rs +5 -5
  23. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/.gitattributes +0 -0
  24. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/.gitignore +0 -0
  25. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/LICENSE +0 -0
  26. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/mapfile_parser/__main__.py +0 -0
  27. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/mapfile_parser/frontends/__init__.py +0 -0
  28. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/mapfile_parser/internals/__init__.py +0 -0
  29. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/mapfile_parser/internals/objdiff_report.py +0 -0
  30. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/mapfile_parser/mapfile_parser.pyi +0 -0
  31. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/mapfile_parser/mapfile_rs.py +0 -0
  32. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/mapfile_parser/progress_stats.py +0 -0
  33. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/mapfile_parser/progress_stats_rs.py +0 -0
  34. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/mapfile_parser/utils.py +0 -0
  35. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/rs/found_symbol_info.rs +0 -0
  36. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/rs/maps_comparison_info.rs +0 -0
  37. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/rs/progress_stats.rs +0 -0
  38. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/rs/report.rs +0 -0
  39. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/rs/symbol.rs +0 -0
  40. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/rs/symbol_comparison_info.rs +0 -0
  41. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/rs/symbol_decomp_state.rs +0 -0
  42. {mapfile_parser-2.9.3 → mapfile_parser-2.10.0}/src/rs/utils.rs +0 -0
@@ -7,6 +7,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.10.0] - 2025-09-01
11
+
12
+ ### Added
13
+
14
+ - Support for partially linked objects (a.k.a. `plf`).
15
+ - This is done by calling a function with a user provided callback that
16
+ converts a given object path into the corresponding mapfile for that `plf`.
17
+ - Rust: `MapFile::resolve_partially_linked_files()`.
18
+ - Python: `MapFile::resolvePartiallyLinkedFiles()`.
19
+ - All the CLI utilities include basic support for `plf`s.
20
+ - Pass the flag `-x .extension` or `--plf-ext .extension` to specify the
21
+ extension of the partially linked objects files that should be replaced with
22
+ a `.map` extension.
23
+ - The frontends API allow to further customize this behavior by passing a
24
+ callback like the one used by `MapFile::resolvePartiallyLinkedFiles`.
25
+
26
+ ## [2.9.4] - 2025-06-02
27
+
28
+ ### Changed
29
+
30
+ - Implement parsing for `mwld` 2.7+ generated mapfiles.
31
+ - Handle `*fill*`s in `mwld`.
32
+
10
33
  ## [2.9.3] - 2025-06-01
11
34
 
12
35
  ### Fixed
@@ -613,6 +636,8 @@ Full changes: <https://github.com/Decompollaborate/mapfile_parser/compare/702a73
613
636
  - Initial release
614
637
 
615
638
  [unreleased]: https://github.com/Decompollaborate/mapfile_parser/compare/master...develop
639
+ [2.10.0]: https://github.com/Decompollaborate/mapfile_parser/compare/2.9.4...2.10.0
640
+ [2.9.4]: https://github.com/Decompollaborate/mapfile_parser/compare/2.9.3...2.9.4
616
641
  [2.9.3]: https://github.com/Decompollaborate/mapfile_parser/compare/2.9.2...2.9.3
617
642
  [2.9.2]: https://github.com/Decompollaborate/mapfile_parser/compare/2.9.1...2.9.2
618
643
  [2.9.1]: https://github.com/Decompollaborate/mapfile_parser/compare/2.9.0...2.9.1
@@ -171,7 +171,7 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
171
171
 
172
172
  [[package]]
173
173
  name = "mapfile_parser"
174
- version = "2.9.3"
174
+ version = "2.10.0"
175
175
  dependencies = [
176
176
  "lazy_static",
177
177
  "objdiff-core",
@@ -3,7 +3,7 @@
3
3
 
4
4
  [package]
5
5
  name = "mapfile_parser"
6
- version = "2.9.3"
6
+ version = "2.10.0"
7
7
  edition = "2021"
8
8
  rust-version = "1.74.0"
9
9
  authors = ["Anghelo Carvajal <angheloalf95@gmail.com>"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mapfile_parser
3
- Version: 2.9.3
3
+ Version: 2.10.0
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
@@ -8,10 +8,6 @@ Requires-Dist: requests
8
8
  Requires-Dist: decomp-settings==0.0.9
9
9
  License-File: LICENSE
10
10
  Summary: Map file parser library focusing decompilation projects
11
- Keywords: mapfile,parser,decomp,decompilation
12
- Author: Anghelo Carvajal <angheloalf95@gmail.com>
13
- Author-email: Anghelo Carvajal <angheloalf95@gmail.com>
14
- License: MIT
15
11
  Requires-Python: >=3.9
16
12
  Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
17
13
  Project-URL: Homepage, https://github.com/Decompollaborate/mapfile_parser
@@ -55,7 +51,7 @@ If you use a `requirements.txt` file in your repository, then you can add
55
51
  this library with the following line:
56
52
 
57
53
  ```txt
58
- mapfile_parser>=2.9.3,<3.0.0
54
+ mapfile_parser>=2.10.0,<3.0.0
59
55
  ```
60
56
 
61
57
  #### Development version
@@ -94,7 +90,7 @@ cargo add mapfile_parser
94
90
  Or add the following line manually to your `Cargo.toml` file:
95
91
 
96
92
  ```toml
97
- mapfile_parser = "2.9.3"
93
+ mapfile_parser = "2.10.0"
98
94
  ```
99
95
 
100
96
  ## Versioning and changelog
@@ -36,7 +36,7 @@ If you use a `requirements.txt` file in your repository, then you can add
36
36
  this library with the following line:
37
37
 
38
38
  ```txt
39
- mapfile_parser>=2.9.3,<3.0.0
39
+ mapfile_parser>=2.10.0,<3.0.0
40
40
  ```
41
41
 
42
42
  #### Development version
@@ -75,7 +75,7 @@ cargo add mapfile_parser
75
75
  Or add the following line manually to your `Cargo.toml` file:
76
76
 
77
77
  ```toml
78
- mapfile_parser = "2.9.3"
78
+ mapfile_parser = "2.10.0"
79
79
  ```
80
80
 
81
81
  ## Versioning and changelog
@@ -3,7 +3,7 @@
3
3
 
4
4
  [project]
5
5
  name = "mapfile_parser"
6
- version = "2.9.3"
6
+ version = "2.10.0"
7
7
  description = "Map file parser library focusing decompilation projects"
8
8
  readme = "README.md"
9
9
  requires-python = ">=3.9"
@@ -5,7 +5,7 @@
5
5
 
6
6
  from __future__ import annotations
7
7
 
8
- __version_info__ = (2, 9, 3)
8
+ __version_info__ = (2, 10, 0)
9
9
  __version__ = ".".join(map(str, __version_info__)) # + "-dev0"
10
10
  __author__ = "Decompollaborate"
11
11
 
@@ -6,6 +6,7 @@
6
6
  from __future__ import annotations
7
7
 
8
8
  import argparse
9
+ from collections.abc import Callable
9
10
  import decomp_settings
10
11
  from pathlib import Path
11
12
 
@@ -13,14 +14,23 @@ from .. import mapfile
13
14
  from .. import utils
14
15
 
15
16
 
16
- def getComparison(mapPath, expectedMapPath, *, reverseCheck: bool=True) -> mapfile.MapsComparisonInfo:
17
- buildMap = mapfile.MapFile()
18
- buildMap.readMapFile(mapPath)
17
+ def getComparison(
18
+ mapPath: Path,
19
+ expectedMapPath: Path,
20
+ *,
21
+ reverseCheck: bool=True,
22
+ plfResolver: Callable[[Path], Path|None]|None=None,
23
+ plfResolverExpected: Callable[[Path], Path|None]|None=None,
24
+ ) -> mapfile.MapsComparisonInfo:
25
+ buildMap = mapfile.MapFile.newFromMapFile(mapPath)
19
26
  buildMap = buildMap.filterBySectionType(".bss")
27
+ if plfResolver is not None:
28
+ buildMap = buildMap.resolvePartiallyLinkedFiles(plfResolver)
20
29
 
21
- expectedMap = mapfile.MapFile()
22
- expectedMap.readMapFile(expectedMapPath)
30
+ expectedMap = mapfile.MapFile.newFromMapFile(expectedMapPath)
23
31
  expectedMap = expectedMap.filterBySectionType(".bss")
32
+ if plfResolverExpected is not None:
33
+ expectedMap = expectedMap.resolvePartiallyLinkedFiles(plfResolverExpected)
24
34
 
25
35
  return buildMap.compareFilesAndSymbols(expectedMap, checkOtherOnSelf=reverseCheck)
26
36
 
@@ -126,7 +136,15 @@ def printFileComparison(comparisonInfo: mapfile.MapsComparisonInfo):
126
136
  utils.eprint("Some files appear to be missing symbols. Have they been renamed or declared as static? You may need to remake 'expected'")
127
137
 
128
138
 
129
- def doBssCheck(mapPath, expectedMapPath, *, printAll: bool=False, reverseCheck: bool=True) -> int:
139
+ def doBssCheck(
140
+ mapPath: Path,
141
+ expectedMapPath: Path,
142
+ *,
143
+ printAll: bool=False,
144
+ reverseCheck: bool=True,
145
+ plfResolver: Callable[[Path], Path|None]|None=None,
146
+ plfResolverExpected: Callable[[Path], Path|None]|None=None,
147
+ ) -> int:
130
148
  if not mapPath.exists():
131
149
  utils.eprint(f"{mapPath} must exist")
132
150
  return 1
@@ -134,7 +152,7 @@ def doBssCheck(mapPath, expectedMapPath, *, printAll: bool=False, reverseCheck:
134
152
  utils.eprint(f"{expectedMapPath} must exist")
135
153
  return 1
136
154
 
137
- comparisonInfo = getComparison(mapPath, expectedMapPath, reverseCheck=reverseCheck)
155
+ comparisonInfo = getComparison(mapPath, expectedMapPath, reverseCheck=reverseCheck, plfResolver=plfResolver, plfResolverExpected=plfResolverExpected)
138
156
  printSymbolComparison(comparisonInfo, printAll)
139
157
 
140
158
  if len(comparisonInfo.badFiles) + len(comparisonInfo.missingFiles) != 0:
@@ -165,8 +183,20 @@ def processArguments(args: argparse.Namespace, decompConfig: decomp_settings.Con
165
183
 
166
184
  printAll: bool = args.print_all
167
185
  reverseCheck: bool = not args.no_reverse_check
186
+ plfExt: list[str]|None = args.plf_ext
168
187
 
169
- exit(doBssCheck(mapPath, expectedMapPath, printAll=printAll, reverseCheck=reverseCheck))
188
+ plfResolver = None
189
+ if plfExt is not None:
190
+ def resolver(x: Path) -> Path|None:
191
+ if x.suffix in plfExt:
192
+ newPath = x.with_suffix(".map")
193
+ if newPath.exists():
194
+ return newPath
195
+ return None
196
+
197
+ plfResolver = resolver
198
+
199
+ exit(doBssCheck(mapPath, expectedMapPath, printAll=printAll, reverseCheck=reverseCheck, plfResolver=plfResolver))
170
200
 
171
201
 
172
202
  def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser], decompConfig: decomp_settings.Config|None=None):
@@ -193,4 +223,6 @@ def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser],
193
223
  parser.add_argument("-a", "--print-all", help="Print all bss, not just non-matching.", action="store_true")
194
224
  parser.add_argument("--no-reverse-check", help="Disable looking for symbols on the expected map that are missing on the built map file.", action="store_true")
195
225
 
226
+ parser.add_argument("-x", "--plf-ext", help="File extension for partially linked files (plf). Will be used to transform the `plf`s path into a mapfile path by replacing the extension. The extension must contain the leading period. This argument can be passed multiple times.", action="append")
227
+
196
228
  parser.set_defaults(func=processArguments)
@@ -6,15 +6,28 @@
6
6
  from __future__ import annotations
7
7
 
8
8
  import argparse
9
+ from collections.abc import Callable
9
10
  import decomp_settings
10
11
  from pathlib import Path
11
- from typing import Callable, Literal
12
+ from typing import Literal
12
13
 
13
14
  from .. import mapfile
14
15
  from .. import utils
15
16
 
16
17
 
17
- def doFirstDiff(mapPath, expectedMapPath, romPath, expectedRomPath, diffCount: int=5, mismatchSize: bool=False, addColons: bool=True, bytesConverterCallback:Callable[[bytes, mapfile.MapFile],str|None]|None=None, endian: Literal["big", "little"] ="big") -> int:
18
+ def doFirstDiff(
19
+ mapPath: Path,
20
+ expectedMapPath: Path,
21
+ romPath: Path,
22
+ expectedRomPath: Path,
23
+ diffCount: int=5,
24
+ mismatchSize: bool=False,
25
+ addColons: bool=True,
26
+ bytesConverterCallback: Callable[[bytes, mapfile.MapFile],str|None]|None=None,
27
+ endian: Literal["big", "little"] ="big",
28
+ plfResolver: Callable[[Path], Path|None]|None=None,
29
+ plfResolverExpected: Callable[[Path], Path|None]|None=None,
30
+ ) -> int:
18
31
  if not mapPath.exists():
19
32
  print(f"{mapPath} must exist")
20
33
  return 1
@@ -41,10 +54,13 @@ def doFirstDiff(mapPath, expectedMapPath, romPath, expectedRomPath, diffCount: i
41
54
  print("No differences!")
42
55
  return 0
43
56
 
44
- builtMapFile = mapfile.MapFile()
45
- builtMapFile.readMapFile(mapPath)
46
- expectedMapFile = mapfile.MapFile()
47
- expectedMapFile.readMapFile(expectedMapPath)
57
+ builtMapFile = mapfile.MapFile.newFromMapFile(mapPath)
58
+ if plfResolver is not None:
59
+ builtMapFile = builtMapFile.resolvePartiallyLinkedFiles(plfResolver)
60
+
61
+ expectedMapFile = mapfile.MapFile.newFromMapFile(expectedMapPath)
62
+ if plfResolverExpected is not None:
63
+ expectedMapFile = expectedMapFile.resolvePartiallyLinkedFiles(plfResolverExpected)
48
64
 
49
65
  endian_diff = 0
50
66
  if endian == "little":
@@ -166,7 +182,20 @@ def processArguments(args: argparse.Namespace, decompConfig: decomp_settings.Con
166
182
 
167
183
  endian = args.endian
168
184
 
169
- exit(doFirstDiff(mapPath, expectedMapPath, romPath, expectedRomPath, diffCount, mismatchSize, endian=endian))
185
+ plfExt: list[str]|None = args.plf_ext
186
+
187
+ plfResolver = None
188
+ if plfExt is not None:
189
+ def resolver(x: Path) -> Path|None:
190
+ if x.suffix in plfExt:
191
+ newPath = x.with_suffix(".map")
192
+ if newPath.exists():
193
+ return newPath
194
+ return None
195
+
196
+ plfResolver = resolver
197
+
198
+ exit(doFirstDiff(mapPath, expectedMapPath, romPath, expectedRomPath, diffCount, mismatchSize, endian=endian, plfResolver=plfResolver))
170
199
 
171
200
 
172
201
  def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser], decompConfig: decomp_settings.Config|None=None):
@@ -200,4 +229,6 @@ def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser],
200
229
  parser.add_argument("-m", "--mismatch-size", help="Do not exit early if the ROM sizes does not match", action="store_true")
201
230
  parser.add_argument("-e", "--endian", help="Specify endianness of the binary", choices=["big", "little"], default="big")
202
231
 
232
+ parser.add_argument("-x", "--plf-ext", help="File extension for partially linked files (plf). Will be used to transform the `plf`s path into a mapfile path by replacing the extension. The extension must contain the leading period. This argument can be passed multiple times.", action="append")
233
+
203
234
  parser.set_defaults(func=processArguments)
@@ -6,6 +6,7 @@
6
6
  from __future__ import annotations
7
7
 
8
8
  import argparse
9
+ from collections.abc import Callable
9
10
  import decomp_settings
10
11
  import json
11
12
  from pathlib import Path
@@ -13,13 +14,20 @@ from pathlib import Path
13
14
  from .. import mapfile
14
15
 
15
16
 
16
- def doJsonify(mapPath: Path, outputPath: Path|None, humanReadable: bool=True, applyFixes: bool=False) -> int:
17
+ def doJsonify(
18
+ mapPath: Path,
19
+ outputPath: Path|None,
20
+ humanReadable: bool=True,
21
+ applyFixes: bool=False,
22
+ plfResolver: Callable[[Path], Path|None]|None=None,
23
+ ) -> int:
17
24
  if not mapPath.exists():
18
25
  print(f"Could not find mapfile at '{mapPath}'")
19
26
  return 1
20
27
 
21
- mapFile = mapfile.MapFile()
22
- mapFile.readMapFile(mapPath)
28
+ mapFile = mapfile.MapFile.newFromMapFile(mapPath)
29
+ if plfResolver is not None:
30
+ mapFile = mapFile.resolvePartiallyLinkedFiles(plfResolver)
23
31
 
24
32
  jsonStr = json.dumps(mapFile.toJson(humanReadable=humanReadable), indent=4)
25
33
 
@@ -44,8 +52,20 @@ def processArguments(args: argparse.Namespace, decompConfig: decomp_settings.Con
44
52
  outputPath: Path|None = Path(args.output) if args.output is not None else None
45
53
  machine: bool = args.machine
46
54
  applyFixes: bool = args.apply_fixes
55
+ plfExt: list[str]|None = args.plf_ext
47
56
 
48
- exit(doJsonify(mapPath, outputPath, humanReadable=not machine, applyFixes=applyFixes))
57
+ plfResolver = None
58
+ if plfExt is not None:
59
+ def resolver(x: Path) -> Path|None:
60
+ if x.suffix in plfExt:
61
+ newPath = x.with_suffix(".map")
62
+ if newPath.exists():
63
+ return newPath
64
+ return None
65
+
66
+ plfResolver = resolver
67
+
68
+ exit(doJsonify(mapPath, outputPath, humanReadable=not machine, applyFixes=applyFixes, plfResolver=plfResolver))
49
69
 
50
70
  def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser], decompConfig: decomp_settings.Config|None=None):
51
71
  parser = subparser.add_parser("jsonify", help="Converts a mapfile into a json format.")
@@ -67,4 +87,6 @@ def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser],
67
87
  parser.add_argument("-m", "--machine", help="Emit numbers as numbers instead of outputting them as pretty strings.", action="store_true")
68
88
  parser.add_argument("-f", "--apply-fixes", help="DEPRECATED, this is applied automatically now. Apply certain fixups, like fixing size calculation of because of the existence of fake `.NON_MATCHING` symbols.", action="store_true")
69
89
 
90
+ parser.add_argument("-x", "--plf-ext", help="File extension for partially linked files (plf). Will be used to transform the `plf`s path into a mapfile path by replacing the extension. The extension must contain the leading period. This argument can be passed multiple times.", action="append")
91
+
70
92
  parser.set_defaults(func=processArguments)
@@ -6,6 +6,7 @@
6
6
  from __future__ import annotations
7
7
 
8
8
  import argparse
9
+ from collections.abc import Callable
9
10
  import dataclasses
10
11
  import decomp_settings
11
12
  from pathlib import Path
@@ -34,13 +35,15 @@ def doObjdiffReport(
34
35
  emitCategories: bool=False,
35
36
  quiet: bool=False,
36
37
  summaryTableConfig: SummaryTableConfig|None=SummaryTableConfig(),
38
+ plfResolver: Callable[[Path], Path|None]|None=None,
37
39
  ) -> int:
38
40
  if not mapPath.exists():
39
41
  print(f"Could not find mapfile at '{mapPath}'")
40
42
  return 1
41
43
 
42
- mapFile = mapfile.MapFile()
43
- mapFile.readMapFile(mapPath)
44
+ mapFile = mapfile.MapFile.newFromMapFile(mapPath)
45
+ if plfResolver is not None:
46
+ mapFile = mapFile.resolvePartiallyLinkedFiles(plfResolver)
44
47
 
45
48
  if emitCategories:
46
49
  printDefaultCategories(mapFile, prefixesToTrim)
@@ -347,6 +350,18 @@ def processArguments(args: argparse.Namespace, decompConfig: decomp_settings.Con
347
350
  else:
348
351
  summaryTableConfig = None
349
352
 
353
+ plfExt: list[str]|None = args.plf_ext
354
+
355
+ plfResolver = None
356
+ if plfExt is not None:
357
+ def resolver(x: Path) -> Path|None:
358
+ if x.suffix in plfExt:
359
+ newPath = x.with_suffix(".map")
360
+ if newPath.exists():
361
+ return newPath
362
+ return None
363
+ plfResolver = resolver
364
+
350
365
  exit(doObjdiffReport(
351
366
  mapPath,
352
367
  outputPath,
@@ -357,6 +372,7 @@ def processArguments(args: argparse.Namespace, decompConfig: decomp_settings.Con
357
372
  nonmatchingsPath=nonmatchingsPath,
358
373
  emitCategories=emitCategories,
359
374
  summaryTableConfig=summaryTableConfig,
375
+ plfResolver=plfResolver,
360
376
  ))
361
377
 
362
378
  def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser], decompConfig: decomp_settings.Config|None=None):
@@ -468,6 +484,8 @@ tools:
468
484
  parser.add_argument("--emit-categories", help="Print automatically-generated categories from your mapfile, using the decomp.yaml format. These categories are expected to be tweaked and not used as-is.", action="store_true")
469
485
  parser.add_argument("--quiet", help="Avoid printing the progress report to the stdout and to the Github action summary.", action="store_true")
470
486
 
487
+ parser.add_argument("-x", "--plf-ext", help="File extension for partially linked files (plf). Will be used to transform the `plf`s path into a mapfile path by replacing the extension. The extension must contain the leading period. This argument can be passed multiple times.", action="append")
488
+
471
489
  parser.set_defaults(func=processArguments)
472
490
 
473
491
 
@@ -6,6 +6,7 @@
6
6
  from __future__ import annotations
7
7
 
8
8
  import argparse
9
+ from collections.abc import Callable
9
10
  import decomp_settings
10
11
  from pathlib import Path
11
12
  from typing import TextIO
@@ -21,13 +22,18 @@ def writePj64SymsToFile(mapFile: mapfile.MapFile, outFile: TextIO):
21
22
  symType = "code" if file.sectionType == ".text" else "data"
22
23
  outFile.write(f"{sym.vram:08X},{symType},{sym.name}\n")
23
24
 
24
- def doPj64Syms(mapPath: Path, outputPath: Path|None) -> int:
25
+ def doPj64Syms(
26
+ mapPath: Path,
27
+ outputPath: Path|None,
28
+ plfResolver: Callable[[Path], Path|None]|None=None,
29
+ ) -> int:
25
30
  if not mapPath.exists():
26
31
  print(f"Could not find mapfile at '{mapPath}'")
27
32
  return 1
28
33
 
29
- mapFile = mapfile.MapFile()
30
- mapFile.readMapFile(mapPath)
34
+ mapFile = mapfile.MapFile.newFromMapFile(mapPath)
35
+ if plfResolver is not None:
36
+ mapFile = mapFile.resolvePartiallyLinkedFiles(plfResolver)
31
37
 
32
38
  if outputPath is None:
33
39
  writePj64SymsToFile(mapFile, sys.stdout)
@@ -48,7 +54,20 @@ def processArguments(args: argparse.Namespace, decompConfig: decomp_settings.Con
48
54
 
49
55
  outputPath: Path = args.output
50
56
 
51
- exit(doPj64Syms(mapPath, outputPath))
57
+ plfExt: list[str]|None = args.plf_ext
58
+
59
+ plfResolver = None
60
+ if plfExt is not None:
61
+ def resolver(x: Path) -> Path|None:
62
+ if x.suffix in plfExt:
63
+ newPath = x.with_suffix(".map")
64
+ if newPath.exists():
65
+ return newPath
66
+ return None
67
+
68
+ plfResolver = resolver
69
+
70
+ exit(doPj64Syms(mapPath, outputPath, plfResolver=plfResolver))
52
71
 
53
72
  def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser], decompConfig: decomp_settings.Config|None=None):
54
73
  parser = subparser.add_parser("pj64_syms", help="Produce a PJ64 compatible symbol map.")
@@ -68,4 +87,6 @@ def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser],
68
87
 
69
88
  parser.add_argument("output", help="Path to output file. If omitted then output will be written to stdout", type=Path, nargs="?")
70
89
 
90
+ parser.add_argument("-x", "--plf-ext", help="File extension for partially linked files (plf). Will be used to transform the `plf`s path into a mapfile path by replacing the extension. The extension must contain the leading period. This argument can be passed multiple times.", action="append")
91
+
71
92
  parser.set_defaults(func=processArguments)
@@ -6,6 +6,7 @@
6
6
  from __future__ import annotations
7
7
 
8
8
  import argparse
9
+ from collections.abc import Callable
9
10
  import decomp_settings
10
11
  import json
11
12
  from pathlib import Path
@@ -14,20 +15,37 @@ from .. import mapfile
14
15
  from .. import progress_stats
15
16
 
16
17
 
17
- def getProgress(mapPath: Path, asmPath: Path, nonmatchingsPath: Path, pathIndex: int=2, checkFunctionFiles: bool=True, debugging: bool=False) -> tuple[progress_stats.ProgressStats, dict[str, progress_stats.ProgressStats]]:
18
- mapFile = mapfile.MapFile()
19
-
20
- mapFile.debugging = debugging
21
- mapFile.readMapFile(mapPath)
22
-
23
- return mapFile.filterBySectionType(".text").getProgress(asmPath, nonmatchingsPath, pathIndex=pathIndex, checkFunctionFiles=checkFunctionFiles)
24
-
25
- def doProgress(mapPath: Path, asmPath: Path, nonmatchingsPath: Path, pathIndex: int=2, checkFunctionFiles: bool=True, print_json: bool=False, debugging: bool=False) -> int:
18
+ def getProgress(
19
+ mapPath: Path,
20
+ asmPath: Path,
21
+ nonmatchingsPath: Path,
22
+ pathIndex: int=2,
23
+ checkFunctionFiles: bool=True,
24
+ debugging: bool=False,
25
+ plfResolver: Callable[[Path], Path|None]|None=None,
26
+ ) -> tuple[progress_stats.ProgressStats, dict[str, progress_stats.ProgressStats]]:
27
+ mapFile = mapfile.MapFile.newFromMapFile(mapPath)
28
+ mapFile.filterBySectionType(".text")
29
+ if plfResolver is not None:
30
+ mapFile = mapFile.resolvePartiallyLinkedFiles(plfResolver)
31
+
32
+ return mapFile.getProgress(asmPath, nonmatchingsPath, pathIndex=pathIndex, checkFunctionFiles=checkFunctionFiles)
33
+
34
+ def doProgress(
35
+ mapPath: Path,
36
+ asmPath: Path,
37
+ nonmatchingsPath: Path,
38
+ pathIndex: int=2,
39
+ checkFunctionFiles: bool=True,
40
+ print_json: bool=False,
41
+ debugging: bool=False,
42
+ plfResolver: Callable[[Path], Path|None]|None=None,
43
+ ) -> int:
26
44
  if not mapPath.exists():
27
45
  print(f"Could not find mapfile at '{mapPath}'")
28
46
  return 1
29
47
 
30
- totalStats, progressPerFolder = getProgress(mapPath, asmPath, nonmatchingsPath, pathIndex=pathIndex, checkFunctionFiles=checkFunctionFiles, debugging=debugging)
48
+ totalStats, progressPerFolder = getProgress(mapPath, asmPath, nonmatchingsPath, pathIndex=pathIndex, checkFunctionFiles=checkFunctionFiles, debugging=debugging, plfResolver=plfResolver)
31
49
 
32
50
  if print_json:
33
51
  json_temp: dict[str, dict[str, int|float]] = {
@@ -59,7 +77,20 @@ def processArguments(args: argparse.Namespace, decompConfig: decomp_settings.Con
59
77
  debugging: bool = args.debugging #! @deprecated
60
78
  print_json: bool = args.json
61
79
 
62
- exit(doProgress(mapPath, asmPath, nonmatchingsPath, pathIndex=pathIndex, checkFunctionFiles=checkFunctionFiles, print_json=print_json, debugging=debugging))
80
+ plfExt: list[str]|None = args.plf_ext
81
+
82
+ plfResolver = None
83
+ if plfExt is not None:
84
+ def resolver(x: Path) -> Path|None:
85
+ if x.suffix in plfExt:
86
+ newPath = x.with_suffix(".map")
87
+ if newPath.exists():
88
+ return newPath
89
+ return None
90
+
91
+ plfResolver = resolver
92
+
93
+ exit(doProgress(mapPath, asmPath, nonmatchingsPath, pathIndex=pathIndex, checkFunctionFiles=checkFunctionFiles, print_json=print_json, debugging=debugging, plfResolver=plfResolver))
63
94
 
64
95
  def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser], decompConfig: decomp_settings.Config|None=None):
65
96
  parser = subparser.add_parser("progress", help="Computes current progress of the matched functions. Relies on a splat (https://github.com/ethteck/splat) folder structure and matched functions not longer having a file.")
@@ -92,4 +123,6 @@ def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser],
92
123
  parser.add_argument("-d", "--debugging", help="Enable debugging prints. This option is deprecated", action="store_true")
93
124
  parser.add_argument("-j", "--json", help="Print the stats as json instead of a human readable format.", action="store_true")
94
125
 
126
+ parser.add_argument("-x", "--plf-ext", help="File extension for partially linked files (plf). Will be used to transform the `plf`s path into a mapfile path by replacing the extension. The extension must contain the leading period. This argument can be passed multiple times.", action="append")
127
+
95
128
  parser.set_defaults(func=processArguments)
@@ -6,6 +6,7 @@
6
6
  from __future__ import annotations
7
7
 
8
8
  import argparse
9
+ from collections.abc import Callable
9
10
  import decomp_settings
10
11
  from pathlib import Path
11
12
 
@@ -13,13 +14,22 @@ from .. import mapfile
13
14
  from .. import utils
14
15
 
15
16
 
16
- def doSymInfo(mapPath: Path, symName: str, *, as_vram: bool=False, as_vrom: bool=False, as_name: bool=False) -> int:
17
+ def doSymInfo(
18
+ mapPath: Path,
19
+ symName: str,
20
+ *,
21
+ as_vram: bool=False,
22
+ as_vrom: bool=False,
23
+ as_name: bool=False,
24
+ plfResolver: Callable[[Path], Path|None]|None=None,
25
+ ) -> int:
17
26
  if not mapPath.exists():
18
27
  print(f"Could not find mapfile at '{mapPath}'")
19
28
  return 1
20
29
 
21
- mapFile = mapfile.MapFile()
22
- mapFile.readMapFile(mapPath)
30
+ mapFile = mapfile.MapFile.newFromMapFile(mapPath)
31
+ if plfResolver is not None:
32
+ mapFile = mapFile.resolvePartiallyLinkedFiles(plfResolver)
23
33
 
24
34
  possibleFiles: list[mapfile.Section] = []
25
35
 
@@ -66,8 +76,20 @@ def processArguments(args: argparse.Namespace, decompConfig: decomp_settings.Con
66
76
  as_vram: bool = args.vram
67
77
  as_vrom: bool = args.vrom
68
78
  as_name: bool = args.name
79
+ plfExt: list[str]|None = args.plf_ext
69
80
 
70
- exit(doSymInfo(mapPath, symName, as_vram=as_vram, as_vrom=as_vrom, as_name=as_name))
81
+ plfResolver = None
82
+ if plfExt is not None:
83
+ def resolver(x: Path) -> Path|None:
84
+ if x.suffix in plfExt:
85
+ newPath = x.with_suffix(".map")
86
+ if newPath.exists():
87
+ return newPath
88
+ return None
89
+
90
+ plfResolver = resolver
91
+
92
+ exit(doSymInfo(mapPath, symName, as_vram=as_vram, as_vrom=as_vrom, as_name=as_name, plfResolver=plfResolver))
71
93
 
72
94
  def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser], decompConfig: decomp_settings.Config|None=None):
73
95
  parser = subparser.add_parser("sym_info", help="Display various information about a symbol or address.")
@@ -86,6 +108,8 @@ def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser],
86
108
  parser.add_argument("mapfile", help="Path to a map file.", type=Path)
87
109
  parser.add_argument("symname", help="Symbol name or VROM/VRAM address to lookup. How to treat this argument will be guessed.")
88
110
 
111
+ parser.add_argument("-x", "--plf-ext", help="File extension for partially linked files (plf). Will be used to transform the `plf`s path into a mapfile path by replacing the extension. The extension must contain the leading period. This argument can be passed multiple times.", action="append")
112
+
89
113
  vram_vrom_group = parser.add_mutually_exclusive_group()
90
114
  vram_vrom_group.add_argument("--vram", help="Treat the argument as a VRAM address instead of guessing.", action="store_true")
91
115
  vram_vrom_group.add_argument("--vrom", help="Treat the argument as a VROM address instead of guessing.", action="store_true")