~thestr4ng3r/mymcplus

9ffab16e37c08e0540323a11aaa0b6de35a3eeef — Florian Märkl 3 years ago 04acb12
Port to Python 3

Also fix Tests except .max import and export
M .gitignore => .gitignore +2 -1
@@ 1,4 1,5 @@
*.pyc
*.swp
.idea/
.pytest_cache/
\ No newline at end of file
.pytest_cache/
/test/data/

M mymc/gui.py => mymc/gui.py +27 -21
@@ 6,13 6,19 @@
#

"""Graphical user-interface for mymc."""
from __future__ import print_function
from __future__ import division

from future import standard_library
standard_library.install_aliases()
from builtins import range
from past.utils import old_div
_SCCS_ID = "@(#) mymc gui.py 1.4 12/10/04 18:51:51\n"

import os
import sys
import struct
import cStringIO
import io
import time

# Work around a problem with mixing wx and py2exe


@@ 100,7 106,7 @@ def single_title(title):
def _get_icon_resource_as_images(name):
	ico = guires.resources[name]
	images = []
	f = cStringIO.StringIO(ico)
	f = io.StringIO(ico)
	count = struct.unpack("<HHH", ico[0:6])[2]
	# count = wx.Image_GetImageCount(f, wx.BITMAP_TYPE_ICO)
	for i in range(count):


@@ 244,7 250,7 @@ class dirlist_control(wx.ListCtrl):
		for (i, a) in enumerate(self.dirtable):
			(ent, icon_sys, size, title) = a
			li = self.InsertItem(i, ent[8])
			self.SetItem(li, 1, "%dK" % (size / 1024))
			self.SetItem(li, 1, "%dK" % (old_div(size, 1024)))
			m = ent[6]
			m = ("%04d-%02d-%02d %02d:%02d"
			     % (m[5], m[4], m[3], m[2], m[1]))


@@ 339,7 345,7 @@ class icon_window(wx.Window):
		r = mymcsup.init_icon_renderer(focus.GetHandle(),
					       self.GetHandle())
		if r == -1:
			print "init_icon_renderer failed"
			print("init_icon_renderer failed")
			self.failed = True
			return
		


