-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add Python patching script for better maintainability
- Loading branch information
Showing
2 changed files
with
113 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Coolscan LS-50 | ||
DF17811 0x170EE "1.02" "2.01" # Version in INQUIRY response | ||
DF17811 0x17106 0x0201 0x0102 # Version in USB descriptor (High Speed) | ||
DF17811 0x17118 0x0201 0x0102 # Version in USB descriptor (Full Speed) | ||
DF17811 0x2A213 0x03 0x42 # Enable adapter ID 3 | ||
DF17811 0x2A219 0x05 0x42 # Enable adapter ID 5 | ||
DF17811 0x2A21F 0x06 0x42 # Enable adapter ID 6 | ||
DF17811 0x49E49 "1.02" "2.01" # Version in strings | ||
DF17811 0x4A114 0x00400000 0x00000000 # READ BUFFER - allowed RAM start | ||
DF17811 0x4A118 0x0041FFFF 0x00FFFFFF # READ BUFFER - allowed RAM end | ||
|
||
# Coolscan LS-40 | ||
PT17035 0x169F4 "1.20" "2.01" # Version in INQUIRY response | ||
PT17035 0x16A33 0x2001 0x0102 # Version in USB descriptor (High Speed) | ||
PT17035 0x29EB3 0x03 0x42 # Enable adapter ID 3 | ||
PT17035 0x29EB9 0x05 0x42 # Enable adapter ID 5 | ||
PT17035 0x29EBF 0x06 0x42 # Enable adapter ID 6 | ||
PT17035 0x47C3B "1.20" "2.01" # Version in strings | ||
PT17035 0x47F06 0x00400000 0x00000000 # READ BUFFER - allowed RAM start | ||
PT17035 0x47F0A 0x0041FFFF 0x00FFFFFF # READ BUFFER - allowed RAM end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
#!/usr/bin/env python | ||
# -*- coding: utf-8 -*- | ||
# | ||
# Coolscan firmware patcher. Just a bunch of helper functions really, | ||
# to make the patches easy to understand and apply. | ||
|
||
|
||
import os | ||
|
||
|
||
class Patch(object): | ||
|
||
def __init__(self, model, offset, length, original, patched): | ||
|
||
self.model = model | ||
self.offset = offset | ||
self.length = length | ||
self.original = original | ||
self.patched = patched | ||
|
||
def __repr__(self): | ||
|
||
return "Patch[%s]<0x%x: %s => %s>" % (self.model, self.offset, self.original.hex(), self.patched.hex()) | ||
|
||
def apply(self, model, target): | ||
|
||
if model != self.model: | ||
return | ||
print(self) | ||
value = bytes(target[self.offset:self.offset+self.length]) | ||
assert value == self.original | ||
target[self.offset:self.offset+self.length] = self.patched | ||
|
||
@classmethod | ||
def parse(cls, line): | ||
|
||
# remove trailing comment | ||
line = line.partition('#')[0] | ||
# remove whitespace | ||
line = line.strip() | ||
# bail out if the line was empty | ||
if not line: | ||
return None | ||
# split into components | ||
model, offset, original, patched = line.split() | ||
# parse/validate them | ||
assert offset.startswith("0x") | ||
offset = int(offset, 0) - 0x10000 # update files start at 0x10000 | ||
assert len(original) == len(patched) | ||
if original.startswith("0x"): | ||
length = len(original)//2 - 1 | ||
original = int(original, 0).to_bytes(length, byteorder='big') | ||
patched = int(patched, 0).to_bytes(length, byteorder='big') | ||
elif original.startswith("\""): | ||
length = len(original)-2 | ||
original = original[1:-1].encode('ascii') | ||
patched = patched[1:-1].encode('ascii') | ||
else: | ||
raise ValueError("Unknown format for original/patched") | ||
return cls(model, offset, length, original, patched) | ||
|
||
|
||
class Patchset(object): | ||
|
||
def __init__(self, path): | ||
|
||
self.patches = [] | ||
lines = open(path).readlines() | ||
for line in lines: | ||
patch = Patch.parse(line) | ||
if patch is not None: | ||
self.patches.append(patch) | ||
|
||
def apply(self, model, target): | ||
for patch in self.patches: | ||
patch.apply(model, target) | ||
|
||
def main(): | ||
source_dir = "firmware/original" | ||
target_dir = "firmware/patched" | ||
files = [ "DF17811.bin", "PT17035.bin" ] | ||
patchset = Patchset("firmware/patches.txt") | ||
|
||
for file in files: | ||
model = file.removesuffix('.bin') | ||
source_path = os.path.join(source_dir, file) | ||
target_path = os.path.join(target_dir, file) | ||
data = bytearray(open(source_path, 'rb').read()) | ||
patchset.apply(model, data) | ||
open(target_path, 'wb').write(data) | ||
|
||
if __name__ == '__main__': | ||
main() |