Skip to content

Commit 618f06e

Browse files
committed
Many clarity updates
- Fix required version in readme (>=3.6 for fstrings) - Simplify isobuster hexdump function - Fix SHA256 in sample - Remove stupid hack suggestion in readme - Add some comments - Misc minor code changes
1 parent f3306cf commit 618f06e

File tree

3 files changed

+37
-47
lines changed

3 files changed

+37
-47
lines changed

README.md

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ Given an ISO file, it will generate a pre-filled Redump submission, containing:
99
- ISO PVD Hexdump
1010
- SFO information
1111

12-
`sfo_info.py` can be used by itself as a standalone sfo_info.exe replacement that works on Linux too.
12+
`sfo_info.py` can be used by itself as a standalone sfo_info.exe replacement.
1313

1414

1515
# Requirements
1616

17-
- Python 3 (>= 3.4)
17+
- Python 3 (>= 3.6)
1818
- pycdlib
1919

2020
Windows exe builds are available in the release tab.
@@ -57,7 +57,7 @@ HashCalc Info:
5757
MD5: dd60041bfb6d677fdaacd2cf9cb6d84a
5858
SHA1: 88a19042041ff368b9cb887432cb5255c654c33c
5959
CRC32: 83adb164
60-
SHA256: 7a9a04d89c1867b7f0ce4e9358b78ff52ec0a6612dc3a15511a3aaa5b1ef9cb4
60+
SHA256: c824f63de2f8bf779e73cad524cd3619fc852d8d669fc00f97f110acecb3015d
6161
[/code]
6262
6363
Primary Volume Descriptor (PVD)
@@ -106,16 +106,7 @@ UPDATER_VER: 1.50
106106
[/code]
107107
```
108108

109-
# Using it in other scripts
110-
111-
Since this is just scripts and was not made like a module, some modifications are needed if you want to import the Python code in some bigger project.
112-
The easiest (and quite ugly) solution is to add a `__init__.py` file, containing:
113-
```Python
114-
import sys
115-
import os
116-
sys.path.append(os.path.join(os.path.dirname(__file__), ".", "."))
117-
```
118-
This adds the whole directory to the path, so beware.
109+
# Automating it
119110

120111
Below is a simple script I've made that auto-generates submissions for every ISO in the given directory.
121112
Make sure it only contains PSP ISOs.
@@ -138,7 +129,8 @@ for root, dirs, files in os.walk(args.dir):
138129
if iso_name + '.nfo' in files:
139130
continue
140131

132+
print(f"Generating submission for {name}...")
141133
gen_psp_redump(os.path.join(root, iso_name + '.iso'),
142134
os.path.join(root, iso_name + '.nfo'))
143-
print(f"Generated submission for {name}")
135+
print("Done.")
144136
```

redump_psp.py

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,23 @@
99

1010

1111
def hexdump(data, offset, size):
12+
"""Return hexdump string of given data in isobuster format."""
13+
def ascii_print(c):
14+
return chr(c) if 32 <= c <= 127 else "."
15+
1216
dump = ""
13-
line_nb = size // 0x10
14-
for i in range(line_nb):
15-
line = f"{offset + i * 16:04x} : "
16-
for j in range(0x10):
17-
line += f"{data[offset + i * 16 + j]:02X}"
18-
line += " " if j == 0x7 else " "
19-
line += " "
20-
r_line = data[offset + i * 0x10: offset + i * 0x10 + 0x10]
21-
line += "".join([chr(b) if 0x20 <= b <= 0x7F else "." for b in r_line])
22-
dump += line
23-
if i < line_nb - 1:
24-
dump += "\n"
17+
for i in range(size // 0x10):
18+
line_offset = offset + i * 0x10
19+
line_data = data[line_offset: line_offset + 0x10]
20+
21+
line_format = "{:04X} :" + " {:02X}" * 8 + " " + " {:02X}" * 8
22+
dump += line_format.format(line_offset, *line_data)
23+
dump += " " + "".join([ascii_print(b) for b in line_data]) + "\n"
2524
return dump
2625

2726

2827
def gen_hashes(filestream):
29-
def read_in_chunks(file_object, chunk_size=1024):
28+
def read_in_chunks(file_object, chunk_size):
3029
while True:
3130
data = file_object.read(chunk_size)
3231
if not data:
@@ -47,14 +46,16 @@ def read_in_chunks(file_object, chunk_size=1024):
4746
return (format(prev_crc32 & 0xFFFFFFFF, 'x').zfill(8),
4847
sha1.hexdigest().zfill(40),
4948
md5.hexdigest().zfill(32),
50-
sha256.hexdigest())
49+
sha256.hexdigest().zfill(64))
5150