@@ 376,7 382,7 @@ class icon_window(wx.Window):
			r = mymcsup.load_icon(icon_sys, len(icon_sys),
					      icon, len(icon))
		if r != 0:
			print "load_icon", r
			print("load_icon", r)
			self.failed = True

	def _set_lighting(self, lighting, vertex_diffuse, alt_lighting,


@@ 624,13 630,13 @@ class gui_frame(wx.Frame):
		if self.mc != None:
			try:
				self.mc.close()
			except EnvironmentError, value:
			except EnvironmentError as value:
				self.mc_error(value)
			self.mc = None
		if self.f != None:
			try:
				self.f.close()
			except EnvironmentError, value:
			except EnvironmentError as value:
				self.mc_error(value)
			self.f = None
		self.mcname = None


@@ 638,7 644,7 @@ class gui_frame(wx.Frame):
	def refresh(self):
		try:
			self.dirlist.update(self.mc)
		except EnvironmentError, value:
		except EnvironmentError as value:
			self.mc_error(value)
			self._close_mc()
			self.dirlist.update(None)


@@ 651,8 657,8 @@ class gui_frame(wx.Frame):
		if mc == None:
			status = "No memory card image"
		else:
			free = mc.get_free_space() / 1024
			limit = mc.get_allocatable_space() / 1024
			free = old_div(mc.get_free_space(), 1024)
			limit = old_div(mc.get_allocatable_space(), 1024)
			status = "%dK of %dK free" % (free, limit)
		self.statusbar.SetStatusText(status, 1)



@@ 666,7 672,7 @@ class gui_frame(wx.Frame):
		try:
			f = file(filename, "r+b")
			mc = ps2mc.ps2mc(f)
		except EnvironmentError, value:
		except EnvironmentError as value:
			if f != None:
				f.close()
			self.mc_error(value, filename)


@@ 708,8 714,8 @@ class gui_frame(wx.Frame):
				icon = f.read()
			finally:
				f.close()
		except EnvironmentError, value:
			print "icon failed to load", value
		except EnvironmentError as value:
			print("icon failed to load", value)
			self.icon_win.load_icon(None, None)
			return



@@ 748,7 754,7 @@ class gui_frame(wx.Frame):
				sf = mc.export_save_file("/" + dirname)
				longname = ps2save.make_longname(dirname, sf)
				sfiles.append((dirname, sf, longname))
			except EnvironmentError, value:
			except EnvironmentError as value:
				self.mc_error(value. dirname)

		if len(sfiles) == 0:


@@ 776,7 782,7 @@ class gui_frame(wx.Frame):
						sf.save_ems(f)
				finally:
					f.close()
			except EnvironmentError, value:
			except EnvironmentError as value:
				self.mc_error(value, fn)
				return



@@ 798,7 804,7 @@ class gui_frame(wx.Frame):
				sf.save_ems(f)
				f.close()
				count += 1
			except EnvironmentError, value:
			except EnvironmentError as value:
				self.mc_error(value, fn)
		if count > 0:
			if os.path.isabs(dir):


@@ 858,7 864,7 @@ class gui_frame(wx.Frame):
			try:
				self._do_import(fn)
				success = fn
			except EnvironmentError, value:
			except EnvironmentError as value:
				self.mc_error(value, fn)

		if success != None:


@@ 894,7 900,7 @@ class gui_frame(wx.Frame):
		for dn in dirnames:
			try:
				mc.rmdir("/" + dn)
			except EnvironmentError, value:
			except EnvironmentError as value:
				self.mc_error(value, dn)

		mc.check()


@@ 926,11 932,11 @@ if __name__ == "__main__":

 	gc.collect()
 	for o in gc.garbage:
 		print 
 		print o
 		print() 
 		print(o)
 		if type(o) == ps2mc.ps2mc_file:
 			for m in dir(o):
 				print m, getattr(o, m)
 				print(m, getattr(o, m))


# 	while True:

M mymc/lzari.py => mymc/lzari.py +63 -61
@@ 10,7 10,12 @@ in Python.  Largely based on LZARI.C, one key difference is the use of
a two level dicitionary look up during compression rather than
LZARI.C's binary search tree.
"""
from __future__ import print_function
from __future__ import division

from builtins import range
from builtins import object
from past.utils import old_div
_SCCS_ID = "@(#) mysc lzari.py 1.6 12/10/04 19:07:53\n"

import sys


@@ 59,15 64,15 @@ MAX_SUFFIX_CHAIN = 50	# limit on how many identical suffixes to try to match
#	print "@@@ %s %04x" % (msg, value)
debug = lambda value, msg: None

_tr_16 = string.maketrans("0123456789abcdef",
_tr_16 = str.maketrans("0123456789abcdef",
			  "\x00\x01\x02\x03"
			  "\x10\x11\x12\x13"
			  "\x20\x21\x22\x23"
			  "\x30\x31\x32\x33")
_tr_4 = string.maketrans("0123",
_tr_4 = str.maketrans("0123",
			 "\x00\x01"
			 "\x10\x11")
_tr_2 = string.maketrans("01", "\x00\x01")
_tr_2 = str.maketrans("01", "\x00\x01")

def string_to_bit_array(s):
	"""Convert a string to an array containing a sequence of bits."""


@@ 77,15 82,13 @@ def string_to_bit_array(s):
	a = array.array('B', s)
	return a

_tr_rev_2 = string.maketrans("\x00\x01", "01")
_tr_rev_4 = string.maketrans("\x00\x01"
			     "\x10\x11",
			     "0123")
_tr_rev_16 = string.maketrans("\x00\x01\x02\x03"
			      "\x10\x11\x12\x13"
			      "\x20\x21\x22\x23"
			      "\x30\x31\x32\x33",
			      "0123456789abcdef")
_tr_rev_2 = bytes.maketrans(b"\x00\x01", b"01")
_tr_rev_4 = bytes.maketrans(b"\x00\x01\x10\x11", b"0123")
_tr_rev_16 = bytes.maketrans(b"\x00\x01\x02\x03"
			      b"\x10\x11\x12\x13"
			      b"\x20\x21\x22\x23"
			      b"\x30\x31\x32\x33",
			      b"0123456789abcdef")
def bit_array_to_string(a):
	"""Convert an array containing a sequence of bits to a string."""
	remainder = len(a) % 8


@@ 93,7 96,7 @@ def bit_array_to_string(a):
		a.fromlist([0] * (8 - remainder))
	s = a.tostring()
	s = binascii.unhexlify(s.translate(_tr_rev_2))
	s = binascii.unhexlify(s.translate(_tr_rev_4))	
	s = binascii.unhexlify(s.translate(_tr_rev_4))
	return binascii.unhexlify(s.translate(_tr_rev_16))

def _match(src, pos, hpos, mlen, end):


@@ 132,28 135,28 @@ class lzari_codec(object):
			self.code = 0
			# reverse the order of sym_cum so bisect_right() can
			# be used for faster searching
			self.sym_cum = range(0, MAX_CHAR + 1)
			self.sym_cum = list(range(0, MAX_CHAR + 1))
		else:
			self.shifts = 0
			self.char_to_symbol = range(1, MAX_CHAR + 1)
			self.sym_cum = range(MAX_CHAR, -1, -1)
			self.char_to_symbol = list(range(1, MAX_CHAR + 1))
			self.sym_cum = list(range(MAX_CHAR, -1, -1))
			self.next_table = [None] * HIST_LEN
			self.next2_table = [None] * HIST_LEN
			self.suffix_table = {}

		self.symbol_to_char = [0] + range(MAX_CHAR)
		self.symbol_to_char = [0] + list(range(MAX_CHAR))
		self.sym_freq = [0] + [1] * MAX_CHAR
		self.position_cum = [0] * (HIST_LEN + 1)
		a = 0
		for i in range(HIST_LEN, 0, -1):
			a =  a + 10000 / (200 + i)
			a =  a + old_div(10000, (200 + i))
			self.position_cum[i - 1] = a
		
	def search(self, table, x):
		c = 1
	        s = len(table) - 1
		s = len(table) - 1
		while True:
			a = (s + c) / 2
			a = old_div((s + c), 2)
			if table[a] <= x:
				s = a
			else:


@@ 172,18 175,18 @@ class lzari_codec(object):
			c = 0
			for i in range(MAX_CHAR, 0, -1):
				self.sym_cum[MAX_CHAR - i] = c
				a = (self.sym_freq[i] + 1) / 2
				a = old_div((self.sym_freq[i] + 1), 2)
				self.sym_freq[i] = a
				c += a
			self.sym_cum[MAX_CHAR] = c
		freq = sym_freq[symbol]
		new_symbol = symbol
		while self.sym_freq[new_symbol - 1] == freq:
		        new_symbol -= 1
			new_symbol -= 1
		# new_symbol = sym_freq.index(freq)
		if new_symbol != symbol:
			symbol_to_char = self.symbol_to_char
		        swap_char = symbol_to_char[new_symbol]
			swap_char = symbol_to_char[new_symbol]
			char = symbol_to_char[symbol]
			symbol_to_char[new_symbol] = char
			symbol_to_char[symbol] = swap_char


@@ 195,21 198,21 @@ class lzari_codec(object):
		sym_freq = self.sym_freq
		sym_cum = self.sym_cum
		
	        if sym_cum[0] >= MAX_CUM:
		if sym_cum[0] >= MAX_CUM:
			c = 0
			for i in range(MAX_CHAR, 0, -1):
				sym_cum[i] = c
				a = (sym_freq[i] + 1) / 2
				a = old_div((sym_freq[i] + 1), 2)
				sym_freq[i] = a
				c += a
			sym_cum[0] = c
		freq = sym_freq[symbol]
		new_symbol = symbol
		while sym_freq[new_symbol - 1] == freq:
		        new_symbol -= 1
			new_symbol -= 1
		if new_symbol != symbol:
			debug(new_symbol, "a")
		        swap_char = self.symbol_to_char[new_symbol]
			swap_char = self.symbol_to_char[new_symbol]
			char = self.symbol_to_char[symbol]
			self.symbol_to_char[new_symbol] = char
			self.symbol_to_char[symbol] = swap_char


@@ 227,10 230,10 @@ class lzari_codec(object):
		
		_range = high - low
		max_cum_freq = sym_cum[MAX_CHAR]
		n = ((code - low + 1) * max_cum_freq - 1) / _range
		n = old_div(((code - low + 1) * max_cum_freq - 1), _range)
		i = bisect_right(sym_cum, n, 1)
		high = low + sym_cum[i] * _range / max_cum_freq
		low += sym_cum[i - 1] * _range / max_cum_freq
		high = low + sym_cum[i] * _range // max_cum_freq
		low += sym_cum[i - 1] * _range // max_cum_freq
		symbol = MAX_CHAR + 1 - i

		while True:


@@ 261,18 264,18 @@ class lzari_codec(object):
		_range = self.high - self.low
		max_cum = self.position_cum[0]
		pos = self.search(self.position_cum,
				  ((self.code - self.low + 1)
				   * max_cum - 1) / _range) - 1
				  old_div(((self.code - self.low + 1)
				   * max_cum - 1), _range)) - 1
		self.high = (self.low +
			     self.position_cum[pos] * _range / max_cum)
		self.low += self.position_cum[pos + 1] * _range / max_cum
			     self.position_cum[pos] * _range // max_cum)
		self.low += self.position_cum[pos + 1] * _range // max_cum
		while True:
			if self.low < QUADRANT2:
				if (self.low < QUADRANT1
				    or self.high > QUADRANT3):
					if self.high > QUADRANT2:
						return pos
 				else:
				else:
					self.low -= QUADRANT1
					self.code -= QUADRANT1
					self.high -= QUADRANT1


@@ 462,8 465,8 @@ class lzari_codec(object):
		symbol = self.char_to_symbol[char]
		range = high - low
	
		high = low + range * sym_cum[symbol - 1] / sym_cum[0]
		low += range * sym_cum[symbol] / sym_cum[0]
		high = low + range * sym_cum[symbol - 1] // sym_cum[0]
		low += range * sym_cum[symbol] // sym_cum[0]
		debug(high, "high");
		debug(low, "low");
		while True:


@@ 491,8 494,8 @@ class lzari_codec(object):
		high = self.high

		range = high - low
		high = low + range * position_cum[position] / position_cum[0]
		low += range * position_cum[position + 1] / position_cum[0]
		high = low + range * position_cum[position] // position_cum[0]
		low += range * position_cum[position + 1] // position_cum[0]

		debug(high, "high");
		debug(low, "low");


@@ 520,7 523,7 @@ class lzari_codec(object):
		
		length = len(src)
		if length == 0:
			return ""
			return b""

		out_array = array.array('B')
		self.out_array = out_array


@@ 530,7 533,7 @@ class lzari_codec(object):

		max_match = min(MAX_MATCH_LEN, length)
		self.max_match = max_match
		self.src = src = "\x20" * max_match + src
		self.src = src = b"\x20" * max_match + src
			
		in_length = len(src)
		


@@ 542,20 545,19 @@ class lzari_codec(object):
		last_percent = -1
		while in_pos < in_length:
			if progress:
				percent = (in_pos - max_match) * 100 / length
				percent = (in_pos - max_match) * 100 // length
				if percent != last_percent:
					sys.stderr.write("%s%3d%%\r"
							 % (progress, percent))
					last_percent = percent
			debug(ord(src[in_pos]), "src")
			debug(src[in_pos], "src")
			(match_pos, match_len) = self.add_suffix(in_pos, True)
			if match_len < MIN_MATCH_LEN:
				self.encode_char(ord(src[in_pos]))
				self.encode_char(src[in_pos])
			else:
				debug(in_pos - match_pos - 1, "match_pos")
				debug(match_len, "match_len")
				self.encode_char(256 - MIN_MATCH_LEN
						 + match_len)
				self.encode_char(256 - MIN_MATCH_LEN + match_len)
				self.encode_position(in_pos - match_pos - 1)
				for i in range(match_len - 1):
					in_pos += 1


@@ 582,9 584,9 @@ class lzari_codec(object):
		
		a = string_to_bit_array(src)
		a.fromlist([0] * 32)	 # add some extra bits 
		self.in_iter = iter(a).next
		self.in_iter = iter(a).__next__

		out = array.array('B', "\0") * out_length
		out = array.array('B', b"\0") * out_length
		outpos = 0
		
		self.init(True)


@@ 601,7 603,7 @@ class lzari_codec(object):
		last_time = time.time()
		while outpos < out_length:
			if progress:
				percent = outpos * 100 / out_length
				percent = outpos * 100 // out_length
				if percent != last_percent:
					now = time.time()
					if now - last_time >= 1:


@@ 646,7 648,7 @@ else:
		out = ctypes.create_string_buffer(out_length)
		if (mylzari_decode(src, len(src), out, out_length, progress)
		    == -1):
			raise ValueError, "compressed input is corrupt"
			raise ValueError("compressed input is corrupt")
		return ctypes.string_at(out, out_length)

	def encode(src, progress = None):


@@ 654,7 656,7 @@ else:
							   progress)
		# print r, compressed.value, comp_len
		if r == -1:
			raise MemoryError, "out of memory during compression"
			raise MemoryError("out of memory during compression")
		if compressed.value == None:
			return ""
		ret = ctypes.string_at(compressed.value, comp_len.value)


@@ 679,7 681,7 @@ def main2(args):
		now = os.times()
	out.write(dest)
	out.close()
	print "time:", now[0] - start[0], now[1] - start[1], now[4] - start[4]
	print("time:", now[0] - start[0], now[1] - start[1], now[4] - start[4])


def _get_hotshot_lineinfo(filename):


@@ 694,7 696,7 @@ def _get_hotshot_lineinfo(filename):
			else:
				a[0] += 1
				a[1] += tdelta
	return timings.items()
	return list(timings.items())

def _dump_hotshot_lineinfo(log):
	a = sorted(_get_hotshot_lineinfo(log))


@@ 703,10 705,10 @@ def _dump_hotshot_lineinfo(log):
	total_time = sum((time[1]
			  for (loc, time) in a))
	for (loc, [count, time]) in a:
		print ("%8d %6.3f%%  %8d %6.3f%%"
		print(("%8d %6.3f%%  %8d %6.3f%%"
		       % (time, time * 100.0 / total_time,
			  count, count * 100.0 / total_count)),
		print "%s:%d(%s)" % loc
			  count, count * 100.0 / total_count)), end=' ')
		print("%s:%d(%s)" % loc)

def _dump_hotshot_lineinfo2(log):
	cur = None


@@ 719,7 721,7 @@ def _dump_hotshot_lineinfo2(log):
		if cur != filename:
			if cur != None and f != None:
				for line in f:
					print line[:-1]
					print(line[:-1])
				f.close()
			try:
				f = file(filename, "r")


@@ 727,17 729,17 @@ def _dump_hotshot_lineinfo2(log):
				f = None
			cur = filename
			l = 0
			print "#", filename
			print("#", filename)
		if f != None:
			while l < lineno:
				print f.readline()[:-1]
				print(f.readline()[:-1])
				l += 1
		print ("# %8d %6.3f%%  %8d %6.3f%%"
		       % (time, time * 100.0 / total_time,
			  count, count * 100.0 / total_count))
	if cur != None and f != None:
		for line in f:
			print line[:-1]
			print(line[:-1])
		f.close()
	
def main(args):


@@ 747,7 749,7 @@ def main(args):
		import profile
		pr = profile.Profile()
		for i in range(5):
			print pr.calibrate(100000)
			print(pr.calibrate(100000))
		return
	elif args[1] == "p":
		import profile

M mymc/mymc.py => mymc/mymc.py +51 -44
@@ 6,7 6,14 @@
#

"""A utility for manipulating PS2 memory card images."""

from __future__ import print_function
from __future__ import division

from builtins import map
from builtins import str
from builtins import range
from past.utils import old_div
from builtins import object
_SCCS_ID = "@(#) mysc mymc.py 1.12 12/10/04 19:09:16\n"[:-1]

import sys


@@ 47,7 54,7 @@ if os.name == "nt":

		def __setattr__(self, name, value):
			if name == "encoding":
				raise TypeError, "readonly attribute"
				raise TypeError("readonly attribute")
			return setattr(object.__getattribute__(self, "_f"),
				       name, value)



@@ 86,7 93,7 @@ def _copy(fout, fin):
	
	while True:
		s = fin.read(1024)
		if s == "":
		if not s:
			break
		fout.write(s)
	


@@ 123,7 130,7 @@ def do_ls(cmd, mc, opts, args, opterr):
					  % (ent[2],
					     tm.tm_year, tm.tm_mon, tm.tm_mday,
					     tm.tm_hour, tm.tm_min, tm.tm_sec,
					     ent[8]))
					     ent[8].decode("ascii")))
		finally:
			dir.close()
			


@@ 154,7 161,7 @@ def do_extract(cmd, mc, opts, args, opterr):
		if opts.use_stdout:
			opterr("The -o and -p options are mutually exclusive.")
		dont_close_out = True
		out = file(opts.output, "wb")
		out = open(opts.output, "wb")
	elif opts.use_stdout:
		out = sys.stdout



@@ 202,7 209,7 @@ def do_import(cmd, mc, opts, args, opterr):
		
	for filename in args:
		sf = ps2save.ps2_save_file()
		f = file(filename, "rb")
		f = open(filename, "rb")
		try:
			ftype = ps2save.detect_file_type(f)
			f.seek(0)


@@ 215,18 222,18 @@ def do_import(cmd, mc, opts, args, opterr):
			elif ftype == "sps":
				sf.load_sharkport(f)
			elif ftype == "npo":
				raise io_error, (EIO, "nPort saves"
				raise io_error(EIO, "nPort saves"
						 " are not supported.",
						 filename)
			else:
				raise io_error, (EIO, "Save file format not"
				raise io_error(EIO, "Save file format not"
						 " recognized", filename)
		finally:
			f.close()
		dirname = opts.directory
		if dirname == None:
			dirname = sf.get_directory()[8]
		print "Importing", filename, "to", dirname
			dirname = sf.get_directory()[8].decode("ascii")
		print("Importing", filename, "to", dirname)
		if not mc.import_save_file(sf, opts.ignore_existing,
						opts.directory):
			print (filename + ": already in memory card image,"


@@ 272,9 279,9 @@ def do_export(cmd, mc, opts, args, opterr):
					continue
				raise io_error(EEXIST, "File exists", filename)
			
		f = file(filename, "wb")
		f = open(filename, "wb")
		try:
			print "Exporing", dirname, "to", filename
			print("Exporing", dirname, "to", filename)
			
			if opts.type == "max":
				sf.save_max_drive(f)


@@ 346,7 353,7 @@ def _get_psx_title(mc, savename, enc):
	(magic, icon, blocks, title) = struct.unpack("<2sBB64s28x32x", s)
	if magic != "SC":
		return None
	return [ps2save.shift_jis_conv(zero_terminate(title), enc), ""]
	return [ps2save.shift_jis_conv(zero_terminate(title), enc).decode(enc), ""]

def do_dir(cmd, mc, opts, args, opterr):
	if len(args) != 0:


@@ 358,7 365,7 @@ def do_dir(cmd, mc, opts, args, opterr):
			dirmode = ent[0]
			if not mode_is_dir(dirmode):
				continue
			dirname = "/" + ent[8]
			dirname = "/" + ent[8].decode("ascii")
			mc.chdir(dirname)
			length = mc.dir_size(".");
			if opts.ascii:


@@ 389,36 396,36 @@ def do_dir(cmd, mc, opts, args, opterr):
			if type != None:
				protection = type
				
			print "%-32s %s" % (ent[8], title[0])
			print("%-32s %s" % (ent[8].decode("ascii"), title[0]))
			print ("%4dKB %-25s %s"
			       % (length / 1024, protection, title[1]))
			print
			       % (old_div(length, 1024), protection, title[1]))
			print()
	finally:
		if f != None:
			f.close()
		dir.close()
		
	free = mc.get_free_space() / 1024
	free = old_div(mc.get_free_space(), 1024)
	if free > 999999:
		free = "%d,%03d,%03d" % (free / 1000000, free / 1000 % 1000,
		free = "%d,%03d,%03d" % (old_div(free, 1000000), free / 1000 % 1000,
					 free % 1000)
	elif free > 999:
		free = "%d,%03d" % (free / 1000, free % 1000)
		free = "%d,%03d" % (old_div(free, 1000), free % 1000)
	else:
		free = "%d" % free

	print free + " KB Free"
	print(free + " KB Free")

def do_df(cmd, mc, opts, args, opterr):
	if len(args) != 0:
		opterr("Incorrect number of arguments.")
	print mc.f.name + ":", mc.get_free_space(), "bytes free."
	print(mc.f.name + ":", mc.get_free_space(), "bytes free.")

def do_check(cmd, mc, opts, args, opterr):
	if len(args) != 0:
		opterr("Incorrect number of arguments.")
	if mc.check():
		print "No errors found."
		print("No errors found.")
		return 0
	return 1
	


@@ 427,8 434,7 @@ def do_format(cmd, mcname, opts, args, opterr):
		opterr("Incorrect number of arguments.")
	pages_per_card = ps2mc.PS2MC_STANDARD_PAGES_PER_CARD
	if opts.clusters != None:
		pages_per_cluster = (ps2mc.PS2MC_CLUSTER_SIZE
				     / ps2mc.PS2MC_STANDARD_PAGE_SIZE)
		pages_per_cluster = (old_div(ps2mc.PS2MC_CLUSTER_SIZE, ps2mc.PS2MC_STANDARD_PAGE_SIZE))
		pages_per_card = opts.clusters * pages_per_cluster
	params = (not opts.no_ecc,
		  ps2mc.PS2MC_STANDARD_PAGE_SIZE,


@@ 438,13 444,13 @@ def do_format(cmd, mcname, opts, args, opterr):
	if not opts.overwrite_existing:
		exists = True
		try:
			file(mcname, "rb").close()
			open(mcname, "rb").close()
		except EnvironmentError:
			exists = False
		if exists:
			raise io_error, (EEXIST, "file exists", mcname)
			raise io_error(EEXIST, "file exists", mcname)

	f = file(mcname, "w+b")
	f = open(mcname, "w+b")
	try:
		ps2mc.ps2mc(f, True, params).close()
	finally:


@@ 467,10 473,10 @@ def do_create_pad(cmd, mc, opts, args, opterr):
	length = mc.clusters_per_card
	if len(args) > 1:
		length = int(args[1])
	pad = "\0" * mc.cluster_size
	pad = b"\0" * mc.cluster_size
	f = mc.open(args[0], "wb")
	try:
		for i in xrange(length):
		for i in range(length):
			f.write(pad)
	finally:
		f.close()


@@ 479,15 485,15 @@ def do_create_pad(cmd, mc, opts, args, opterr):
def do_frob(cmd, mc, opts, args, opterr):
	mc.write_superblock()

_trans = string.maketrans("".join(map(chr, range(32))), " " * 32)
_trans = str.maketrans("".join(map(chr, list(range(32)))), " " * 32)

def _print_bin(base, s):
	for off in range(0, len(s), 16):
		print "%04X" % (base + off),
		print("%04X" % (base + off), end=' ')
		a = s[off : off + 16]
		for b in a:
			print "%02X" % ord(b),
		print "", a.translate(_trans)
			print("%02X" % ord(b), end=' ')
		print("", a.translate(_trans))
	
def _print_erase_block(mc, n):
	ppb = mc.pages_per_erase_block


@@ 495,12 501,12 @@ def _print_erase_block(mc, n):
	for i in range(ppb):
		s = mc.read_page(base + i)
		_print_bin(i * mc.page_size, s)
		print
		print()
		
def do_print_good_blocks(cmd, mc, opts, args, opterr):
	print "good_block2:"
	print("good_block2:")
	_print_erase_block(mc, mc.good_block2)
	print "good_block1:"
	print("good_block1:")
	_print_erase_block(mc, mc.good_block1)

def do_ecc_check(cmd, mc, opts, args, opterr):


@@ 508,7 514,7 @@ def do_ecc_check(cmd, mc, opts, args, opterr):
		try:
			mc.read_page(i)
		except ps2mc.ecc_error:
			print "bad: %05x" % i
			print("bad: %05x" % i)

opt = optparse.make_option



@@ 680,7 686,7 @@ class suboption_parser(optparse.OptionParser):
	def exit(self, status = 0, msg = None):
		if msg:
			sys.stderr.write(msg)
		raise subopt_error, status
		raise subopt_error(status)

class my_help_formatter(optparse.IndentedHelpFormatter):
	"""A better formatter for optparser's help message"""


@@ 705,7 711,7 @@ class my_help_formatter(optparse.IndentedHelpFormatter):
		return "\n".join(lines) + "\n"

def main(argv):
	prog = argv[0].decode(sys.getdefaultencoding(), "replace")
	prog = argv[0]
	usage = "usage: %prog [-ih] memcard.ps2 command [...]"
	description = ("Manipulate PS2 memory card images.\n\n"
		       "Supported commands: ")


@@ 771,7 777,7 @@ def main(argv):
				ret = fn(cmd, mcname, subopts, subargs,
					 subopt_parser.error)
			else:
				f = file(mcname, mode)
				f = open(mcname, mode)
				mc = ps2mc.ps2mc(f, opts.ignore_ecc)
				ret = fn(cmd, mc, subopts, subargs,
					 subopt_parser.error)


@@ 782,7 788,7 @@ def main(argv):
				# print "f.close()"
				f.close()

	except EnvironmentError, value:
	except EnvironmentError as value:
		if getattr(value, "filename", None) != None:
			write_error(value.filename, value.strerror)
			ret = 1


@@ 795,10 801,11 @@ def main(argv):
		if opts.debug:
			raise

	except subopt_error, (ret,):
	except subopt_error as xxx_todo_changeme:
		(ret,) = xxx_todo_changeme.args
		pass
	
	except (ps2mc.error, ps2save.error), value:
	except (ps2mc.error, ps2save.error) as value:
		fn = getattr(value, "filename", None)
		if fn == None:
			fn = mcname

M mymc/ps2mc.py => mymc/ps2mc.py +143 -148
@@ 6,7 6,14 @@
#

"""Manipulate PS2 memory card images."""

from __future__ import print_function
from __future__ import division

from builtins import str
from builtins import map
from builtins import range
from past.utils import old_div
from builtins import object
_SCCS_ID = "@(#) mysc ps2mc.py 1.10 12/10/04 19:10:35\n"

import sys


@@ 22,7 29,7 @@ from ps2mc_ecc import *
from ps2mc_dir import *
import ps2save

PS2MC_MAGIC = "Sony PS2 Memory Card Format "
PS2MC_MAGIC = b"Sony PS2 Memory Card Format "
PS2MC_FAT_ALLOCATED_BIT = 0x80000000
PS2MC_FAT_CHAIN_END = 0xFFFFFFFF
PS2MC_FAT_CHAIN_END_UNALLOC = 0x7FFFFFFF


@@ 124,10 131,10 @@ class lru_cache(object):
		lru_list = self._lru_list
		i = 0
		while i != len(self._lru_list):
			print "%d: %s, " % (i, str(lru_list[i][1])), 
			print("%d: %s, " % (i, str(lru_list[i][1])), end=' ') 
			i = lru_list[i][3]
		print
		print self._index_map
		print()
		print(self._index_map)
			
	def _move_to_front(self, i):
		lru_list = self._lru_list


@@ 325,7 332,7 @@ class ps2mc_file(object):

		if (cluster < file_cluster_end
		    or len(self.fat_chain) != file_cluster_end):
			raise corrupt, ("file length doesn't match cluster"
			raise corrupt("file length doesn't match cluster"
					" chain length", mc.f)

		for i in range(file_cluster_end, n):


@@ 338,7 345,7 @@ class ps2mc_file(object):
							 True)
				return False
			mc.write_allocatable_cluster(cluster,
						     ["\0"] * cluster_size)
						     [b"\0"] * cluster_size)
		
		cluster = self._extend_file(n)
		if cluster == None:


