splat64 0.36.4__py3-none-any.whl → 0.37.1__py3-none-any.whl

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.
splat/__init__.py CHANGED
@@ -1,7 +1,7 @@
1
1
  __package_name__ = __name__
2
2
 
3
3
  # Should be synced with pyproject.toml
4
- __version__ = "0.36.4"
4
+ __version__ = "0.37.1"
5
5
  __author__ = "ethteck"
6
6
 
7
7
  from . import util as util
@@ -7,7 +7,7 @@ from typing import Set
7
7
 
8
8
  class SpimdisasmDisassembler(disassembler.Disassembler):
9
9
  # This value should be kept in sync with the version listed on requirements.txt and pyproject.toml
10
- SPIMDISASM_MIN = (1, 38, 0)
10
+ SPIMDISASM_MIN = (1, 39, 0)
11
11
 
12
12
  def configure(self):
13
13
  # Configure spimdisasm
@@ -74,6 +74,8 @@ class SpimdisasmDisassembler(disassembler.Disassembler):
74
74
  spimdisasm.common.GlobalConfig.SYMBOL_FINDER_FILTERED_ADDRESSES_AS_HILO = (
75
75
  False
76
76
  )
77
+ if options.opts.align_on_branch_labels:
78
+ spimdisasm.common.GlobalConfig.ASM_EMIT_ALIGN_BRANCH_LABELS = True
77
79
  rabbitizer.config.toolchainTweaks_treatJAsUnconditionalBranch = (
78
80
  selected_compiler.j_as_branch
79
81
  )
splat/scripts/split.py CHANGED
@@ -581,7 +581,7 @@ def add_arguments_to_parser(parser: argparse.ArgumentParser):
581
581
  nargs="+",
582
582
  type=Path,
583
583
  )
584
- parser.add_argument("--modes", nargs="+", default="all")
584
+ parser.add_argument("--modes", nargs="+", default=["all"])
585
585
  parser.add_argument("--verbose", action="store_true", help="Enable debug logging")