5251

5352
def get_pvd_dump(filestream):
53+
# Locate PVD sector, starting from sector 0x10
54+
# See: https://wiki.osdev.org/ISO_9660#Volume_Descriptors
5455
filestream.seek(0x8000)
5556
raw_sector = filestream.read(0x800)
5657
while raw_sector[0] != 0xFF:
57-
if raw_sector[6] == 0x1:
58+
if raw_sector[0] == 0x01:
5859
return hexdump(raw_sector, 0x320, 0x60)
5960
raw_sector = filestream.read(0x800)
6061
raise Exception("Could not find PVD")
@@ -75,7 +76,7 @@ def gen_psp_redump(iso, out):
7576
dump = TEMPLATE.format(
7677
size_mb=size_mb, size_b=size_b,
7778
md5=hashes[2], sha1=hashes[1], crc32=hashes[0], sha256=hashes[3],
78-
pvd_hexdump=pvd_dump, sfo_info=sfo_info)
79+
pvd_hexdump=pvd_dump.strip('\n'), sfo_info=sfo_info)
7980
if out:
8081
with open(out, 'w', encoding='utf8') as f:
8182
f.write(dump)

sfo_info.py

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,6 @@ class SFODataFormat(IntEnum):
1212
INT32 = 0x0404
1313

1414

15-
class SFOHeader:
16-
def __init__(self, raw):
17-
# Check magic
18-
assert(raw[:0x4] == b"\x00PSF")
19-
version_minor = struct.unpack("<I", raw[0x5:0x8] + b"\x00")[0]
20-
self.version = f"{raw[0x04]}.{version_minor}"
21-
self.key_table_start, self.data_table_start, self.table_entries = \
22-
struct.unpack('<III', raw[0x08:0x14])
23-
24-
2515
class SFOIndexTableEntry:
2616
def __init__(self, raw, offset):
2717
fields = struct.unpack('<HHIII', raw[offset: offset + 0x10])
@@ -34,20 +24,28 @@ def __init__(self, raw, offset):
3424

3525
class SFO:
3626
def __init__(self, raw_sfo):
37-
self.header = SFOHeader(raw_sfo)
27+
# Read header
28+
assert(raw_sfo[:0x4] == b"\x00PSF")
29+
version_minor = struct.unpack("<I", raw_sfo[0x5:0x8] + b"\x00")[0]
30+
self.version = f"{raw_sfo[0x04]}.{version_minor}"
31+
self.key_table_start, self.data_table_start, self.table_entries = \
32+
struct.unpack('<III', raw_sfo[0x08:0x14])
3833

34+
# Read index table entries
3935
self.idx_table = []
40-
for idx in range(self.header.table_entries):
36+
for idx in range(self.table_entries):
4137
self.idx_table.append(
4238
SFOIndexTableEntry(raw_sfo, 0x14 + idx * 0x10))
4339

40+
# Read data entries
4441
self.data = {}
4542
for i in range(len(self.idx_table)):
4643
self._read_entry(raw_sfo, i)
4744

4845
def _read_entry(self, raw_sfo, idx):
49-
key_table_start = self.header.key_table_start
50-
data_table_start = self.header.data_table_start
46+
# Offsets
47+
key_table_start = self.key_table_start
48+
data_table_start = self.data_table_start
5149
entry = self.idx_table[idx]
5250

5351
# Read key from key table
@@ -69,8 +67,7 @@ def _read_entry(self, raw_sfo, idx):
6967
self.data[key] = data
7068

7169
def dump(self):
72-
dump = ""
73-
dump += f"SFO Version: {self.header.version}\n"
70+
dump = f"SFO Version: {self.version}\n"
7471
for key in self.data.keys():
7572
dump += f"{key}: {self.data[key]}\n"
7673
return dump
@@ -96,7 +93,7 @@ def get_sfo_info(path):
9693
iso.close()
9794

9895
if out:
99-
out = out[:-2]
96+
out = out[:-2] # Strip trailing backlines
10097
return out
10198

10299

0 commit comments

Comments
 (0)