Skip to content

Commit 13e4d35

Browse files
itismadnessitismadness
authored and
itismadness
committed
Initial group of work to match EAC logchecker
1 parent aa53cb9 commit 13e4d35

File tree

3 files changed

+64
-52
lines changed

3 files changed

+64
-52
lines changed

.travis.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
language: python
2+
dist: trusty
3+
sudo: true
4+
5+
jobs:
6+
include:
7+
- python: "3.4"
8+
- python: "3.5"
9+
- python: "3.6"
10+
- python: "3.7"
11+
dist: xenial
12+
13+
install:
14+
- pip install pyinstaller
15+
16+
script:
17+
- ./eac_logchecker.py logs/01.log

eac.py renamed to eac_logchecker.py

Lines changed: 47 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
#!/usr/bin/python
1+
#!/usr/bin/env python3
22

33
import sys
44
import argparse
55
import contextlib
6+
import json
67

78
CHECKSUM_MIN_VERSION = ('V1.0', 'beta', '1')
89

@@ -13,12 +14,15 @@ def BYTE4(n):
1314
def BYTE3(n):
1415
return (n & 0x00FF0000) >> 16
1516

17+
1618
def BYTE2(n):
1719
return (n & 0x0000FF00) >> 8
1820

21+
1922
def BYTE1(n):
2023
return (n & 0x000000FF) >> 0
2124

25+
2226
def rotate_right(n):
2327
return ((n & 0x000000FF) << 24) | (n >> 8)
2428

@@ -94,6 +98,9 @@ def eac_checksum(text):
9498

9599

96100
def extract_info(text):
101+
if len(text) == 0:
102+
return text, None, None
103+
97104
version = text.splitlines()[0]
98105

99106
if not version.startswith('Exact Audio Copy'):
@@ -110,8 +117,12 @@ def extract_info(text):
110117
return text, version, signature
111118

112119

113-
def eac_verify(data):
114-
# Log is encoded as Little Endian UTF-16
120+
def eac_verify(text):
121+
unsigned_text, version, old_signature = extract_info(text)
122+
return unsigned_text, version, old_signature, eac_checksum(unsigned_text)
123+
124+
125+
def get_logs(data):
115126
text = data.decode('utf-16-le')
116127

117128
# Strip off the BOM
@@ -121,14 +132,12 @@ def eac_verify(data):
121132
# Null bytes screw it up
122133
if '\x00' in text:
123134
text = text[:text.index('\x00')]
124-
135+
125136
# EAC crashes if there are more than 2^14 bytes in a line
126137
if any(len(l) + 1 > 2**13 for l in text.split('\n')):
127138
raise RuntimeError('EAC cannot handle lines longer than 2^13 chars')
128139

129-
unsigned_text, version, old_signature = extract_info(text)
130-
131-
return unsigned_text, version, old_signature, eac_checksum(unsigned_text)
140+
return [x.strip() for x in text.split('-' * 60)]
132141

133142

134143
class FixedFileType(argparse.FileType):
@@ -144,57 +153,43 @@ def __call__(self, string):
144153

145154
if __name__ == '__main__':
146155
parser = argparse.ArgumentParser(description='Verifies and resigns EAC logs')
156+
parser.add_argument('--json', action='store_true', help='Output as JSON')
157+
parser.add_argument('files', type=FixedFileType(mode='rb'), nargs='+', help='input log file(s)')
147158

148-
subparsers = parser.add_subparsers(dest='command', required=True)
149-
150-
verify_parser = subparsers.add_parser('verify', help='verify a log')
151-
verify_parser.add_argument('files', type=FixedFileType(mode='rb'), nargs='+', help='input log file(s)')
159+
args = parser.parse_args()
152160

153-
sign_parser = subparsers.add_parser('sign', help='sign or fix an existing log')
154-
sign_parser.add_argument('--force', action='store_true', help='forces signing even if EAC version is too old')
155-
sign_parser.add_argument('input_file', type=FixedFileType(mode='rb'), help='input log file')
156-
sign_parser.add_argument('output_file', type=FixedFileType(mode='wb'), help='output log file')
161+
max_length = max(len(f.name) for f in args.files)
157162

158-
args = parser.parse_args()
163+
cnt = 1
164+
output = {}
165+
print('Log Integrity Checker (C) 2010 by Andre Wiethoff')
166+
for file in args.files:
167+
prefix = (file.name + ':').ljust(max_length + 2)
159168

160-
if args.command == 'sign':
161-
with contextlib.closing(args.input_file) as handle:
169+
with contextlib.closing(file) as open_file:
170+
logs = get_logs(open_file.read())
171+
for log in logs:
162172
try:
163-
data, version, old_signature, actual_signature = eac_verify(handle.read())
173+
data, version, old_signature, actual_signature = eac_verify(log)
174+
except RuntimeError as e:
175+
print(prefix, e)
176+
continue
164177
except ValueError as e:
165-
print(args.input_file, ': ', e, sep='')
166-
sys.exit(1)
167-
168-
if not args.force and (version is None or version <= CHECKSUM_MIN_VERSION):
169-
raise ValueError('EAC version is too old to be signed')
170-
171-
data += f'\r\n\r\n==== Log checksum {actual_signature} ====\r\n'
172-
173-
with contextlib.closing(args.output_file or args.input_file) as handle:
174-
handle.write(b'\xff\xfe' + data.encode('utf-16le'))
175-
elif args.command == 'verify':
176-
max_length = max(len(f.name) for f in args.files)
177-
178-
for file in args.files:
179-
prefix = (file.name + ':').ljust(max_length + 2)
180-
181-
with contextlib.closing(file) as handle:
182-
try:
183-
data, version, old_signature, actual_signature = eac_verify(handle.read())
184-
except RuntimeError as e:
185-
print(prefix, e)
186-
continue
187-
except ValueError as e:
188-
print(prefix, 'Not a log file')
189-
continue
190-
191-
if version is None:
192178
print(prefix, 'Not a log file')
193-
elif old_signature is None:
194-
print(prefix, 'Log file without a signature')
179+
continue
180+
181+
if version is None or old_signature is None:
182+
message = 'Log entry has no checksum!'
195183
elif old_signature != actual_signature:
196-
print(prefix, 'Malformed')
197-
elif version <= CHECKSUM_MIN_VERSION:
198-
print(prefix, 'Forged')
184+
message = 'Log entry was modified, checksum incorrect!'
199185
else:
200-
print(prefix, 'OK')
186+
message = 'Log entry is fine!'
187+
188+
if args.json:
189+
output[file.name] = message
190+
else:
191+
print('{:d}. {:s}'.format(cnt, message))
192+
cnt += 1
193+
194+
if args.json:
195+
print(json.dumps(output))

logs/01.log

18.8 KB
Binary file not shown.

0 commit comments

Comments
 (0)