Update sources to 2.7 from author's website

http://www.csclub.uwaterloo.ca:11068/mymc/
-updated to use Python 2.7 and Visual C++ 2008 runtime
-add a rename command to the command line interface
-a few minor bugs fixed
This commit is contained in:
AKuHAK 2022-09-15 12:04:48 +03:00
parent 8cdf72b321
commit ddfa6a79f9
12 changed files with 5898 additions and 5761 deletions

182
gui.py
View File

@ -7,13 +7,14 @@
"""Graphical user-interface for mymc.""" """Graphical user-interface for mymc."""
_SCCS_ID = "@(#) mymc gui.py 1.4 12/10/04 18:51:51\n" _SCCS_ID = "@(#) mymc gui.py 1.8 22/02/05 19:20:59\n"
import os import os
import sys import sys
import struct import struct
import cStringIO import cStringIO
import time import time
from functools import partial
# Work around a problem with mixing wx and py2exe # Work around a problem with mixing wx and py2exe
if os.name == "nt" and hasattr(sys, "setdefaultencoding"): if os.name == "nt" and hasattr(sys, "setdefaultencoding"):
@ -26,16 +27,16 @@ import guires
try: try:
import ctypes import ctypes
import mymcsup import mymcicon
D3DXVECTOR3 = mymcsup.D3DXVECTOR3 D3DXVECTOR3 = mymcicon.D3DXVECTOR3
D3DXVECTOR4 = mymcsup.D3DXVECTOR4 D3DXVECTOR4 = mymcicon.D3DXVECTOR4
D3DXVECTOR4_ARRAY3 = mymcsup.D3DXVECTOR4_ARRAY3 D3DXVECTOR4_ARRAY3 = mymcicon.D3DXVECTOR4_ARRAY3
def mkvec4arr3(l): def mkvec4arr3(l):
return D3DXVECTOR4_ARRAY3(*[D3DXVECTOR4(*vec) return D3DXVECTOR4_ARRAY3(*[D3DXVECTOR4(*vec)
for vec in l]) for vec in l])
except ImportError: except ImportError:
mymcsup = None mymcicon = None
lighting_none = {"lighting": False, lighting_none = {"lighting": False,
"vertex_diffuse": False, "vertex_diffuse": False,
@ -89,7 +90,7 @@ camera_near = [0, 3, -6]
camera_flat = [0, 2, -7.5] camera_flat = [0, 2, -7.5]
def get_dialog_units(win): def get_dialog_units(win):
return win.ConvertDialogPointToPixels((1, 1))[0] return win.ConvertDialogToPixels((1, 1))[0]
def single_title(title): def single_title(title):
"""Convert the two parts of an icon.sys title into one string.""" """Convert the two parts of an icon.sys title into one string."""
@ -105,7 +106,7 @@ def _get_icon_resource_as_images(name):
# count = wx.Image_GetImageCount(f, wx.BITMAP_TYPE_ICO) # count = wx.Image_GetImageCount(f, wx.BITMAP_TYPE_ICO)
for i in range(count): for i in range(count):
f.seek(0) f.seek(0)
images.append(wx.ImageFromStream(f, wx.BITMAP_TYPE_ICO, i)) images.append(wx.Image(f, wx.BITMAP_TYPE_ICO, i))
return images return images
def get_icon_resource(name): def get_icon_resource(name):
@ -113,8 +114,8 @@ def get_icon_resource(name):
bundle = wx.IconBundle() bundle = wx.IconBundle()
for img in _get_icon_resource_as_images(name): for img in _get_icon_resource_as_images(name):
bmp = wx.BitmapFromImage(img) bmp = wx.Bitmap(img)
icon = wx.IconFromBitmap(bmp) icon = wx.Icon(bmp)
bundle.AddIcon(icon) bundle.AddIcon(icon)
return bundle return bundle
@ -128,7 +129,7 @@ def get_icon_resource_bmp(name, size):
for img in _get_icon_resource_as_images(name): for img in _get_icon_resource_as_images(name):
sz = (img.GetWidth(), img.GetHeight()) sz = (img.GetWidth(), img.GetHeight())
if sz == size: if sz == size:
return wx.BitmapFromImage(img) return wx.Bitmap(img)
if sz[0] >= size[0] and sz[1] >= size[1]: if sz[0] >= size[0] and sz[1] >= size[1]:
if ((best_size[0] < size[0] or best_size[1] < size[1]) if ((best_size[0] < size[0] or best_size[1] < size[1])
or sz[0] * sz[1] < best_size[0] * best_size[1]): or sz[0] * sz[1] < best_size[0] * best_size[1]):
@ -138,7 +139,7 @@ def get_icon_resource_bmp(name, size):
best = img best = img
best_size = sz best_size = sz
img = best.Rescale(size[0], size[1], wx.IMAGE_QUALITY_HIGH) img = best.Rescale(size[0], size[1], wx.IMAGE_QUALITY_HIGH)
return wx.BitmapFromImage(img) return wx.Bitmap(img)
class dirlist_control(wx.ListCtrl): class dirlist_control(wx.ListCtrl):
@ -150,10 +151,11 @@ class dirlist_control(wx.ListCtrl):
self.evt_select = evt_select self.evt_select = evt_select
wx.ListCtrl.__init__(self, parent, wx.ID_ANY, wx.ListCtrl.__init__(self, parent, wx.ID_ANY,
style = wx.LC_REPORT) style = wx.LC_REPORT)
wx.EVT_LIST_COL_CLICK(self, -1, self.evt_col_click) self.Bind(wx.EVT_LIST_COL_CLICK, self.evt_col_click)
wx.EVT_LIST_ITEM_FOCUSED(self, -1, evt_focus) self.Bind(wx.EVT_LIST_ITEM_FOCUSED, evt_focus)
wx.EVT_LIST_ITEM_SELECTED(self, -1, self.evt_item_selected) self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.evt_item_selected)
wx.EVT_LIST_ITEM_DESELECTED(self, -1, self.evt_item_deselected) self.Bind(wx.EVT_LIST_ITEM_DESELECTED,
self.evt_item_deselected)
def _update_dirtable(self, mc, dir): def _update_dirtable(self, mc, dir):
self.dirtable = table = [] self.dirtable = table = []
@ -182,33 +184,42 @@ class dirlist_control(wx.ListCtrl):
finally: finally:
dir.close() dir.close()
def cmp_dir_name(self, i1, i2): def get_dir_name(self, i):
return self.dirtable[i1][0][8] > self.dirtable[i2][0][8] return self.dirtable[i][0][8]
def cmp_dir_title(self, i1, i2): def get_dir_title(self, i):
return self.dirtable[i1][3] > self.dirtable[i2][3] return self.dirtable[i][3]
def cmp_dir_size(self, i1, i2): def get_dir_size(self, i):
return self.dirtable[i1][2] > self.dirtable[i2][2] return self.dirtable[i][2]
def cmp_dir_modified(self, i1, i2): def get_dir_modified(self, i):
m1 = list(self.dirtable[i1][0][6]) m = list(self.dirtable[i][0][6])
m2 = list(self.dirtable[i2][0][6]) m.reverse()
m1.reverse() return m
m2.reverse()
return m1 > m2 def sort_items(self, key):
def cmp(i1, i2):
a1 = key(i1)
a2 = key(i2)
if a1 < a2:
return -1
if a1 > a2:
return 1
return 0
self.SortItems(cmp)
def evt_col_click(self, event): def evt_col_click(self, event):
col = event.m_col col = event.GetColumn()
if col == 0: if col == 0:
cmp = self.cmp_dir_name key = self.get_dir_name
elif col == 1: elif col == 1:
cmp = self.cmp_dir_size key = self.get_dir_size
elif col == 2: elif col == 2:
cmp = self.cmp_dir_modified key = self.get_dir_modified
elif col == 3: elif col == 3:
cmp = self.cmp_dir_title key = self.get_dir_title
self.SortItems(cmp) self.sort_items(key)
return return
def evt_item_selected(self, event): def evt_item_selected(self, event):
@ -236,34 +247,33 @@ class dirlist_control(wx.ListCtrl):
self.update_dirtable(mc) self.update_dirtable(mc)
empty = len(self.dirtable) == 0 empty = (len(self.dirtable) == 0)
self.Enable(not empty) self.Enable(not empty)
if empty: if empty:
return return
for (i, a) in enumerate(self.dirtable): for (i, a) in enumerate(self.dirtable):
(ent, icon_sys, size, title) = a (ent, icon_sys, size, title) = a
li = self.InsertStringItem(i, ent[8]) li = self.InsertItem(i, ent[8])
self.SetStringItem(li, 1, "%dK" % (size / 1024)) self.SetItem(li, 1, "%dK" % (size / 1024))
m = ent[6] m = ent[6]
m = ("%04d-%02d-%02d %02d:%02d" self.SetItem(li, 2, ("%04d-%02d-%02d %02d:%02d"
% (m[5], m[4], m[3], m[2], m[1])) % (m[5], m[4], m[3], m[2], m[1])))
self.SetStringItem(li, 2, m) self.SetItem(li, 3, single_title(title))
self.SetStringItem(li, 3, single_title(title))
self.SetItemData(li, i) self.SetItemData(li, i)
du = get_dialog_units(self) du = get_dialog_units(self)
for i in range(4): for i in range(4):
self.SetColumnWidth(i, wx.LIST_AUTOSIZE) self.SetColumnWidth(i, wx.LIST_AUTOSIZE)
self.SetColumnWidth(i, self.GetColumnWidth(i) + du) self.SetColumnWidth(i, self.GetColumnWidth(i) + du)
self.SortItems(self.cmp_dir_name) self.sort_items(self.get_dir_name)
class icon_window(wx.Window): class icon_window(wx.Window):
"""Displays a save file's 3D icon. Windows only. """Displays a save file's 3D icon. Windows only.
The rendering of the 3D icon is handled by C++ code in the The rendering of the 3D icon is handled by C++ code in the
mymcsup DLL which subclasses this window. This class mainly mymcicon DLL which subclasses this window. This class mainly
handles configuration options that affect how the 3D icon is handles configuration options that affect how the 3D icon is
displayed. displayed.
""" """
@ -310,40 +320,38 @@ class icon_window(wx.Window):
menu.AppendRadioItem(icon_window.ID_CMD_CAMERA_HIGH, menu.AppendRadioItem(icon_window.ID_CMD_CAMERA_HIGH,
"Camera High") "Camera High")
wx.EVT_MENU(win, icon_window.ID_CMD_ANIMATE, bind_menu = partial(win.Bind, wx.EVT_MENU)
self.evt_menu_animate)
wx.EVT_MENU(win, icon_window.ID_CMD_LIGHT_NONE,
self.evt_menu_light)
wx.EVT_MENU(win, icon_window.ID_CMD_LIGHT_ICON,
self.evt_menu_light)
wx.EVT_MENU(win, icon_window.ID_CMD_LIGHT_ALT1,
self.evt_menu_light)
wx.EVT_MENU(win, icon_window.ID_CMD_LIGHT_ALT2,
self.evt_menu_light)
wx.EVT_MENU(win, icon_window.ID_CMD_CAMERA_FLAT, bind_menu(self.evt_menu_animate, None,
self.evt_menu_camera) icon_window.ID_CMD_ANIMATE)
wx.EVT_MENU(win, icon_window.ID_CMD_CAMERA_DEFAULT,
self.evt_menu_camera) bind_menu_light = partial(bind_menu, self.evt_menu_light, None)
wx.EVT_MENU(win, icon_window.ID_CMD_CAMERA_NEAR, bind_menu_light(icon_window.ID_CMD_LIGHT_NONE)
self.evt_menu_camera) bind_menu_light(icon_window.ID_CMD_LIGHT_ICON)
wx.EVT_MENU(win, icon_window.ID_CMD_CAMERA_HIGH, bind_menu_light(icon_window.ID_CMD_LIGHT_ALT1)
self.evt_menu_camera) bind_menu_light(icon_window.ID_CMD_LIGHT_ALT2)
bind_menu_camera = partial(bind_menu,
self.evt_menu_camera, None)
bind_menu_camera(icon_window.ID_CMD_CAMERA_FLAT)
bind_menu_camera(icon_window.ID_CMD_CAMERA_DEFAULT)
bind_menu_camera(icon_window.ID_CMD_CAMERA_NEAR)
bind_menu_camera(icon_window.ID_CMD_CAMERA_HIGH)
def __init__(self, parent, focus): def __init__(self, parent, focus):
self.failed = False self.failed = False
wx.Window.__init__(self, parent) wx.Window.__init__(self, parent)
if mymcsup == None: if mymcicon == None:
self.failed = True self.failed = True
return return
r = mymcsup.init_icon_renderer(focus.GetHandle(), r = mymcicon.init_icon_renderer(focus.GetHandle(),
self.GetHandle()) self.GetHandle())
if r == -1: if r == -1:
print "init_icon_renderer failed" print "init_icon_renderer failed"
self.failed = True self.failed = True
return return
self.config = config = mymcsup.icon_config() self.config = config = mymcicon.icon_config()
config.animate = True config.animate = True
self.menu = wx.Menu() self.menu = wx.Menu()
@ -351,11 +359,11 @@ class icon_window(wx.Window):
self.set_lighting(self.ID_CMD_LIGHT_ALT2) self.set_lighting(self.ID_CMD_LIGHT_ALT2)
self.set_camera(self.ID_CMD_CAMERA_DEFAULT) self.set_camera(self.ID_CMD_CAMERA_DEFAULT)
wx.EVT_CONTEXT_MENU(self, self.evt_context_menu) self.Bind(wx.EVT_CONTEXT_MENU, self.evt_context_menu)
def __del__(self): def __del__(self):
if mymcsup != None: if mymcicon != None:
mymcsup.delete_icon_renderer() mymcicon.delete_icon_renderer()
def update_menu(self, menu): def update_menu(self, menu):
"""Update the content menu according to the current config.""" """Update the content menu according to the current config."""
@ -371,9 +379,9 @@ class icon_window(wx.Window):
return return
if icon_sys == None or icon == None: if icon_sys == None or icon == None:
r = mymcsup.load_icon(None, 0, None, 0) r = mymcicon.load_icon(None, 0, None, 0)
else: else:
r = mymcsup.load_icon(icon_sys, len(icon_sys), r = mymcicon.load_icon(icon_sys, len(icon_sys),
icon, len(icon)) icon, len(icon))
if r != 0: if r != 0:
print "load_icon", r print "load_icon", r
@ -390,7 +398,7 @@ class icon_window(wx.Window):
config.light_dirs = mkvec4arr3(light_dirs) config.light_dirs = mkvec4arr3(light_dirs)
config.light_colours = mkvec4arr3(light_colours) config.light_colours = mkvec4arr3(light_colours)
config.ambient = D3DXVECTOR4(*ambient) config.ambient = D3DXVECTOR4(*ambient)
if mymcsup.set_config(config) == -1: if mymcicon.set_config(config) == -1:
self.failed = True self.failed = True
def set_lighting(self, id): def set_lighting(self, id):
@ -401,14 +409,14 @@ class icon_window(wx.Window):
if self.failed: if self.failed:
return return
self.config.animate = animate self.config.animate = animate
if mymcsup.set_config(self.config) == -1: if mymcicon.set_config(self.config) == -1:
self.failed = True self.failed = True
def _set_camera(self, camera): def _set_camera(self, camera):
if self.failed: if self.failed:
return return
self.config.camera = mymcsup.D3DXVECTOR3(*camera) self.config.camera = mymcicon.D3DXVECTOR3(*camera)
if mymcsup.set_config(self.config) == -1: if mymcicon.set_config(self.config) == -1:
self.failed = True self.failed = True
def set_camera(self, id): def set_camera(self, id):
@ -460,7 +468,7 @@ class gui_config(wx.Config):
def add_tool(toolbar, id, label, ico): def add_tool(toolbar, id, label, ico):
tbsize = toolbar.GetToolBitmapSize() tbsize = toolbar.GetToolBitmapSize()
bmp = get_icon_resource_bmp(ico, tbsize) bmp = get_icon_resource_bmp(ico, tbsize)
return toolbar.AddLabelTool(id, label, bmp, shortHelp = label) return toolbar.AddTool(id, label, bmp, shortHelp = label)
class gui_frame(wx.Frame): class gui_frame(wx.Frame):
"""The main top level window.""" """The main top level window."""
@ -502,23 +510,25 @@ class gui_frame(wx.Frame):
self.icon_win = None self.icon_win = None
size = (750, 350) size = (750, 350)
if mymcsup == None: if mymcicon == None:
size = (500, 350) size = (500, 350)
wx.Frame.__init__(self, parent, wx.ID_ANY, title, size = size) wx.Frame.__init__(self, parent, wx.ID_ANY, title, size = size)
wx.EVT_CLOSE(self, self.evt_close) self.Bind(wx.EVT_CLOSE, self.evt_close)
self.config = gui_config() self.config = gui_config()
self.title = title self.title = title
self.SetIcons(get_icon_resource("mc4.ico")) self.SetIcons(get_icon_resource("mc4.ico"))
wx.EVT_MENU(self, self.ID_CMD_EXIT, self.evt_cmd_exit) bind_menu = (lambda handler, id:
wx.EVT_MENU(self, self.ID_CMD_OPEN, self.evt_cmd_open) self.Bind(wx.EVT_MENU, handler, None, id))
wx.EVT_MENU(self, self.ID_CMD_EXPORT, self.evt_cmd_export) bind_menu(self.evt_cmd_exit, self.ID_CMD_EXIT)
wx.EVT_MENU(self, self.ID_CMD_IMPORT, self.evt_cmd_import) bind_menu(self.evt_cmd_open, self.ID_CMD_OPEN)
wx.EVT_MENU(self, self.ID_CMD_DELETE, self.evt_cmd_delete) bind_menu(self.evt_cmd_export, self.ID_CMD_EXPORT)
wx.EVT_MENU(self, self.ID_CMD_ASCII, self.evt_cmd_ascii) bind_menu(self.evt_cmd_import, self.ID_CMD_IMPORT)
bind_menu(self.evt_cmd_delete, self.ID_CMD_DELETE)
bind_menu(self.evt_cmd_ascii, self.ID_CMD_ASCII, )
filemenu = wx.Menu() filemenu = wx.Menu()
filemenu.Append(self.ID_CMD_OPEN, "&Open...", filemenu.Append(self.ID_CMD_OPEN, "&Open...",
@ -541,7 +551,7 @@ class gui_frame(wx.Frame):
"Show descriptions in ASCII instead of Shift-JIS") "Show descriptions in ASCII instead of Shift-JIS")
wx.EVT_MENU_OPEN(self, self.evt_menu_open); self.Bind(wx.EVT_MENU_OPEN, self.evt_menu_open);
self.CreateToolBar(wx.TB_HORIZONTAL) self.CreateToolBar(wx.TB_HORIZONTAL)
self.toolbar = toolbar = self.GetToolBar() self.toolbar = toolbar = self.GetToolBar()
@ -554,7 +564,7 @@ class gui_frame(wx.Frame):
toolbar.Realize() toolbar.Realize()
self.statusbar = self.CreateStatusBar(2, self.statusbar = self.CreateStatusBar(2,
style = wx.ST_SIZEGRIP) style = wx.STB_SIZEGRIP)
self.statusbar.SetStatusWidths([-2, -1]) self.statusbar.SetStatusWidths([-2, -1])
panel = wx.Panel(self, wx.ID_ANY, (0, 0)) panel = wx.Panel(self, wx.ID_ANY, (0, 0))
@ -573,7 +583,7 @@ class gui_frame(wx.Frame):
sizer.AddSpacer(5) sizer.AddSpacer(5)
icon_win = None icon_win = None
if mymcsup != None: if mymcicon != None:
icon_win = icon_window(panel, self) icon_win = icon_window(panel, self)
if icon_win.failed: if icon_win.failed:
icon_win.Destroy() icon_win.Destroy()
@ -914,7 +924,7 @@ class gui_frame(wx.Frame):
def run(filename = None): def run(filename = None):
"""Display a GUI for working with memory card images.""" """Display a GUI for working with memory card images."""
wx_app = wx.PySimpleApp() wx_app = wx.App()
frame = gui_frame(None, "mymc", filename) frame = gui_frame(None, "mymc", filename)
return wx_app.MainLoop() return wx_app.MainLoop()

View File

@ -11,7 +11,7 @@ a two level dicitionary look up during compression rather than
LZARI.C's binary search tree. LZARI.C's binary search tree.
""" """
_SCCS_ID = "@(#) mysc lzari.py 1.6 12/10/04 19:07:53\n" _SCCS_ID = "@(#) mymc lzari.py 1.6 12/10/04 19:07:53\n"
import sys import sys
import array import array

17
mymc.py
View File

@ -7,7 +7,7 @@
"""A utility for manipulating PS2 memory card images.""" """A utility for manipulating PS2 memory card images."""
_SCCS_ID = "@(#) mysc mymc.py 1.12 12/10/04 19:09:16\n"[:-1] _SCCS_ID = "@(#) mymc mymc.py 1.13 22/01/15 01:04:45\n"[:-1]
import sys import sys
import os import os
@ -18,6 +18,9 @@ import binascii
import string import string
from errno import EEXIST, EIO from errno import EEXIST, EIO
#import gc
#gc.set_debug(gc.DEBUG_LEAK)
import ps2mc import ps2mc
import ps2save import ps2save
from ps2mc_dir import * from ps2mc_dir import *
@ -328,6 +331,11 @@ def do_setmode(cmd, mc, opts, args, opterr):
ent[0] = value ent[0] = value
mc.set_dirent(arg, ent) mc.set_dirent(arg, ent)
def do_rename(cmd, mc, opts, args, opterr):
if len(args) != 2:
opterr("Old and new names required")
mc.rename(args[0], args[1])
def _get_ps2_title(mc, enc): def _get_ps2_title(mc, enc):
s = mc.get_icon_sys("."); s = mc.get_icon_sys(".");
if s == None: if s == None:
@ -549,7 +557,7 @@ cmd_table = {
"Import save files into the memory card.", "Import save files into the memory card.",
[opt("-i", "--ignore-existing", action="store_true", [opt("-i", "--ignore-existing", action="store_true",
help = ("Ignore files that already exist" help = ("Ignore files that already exist"
"on the image.")), " on the image.")),
opt("-d", "--directory", metavar="DEST", opt("-d", "--directory", metavar="DEST",
help = 'Import to "DEST".')]), help = 'Import to "DEST".')]),
"export": (do_export, "rb", "export": (do_export, "rb",
@ -614,6 +622,10 @@ cmd_table = {
help = "Clear executable flag"), help = "Clear executable flag"),
opt("-X", dest="hex_value", default=None, opt("-X", dest="hex_value", default=None,
help = optparse.SUPPRESS_HELP)]), help = optparse.SUPPRESS_HELP)]),
"rename": (do_rename, "r+b",
"oldname newname",
"Rename a file or directory",
[]),
"dir": (do_dir, "rb", "dir": (do_dir, "rb",
None, None,
"Display save file information.", "Display save file information.",
@ -731,6 +743,7 @@ def main():
except ImportError: except ImportError:
gui = None gui = None
if gui != None: if gui != None:
optparser.destroy()
gui.run() gui.run()
sys.exit(0) sys.exit(0)

258
ps2mc.py
View File

@ -7,13 +7,13 @@
"""Manipulate PS2 memory card images.""" """Manipulate PS2 memory card images."""
_SCCS_ID = "@(#) mysc ps2mc.py 1.10 12/10/04 19:10:35\n" _SCCS_ID = "@(#) mymc ps2mc.py 1.11 22/01/15 01:17:07\n"
import sys import sys
import array import array
import struct import struct
from errno import EACCES, ENOENT, EEXIST, ENOTDIR, EISDIR, EROFS, ENOTEMPTY,\ from errno import EACCES, ENOENT, EEXIST, ENOTDIR, EISDIR, EROFS, ENOTEMPTY,\
ENOSPC, EIO, EBUSY ENOSPC, EIO, EBUSY, EINVAL
import fnmatch import fnmatch
import traceback import traceback
@ -82,6 +82,7 @@ if sys.byteorder == "big":
def unpack_32bit_array(s): def unpack_32bit_array(s):
a = array.array('I', s) a = array.array('I', s)
a.byteswap() a.byteswap()
return a
def pack_32bit_array(a): def pack_32bit_array(a):
a = a[:] a = a[:]
@ -114,6 +115,16 @@ def pack_superblock(sb):
unpack_fat = unpack_32bit_array unpack_fat = unpack_32bit_array
pack_fat = pack_32bit_array pack_fat = pack_32bit_array
def pathname_split(pathname):
if pathname == "":
return (None, False, False)
components = pathname.split("/")
return ([name
for name in components
if name != ""],
components[0] != "",
components[-1] == "")
class lru_cache(object): class lru_cache(object):
def __init__(self, length): def __init__(self, length):
self._lru_list = [[i - 1, None, None, i + 1] self._lru_list = [[i - 1, None, None, i + 1]
@ -539,14 +550,9 @@ class ps2mc_directory(object):
mode = ((new_ent[0] & ~(DF_FILE | DF_DIR | DF_EXISTS)) mode = ((new_ent[0] & ~(DF_FILE | DF_DIR | DF_EXISTS))
| (mode & (DF_FILE | DF_DIR | DF_EXISTS))) | (mode & (DF_FILE | DF_DIR | DF_EXISTS)))
ent[0] = mode ent[0] = mode
if new_ent[1] != None: for i in [1, 3, 6, 7, 8]: # ???, created, modifed, attr
ent[1] = new_ent[1] if new_ent[i] != None:
if new_ent[3] != None: ent[i] = new_ent[i]
ent[3] = new_ent[3]
if new_ent[6] != None:
ent[6] = new_ent[6]
if new_ent[7] != None:
ent[7] = new_ent[7]
self.write_raw_ent(index, ent, False) self.write_raw_ent(index, ent, False)
def close(self): def close(self):
@ -1155,6 +1161,9 @@ class ps2mc(object):
def create_dir_entry(self, parent_dirloc, name, mode): def create_dir_entry(self, parent_dirloc, name, mode):
"""Create a new directory entry in a directory.""" """Create a new directory entry in a directory."""
if name == "":
raise file_not_found, name
# print "@@@ create_dir_ent", parent_dirloc, name # print "@@@ create_dir_ent", parent_dirloc, name
dir_ent = self._dirloc_to_ent(parent_dirloc) dir_ent = self._dirloc_to_ent(parent_dirloc)
dir = self._directory(parent_dirloc, dir_ent[4], dir_ent[2], dir = self._directory(parent_dirloc, dir_ent[4], dir_ent[2],
@ -1262,49 +1271,54 @@ class ps2mc(object):
directory, if it exists, otherwise it's the dirloc the directory, if it exists, otherwise it's the dirloc the
pathname's parent directory, if that exists otherwise pathname's parent directory, if that exists otherwise
it's None. The second component is directory entry it's None. The second component is directory entry
for pathname if it exists, otherwise None. The third for pathname if it exists, otherwise its dummy entry
with the first element set to 0, and the last element
set to the final component of the pathname. The third
is a boolean value that's true if the pathname refers is a boolean value that's true if the pathname refers
a directory.""" a directory."""
components = pathname.split("/") # print "@@@ path_search", repr(pathname)
if len(components) < 1: if pathname == "":
# could return curdir
return (None, None, False) return (None, None, False)
dirloc = self.curdir (components, relative, is_dir) = pathname_split(pathname)
if components[0] == "":
dirloc = (0, 0) dirloc = (0, 0)
if relative:
dirloc = self.curdir
tmpname = "<path_search temp>"
_directory = self._directory
if dirloc == (0, 0): if dirloc == (0, 0):
rootent = self.read_allocatable_cluster(0) rootent = self.read_allocatable_cluster(0)
ent = unpack_dirent(rootent[:PS2MC_DIRENT_LENGTH]) ent = unpack_dirent(rootent[:PS2MC_DIRENT_LENGTH])
dir_cluster = 0 dir_cluster = 0
dir = self._directory(dirloc, dir_cluster, ent[2], dir = _directory(dirloc, dir_cluster, ent[2],
name = "<path_search temp>") name = tmpname)
else: else:
ent = self._dirloc_to_ent(dirloc) ent = self._dirloc_to_ent(dirloc)
dir = self._directory(dirloc, ent[4], ent[2], dir = _directory(dirloc, ent[4], ent[2],
name = "<path_search temp>") name = tmpname)
for s in components: for s in components:
# print "@@@", dirloc, repr(s), dir == None, ent # print "@@@", dirloc, repr(s), dir == None, ent
if s == "":
continue
if dir == None: if dir == None:
# tried to traverse a file or a # tried to traverse a file or a
# non-existent directory # non-existent directory
return (None, None, False) return (None, (0, 0, 0, 0, 0, 0, 0, 0, None),
False)
if s == "" or s == ".": if s == ".":
continue continue
if s == "..": if s == "..":
dotent = dir[0] dotent = dir[0]
dir.close() dir.close()
dirloc = (dotent[4], dotent[5]) dirloc = (dotent[4], dotent[5])
ent = self._dirloc_to_ent(dirloc) ent = self._dirloc_to_ent(dirloc)
dir = self._directory(dirloc, ent[4], ent[2], dir = _directory(dirloc, ent[4], ent[2],
name name = tmpname)
= "<path_search temp>")
continue continue
dir_cluster = ent[4] dir_cluster = ent[4]
@ -1317,29 +1331,34 @@ class ps2mc(object):
dirloc = (dir_cluster, i) dirloc = (dir_cluster, i)
if ent[0] & DF_DIR: if ent[0] & DF_DIR:
dir = self._directory(dirloc, ent[4], ent[2], dir = _directory(dirloc, ent[4], ent[2],
name name = tmpname)
= "<path_search temp>")
if dir != None: if dir != None:
dir.close() dir.close()
is_dir = True
elif ent != None:
is_dir = False
return (dirloc, ent, dir != None) if ent == None:
ent = (0, 0, 0, 0, 0, 0, 0, 0, components[-1])
return (dirloc, ent, is_dir)
def open(self, filename, mode = "r"): def open(self, filename, mode = "r"):
"""Open a file, returning a new file-like object for it.""" """Open a file, returning a new file-like object for it."""
(dirloc, ent, is_dir) = self.path_search(filename) (dirloc, ent, is_dir) = self.path_search(filename)
# print "@@@ open", (dirloc, ent) # print "@@@ open", (dirloc, ent)
if dirloc == None or (ent == None and is_dir): if dirloc == None:
raise path_not_found, filename raise path_not_found, filename
if is_dir: if is_dir:
raise io_error, (EISDIR, "not a regular file", raise io_error, (EISDIR, "not a regular file",
filename) filename)
if ent == None: if ent[0] == 0:
if mode[0] not in "wa": if mode[0] not in "wa":
raise file_not_found, filename raise file_not_found, filename
name = filename.split("/")[-1] name = ent[8]
(dirloc, ent) = self.create_dir_entry(dirloc, name, (dirloc, ent) = self.create_dir_entry(dirloc, name,
DF_FILE | DF_RWX DF_FILE | DF_RWX
| DF_0400); | DF_0400);
@ -1354,7 +1373,7 @@ class ps2mc(object):
(dirloc, ent, is_dir) = self.path_search(filename) (dirloc, ent, is_dir) = self.path_search(filename)
if dirloc == None: if dirloc == None:
raise path_not_found, filename raise path_not_found, filename
if ent == None: if ent[0] == 0:
raise dir_not_found, filename raise dir_not_found, filename
if not is_dir: if not is_dir:
raise io_error, (ENOTDIR, "not a directory", filename) raise io_error, (ENOTDIR, "not a directory", filename)
@ -1364,12 +1383,9 @@ class ps2mc(object):
(dirloc, ent, is_dir) = self.path_search(filename) (dirloc, ent, is_dir) = self.path_search(filename)
if dirloc == None: if dirloc == None:
raise path_not_found, filename raise path_not_found, filename
if ent != None: if ent[0] != 0:
raise io_error, (EEXIST, "directory exists", filename) raise io_error, (EEXIST, "directory exists", filename)
a = filename.split("/") name = ent[8]
name = a.pop()
while name == "":
name = a.pop()
self.create_dir_entry(dirloc, name, DF_DIR | DF_RWX | DF_0400) self.create_dir_entry(dirloc, name, DF_DIR | DF_RWX | DF_0400)
self.flush() self.flush()
@ -1392,7 +1408,7 @@ class ps2mc(object):
(dirloc, ent, is_dir) = self.path_search(filename) (dirloc, ent, is_dir) = self.path_search(filename)
if dirloc == None: if dirloc == None:
raise path_not_found, filename raise path_not_found, filename
if ent == None: if ent[0] == 0:
raise file_not_found, filename raise file_not_found, filename
if is_dir: if is_dir:
if ent[4] == 0: if ent[4] == 0:
@ -1410,7 +1426,7 @@ class ps2mc(object):
(dirloc, ent, is_dir) = self.path_search(filename) (dirloc, ent, is_dir) = self.path_search(filename)
if dirloc == None: if dirloc == None:
raise path_not_found, filename raise path_not_found, filename
if ent == None: if ent[0] == 0:
raise dir_not_found, filename raise dir_not_found, filename
if not is_dir: if not is_dir:
raise io_error, (ENOTDIR, "not a directory", filename) raise io_error, (ENOTDIR, "not a directory", filename)
@ -1423,7 +1439,7 @@ class ps2mc(object):
throwing a error.""" throwing a error."""
(dirloc, ent, is_dir) = self.path_search(filename) (dirloc, ent, is_dir) = self.path_search(filename)
if ent == None: if ent[0] == 0:
return None return None
return ent[0] return ent[0]
@ -1433,7 +1449,7 @@ class ps2mc(object):
(dirloc, ent, is_dir) = self.path_search(filename) (dirloc, ent, is_dir) = self.path_search(filename)
if dirloc == None: if dirloc == None:
raise path_not_found, filename raise path_not_found, filename
if ent == None: if ent[0] == 0:
raise file_not_found, filename raise file_not_found, filename
return ent return ent
@ -1446,16 +1462,101 @@ class ps2mc(object):
(dirloc, ent, is_dir) = self.path_search(filename) (dirloc, ent, is_dir) = self.path_search(filename)
if dirloc == None: if dirloc == None:
raise path_not_found, filename raise path_not_found, filename
if ent == None: if ent[0] == 0:
raise file_not_found, filename raise file_not_found, filename
dir = self._opendir_parent_dirloc(dirloc) dir = self._opendir_parent_dirloc(dirloc, "r+b")
try: try:
new_ent = list(new_ent)
new_ent[8] = None
dir[dirloc[1]] = new_ent dir[dirloc[1]] = new_ent
finally: finally:
dir.close() dir.close()
self.flush() self.flush()
return ent return ent
def is_ancestor(self, dirloc, olddirloc):
while True:
if dirloc == olddirloc:
return True
if dirloc == (0, 0):
return False
dirloc = self._get_parent_dirloc(dirloc)
def rename(self, oldpathname, newpathname):
(olddirloc, oldent, is_dir) = self.path_search(oldpathname)
if olddirloc == None:
raise path_not_found, oldpathname
if oldent[0] == 0:
raise file_not_found, oldpathname
if olddirloc == (0, 0):
raise io_error, (EINVAL,
"cannot rename root directory",
oldpathname)
if olddirloc in self.open_files:
raise io_error, (EBUSY, "cannot rename open file",
newname)
(newparentdirloc, newent, x) = self.path_search(newpathname)
if newparentdirloc == None:
raise path_not_found, newpathname
if newent[0] != 0:
raise io_error, (EEXIST, "file exists", newpathname)
newname = newent[8]
oldparentdirloc = self._get_parent_dirloc(olddirloc)
if oldparentdirloc == newparentdirloc:
dir = self._opendir_dirloc(oldparentdirloc, "r+b")
try:
dir[olddirloc[1]] = (None, None, None, None,
None, None, None, None,
newname)
finally:
dir.close()
return
if is_dir and self.is_ancestor(newparentdirloc, olddirloc):
raise io_error, (EINVAL, "cannot move directory"
" beneath itself", oldpathname)
newparentdir = None
newent = None
try:
tmpmode = (oldent[0] & ~DF_DIR) | DF_FILE
(newdirloc, newent) \
= self.create_dir_entry(newparentdirloc,
newname, tmpmode)
newent[:8] = oldent[:8]
newparentdir = self._opendir_dirloc(newparentdirloc)
newparentdir.write_raw_ent(newdirloc[1], newent, True)
newent = None
oldent[0] &= ~DF_EXISTS
self.update_dirent_all(olddirloc, None, oldent)
except:
if newent != None:
self.delete_dirloc(newdirloc, False,
newpathname)
finally:
if newparentdir != None:
newparentdir.close()
if not is_dir:
return
newdir = self._opendir_dirloc(newdirloc)
try:
dotent = list(newdir[0])
dotent[4:6] = newdirloc
newdir.write_raw_ent(0, dotent, False)
finally:
newdir.close()
def import_save_file(self, sf, ignore_existing, dirname = None): def import_save_file(self, sf, ignore_existing, dirname = None):
"""Copy the contents a ps2_save_file object to a directory. """Copy the contents a ps2_save_file object to a directory.
@ -1468,30 +1569,20 @@ class ps2mc(object):
dir_ent = sf.get_directory() dir_ent = sf.get_directory()
if dirname == None: if dirname == None:
dir_ent_name = dir_ent[8]
dirname = "/" + dir_ent[8] dirname = "/" + dir_ent[8]
else:
if dirname == "":
raise path_not_found, dirname
# remove trailing slashes
dirname = dirname.rstrip("/")
if dirname == "":
dirname = "/"
dir_ent_name = dirname.split("/")[0]
(root_dirloc, ent, is_dir) = self.path_search(dirname) (root_dirloc, ent, is_dir) = self.path_search(dirname)
if root_dirloc == None: if root_dirloc == None:
raise path_not_found, dirname raise path_not_found, dirname
if ent != None: if ent[0] != 0:
if ignore_existing: if ignore_existing:
return False return False
raise io_error, (EEXIST, "directory exists", dirname) raise io_error, (EEXIST, "directory exists", dirname)
name = ent[8]
mode = DF_DIR | (dir_ent[0] & ~DF_FILE) mode = DF_DIR | (dir_ent[0] & ~DF_FILE)
(dir_dirloc, ent) = self.create_dir_entry(root_dirloc, (dir_dirloc, ent) = self.create_dir_entry(root_dirloc,
dir_ent_name, name, mode)
mode)
try: try:
assert dirname != "/" assert dirname != "/"
dirname = dirname + "/" dirname = dirname + "/"
@ -1541,7 +1632,9 @@ class ps2mc(object):
dir = self._opendir_dirloc(root_dirloc, "r+b") dir = self._opendir_dirloc(root_dirloc, "r+b")
try: try:
dir[dir_dirloc[1]] = dir_ent a = dir_ent[:]
a[8] = None # don't change the name
dir[dir_dirloc[1]] = a
finally: finally:
dir.close() dir.close()
@ -1552,7 +1645,7 @@ class ps2mc(object):
(dir_dirloc, dirent, is_dir) = self.path_search(filename) (dir_dirloc, dirent, is_dir) = self.path_search(filename)
if dir_dirloc == None: if dir_dirloc == None:
raise path_not_found, filename raise path_not_found, filename
if dirent == None: if dirent[0] == 0:
raise dir_not_found, filename raise dir_not_found, filename
if not is_dir: if not is_dir:
raise io_error, (ENOTDIR, "not a directory", filename) raise io_error, (ENOTDIR, "not a directory", filename)
@ -1619,7 +1712,7 @@ class ps2mc(object):
(dirloc, ent, is_dir) = self.path_search(dirname) (dirloc, ent, is_dir) = self.path_search(dirname)
if dirloc == None: if dirloc == None:
raise path_not_found, dirname raise path_not_found, dirname
if ent == None: if ent[0] == 0:
raise dir_not_found, dirname raise dir_not_found, dirname
if not is_dir: if not is_dir:
raise io_error, (ENOTDIR, "not a directory", dirname) raise io_error, (ENOTDIR, "not a directory", dirname)
@ -1740,24 +1833,33 @@ class ps2mc(object):
return ret return ret
def _glob(self, dirname, components): def _globdir(self, dirname, components, is_dir):
pattern = components[0] pattern = components[0]
if len(components) == 1: if dirname == "":
if pattern == "": dir = self.dir_open(".")
return [dirname] else:
dir = self.dir_open(dirname) dir = self.dir_open(dirname)
try: try:
return [dirname + ent[8] return [dirname + ent[8]
for ent in dir for ent in dir
if ((ent[0] & DF_EXISTS) if ((ent[0] & DF_EXISTS)
and (not is_dir or (ent[8] & DF_DIR))
and (ent[8] not in [".", ".."] and (ent[8] not in [".", ".."]
or ent[8] == pattern) or ent[8] == pattern)
and fnmatch.fnmatchcase(ent[8], and fnmatch.fnmatchcase(ent[8],
pattern))] pattern))]
finally: finally:
dir.close() dir.close()
if pattern == "":
return self._glob(dirname + "/", components[1:]) def _glob(self, dirname, components, is_dir):
pattern = components[0]
components = components[1:]
if len(components) == 1:
_glob = self._globdir
else:
_glob = self._glob
if dirname == "": if dirname == "":
dir = self.dir_open(".") dir = self.dir_open(".")
else: else:
@ -1774,18 +1876,28 @@ class ps2mc(object):
continue continue
elif not fnmatch.fnmatchcase(name, pattern): elif not fnmatch.fnmatchcase(name, pattern):
continue continue
ret += self._glob(dirname + name + "/", ret += _glob(dirname + name + "/",
components[1:]) components, is_dir)
finally: finally:
dir.close() dir.close()
return ret return ret
def glob(self, pattern): def glob(self, pattern):
if pattern == "": if pattern == "":
return [] return [""]
ret = self._glob("", pattern.split("/")) (components, relative, isdir) = pathname_split(pattern)
if len(components) == 0:
return ["/"]
if relative:
dirname = ""
else:
dirname = "/"
if len(components) == 1:
ret = self._globdir(dirname, components, isdir)
else:
ret = self._glob(dirname, components, isdir)
# print pattern, "->", ret # print pattern, "->", ret
return self._glob("", pattern.split("/")) return ret
def get_icon_sys(self, dirname): def get_icon_sys(self, dirname):
"""Get contents of a directory's icon.sys file, if it exits.""" """Get contents of a directory's icon.sys file, if it exits."""

View File

@ -7,7 +7,7 @@
"""Functions for working with PS2 memory card directory entries.""" """Functions for working with PS2 memory card directory entries."""
_SCCS_ID = "@(#) mysc ps2mc_dir.py 1.4 12/10/04 19:11:08\n" _SCCS_ID = "@(#) mymc ps2mc_dir.py 1.4 12/10/04 19:11:08\n"
import struct import struct
import time import time

View File

@ -10,7 +10,7 @@ Routines for calculating the Hamming codes, a simple form of error
correcting codes (ECC), as used on PS2 memory cards. correcting codes (ECC), as used on PS2 memory cards.
""" """
_SCCS_ID = "@(#) mysc ps2mc_ecc.py 1.4 07/12/17 02:34:04\n" _SCCS_ID = "@(#) mymc ps2mc_ecc.py 1.4 07/12/17 02:34:04\n"
import array import array

View File

@ -7,7 +7,7 @@
# A simple interface for working with various PS2 save file formats. # A simple interface for working with various PS2 save file formats.
# #
_SCCS_ID = "@(#) mysc ps2save.py 1.7 12/10/04 19:17:16\n" _SCCS_ID = "@(#) mymc ps2save.py 1.8 22/01/15 01:25:25\n"
import sys import sys
import os import os
@ -142,6 +142,8 @@ char_substs = {
u'\u254b': u"+", u'\u254b': u"+",
u'\u25a0': u"#", u'\u25a0': u"#",
u'\u25a1': u"#", u'\u25a1': u"#",
u'\u2605': u"*",
u'\u2606': u"*",
u'\u3001': u",", u'\u3001': u",",
u'\u3002': u".", u'\u3002': u".",
u'\u3003': u'"', u'\u3003': u'"',
@ -279,7 +281,7 @@ class ps2_save_file(object):
self.file_data[i] = data self.file_data[i] = data
def get_directory(self): def get_directory(self):
return self.dirent return self.dirent[:]
def get_file(self, i): def get_file(self, i):
if self._defer_load_max: if self._defer_load_max:
@ -589,10 +591,10 @@ _bad_filename_chars = ("".join(map(chr, range(32)))
_bad_filename_repl = "_" * len(_bad_filename_chars) _bad_filename_repl = "_" * len(_bad_filename_chars)
if os.name in ["nt", "os2", "ce"]: if os.name in ["nt", "os2", "ce"]:
_bad_filename_chars += '<>:"/\\|' _bad_filename_chars += '<>:"/\\|?*'
_bad_filename_repl += "()_'___" _bad_filename_repl += "()_'_____"
_bad_filename_chars2 = _bad_filename_chars + "?* " _bad_filename_chars2 = _bad_filename_chars + " "
_bad_filename_repl2 = _bad_filename_repl + "___" _bad_filename_repl2 = _bad_filename_repl + "_"
else: else:
_bad_filename_chars += "/" _bad_filename_chars += "/"
_bad_filename_repl += "_" _bad_filename_repl += "_"

View File

@ -7,7 +7,7 @@
# Simple rounding functions. # Simple rounding functions.
# #
_SCCS_ID = "@(#) mysc round.py 1.3 07/04/17 02:10:27\n" _SCCS_ID = "@(#) mymc round.py 1.3 07/04/17 02:10:27\n"
def div_round_up(a, b): def div_round_up(a, b):
return (a + b - 1) / b return (a + b - 1) / b

View File

@ -1,2 +1,2 @@
MYMC_VERSION_BUILD = r'''6''' MYMC_VERSION_BUILD = r'''7'''
MYMC_VERSION_MAJOR = r'''2''' MYMC_VERSION_MAJOR = r'''2'''