diff --git a/README.txt b/README.txt old mode 100644 new mode 100755 index 8557a40..0ba188e --- a/README.txt +++ b/README.txt @@ -3,7 +3,7 @@ README.txt By Ross Ridge Pubic Domain -@(#) mymc README.txt 1.5 08/02/06 13:26:26 +@(#) mymc README.txt 1.6 12/10/04 19:18:08 This file describes mymc, a utility for manipulating PlayStation 2 @@ -109,15 +109,15 @@ saves to someone else to use or just keep them on your hard drive as a backup. The following command demonstrates how to export a save in the EMS format using mymc: - c:\mymc\mymc c:\pcsx2\memcards\Mcd001.ps2 export BASLUS-20448-000D + c:\mymc\mymc c:\pcsx2\memcards\Mcd001.ps2 export BASLUS-20448-0000D -This will create a file called "BASLUS-20448-000D.psu" in the current +This will create a file called "BASLUS-20448-0000D.psu" in the current directory. To create a file in the MAX format instead, use the export command's -m option: - c:\mymc\mymc c:\pcsx2\memcards\Mcd001.ps2 export -m BASLUS-20448-000D + c:\mymc\mymc c:\pcsx2\memcards\Mcd001.ps2 export -m BASLUS-20448-0000D -This creates a file named "BASLUS-20448-000D.max". Note the "-m" +This creates a file named "BASLUS-20448-0000D.max". Note the "-m" option that appears after the "export" command. Importing save files is similar. The save file type is auto-detected, diff --git a/gui.py b/gui.py old mode 100644 new mode 100755 index 3733679..b5d2220 --- a/gui.py +++ b/gui.py @@ -7,7 +7,7 @@ """Graphical user-interface for mymc.""" -_SCCS_ID = "@(#) mymc gui.py 1.3 08/02/06 13:15:41\n" +_SCCS_ID = "@(#) mymc gui.py 1.4 12/10/04 18:51:51\n" import os import sys @@ -482,12 +482,17 @@ class gui_frame(wx.Frame): def mc_error(self, value, filename = None): """Display a message box for EnvironmentError exeception.""" + if filename == None: + filename = getattr(value, "filename") if filename == None: filename = self.mcname - if filename == None: - filename = "???" - filename = getattr(value, "filename", filename) - strerror = getattr(value, "strerror", "unknown error") + if filename == None: + filename = "???" + + strerror = getattr(value, "strerror", None) + if strerror == None: + strerror = "unknown error" + return self.error_box(filename + ": " + strerror) def __init__(self, parent, title, mcname = None): diff --git a/guires.py b/guires.py old mode 100644 new mode 100755 diff --git a/lzari.py b/lzari.py old mode 100644 new mode 100755 index f5d2571..f80f6f0 --- a/lzari.py +++ b/lzari.py @@ -11,7 +11,7 @@ a two level dicitionary look up during compression rather than LZARI.C's binary search tree. """ -_SCCS_ID = "@(#) mysc lzari.py 1.5 08/02/05 16:00:34\n" +_SCCS_ID = "@(#) mysc lzari.py 1.6 12/10/04 19:07:53\n" import sys import array @@ -655,6 +655,8 @@ else: # print r, compressed.value, comp_len if r == -1: raise MemoryError, "out of memory during compression" + if compressed.value == None: + return "" ret = ctypes.string_at(compressed.value, comp_len.value) mylzari_free_encoded(compressed) return ret; diff --git a/mymc.py b/mymc.py old mode 100644 new mode 100755 index 732f046..54f3262 --- a/mymc.py +++ b/mymc.py @@ -7,7 +7,7 @@ """A utility for manipulating PS2 memory card images.""" -_SCCS_ID = "@(#) mysc mymc.py 1.11 08/08/11 14:12:26\n"[:-1] +_SCCS_ID = "@(#) mysc mymc.py 1.12 12/10/04 19:09:16\n"[:-1] import sys import os @@ -323,7 +323,7 @@ def do_setmode(cmd, mc, opts, args, opterr): ent = mc.get_dirent(arg) if value == None: ent[0] = (ent[0] & clear_mask) | set_mask - print "new %04x" % ent[0] + # print "new %04x" % ent[0] else: ent[0] = value mc.set_dirent(arg, ent) @@ -427,7 +427,7 @@ def do_format(cmd, mcname, opts, args, opterr): pages_per_cluster = (ps2mc.PS2MC_CLUSTER_SIZE / ps2mc.PS2MC_STANDARD_PAGE_SIZE) pages_per_card = opts.clusters * pages_per_cluster - params = (True, + params = (not opts.no_ecc, ps2mc.PS2MC_STANDARD_PAGE_SIZE, ps2mc.PS2MC_STANDARD_PAGES_PER_ERASE_BLOCK, pages_per_card) @@ -632,7 +632,9 @@ cmd_table = { [opt("-c", "--clusters", type="int", help = "Size in clusters of the memory card."), opt("-f", "--overwrite-existing", action="store_true", - help = "Overwrite any existing file")]), + help = "Overwrite any existing file"), + opt("-e", "--no-ecc", action="store_true", + help = "Create an image without ECC")]), "gui": (do_gui, None, "", "Starts the graphical user interface.", diff --git a/ps2mc.py b/ps2mc.py old mode 100644 new mode 100755 index 1c916bb..6165229 --- a/ps2mc.py +++ b/ps2mc.py @@ -7,7 +7,7 @@ """Manipulate PS2 memory card images.""" -_SCCS_ID = "@(#) mysc ps2mc.py 1.9 08/08/13 15:31:32\n" +_SCCS_ID = "@(#) mysc ps2mc.py 1.10 12/10/04 19:10:35\n" import sys import array @@ -62,6 +62,11 @@ class dir_not_found(io_error): io_error.__init__(self, ENOENT, "directory not found", filename) +class dir_index_not_found(io_error, IndexError): + def __init__(self, filename, index): + msg = "index (%d) past of end of directory" % index + io_error.__init__(self, ENOENT, msg, filename) + class corrupt(io_error): def __init__(self, msg, f = None): filename = None @@ -521,8 +526,8 @@ class ps2mc_directory(object): # print "@@@ getitem", index, self.f.name self.seek(index) dirent = self.f.read(PS2MC_DIRENT_LENGTH) - if dirent == "": - raise IndexError + if len(dirent) != PS2MC_DIRENT_LENGTH: + raise dir_index_not_found(self.f.name, index) return unpack_dirent(dirent) def __setitem__(self, index, new_ent): @@ -624,20 +629,21 @@ class ps2mc(object): self.good_block2 = sb[11] self.indirect_fat_cluster_list = sb[12] self.bad_erase_block_list = sb[13] - self._calculate_derived() - - self.f = f - self.ignore_ecc = False - try: - self.read_page(0) - self.ignore_ecc = ignore_ecc - except ecc_error: - # the error might be due the fact the file image - # doesn't contain ECC data - self.spare_size = 0 - self.raw_page_size = self.page_size - ignore_ecc = True + self._calculate_derived() + + self.f = f + self.ignore_ecc = False + + try: + self.read_page(0) + self.ignore_ecc = ignore_ecc + except ecc_error: + # the error might be due the fact the file + # image doesn't contain ECC data + self.spare_size = 0 + self.raw_page_size = self.page_size + ignore_ecc = True # sanity check root = self._directory(None, 0, 1) @@ -853,7 +859,11 @@ class ps2mc(object): cluster_size = self.cluster_size if self.spare_size == 0: self.f.seek(cluster_size * n) - return self.f.write(cluster_size, buf) + if len(buf) != cluster_size: + raise error, ("internal error: write_cluster:" + " %d != %d" % (len(buf), + cluster_size)) + return self.f.write(buf) n *= pages_per_cluster pgsize = self.page_size for i in range(pages_per_cluster): @@ -1133,7 +1143,11 @@ class ps2mc(object): if start == -1: start = 0 for i in range(start, len(dir)) + range(0, start): - ent = dir[i] + try: + ent = dir[i] + except IndexError: + raise corrupt("Corrupt directory", dir.f) + if ent[8] == name and (ent[0] & DF_EXISTS): return (i, ent) return (None, None) @@ -1800,8 +1814,8 @@ class ps2mc(object): self.cluster_size) elif (mode_is_dir(ent[0]) and ent[8] not in [".", ".."]): - length += self._dir_size(dirname + "/" - + ent[8]) + length += self.dir_size(dirname + "/" + + ent[8]) finally: dir.close() return length diff --git a/ps2mc_dir.py b/ps2mc_dir.py old mode 100644 new mode 100755 index c18eb5b..9d21e07 --- a/ps2mc_dir.py +++ b/ps2mc_dir.py @@ -7,7 +7,7 @@ """Functions for working with PS2 memory card directory entries.""" -_SCCS_ID = "@(#) mysc ps2mc_dir.py 1.3 08/02/05 15:51:58\n" +_SCCS_ID = "@(#) mysc ps2mc_dir.py 1.4 12/10/04 19:11:08\n" import struct import time @@ -122,7 +122,10 @@ def tod_to_time(tod): def tod_now(): """Get the current time as a ToD tuple.""" return time_to_tod(time.time()) - + +def tod_from_file(filename): + return time_to_tod(os.stat(filename).st_mtime) + def mode_is_file(mode): return (mode & (DF_FILE | DF_DIR | DF_EXISTS)) == (DF_FILE | DF_EXISTS) diff --git a/ps2mc_ecc.py b/ps2mc_ecc.py old mode 100644 new mode 100755 diff --git a/ps2save.py b/ps2save.py old mode 100644 new mode 100755 index 98f5f61..0c90a09 --- a/ps2save.py +++ b/ps2save.py @@ -7,7 +7,7 @@ # A simple interface for working with various PS2 save file formats. # -_SCCS_ID = "@(#) mysc ps2save.py 1.6 08/08/11 14:11:54\n" +_SCCS_ID = "@(#) mysc ps2save.py 1.7 12/10/04 19:17:16\n" import sys import os @@ -167,10 +167,10 @@ char_substs = { def shift_jis_conv(src, encoding = None): """Convert Shift-JIS strings to a graphically similar representation. - If encoding is "unicode" then a Unicode string is returned, - otherwise a string in encoding specified is returned. If necessary, + If encoding is "unicode" then a Unicode string is returned, otherwise + a string in the encoding specified is returned. If necessary, graphically similar characters are used to replace characters not - exactly representable in the desired encoding. + exactly representable in the desired encoding. """ if encoding == None: @@ -272,7 +272,7 @@ class ps2_save_file(object): self._compressed = None self.file_ents = [None] * ent[2] self.file_data = [None] * ent[2] - self.dirent = ent + self.dirent = list(ent) def set_file(self, i, ent, data): self.file_ents[i] = ent @@ -344,6 +344,8 @@ class ps2_save_file(object): (ent, data) = self.get_file(i) f.write(pack_dirent(ent)) if not mode_is_file(ent[0]): + # print ent + # print hex(ent[0]) raise error, "Directory has a subdirectory." f.write(data) f.write("\0" * (round_up(len(data), cluster_size) @@ -360,7 +362,7 @@ class ps2_save_file(object): s = lzari.decode(s, length, "decompressing " + self.dirent[8] + ": ") dirlen = self.dirent[2] - now = tod_now() + timestamp = self.dirent[3] off = 0 for i in range(dirlen): if len(s) - off < 36: @@ -373,13 +375,14 @@ class ps2_save_file(object): if len(data) != l: raise eof, f self.set_file(i, - (DF_RWX | DF_FILE | DF_0400, 0, l, - now, 0, 0, now, 0, name), + (DF_RWX | DF_FILE | DF_0400 | DF_EXISTS, + 0, l, timestamp, 0, 0, timestamp, 0, + name), data) off += l off = round_up(off + 8, 16) - 8 - def load_max_drive(self, f): + def load_max_drive(self, f, timestamp = None): s = f.read(0x5C) magic = None if len(s) == 0x5C: @@ -394,9 +397,11 @@ class ps2_save_file(object): else: s = _read_fixed(f, clen - 4) dirname = zero_terminate(dirname) - now = tod_now() - self.set_directory((DF_RWX | DF_DIR | DF_0400, 0, - dirlen, now, 0, 0, now, 0, dirname), + if timestamp == None: + timestamp = tod_now() + self.set_directory((DF_RWX | DF_DIR | DF_0400 | DF_EXISTS, + 0, dirlen, timestamp, 0, 0, timestamp, 0, + dirname), True) self._compressed = (length, s) diff --git a/round.py b/round.py old mode 100644 new mode 100755 diff --git a/sjistab.py b/sjistab.py old mode 100644 new mode 100755 diff --git a/verbuild.py b/verbuild.py old mode 100644 new mode 100755 index 519fd0e..68c0d52 --- a/verbuild.py +++ b/verbuild.py @@ -1,2 +1,2 @@ -MYMC_VERSION_BUILD = r'''5''' +MYMC_VERSION_BUILD = r'''6''' MYMC_VERSION_MAJOR = r'''2'''