@@ 359,18 366,18 @@ class ps2mc_file(object):
		
	def read(self, size = None, eol = None):
		if self.closed:
			raise ValueError, "file is closed"
			raise ValueError("file is closed")

		pos = self._pos
		cluster_size = self.mc.cluster_size
		if size == None:
			size = self.length
		size = max(min(self.length - pos, size), 0)
		ret = ""
		ret = b""
		while size > 0:
			off = pos % cluster_size
			l = min(cluster_size - off, size)
			buf = self.read_file_cluster(pos / cluster_size)
			buf = self.read_file_cluster(old_div(pos, cluster_size))
			if buf == None:
				break
			if eol != None:


@@ 386,21 393,21 @@ class ps2mc_file(object):

	def write(self, out, _set_modified = True):
		if self.closed:
			raise ValueError, "file is closed"
			raise ValueError("file is closed")
	
		cluster_size = self.mc.cluster_size
		pos = self._pos
		if self._append: 
			pos = self.length
		elif not self._write:
			raise io_error, (EACCES, "file not opened for writing",
			raise io_error(EACCES, "file not opened for writing",
					 self.name)

		size = len(out)
		# print "@@@ write", pos, size
		i = 0
		while size > 0:
			cluster = pos / cluster_size
			cluster = old_div(pos, cluster_size)
			off = pos % cluster_size
			l = min(cluster_size - off, size)
			s = out[i : i + l]


@@ 410,10 417,10 @@ class ps2mc_file(object):
			else:
				buf = self.read_file_cluster(cluster)
				if buf == None:
					buf = "\0" * cluster_size
					buf = b"\0" * cluster_size
				buf = buf[:off] + s + buf[off + l:]
			if not self.write_file_cluster(cluster, buf):
				raise io_error, (ENOSPC,
				raise io_error(ENOSPC,
						 "out of space on image",
						 self.name)
			self._pos = pos


@@ 435,7 442,7 @@ class ps2mc_file(object):
		self.fat_chain = None
		self.buffer = None

	def next(self):
	def __next__(self):
		r = self.readline()
		if r == "":
			raise StopIteration


@@ 449,7 456,7 @@ class ps2mc_file(object):

	def seek(self, offset, whence = 0):
		if self.closed:
			raise ValueError, "file is closed"
			raise ValueError("file is closed")

		if whence == 1:
			base = self._pos


@@ 462,7 469,7 @@ class ps2mc_file(object):

	def tell(self):
		if self.closed:
			raise ValueError, "file is closed"
			raise ValueError("file is closed")
		return self._pos

	def __enter__(self):


@@ 501,10 508,10 @@ class ps2mc_directory(object):
		self.f.write(pack_dirent(ent),
			     _set_modified = set_modified)

	def next(self):
	def __next__(self):
		# print "@@@ next", self.tell(), self.f.name
		dirent = self.f.read(PS2MC_DIRENT_LENGTH)
		if dirent == "":
		if dirent == b"":
			if 0 == self._iter_end:
				raise StopIteration
			self.seek(0)


@@ 517,10 524,10 @@ class ps2mc_directory(object):
		self.f.seek(offset * PS2MC_DIRENT_LENGTH, whence)

	def tell(self):
		return self.f.tell() / PS2MC_DIRENT_LENGTH
		return old_div(self.f.tell(), PS2MC_DIRENT_LENGTH)

	def __len__(self):
		return self.f.length / PS2MC_DIRENT_LENGTH
		return old_div(self.f.length, PS2MC_DIRENT_LENGTH)
	
	def __getitem__(self, index):
		# print "@@@ getitem", index, self.f.name


@@ 590,12 597,11 @@ class ps2mc(object):
		self.spare_size = div_round_up(self.page_size, 128) * 4
		self.raw_page_size = self.page_size + self.spare_size
		self.cluster_size = self.page_size * self.pages_per_cluster
		self.entries_per_cluster = (self.page_size
					    * self.pages_per_cluster / 4)
		self.entries_per_cluster = self.page_size * self.pages_per_cluster // 4

		limit = (min(self.good_block2, self.good_block1)
			 * self.pages_per_erase_block
			 / self.pages_per_cluster
			 // self.pages_per_cluster
			 - self.allocatable_cluster_offset)
		self.allocatable_cluster_limit = limit



@@ 611,7 617,7 @@ class ps2mc(object):
		s = f.read(0x154)
		if len(s) != 0x154 or not s.startswith(PS2MC_MAGIC):
			if (params == None):
				raise corrupt, ("Not a PS2 memory card image",
				raise corrupt("Not a PS2 memory card image",
						f)
			self.f = f
			self.format(params)


@@ 650,9 656,9 @@ class ps2mc(object):
		dot = root[0]
		dotdot = root[1]
		root.close()
		if (dot[8] != "." or dotdot[8] != ".."
		if (dot[8] != b"." or dotdot[8] != b".."
		    or not mode_is_dir(dot[0]) or not mode_is_dir(dotdot[0])):
			raise corrupt, "Root directory damaged."
			raise corrupt("Root directory damaged.")
		
		self.fat_cursor = 0
		self.curdir = (0, 0)


@@ 674,10 680,10 @@ class ps2mc(object):
				     self.bad_erase_block_list,
				     2,
				     0x2B))
		s += "\x00" * (self.page_size - len(s))
		s += b"\x00" * (self.page_size - len(s))
		self.write_page(0, s)

		page = "\xFF" * self.raw_page_size
		page = b"\xFF" * self.raw_page_size
		self.f.seek(self.good_block2 * self.pages_per_erase_block
			    * self.raw_page_size)
		for i in range(self.pages_per_erase_block):


@@ 693,23 699,22 @@ class ps2mc(object):
		 pages_per_erase_block, param_pages_per_card) = params

		if pages_per_erase_block < 1:
			raise error, ("invalid pages per erase block (%d)"
			raise error("invalid pages per erase block (%d)"
				      % page_size)
			
		pages_per_card = round_down(param_pages_per_card,
					    pages_per_erase_block)
		cluster_size = PS2MC_CLUSTER_SIZE
		pages_per_cluster = cluster_size / page_size
		clusters_per_erase_block = (pages_per_erase_block
					    / pages_per_cluster)
		erase_blocks_per_card = pages_per_card / pages_per_erase_block
		clusters_per_card = pages_per_card / pages_per_cluster
		epc = cluster_size / 4
		pages_per_cluster = old_div(cluster_size, page_size)
		clusters_per_erase_block = (old_div(pages_per_erase_block, pages_per_cluster))
		erase_blocks_per_card = old_div(pages_per_card, pages_per_erase_block)
		clusters_per_card = old_div(pages_per_card, pages_per_cluster)
		epc = old_div(cluster_size, 4)

		if (page_size < PS2MC_DIRENT_LENGTH
		    or pages_per_cluster < 1
		    or pages_per_cluster * page_size != cluster_size):
			raise error, "invalid page size (%d)" % page_size
			raise error("invalid page size (%d)" % page_size)
		
		good_block1 = erase_blocks_per_card - 1
		good_block2 = erase_blocks_per_card - 2


@@ 731,15 736,15 @@ class ps2mc(object):
					   * clusters_per_erase_block
					   - allocatable_cluster_offset)
		if allocatable_cluster_end < 1:
			raise error, ("memory card image too small"
			raise error("memory card image too small"
				      " to be formatted")

		ifc_list = unpack_fat("\0\0\0\0"
		ifc_list = unpack_fat(b"\0\0\0\0"
				      * PS2MC_MAX_INDIRECT_FAT_CLUSTERS)
		for i in range(indirect_fat_clusters):
			ifc_list[i] = first_ifc + i

		self.version = "1.2.0.0"
		self.version = b"1.2.0.0"
		self.page_size = page_size
		self.pages_per_cluster = pages_per_cluster
		self.pages_per_erase_block = pages_per_erase_block


@@ 750,19 755,18 @@ class ps2mc(object):
		self.good_block1 = good_block1
		self.good_block2 = good_block2
		self.indirect_fat_cluster_list = ifc_list
		bebl = "\xFF\xFF\xFF\xFF" * 32		
		bebl = b"\xFF\xFF\xFF\xFF" * 32
		self.bad_erase_block_list = unpack_32bit_array(bebl)
		
		self._calculate_derived()

		self.ignore_ecc = not with_ecc
		erased = "\0" * page_size
		erased = b"\0" * page_size
		if not with_ecc:
			self.spare_size = 0
		else:
			ecc = "".join(["".join(map(chr, s))
				       for s in ecc_calculate_page(erased)])
			erased += ecc + "\0" * (self.spare_size - len(ecc))
			ecc = b"".join([bytes(s) for s in ecc_calculate_page(erased)])
			erased += ecc + b"\0" * (self.spare_size - len(ecc))

		self.f.seek(0)
		for page in range(pages_per_card):


@@ 774,7 778,7 @@ class ps2mc(object):
		remainder = fat_clusters % epc
		for i in range(indirect_fat_clusters):
			base = first_fat_cluster + i * epc
			buf = unpack_fat(range(base, base + epc))
			buf = unpack_fat(list(range(base, base + epc)))
			if (i == indirect_fat_clusters - 1
			    and remainder != 0):
				del buf[remainder:]


@@ 795,14 799,14 @@ class ps2mc(object):
		now = tod_now()
		s = pack_dirent((DF_RWX | DF_DIR | DF_0400 | DF_EXISTS,
				 0, 2, now,
				 0, 0, now, 0, "."))
		s += "\0" * (cluster_size - len(s))
				 0, 0, now, 0, b"."))
		s += b"\0" * (cluster_size - len(s))
		self.write_allocatable_cluster(0, s)
		dir = self._directory((0, 0), 0, 2, "wb", "/")
		dir.write_raw_ent(1, (DF_WRITE | DF_EXECUTE | DF_DIR | DF_0400
				      | DF_HIDDEN | DF_EXISTS,
				      0, 0, now,
				      0, 0, now, 0, ".."), False)
				      0, 0, now, 0, b".."), False)
		dir.close()

		self.flush()