586
586
  parser.add_argument(
587
587
  "--use-cache", action="store_true", help="Only split changed segments in config"
@@ -152,6 +152,8 @@ class CommonSegC(CommonSegCodeSubsegment):
152
152
 
153
153
  def split(self, rom_bytes: bytes):
154
154
  if self.is_auto_segment:
155
+ if options.opts.make_full_disasm_for_code:
156
+ self.split_as_asmtu_file(self.asm_out_path())
155
157
  return
156
158
 
157
159
  if self.rom_start != self.rom_end:
@@ -252,22 +252,21 @@ class CommonSegCodeSubsegment(Segment):
252
252
  f.write(self.spim_section.disassemble())
253
253
 
254
254
  # Same as above but write all sections from siblings
255
- def split_as_asmtu_file(self, out_path: Optional[Path]):
256
- if self.spim_section is None:
257
- return
258
-
259
- if not out_path:
260
- return
261
-
255
+ def split_as_asmtu_file(self, out_path: Path):
262
256
  out_path.parent.mkdir(parents=True, exist_ok=True)
263
257
 
264
258
  self.print_file_boundaries()
265
259
 
266
260
  with open(out_path, "w", newline="\n") as f:
267
- # Write `.text` contents
268
- for line in self.get_asm_file_header():
269
- f.write(line + "\n")
270
- f.write(self.spim_section.disassemble())
261
+ # self.spim_section would be None if the current section was
262
+ # declared `auto` in the yaml.
263
+ # This can be useful when there are TUs with only data/rodata/bss/etc
264
+ # sections but not text section.
265
+ if self.spim_section is not None:
266
+ # Write `.text` contents
267
+ for line in self.get_asm_file_header():
268
+ f.write(line + "\n")
269
+ f.write(self.spim_section.disassemble())
271
270
 
272
271
  # Disassemble the siblings to this file by respecting the `section_order`
273
272
  for sect in self.section_order:
@@ -281,25 +280,31 @@ class CommonSegCodeSubsegment(Segment):
281
280
  if (
282
281
  isinstance(sibling, CommonSegCodeSubsegment)
283
282
  and sibling.spim_section is not None
284
- and not sibling.should_self_split()
283
+ and (
284
+ not sibling.should_self_split()
285
+ or options.opts.make_full_disasm_for_code
286
+ )
285
287
  ):
286
288
  f.write("\n")
287
289
  f.write(f"{sibling.get_section_asm_line()}\n\n")
288
290
  f.write(sibling.spim_section.disassemble())
289
291
 
290
- # Another loop to check anything that somehow may not be present on the `section_order`
292
+ # Another loop to check anything that somehow may not be present in the `section_order`
291
293
  for sect, sibling in self.siblings.items():
292
294
  if sect == self.get_linker_section_linksection():
293
295
  continue
294
296
 
295
297
  if sect in self.section_order:
296
- # Already handled on the above loop
298
+ # Already handled in the above loop
297
299
  continue
298
300
 
299
301
  if (
300
302
  isinstance(sibling, CommonSegCodeSubsegment)
301
303
  and sibling.spim_section is not None
302
- and not sibling.should_self_split()
304
+ and (
305
+ not sibling.should_self_split()
306
+ or options.opts.make_full_disasm_for_code
307
+ )
303
308
  ):
304
309
  f.write("\n")
305
310
  f.write(f"{sibling.get_section_asm_line()}\n\n")
splat/util/compiler.py CHANGED
@@ -18,6 +18,7 @@ class Compiler:
18
18
  asm_emit_size_directive: Optional[bool] = None
19
19
  j_as_branch: bool = False
20
20
  uses_include_asm: bool = True
21
+ align_on_branch_labels: bool = False
21
22
 
22
23
 
23
24
  GCC = Compiler(
@@ -61,7 +62,7 @@ PSYQ = Compiler(
61
62
 
62
63
  # PS2
63
64
  MWCCPS2 = Compiler("MWCCPS2", uses_include_asm=False)
64
- EEGCC = Compiler("EEGCC")
65
+ EEGCC = Compiler("EEGCC", align_on_branch_labels=True)
65
66
 
66
67
  compiler_for_name: Dict[str, Compiler] = {
67
68
  x.name: x
@@ -5,10 +5,12 @@ This includes writing files like:
5
5
  - include/macro.inc
6
6
  - include/labels.inc
7
7
  - include/gte_macros.inc
8
+
9
+ The directory where these files are written to can be controlled with
10
+ `options.opts.generated_asm_macros_directory`.
8
11
  """
9
12
 
10
13
  from pathlib import Path
11
- import os
12
14
 
13
15
  from . import options, log
14
16
 
@@ -22,7 +24,7 @@ def write_all_files():
22
24
 
23
25
 
24
26
  def _write(filepath: str, contents: str):
25
- p = Path(os.path.normpath(options.opts.base_path / filepath))
27
+ p = Path(filepath)
26
28
  p.parent.mkdir(parents=True, exist_ok=True)
27
29
 
28
30
  if p.exists():
@@ -39,6 +41,8 @@ def write_include_asm_h():
39
41
  # These compilers do not use the `INCLUDE_ASM` macro.
40
42
  return
41
43
 
44
+ directory = options.opts.generated_asm_macros_directory.as_posix()
45
+
42
46
  if options.opts.include_asm_macro_style == "maspsx_hack":
43
47
  include_asm_macro = """\
44
48
  #define INCLUDE_ASM(FOLDER, NAME) \\
@@ -88,7 +92,12 @@ def write_include_asm_h():
88
92
  #ifndef INCLUDE_RODATA
89
93
  {include_rodata_macro}\
90
94
  #endif
91
- __asm__(".include \\"include/labels.inc\\"\\n");
95
+
96
+ #if INCLUDE_ASM_USE_MACRO_INC
97
+ __asm__(".include \\"{directory}/macro.inc\\"\\n");
98
+ #else
99
+ __asm__(".include \\"{directory}/labels.inc\\"\\n");
100
+ #endif
92
101
 
93
102
  #else
94
103
 
@@ -103,10 +112,12 @@ __asm__(".include \\"include/labels.inc\\"\\n");
103
112
 
104
113
  #endif /* INCLUDE_ASM_H */
105
114
  """
106
- _write("include/include_asm.h", file_data)
115
+ _write(f"{directory}/include_asm.h", file_data)
107
116
 
108
117
 
109
118
  def write_assembly_inc_files():
119
+ directory = options.opts.generated_asm_macros_directory.as_posix()
120
+
110
121
  func_macros = f"""\
111
122
  # A function symbol.
112
123
  .macro {options.opts.asm_function_macro} label, visibility=global
@@ -230,7 +241,7 @@ def write_assembly_inc_files():
230
241
  {data_macros}
231
242
  {nm_macros}\
232
243
  """
233
- _write("include/labels.inc", labels_inc)
244
+ _write(f"{directory}/labels.inc", labels_inc)
234
245
 
235
246
  if options.opts.platform in {"n64", "psx"}:
236
247
  gas = macros_inc
@@ -338,7 +349,7 @@ def write_assembly_inc_files():
338
349
  {gas}
339
350
  .endif
340
351
  """
341
- _write("include/macro.inc", f"{preamble}\n{gas}")
352
+ _write(f"{directory}/macro.inc", f"{preamble}\n{gas}")
342
353
 
343
354
 
344
355
  def write_gte_macros():
@@ -762,4 +773,5 @@ def write_gte_macros():
762
773
  .endif
763
774
  """
764
775
 
765
- _write("include/gte_macros.inc", gte_macros)
776
+ directory = options.opts.generated_asm_macros_directory.as_posix()
777
+ _write(f"{directory}/gte_macros.inc", gte_macros)
splat/util/options.py CHANGED
@@ -43,6 +43,8 @@ class SplatOpts:
43
43
  # default: The default one.
44
44
  # maspsx_hack: Use the maspsx hack workaround definition https://github.com/mkst/maspsx?tab=readme-ov-file#include_asm-reordering-workaround-hack
45
45
  include_asm_macro_style: Literal["default", "maspsx_hack"]
46
+ # Directory to place the generated asm macros files.
47
+ generated_asm_macros_directory: Path
46
48
  # Determines whether to use .o as the suffix for all binary files?... TODO document
47
49
  use_o_as_suffix: bool
48
50
  # the value of the $gp register to correctly calculate offset to %gp_rel relocs
@@ -278,6 +280,8 @@ class SplatOpts:
278
280
  # Determines whether to use a legacy INCLUDE_ASM macro format in c files
279
281
  # only applies to GCC/SN64
280
282
  use_legacy_include_asm: bool
283
+ # Emit alignment directives in branch labels, as a way to workaround the short loop bug present in SN PS2 compilers
284
+ align_on_branch_labels: bool
281
285
 
282
286
  # Returns whether the given mode is currently enabled
283
287
  def is_mode_active(self, mode: str) -> bool:
@@ -392,6 +396,11 @@ def _parse_yaml(
392
396
  if asm_emit_size_directive is None:
393
397
  asm_emit_size_directive = comp.asm_emit_size_directive
394
398
 
399
+ align_on_branch_labels = p.parse_optional_opt("align_on_branch_labels", bool)
400
+ # If option not provided then use the compiler default
401
+ if align_on_branch_labels is None:
402
+ align_on_branch_labels = comp.align_on_branch_labels
403
+
395
404
  def parse_endianness() -> Literal["big", "little"]:
396
405
  endianness = p.parse_opt_within(
397
406
  "endianness",
@@ -454,6 +463,9 @@ def _parse_yaml(
454
463
  ),
455
464
  generate_asm_macros_files=p.parse_opt("generate_asm_macros_files", bool, True),
456
465
  include_asm_macro_style=parse_include_asm_macro_style(),
466
+ generated_asm_macros_directory=p.parse_path(
467
+ base_path, "generated_asm_macros_directory", "include"
468
+ ),
457
469
  use_o_as_suffix=p.parse_opt("o_as_suffix", bool, False),
458
470
  gp=p.parse_optional_opt("gp_value", int),
459
471
  check_consecutive_segment_types=p.parse_opt(
@@ -608,6 +620,7 @@ def _parse_yaml(
608
620
  hardware_regs=p.parse_opt("hardware_regs", bool, False),
609
621
  image_type_in_extension=p.parse_opt("image_type_in_extension", bool, False),
610
622
  use_legacy_include_asm=p.parse_opt("use_legacy_include_asm", bool, False),
623
+ align_on_branch_labels=align_on_branch_labels,
611
624
  disasm_unknown=p.parse_opt("disasm_unknown", bool, False),
612
625
  detect_redundant_function_end=p.parse_opt(
613
626
  "detect_redundant_function_end", bool, True
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: splat64
3
- Version: 0.36.4
3
+ Version: 0.37.1
4
4
  Summary: A binary splitting tool to assist with decompilation and modding projects
5
5
  Project-URL: Repository, https://github.com/ethteck/splat
6
6
  Project-URL: Issues, https://github.com/ethteck/splat/issues
@@ -42,7 +42,7 @@ Requires-Dist: n64img>=0.3.3; extra == 'dev'
42
42
  Requires-Dist: pygfxd>=1.0.5; extra == 'dev'
43
43
  Requires-Dist: rabbitizer<2.0.0,>=1.12.0; extra == 'dev'
44
44
  Requires-Dist: ruff; extra == 'dev'
45
- Requires-Dist: spimdisasm<2.0.0,>=1.38.0; extra == 'dev'
45
+ Requires-Dist: spimdisasm<2.0.0,>=1.39.0; extra == 'dev'
46
46
  Requires-Dist: types-colorama; extra == 'dev'
47
47
  Requires-Dist: types-pyyaml; extra == 'dev'
48
48
  Provides-Extra: mips
@@ -50,7 +50,7 @@ Requires-Dist: crunch64<1.0.0,>=0.5.1; extra == 'mips'
50
50
  Requires-Dist: n64img>=0.3.3; extra == 'mips'
51
51
  Requires-Dist: pygfxd>=1.0.5; extra == 'mips'
52
52
  Requires-Dist: rabbitizer<2.0.0,>=1.12.0; extra == 'mips'
53
- Requires-Dist: spimdisasm<2.0.0,>=1.38.0; extra == 'mips'
53
+ Requires-Dist: spimdisasm<2.0.0,>=1.39.0; extra == 'mips'
54
54
  Description-Content-Type: text/markdown
55
55
 
56
56
  # splat
@@ -76,7 +76,7 @@ The brackets corresponds to the optional dependencies to install while installin
76
76
  If you use a `requirements.txt` file in your repository, then you can add this library with the following line:
77
77
 
78
78
  ```txt
79
- splat64[mips]>=0.36.4,<1.0.0
79
+ splat64[mips]>=0.37.1,<1.0.0
80
80
  ```
81
81
 
82
82
  ### Optional dependencies
@@ -1,4 +1,4 @@
1
- splat/__init__.py,sha256=K7V_4INbs5mtgBs_XECCUNEhSPHURCOviws3SKjutbc,291
1
+ splat/__init__.py,sha256=u9i1mpp1a75UqxBlneTIdu6BW5x33bBJEUxT2u14sKQ,291
2
2
  splat/__main__.py,sha256=T333dHDgr-2HYYhtARnYMEjdECnYiNIKfcXDD99o22A,732
3
3
  splat/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  splat/disassembler/__init__.py,sha256=LXuCElHxOvbb9xuSSeswT8W_v78chwtqjKq_9nxFVzQ,167
@@ -6,7 +6,7 @@ splat/disassembler/disassembler.py,sha256=2ynehZRz1P6UnaBk6DWRy4c3ynRnnWApMhf0K9
6
6
  splat/disassembler/disassembler_instance.py,sha256=09GW7QYoNolgE2wnO7ALngw_CxgF-mfyLiXBsyv22jA,916
7
7
  splat/disassembler/disassembler_section.py,sha256=J9jtplQVDVeGBmyEOcMpC3Hv3DyecqaNjlYc7zqEqDI,7459
8
8
  splat/disassembler/null_disassembler.py,sha256=g1LCsCJ5mBClyPW-Sf7t_nudKLoTk9q1m9dwdR0QrW4,291
9
- splat/disassembler/spimdisasm_disassembler.py,sha256=-COKUTd2YmggXKYNLqYmrzJXWmdD_PrZoV-FF9LnoWs,5920
9
+ splat/disassembler/spimdisasm_disassembler.py,sha256=a-IG4VcEsmFk2oPXZ0WN94Fl9LZf5_wOi4w4ljc2w8E,6047
10
10
  splat/platforms/__init__.py,sha256=qjqKi63k5N3DUdILNfuk6qpJJkVeAWpjAs36L97vvP4,100
11
11
  splat/platforms/n64.py,sha256=kgWr6nesGC0X-qVydmu8tSq48NbqVf9mF6EyqvUuoUM,421
12
12
  splat/platforms/ps2.py,sha256=7wefhMRNxTguyxofWyDGrLGD59K6oDwzJu3Btpez3q4,298
@@ -15,7 +15,7 @@ splat/platforms/psx.py,sha256=YxQERdOBr4p3ab9Wk80FNhVYi-uvmh7p_jeykSFp23M,40
15
15
  splat/scripts/__init__.py,sha256=OY0nHg6a7JB437Sb96qLbZ_7ByVsal1gStj35wJAI_Y,101
16
16
  splat/scripts/capy.py,sha256=svbOfLO34-QN3xLiBy9vk2RGs_To8TWMWEKBw6yx2xQ,3674
17
17
  splat/scripts/create_config.py,sha256=Xt0BgS9ql5GfLrNKWQRMuKWea0sXUygRV1_wCYGrrPE,17949
18
- splat/scripts/split.py,sha256=wWib2lDdedzjcNLH-Ay48gM2XGZ9JCUsrriamuHzkOU,21935
18
+ splat/scripts/split.py,sha256=rstKTy1osrD4Cqp07NGNVpLeBVQSNbeeTYC-AORrSJs,21937
19
19
  splat/segtypes/__init__.py,sha256=-upUw_4JGQtvyp6IfTMzOq_CK3xvVaT_0K0_EipHyOo,208
20
20
  splat/segtypes/linker_entry.py,sha256=WHFdVFC_NW6_ub-LJbfwze-FZGCTRtjEZHz_bhIkX-M,25160
21
21
  splat/segtypes/segment.py,sha256=IcmF7FxDrJ1ZP5AKFO-skNrGfYhGIYwawyepKzeTF3A,30619
@@ -24,9 +24,9 @@ splat/segtypes/common/asm.py,sha256=gpR4uZ57l4Q9G0XTOeO1JIk9P5d8xXBxRfkrPIN-M1A,
24
24
  splat/segtypes/common/asmtu.py,sha256=C52kKh-8YeDHu0EucEfQ-tQMtDgfKfwAJ6wwiW6nOBU,354
25
25
  splat/segtypes/common/bin.py,sha256=qZeuvHNSrRuxdk-8V0xW0tcFhtzPk6doyf43E_t7D9Q,1250
26
26
  splat/segtypes/common/bss.py,sha256=cX0RO7LRcBRO6t463AUSSV8sGdlxZTcd5_McZjjqfFo,3107
27
- splat/segtypes/common/c.py,sha256=RkevmqKXK9RKQ_yPClFFur1Uq4jGGdVtL1BnScbHhok,21327
27
+ splat/segtypes/common/c.py,sha256=_YxDn2jyDjfk8ttqsTPrZvD-c6OStmERjz_P98ihS3g,21444
28
28
  splat/segtypes/common/code.py,sha256=FfBuy6x8fQXoJYX2Ul80uOs-CzlVslUaveD-hBmvKXM,10693
29
- splat/segtypes/common/codesubsegment.py,sha256=XpPzNwGSNL4HE7Qgi7-tSVXlYtfdXug9PrzQIJu3yDI,10720
29
+ splat/segtypes/common/codesubsegment.py,sha256=a9AGNfWrQRfMVKP84_a_2BBfQSwOVviAltp8ZjOivT0,11140
30
30
  splat/segtypes/common/cpp.py,sha256=p-duowCt4czrmaWgj1LuFw5LGfdyB_uaeLTKVmH80Cg,180
31
31
  splat/segtypes/common/data.py,sha256=l3CCa95vHH8XwiksamaxuZuSF_rOGqcozGlZj0bt9Yw,5712
32
32
  splat/segtypes/common/databin.py,sha256=nDI1ciAv0QLt2xDYjEtGJHSoONZzJZKyST-BuSKML2Q,1169
@@ -78,11 +78,11 @@ splat/segtypes/psx/header.py,sha256=2S8XG_6zfLGzmEA0XpFqs0-4nf52YD9Erk6SbMUlVzo,
78
78
  splat/util/__init__.py,sha256=vejj8R_nldFOlIOEoG492Lycg1zUCTQewoPF9c3P6fw,538
79
79
  splat/util/cache_handler.py,sha256=BrTWo8U4bj8TBcZfIRwiAYmogc3YUlBz9P-34Y0aIrg,1851
80
80
  splat/util/color.py,sha256=FSmy0dAQJ9FzRBc99Yt4kBEyB62MC_YiVkqoWgPMsRU,371
81
- splat/util/compiler.py,sha256=uXShMm49380ENecSFlsi75LWI45yakWkExZX8NT5pOU,1778
81
+ splat/util/compiler.py,sha256=n5hlxazUy8rq-t7DADBbC0n6ZGuLDzp3ma3883oHQ3E,1848
82
82
  splat/util/conf.py,sha256=0Qcv5d5XAvdVzqF4i4L_lJuC5hI0PEufeob58YaN-xs,3230
83
- splat/util/file_presets.py,sha256=whms6WHRwvVfg-PQTwao4QimvVHSxfUIUaz-qXdcEbM,18585
83
+ splat/util/file_presets.py,sha256=4UsDMqQy5ZACSafjCba1pwwTQKK_2leOycwTFkNG4Ac,18985
84
84
  splat/util/log.py,sha256=aJA1rg8IirJu1wGzjNuATHvepYvD3k5CtEyMasyJWxI,1193
85
- splat/util/options.py,sha256=bXFruGE-tcqsdM0nYNqf_IQIiqxFCxn7NWEo_igOZIc,31252
85
+ splat/util/options.py,sha256=Lq1noBa-2f_j7lSvFfOyq4b2rFhBuCvB-M_s1Czu1Pg,31931
86
86
  splat/util/palettes.py,sha256=d3KoZnwt-zunI9eNwb3txysXg4DY3xnF0O5aQRxM4so,2920
87
87
  splat/util/progress_bar.py,sha256=41VehpIFK1cphENaXV_Aq6_3mFx25eQ8V7Z51SKFPeM,166
88
88
  splat/util/relocs.py,sha256=j8fzM9u0ZQwZa1b1Dd26ho9GwIooBXt8mE0jAN7wqV0,4153
@@ -97,8 +97,8 @@ splat/util/ps2/__init__.py,sha256=hAU12HtQLOc_sxc8_rzxOERBT5wjg3DhQ8XRN9hBXfA,39
97
97
  splat/util/ps2/ps2elfinfo.py,sha256=v6nTPabzXpG1N-MhhkbVeLoGjgsjBEpHL1DoPv26-Hs,7982
98
98
  splat/util/psx/__init__.py,sha256=kCCaR-KB1mNlIcXB4OuuSQ2zVLbWg_SnIZIUeyjeBBI,39
99
99
  splat/util/psx/psxexeinfo.py,sha256=Oxd5Lt8HTNHuUzw3cVujdyJRqEG-yo0XT78wEISUXms,5705
100
- splat64-0.36.4.dist-info/METADATA,sha256=sQtM6Sc89JJYxes3KqZRDfIKyDRLqzFuXUbiD82IXR4,3879
101
- splat64-0.36.4.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
102
- splat64-0.36.4.dist-info/entry_points.txt,sha256=O7Xy-qNOHcI87-OQrWJ-OhRDws74SuwVb_4rtnp0eLo,52
103
- splat64-0.36.4.dist-info/licenses/LICENSE,sha256=97VMVzjG8yQvsf8NG2M9IFSbh7R8cifJnc6QK1cZqj8,1070
104
- splat64-0.36.4.dist-info/RECORD,,
100
+ splat64-0.37.1.dist-info/METADATA,sha256=3QvXBmz8S6MtVua2En81GEBd_2Q2CSy6SWS7k0gA9UQ,3879
101
+ splat64-0.37.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
102
+ splat64-0.37.1.dist-info/entry_points.txt,sha256=O7Xy-qNOHcI87-OQrWJ-OhRDws74SuwVb_4rtnp0eLo,52
103
+ splat64-0.37.1.dist-info/licenses/LICENSE,sha256=97VMVzjG8yQvsf8NG2M9IFSbh7R8cifJnc6QK1cZqj8,1070
104
+ splat64-0.37.1.dist-info/RECORD,,