@@ 813,17 817,17 @@ class ps2mc(object):
		f.seek(self.raw_page_size * n)
		page = f.read(self.page_size)
		if len(page) != self.page_size:
			raise corrupt, ("attempted to read past EOF"
			raise corrupt("attempted to read past EOF"
					" (page %05X)" % n, f)
		if self.ignore_ecc:
			return page
		spare = f.read(self.spare_size)
		if len(spare) != self.spare_size:
			raise corrupt, ("attempted to read past EOF"
			raise corrupt("attempted to read past EOF"
					" (page %05X)" % n, f)
		(status, page, spare) = ecc_check_page(page, spare)
		if status == ECC_CHECK_FAILED:
			raise ecc_error, ("Unrecoverable ECC error (page %d)"
			raise ecc_error("Unrecoverable ECC error (page %d)"
					  % n)
		return page



@@ 832,7 836,7 @@ class ps2mc(object):
		f.seek(self.raw_page_size * n)
		self.modified = True
		if len(buf) != self.page_size:
			raise error, ("internal error: write_page:"
			raise error("internal error: write_page:"
				      " %d != %d" % (len(buf), self.page_size))
		f.write(buf)
		if self.spare_size != 0:


@@ 840,7 844,7 @@ class ps2mc(object):
			for s in ecc_calculate_page(buf):
				a.fromlist(s)
			a.tofile(f)
			f.write("\0" * (self.spare_size - len(a)))
			f.write(b"\0" * (self.spare_size - len(a)))
			
	def read_cluster(self, n):
		pages_per_cluster = self.pages_per_cluster


@@ 852,7 856,7 @@ class ps2mc(object):
		if pages_per_cluster == 2:
			return self.read_page(n) + self.read_page(n + 1)
		return "".join(map(self.read_page,
				   range(n, n + pages_per_cluster)))
				   list(range(n, n + pages_per_cluster))))

	def write_cluster(self, n, buf):
		pages_per_cluster = self.pages_per_cluster


@@ 860,7 864,7 @@ class ps2mc(object):
		if self.spare_size == 0:
			self.f.seek(cluster_size * n)
			if len(buf) != cluster_size:
				raise error, ("internal error: write_cluster:"
				raise error("internal error: write_cluster:"
					      " %d != %d" % (len(buf),
							     cluster_size))
			return self.f.write(buf)


@@ 894,7 898,7 @@ class ps2mc(object):
	def flush_fat_cache(self):
		if self.fat_cache == None:
			return
		for (n, v) in self.fat_cache.items():
		for (n, v) in list(self.fat_cache.items()):
			[fat, dirty] = v
			if dirty:
				self.write_cluster(n, pack_fat(fat))


@@ 924,7 928,7 @@ class ps2mc(object):
	def flush_alloc_cluster_cache(self):
		if self.alloc_cluster_cache == None:
			return
		for (n, a) in self.alloc_cluster_cache.items():
		for (n, a) in list(self.alloc_cluster_cache.items()):
			[buf, dirty] = a
			if dirty:
				n += self.allocatable_cluster_offset


@@ 933,7 937,7 @@ class ps2mc(object):

	def read_fat_cluster(self, n):
		indirect_offset = n % self.entries_per_cluster
		dbl_offset = n / self.entries_per_cluster
		dbl_offset = old_div(n, self.entries_per_cluster)
		indirect_cluster = self.indirect_fat_cluster_list[dbl_offset]
		indirect_fat = self._read_fat_cluster(indirect_cluster)
		cluster = indirect_fat[indirect_offset]


@@ 941,11 945,11 @@ class ps2mc(object):
					      
	def read_fat(self, n):
		if n < 0 or n >= self.allocatable_cluster_end:
			raise io_error, (EIO,
			raise io_error(EIO,
					 "FAT cluster index out of range"
					 " (%d)" % n)
		offset = n % self.entries_per_cluster
		fat_cluster = n / self.entries_per_cluster
		fat_cluster = old_div(n, self.entries_per_cluster)
		(fat, cluster) = self.read_fat_cluster(fat_cluster)
		return (fat, offset, cluster)



@@ 1075,7 1079,7 @@ class ps2mc(object):

		if is_dir and thisf != None and new_ent[2] != None:
			new_ent = list(new_ent)
			new_ent[2] /= PS2MC_DIRENT_LENGTH
			new_ent[2] //= PS2MC_DIRENT_LENGTH
			
		# print "len: ", ent[2], new_ent[2]



@@ 1142,13 1146,13 @@ class ps2mc(object):
		start = dir.tell() - 1
		if start == -1:
			start = 0
		for i in range(start, len(dir)) + range(0, start):
		for i in list(range(start, len(dir))) + list(range(0, start)):
			try:
				ent = dir[i]
			except IndexError:
				raise corrupt("Corrupt directory", dir.f)
				
			if ent[8] == name and (ent[0] & DF_EXISTS):
			if ent[8].decode("ascii") == name and (ent[0] & DF_EXISTS):
				return (i, ent)
		return (None, None)



@@ 1189,7 1193,7 @@ class ps2mc(object):
		ent[5] = 0
		ent[6] = now
		ent[7] = 0
		ent[8] = name[:32]
		ent[8] = name[:32].encode("ascii")
		dir.write_raw_ent(i, ent, True)
		dir.close()



@@ 1199,15 1203,15 @@ class ps2mc(object):

		dirent = pack_dirent((DF_RWX | DF_0400 | DF_DIR | DF_EXISTS,
				      0, 0, now, dirloc[0], dirloc[1],
				      now, 0, "."))
		dirent += "\0" * (self.cluster_size - PS2MC_DIRENT_LENGTH)
				      now, 0, b"."))
		dirent += b"\0" * (self.cluster_size - PS2MC_DIRENT_LENGTH)
		self.write_allocatable_cluster(cluster, dirent)
		dir = self._directory(dirloc, cluster, 1, "wb",
				      name = "<create_dir_entry temp>")
		dir.write_raw_ent(1, (DF_RWX | DF_0400 | DF_DIR | DF_EXISTS,
				      0, 0, now,
				      0, 0,
				      now, 0, ".."), False)
				      now, 0, b".."), False)
		dir.close()
		ent[2] = 2
		# print "@@@ ret", dirloc, ent


@@ 1217,16 1221,16 @@ class ps2mc(object):
		"""Delete or truncate the file or directory given by dirloc."""
		
		if dirloc == (0, 0):
			raise io_error, (EACCES,
			raise io_error(EACCES,
					 "cannot remove root directory",
					 name)
		if dirloc[1] in [0, 1]:
			raise io_error, (EACCES,
			raise io_error(EACCES,
					 'cannot remove "." or ".." entries',
					 name)

		if dirloc in self.open_files:
			raise io_error, (EBUSY,
			raise io_error(EBUSY,
					 "cannot remove open file", filename)

		epc = self.entries_per_cluster


@@ 1242,8 1246,8 @@ class ps2mc(object):
		self.update_dirent_all(dirloc, None, ent)
		
		while cluster != PS2MC_FAT_CHAIN_END:
			if cluster / epc < self.fat_cursor:
				self.fat_cursor = cluster / epc
			if old_div(cluster, epc) < self.fat_cursor:
				self.fat_cursor = old_div(cluster, epc)
			next_cluster = self.lookup_fat(cluster)
			if next_cluster & PS2MC_FAT_ALLOCATED_BIT == 0:
				# corrupted


@@ 1332,13 1336,13 @@ class ps2mc(object):
		(dirloc, ent, is_dir) = self.path_search(filename)
		# print "@@@ open", (dirloc, ent)
		if dirloc == None or (ent == None and is_dir):
			raise path_not_found, filename
			raise path_not_found(filename)
		if is_dir:
			raise io_error, (EISDIR, "not a regular file",
			raise io_error(EISDIR, "not a regular file",
					 filename)
		if ent == None:
			if mode[0] not in "wa":
				raise file_not_found, filename
				raise file_not_found(filename)
			name = filename.split("/")[-1]
			(dirloc, ent) = self.create_dir_entry(dirloc, name,
							      DF_FILE | DF_RWX


@@ 1353,19 1357,19 @@ class ps2mc(object):
	def dir_open(self, filename, mode = "rb"):
		(dirloc, ent, is_dir) = self.path_search(filename)
		if dirloc == None:
			raise path_not_found, filename
			raise path_not_found(filename)
		if ent == None:
			raise dir_not_found, filename
			raise dir_not_found(filename)
		if not is_dir:
			raise io_error, (ENOTDIR, "not a directory", filename)
			raise io_error(ENOTDIR, "not a directory", filename)
		return self.directory(dirloc, ent[4], ent[2], mode, filename)

	def mkdir(self, filename):
		(dirloc, ent, is_dir) = self.path_search(filename)
		if dirloc == None:
			raise path_not_found, filename
			raise path_not_found(filename)
		if ent != None:
			raise io_error, (EEXIST, "directory exists", filename)
			raise io_error(EEXIST, "directory exists", filename)
		a = filename.split("/")
		name = a.pop()
		while name == "":


@@ 1391,16 1395,16 @@ class ps2mc(object):
		
		(dirloc, ent, is_dir) = self.path_search(filename)
		if dirloc == None:
			raise path_not_found, filename
			raise path_not_found(filename)
		if ent == None:
			raise file_not_found, filename
			raise file_not_found(filename)
		if is_dir:
			if ent[4] == 0:
				raise io_error, (EACCES,
				raise io_error(EACCES,
						 "cannot remove"
						 " root directory")
			if not self._is_empty(dirloc, ent, filename):
				raise io_error, (ENOTEMPTY,
				raise io_error(ENOTEMPTY,
						 "directory not empty",
						 filename)
		self.delete_dirloc(dirloc, False, filename)


@@ 1409,11 1413,11 @@ class ps2mc(object):
	def chdir(self, filename):
		(dirloc, ent, is_dir) = self.path_search(filename)
		if dirloc == None:
			raise path_not_found, filename
			raise path_not_found(filename)
		if ent == None:
			raise dir_not_found, filename
			raise dir_not_found(filename)
		if not is_dir:
			raise io_error, (ENOTDIR, "not a directory", filename)
			raise io_error(ENOTDIR, "not a directory", filename)
		self.curdir = dirloc

	def get_mode(self, filename):


@@ 1432,9 1436,9 @@ class ps2mc(object):
		
		(dirloc, ent, is_dir) = self.path_search(filename)
		if dirloc == None:
			raise path_not_found, filename
			raise path_not_found(filename)
		if ent == None:
			raise file_not_found, filename
			raise file_not_found(filename)
		return ent

	def set_dirent(self, filename, new_ent):


@@ 1445,9 1449,9 @@ class ps2mc(object):
		
		(dirloc, ent, is_dir) = self.path_search(filename)
		if dirloc == None:
			raise path_not_found, filename
			raise path_not_found(filename)
		if ent == None:
			raise file_not_found, filename
			raise file_not_found(filename)
		dir = self._opendir_parent_dirloc(dirloc)
		try:
			dir[dirloc[1]] = new_ent


@@ 1468,11 1472,11 @@ class ps2mc(object):
		
		dir_ent = sf.get_directory()
		if dirname == None:
			dir_ent_name = dir_ent[8]
			dirname = "/" + dir_ent[8]
			dir_ent_name = dir_ent[8].decode("ascii")
			dirname = "/" + dir_ent_name
		else:
			if dirname == "":
				raise path_not_found, dirname
				raise path_not_found(dirname)
			
			# remove trailing slashes
			dirname = dirname.rstrip("/")


@@ 1482,11 1486,11 @@ class ps2mc(object):

		(root_dirloc, ent, is_dir) = self.path_search(dirname)
		if root_dirloc == None:
			raise path_not_found, dirname
			raise path_not_found(dirname)
		if ent != None:
			if ignore_existing:
				return False
			raise io_error, (EEXIST, "directory exists", dirname)
			raise io_error(EEXIST, "directory exists", dirname)
		mode = DF_DIR | (dir_ent[0] & ~DF_FILE)

		(dir_dirloc, ent) = self.create_dir_entry(root_dirloc,


@@ 1498,12 1502,9 @@ class ps2mc(object):
			for i in range(dir_ent[2]):
				(ent, data) = sf.get_file(i)
				mode = DF_FILE | (ent[0] & ~DF_DIR)
				(dirloc, ent) \
					= self.create_dir_entry(dir_dirloc,
								ent[8], mode)
				(dirloc, ent) = self.create_dir_entry(dir_dirloc, ent[8].decode("ascii"), mode)
				# print "@@@ file", dirloc, ent[4], ent[2]
				f = self.file(dirloc, ent[4], ent[2], "wb",
					      dirname + ent[8])
				f = self.file(dirloc, ent[4], ent[2], "wb", dirname + ent[8].decode("ascii"))
				try:
					f.write(data)
				finally:


@@ 1516,17 1517,17 @@ class ps2mc(object):
						(ent, data) = sf.get_file(i)
						# print "@@@ remove", ent[8]
						self.remove(dirname + ent[8])
				except EnvironmentError, why:
				except EnvironmentError as why:
					# print "@@@ failed", why
					pass
			
				try:
					# print "@@@ remove dir", dirname
					self.remove(dirname)
				except EnvironmentError, why:
				except EnvironmentError as why:
					# print "@@@ failed", why
					pass
				raise type, what, where
				raise type(what, where)
			finally:
				del where



@@ 1551,13 1552,13 @@ class ps2mc(object):
	def export_save_file(self, filename):
		(dir_dirloc, dirent, is_dir) = self.path_search(filename)
		if dir_dirloc == None:
			raise path_not_found, filename
			raise path_not_found(filename)
		if dirent == None:
			raise dir_not_found, filename
			raise dir_not_found(filename)
		if not is_dir:
			raise io_error, (ENOTDIR, "not a directory", filename)
			raise io_error(ENOTDIR, "not a directory", filename)
		if dir_dirloc == (0, 0):
			raise io_error, (EACCES, "can't export root directory",
			raise io_error(EACCES, "can't export root directory",
					 filename)
		sf = ps2save.ps2_save_file()
		files = []


@@ 1610,7 1611,7 @@ class ps2mc(object):
			else:
				# print "deleting", dirname + ent[8]
				self.delete_dirloc((first_cluster, i), False,
						   dirname + ent[8])
						   dirname + ent[8].decode("utf-8"))
		self.delete_dirloc(dirloc, False, dirname)
		
	def rmdir(self, dirname):


@@ 1618,13 1619,13 @@ class ps2mc(object):
		
		(dirloc, ent, is_dir) = self.path_search(dirname)
		if dirloc == None:
			raise path_not_found, dirname
			raise path_not_found(dirname)
		if ent == None:
			raise dir_not_found, dirname
			raise dir_not_found(dirname)
		if not is_dir:
			raise io_error, (ENOTDIR, "not a directory", dirname)
			raise io_error(ENOTDIR, "not a directory", dirname)
		if dirloc == (0, 0):
			raise io_error, (EACCES, "can't delete root directory",
			raise io_error(EACCES, "can't delete root directory",
					 dirname)

		if dirname != "" and dirname[-1] != "/":


@@ 1635,7 1636,7 @@ class ps2mc(object):
		"""Returns the amount of free space in bytes."""
		
		free = 0
		for i in xrange(self.allocatable_cluster_end):
		for i in range(self.allocatable_cluster_end):
			if (self.lookup_fat(i) & PS2MC_FAT_ALLOCATED_BIT) == 0:
				free += 1
		return free * self.cluster_size


@@ 1672,7 1673,7 @@ class ps2mc(object):
		why = self._check_file(fat, ent[4],
				       ent[2] * PS2MC_DIRENT_LENGTH)
		if why != None:
			print "bad directory:", dirname + ":", why
			print("bad directory:", dirname + ":", why)
			return False
		ret = True
		first_cluster = ent[4]


@@ 1680,31 1681,29 @@ class ps2mc(object):
		dir = self._directory(dirloc, first_cluster, length,
				      "rb", dirname)
		dot_ent = dir[0]
		if dot_ent[8] != ".":
			print "bad directory:", dirname + ': missing "." entry'
		if dot_ent[8].decode("ascii") != ".":
			print("bad directory:", dirname + ': missing "." entry')
			ret = False
		if (dot_ent[4], dot_ent[5]) != dirloc:
			print "bad directory:", dirname + ': bad "." entry'
			print("bad directory:", dirname + ': bad "." entry')
			ret = False
		if dir[1][8] != "..":
			print "bad directory:", (dirname
						 + ': missing ".." entry')
		if dir[1][8].decode("ascii") != "..":
			print("bad directory:", (dirname
						 + ': missing ".." entry'))
			ret = False
		for i in xrange(2, length):
		for i in range(2, length):
			ent = dir[i]
			mode = ent[0]
			if not (mode & DF_EXISTS):
				continue
			if mode & DF_DIR:
				if not self._check_dir(fat, (first_cluster, i),
						       dirname + ent[8] + "/",
						       ent):
						       dirname + ent[8].decode("ascii") + "/", ent):
					ret = False
			else:
				why = self._check_file(fat, ent[4], ent[2])
				if why != None:
					print "bad file:", (dirname + ent[8]
							    + ":"), why
					print("bad file:", (dirname + ent[8].decode("ascii") + ":"), why)
					ret = False
				
		dir.close()


@@ 1719,7 1718,7 @@ class ps2mc(object):

		fat_len = int(str(self.allocatable_cluster_end)) 
		if not isinstance(fat_len, int):
			raise error, "Memory card image too big to check."
			raise error("Memory card image too big to check.")

		fat = array.array('B', [0]) * fat_len



@@ 1728,14 1727,14 @@ class ps2mc(object):
		ret = self._check_dir(fat, (0, 0), "/", ent)

		lost_clusters = 0
		for i in xrange(self.allocatable_cluster_end):
		for i in range(self.allocatable_cluster_end):
			a = self.lookup_fat(i)
			if (a & PS2MC_FAT_ALLOCATED_BIT) and not fat[i]:
				print i,
				print(i, end=' ')
				lost_clusters += 1
		if lost_clusters > 0:
			print
			print "found", lost_clusters, "lost clusters"
			print()
			print("found", lost_clusters, "lost clusters")
			ret = False
			
		return ret


@@ 1747,13 1746,11 @@ class ps2mc(object):
				return [dirname]
			dir = self.dir_open(dirname)
			try:
				return [dirname + ent[8]
				return [dirname + ent[8].decode("ascii")
					for ent in dir
					if ((ent[0] & DF_EXISTS)
					    and (ent[8] not in [".", ".."]
						 or ent[8] == pattern)
					    and fnmatch.fnmatchcase(ent[8],
								    pattern))]
					if ((ent[0] & DF_EXISTS) and (ent[8].decode("ascii") not in [".", ".."]
						 or ent[8].decode("ascii") == pattern)
					    and fnmatch.fnmatchcase(ent[8].decode("ascii"), pattern))]
			finally:
				dir.close()
		if pattern == "":


@@ 1765,7 1762,7 @@ class ps2mc(object):
		try:
			ret = []
			for ent in dir:
				name = ent[8]
				name = ent[8].decode("ascii")
				if ((ent[0] & DF_EXISTS) == 0
				    or (ent[0] & DF_DIR) == 0):
					continue


@@ 1797,7 1794,7 @@ class ps2mc(object):
		f = self.open(icon_sys, "rb")
		s = f.read(964)
		f.close()
		if len(s) == 964 and s[0:4] == "PS2D":
		if len(s) == 964 and s[0:4] == b"PS2D":
			return s;
		return None



@@ 1809,13 1806,11 @@ class ps2mc(object):
			length = round_up(len(dir) * PS2MC_DIRENT_LENGTH,
					  self.cluster_size)
			for ent in dir:
				name = ent[8].decode("ascii")
				if mode_is_file(ent[0]):
					length += round_up(ent[2],
							   self.cluster_size)
				elif (mode_is_dir(ent[0])
				      and ent[8] not in [".", ".."]):
					length += self.dir_size(dirname + "/"
								+ ent[8])
					length += round_up(ent[2], self.cluster_size)
				elif mode_is_dir(ent[0]) and name not in [".", ".."]:
					length += self.dir_size(dirname + "/" + name)
		finally:
			dir.close()
		return length


@@ 1846,7 1841,7 @@ class ps2mc(object):
				# this is complicated by the fact as
				# files are closed they will remove
				# themselves from the list of open files
				for (dir, files) in open_files.values():
				for (dir, files) in list(open_files.values()):
					for f in list(files):
						f.close()
				while len(open_files) > 0:

M mymc/ps2mc_dir.py => mymc/ps2mc_dir.py +1 -1
@@ 36,7 36,7 @@ DF_EXISTS      = 0x8000
def zero_terminate(s):
	"""Truncate a string at the first NUL ('\0') character, if any."""
	
	i = s.find('\0')
	i = s.find(b'\0')
	if i == -1:
		return s
	return s[:i]

M mymc/ps2mc_ecc.py => mymc/ps2mc_ecc.py +7 -3
@@ 9,7 9,11 @@
Routines for calculating the Hamming codes, a simple form of error
correcting codes (ECC), as used on PS2 memory cards.  
"""
from __future__ import print_function

from builtins import chr
from builtins import map
from builtins import range
_SCCS_ID = "@(#) mysc ps2mc_ecc.py 1.4 07/12/17 02:34:04\n"

import array


@@ 105,13 109,13 @@ def _ecc_check(s, ecc):
	#				    lp_comp, cp_comp)

	if lp_comp == 0x7F and cp_comp == 0x07:
		print "corrected 1"
		print("corrected 1")
		# correctable 1 bit error in data
		s[lp1_diff] ^= 1 << (cp_diff >> 4)
		return ECC_CHECK_CORRECTED
	if ((cp_diff == 0 and lp0_diff == 0 and lp1_diff == 0)
	      or _popcount(lp_comp) + _popcount(cp_comp) == 1):
		print "corrected 2"
		print("corrected 2")
		# correctable 1 bit error in ECC
		# (and/or one of the unused bits was set)
		ecc[0] = computed[0]


@@ 141,7 145,7 @@ def ecc_check_page(page, spare):
	for i in range(div_round_up(len(page), 128)):
		a = array.array('B')
		a.fromstring(page[i * 128 : i * 128 + 128])
		chunks.append((a, map(ord, spare[i * 3 : i * 3 + 3])))
		chunks.append((a, list(spare[i * 3 : i * 3 + 3])))
	
	r = [ecc_check(s, ecc)
	     for (s, ecc) in chunks]

M mymc/ps2save.py => mymc/ps2save.py +48 -45
@@ 7,6 7,9 @@
# A simple interface for working with various PS2 save file formats.
#

from builtins import map
from builtins import range
from builtins import object
_SCCS_ID = "@(#) mysc ps2save.py 1.7 12/10/04 19:17:16\n"

import sys


@@ 26,10 29,10 @@ try:
except ImportError:
	lzari = None

PS2SAVE_MAX_MAGIC = "Ps2PowerSave"
PS2SAVE_SPS_MAGIC = "\x0d\0\0\0SharkPortSave"
PS2SAVE_CBS_MAGIC = "CFU\0"
PS2SAVE_NPO_MAGIC = "nPort"
PS2SAVE_MAX_MAGIC = b"Ps2PowerSave"
PS2SAVE_SPS_MAGIC = b"\x0d\0\0\0SharkPortSave"
PS2SAVE_CBS_MAGIC = b"CFU\0"
PS2SAVE_NPO_MAGIC = b"nPort"

# This is the initial permutation state ("S") for the RC4 stream cipher
# algorithm used to encrpyt and decrypt Codebreaker saves.


@@ 226,7 229,7 @@ def unpack_icon_sys(s):
	a = list(a)
	for i in range(3, 7):
		a[i] = struct.unpack("<4L", a[i])
		a[i] = map(hex, a[i])
		a[i] = list(map(hex, a[i]))
	for i in range(7, 14):
		a[i] = struct.unpack("<4f", a[i])
	a[14] = zero_terminate(a[14])


@@ 240,8 243,8 @@ def icon_sys_title(icon_sys, encoding = None):
	
	offset = icon_sys[1]
	title = icon_sys[14]
	title2 = shift_jis_conv(title[offset:], encoding)
	title1 = shift_jis_conv(title[:offset], encoding)
	title2 = shift_jis_conv(title[offset:], encoding).decode(encoding)
	title1 = shift_jis_conv(title[:offset], encoding).decode(encoding)
	return (title1, title2)

def _read_fixed(f, n):


@@ 249,7 252,7 @@ def _read_fixed(f, n):
	
	s = f.read(n)
	if len(s) != n:
		raise eof, f
		raise eof(f)
	return s

def _read_long_string(f):


@@ 296,7 299,7 @@ class ps2_save_file(object):
	def get_icon_sys(self):
		for i in range(self.dirent[2]):
			(ent, data) = self.get_file(i)
			if ent[8] == "icon.sys" and len(data) >= 964:
			if ent[8].decode("ascii") == "icon.sys" and len(data) >= 964:
				return unpack_icon_sys(data[:964])
		return None



@@ 312,7 315,7 @@ class ps2_save_file(object):
		    or not mode_is_dir(dotent[0])
		    or not mode_is_dir(dotdotent[0])
		    or dirent[2] < 2):
			raise corrupt, ("Not a EMS (.psu) save file.", f)
			raise corrupt("Not a EMS (.psu) save file.", f)

		dirent[2] -= 2
		self.set_directory(dirent)


@@ 321,7 324,7 @@ class ps2_save_file(object):
			ent = unpack_dirent(_read_fixed(f,
							PS2MC_DIRENT_LENGTH))
			if not mode_is_file(ent[0]):
				raise subdir, f
				raise subdir(f)
			flen = ent[2]
			self.set_file(i, ent, _read_fixed(f, flen))
			_read_fixed(f, round_up(flen, cluster_size) - flen)


@@ 335,10 338,10 @@ class ps2_save_file(object):
		f.write(pack_dirent(dirent))
		f.write(pack_dirent((DF_RWX | DF_DIR | DF_0400 | DF_EXISTS,
				     0, 0, dirent[3],
				     0, 0, dirent[3], 0, ".")))
				     0, 0, dirent[3], 0, b".")))
		f.write(pack_dirent((DF_RWX | DF_DIR | DF_0400 | DF_EXISTS,
				     0, 0, dirent[3],
				     0, 0, dirent[3], 0, "..")))
				     0, 0, dirent[3], 0, b"..")))
				     
		for i in range(dirent[2] - 2):
			(ent, data) = self.get_file(i)


@@ 346,9 349,9 @@ class ps2_save_file(object):
			if not mode_is_file(ent[0]):
				# print ent
				# print hex(ent[0])
				raise error, "Directory has a subdirectory."
				raise error("Directory has a subdirectory.")
			f.write(data)
			f.write("\0" * (round_up(len(data), cluster_size)
			f.write(b"\0" * (round_up(len(data), cluster_size)
					- len(data)))
		f.flush()



@@ 357,7 360,7 @@ class ps2_save_file(object):
		self._compressed = None
		
		if lzari == None:
			raise error, ("The lzari module is needed to "
			raise error("The lzari module is needed to "
				      " decompress MAX Drive saves.")
		s = lzari.decode(s, length,
				 "decompressing " + self.dirent[8] + ": ")


@@ 366,14 369,14 @@ class ps2_save_file(object):
		off = 0
		for i in range(dirlen):
			if len(s) - off < 36:
				raise eof, f
				raise eof(f)
			(l, name) = struct.unpack("<L32s", s[off : off + 36])
			name = zero_terminate(name)
			# print "%08x %08x %s" % (off, l, name)
			off += 36
			data = s[off : off + l]
			if len(data) != l:
				raise eof, f
				raise eof(f)
			self.set_file(i,
				      (DF_RWX | DF_FILE | DF_0400 | DF_EXISTS,
				       0, l, timestamp, 0, 0, timestamp, 0,


@@ 389,7 392,7 @@ class ps2_save_file(object):
			(magic, crc, dirname, iconsysname, clen, dirlen,
			 length) = struct.unpack("<12sL32s32sLLL", s)
		if magic != PS2SAVE_MAX_MAGIC:
			raise corrupt, ("Not a MAX Drive save file", f)
			raise corrupt("Not a MAX Drive save file", f)
		if clen == length:
			# some saves have the uncompressed size here
			# instead of the compressed size


@@ 407,7 410,7 @@ class ps2_save_file(object):
		
	def save_max_drive(self, f):
		if lzari == None:
			raise error, ("The lzari module is needed to "
			raise error("The lzari module is needed to "
				      " decompress MAX Drive saves.")
		iconsysname = ""
		icon_sys = self.get_icon_sys()


@@ 417,25 420,25 @@ class ps2_save_file(object):
				iconsysname = title[0] + " " + title[1].strip()
			else:
				iconsysname = title[0] + title[1].rstrip()
		s = ""
		s = b""
		dirent = self.dirent
		for i in range(dirent[2]):
			(ent, data) = self.get_file(i)
			if not mode_is_file(ent[0]):
				raise error, "Non-file in save file."
				raise error("Non-file in save file.")
			s += struct.pack("<L32s", ent[2], ent[8])
			s += data
			s += "\0" * (round_up(len(s) + 8, 16) - 8 - len(s))
			s += b"\0" * (round_up(len(s) + 8, 16) - 8 - len(s))
		length = len(s)
		progress =  "compressing " + dirent[8] + ": "
		progress =  "compressing " + dirent[8].decode("ascii") + ": "
		compressed = lzari.encode(s, progress)
		hdr = struct.pack("<12sL32s32sLLL", PS2SAVE_MAX_MAGIC,
				  0, dirent[8], iconsysname,
				  0, dirent[8], iconsysname.encode("ascii"),
				  len(compressed) + 4, dirent[2], length)
		crc = binascii.crc32(hdr)
		crc = binascii.crc32(compressed, crc)
		f.write(struct.pack("<12sL32s32sLLL", PS2SAVE_MAX_MAGIC,
				    crc & 0xFFFFFFFF, dirent[8], iconsysname,
				    crc & 0xFFFFFFFF, dirent[8], iconsysname.encode("ascii"),
				    len(compressed) + 4, dirent[2], length))
		f.write(compressed)
		f.flush()


@@ 443,10 446,10 @@ class ps2_save_file(object):
	def load_codebreaker(self, f):
		magic = f.read(4)
		if magic != PS2SAVE_CBS_MAGIC:
			raise corrupt, ("Not a Codebreaker save file.", f)
			raise corrupt("Not a Codebreaker save file.", f)
		(d04, hlen) = struct.unpack("<LL", _read_fixed(f, 8))
		if hlen < 92 + 32:
			raise corrupt, ("Header lengh too short.", f)
			raise corrupt("Header lengh too short.", f)
		(dlen, flen, dirname, created, modified, d44, d48, dirmode,
		 d50, d54, d58, title) \
		       = struct.unpack("<LL32s8s8sLLLLLL%ds" % (hlen - 92),


@@ 469,20 472,20 @@ class ps2_save_file(object):
		body = f.read(flen)
		clen = len(body)
		if clen != flen and clen != flen - hlen:
			raise eof, f
			raise eof(f)
		body = rc4_crypt(PS2SAVE_CBS_RC4S, body)
		dcobj = zlib.decompressobj()
		body = dcobj.decompress(body, dlen)

		files = []
		while body != "":
		while body != b"":
			if len(body) < 64:
				raise eof, f
				raise eof(f)
			header = struct.unpack("<8s8sLHHLL32s", body[:64])
			size = header[2]
			data = body[64 : 64 + size]
			if len(data) != size:
				raise eof, f
				raise eof(f)
			body = body[64 + size:]
			files.append((header, data))
			


@@ 496,7 499,7 @@ class ps2_save_file(object):
			created = unpack_tod(created)
			modified = unpack_tod(modified)
			if not mode_is_file(mode):
				raise subdir, f
				raise subdir(f)
			if tod_to_time(created) == 0:
				created = tod_now()
			if tod_to_time(modified) == 0:


@@ 507,7 510,7 @@ class ps2_save_file(object):
	def load_sharkport(self, f):
		magic = f.read(17)
		if magic != PS2SAVE_SPS_MAGIC:
			raise corrupt, ("Not a SharkPort/X-Port save file.", f)
			raise corrupt("Not a SharkPort/X-Port save file.", f)
		(savetype,) = struct.unpack("<L", _read_fixed(f, 4))
		dirname = _read_long_string(f)
		datestamp = _read_long_string(f)


@@ 524,10 527,10 @@ class ps2_save_file(object):
		modified = unpack_tod(modified)

		# mode values are byte swapped
		dirmode = dirmode / 256 % 256 + dirmode % 256 * 256
		dirmode = dirmode // 256 % 256 + dirmode % 256 * 256
		dirlen -= 2
		if not mode_is_dir(dirmode) or dirlen < 0:
			raise corrupt, ("Bad values in directory entry.", f)
			raise corrupt("Bad values in directory entry.", f)
		self.set_directory((dirmode, 0, dirlen, created, 0, 0,
				    modified, 0, dirname))



@@ 536,14 539,14 @@ class ps2_save_file(object):
			       = struct.unpack("<H64sL8xH2x8s8s",
					       _read_fixed(f, 98))
			if hlen < 98:
				raise corrupt, ("Header length too short.", f)
				raise corrupt("Header length too short.", f)
			_read_fixed(f, hlen - 98)
			name = zero_terminate(name)
			created = unpack_tod(created)
			modified = unpack_tod(modified)
			mode = mode / 256 % 256 + mode % 256 * 256
			mode = mode // 256 % 256 + mode % 256 * 256
			if not mode_is_file(mode):
				raise subdir, f
				raise subdir(f)
			self.set_file(i, (mode, 0, flen, created, 0, 0,
					  modified, 0, name),
				      _read_fixed(f, flen))


@@ 577,15 580,15 @@ def detect_file_type(f):
	dotdotent = unpack_dirent(hdr[PS2MC_DIRENT_LENGTH * 2:])
	if (mode_is_dir(dirent[0]) and mode_is_dir(dotent[0])
	    and mode_is_dir(dotdotent[0]) and dirent[2] >= 2
	    and dotent[8] == "." and dotdotent[8] == ".."):
	    and dotent[8] == b"." and dotdotent[8] == b".."):
		return "psu"
	return None

#
# Set up tables of illegal and problematic characters in file names.
#
_bad_filename_chars = ("".join(map(chr, range(32)))
		       + "".join(map(chr, range(127, 256))))
_bad_filename_chars = ("".join(map(chr, list(range(32))))
		       + "".join(map(chr, list(range(127, 256)))))
_bad_filename_repl = "_" * len(_bad_filename_chars)

if os.name in ["nt", "os2", "ce"]:


@@ 599,8 602,8 @@ else:
	_bad_filename_chars2 = _bad_filename_chars + "?*'&|:[<>] \\\""
	_bad_filename_repl2 = _bad_filename_repl +   "______(())___"

_filename_trans = string.maketrans(_bad_filename_chars, _bad_filename_repl);
_filename_trans2 = string.maketrans(_bad_filename_chars2, _bad_filename_repl2);
_filename_trans = str.maketrans(_bad_filename_chars, _bad_filename_repl);
_filename_trans2 = str.maketrans(_bad_filename_chars2, _bad_filename_repl2);

def fix_filename(filename):
	"""Replace illegal or problematic characters from a filename."""


@@ 618,7 621,7 @@ def make_longname(dirname, sf):
	crc = binascii.crc32("")
	for (ent, data) in sf:
		crc = binascii.crc32(data, crc)
 	if len(dirname) >= 12 and (dirname[0:2] in ("BA", "BJ", "BE", "BK")):
	if len(dirname) >= 12 and (dirname[0:2] in ("BA", "BJ", "BE", "BK")):
		if dirname[2:6] == "DATA":
			title = ""
		else:

M mymc/round.py => mymc/round.py +4 -3
@@ 1,3 1,4 @@
from __future__ import division
#
# round.py
#


@@ 10,12 11,12 @@
_SCCS_ID = "@(#) mysc round.py 1.3 07/04/17 02:10:27\n"

def div_round_up(a, b):
	return (a + b - 1) / b
	return (a + b - 1) // b

def round_up(a, b):
	return (a + b - 1) / b * b
	return (a + b - 1) // b * b

def round_down(a, b):
	return a / b * b
	return a // b * b



M test/memorycard.py => test/memorycard.py +1 -1
@@ 96,7 96,7 @@ def test_check_root_directory(capsys, mc01_copy):
    mc_file = mc01_copy.join("mc01.ps2").strpath
    with open(mc_file, "r+b") as f:
        f.seek(0x200)
        f.write("\x13\x37")
        f.write(b"\x13\x37")

    assert md5(mc_file) == "bec7e8c3884806024b9eb9599dc4315f"