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

17
mymc.py
View File

@ -7,7 +7,7 @@
"""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 os
@ -18,6 +18,9 @@ import binascii
import string
from errno import EEXIST, EIO
#import gc
#gc.set_debug(gc.DEBUG_LEAK)
import ps2mc
import ps2save
from ps2mc_dir import *
@ -328,6 +331,11 @@ def do_setmode(cmd, mc, opts, args, opterr):
ent[0] = value
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):
s = mc.get_icon_sys(".");
if s == None:
@ -549,7 +557,7 @@ cmd_table = {
"Import save files into the memory card.",
[opt("-i", "--ignore-existing", action="store_true",
help = ("Ignore files that already exist"
"on the image.")),
" on the image.")),
opt("-d", "--directory", metavar="DEST",
help = 'Import to "DEST".')]),
"export": (do_export, "rb",
@ -614,6 +622,10 @@ cmd_table = {
help = "Clear executable flag"),
opt("-X", dest="hex_value", default=None,
help = optparse.SUPPRESS_HELP)]),
"rename": (do_rename, "r+b",
"oldname newname",
"Rename a file or directory",
[]),
"dir": (do_dir, "rb",
None,
"Display save file information.",
@ -731,6 +743,7 @@ def main():
except ImportError:
gui = None
if gui != None:
optparser.destroy()
gui.run()
sys.exit(0)

258
ps2mc.py
View File

@ -7,13 +7,13 @@
"""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 array
import struct
from errno import EACCES, ENOENT, EEXIST, ENOTDIR, EISDIR, EROFS, ENOTEMPTY,\
ENOSPC, EIO, EBUSY
ENOSPC, EIO, EBUSY, EINVAL
import fnmatch
import traceback
@ -82,6 +82,7 @@ if sys.byteorder == "big":
def unpack_32bit_array(s):
a = array.array('I', s)
a.byteswap()
return a
def pack_32bit_array(a):
a = a[:]
@ -114,6 +115,16 @@ def pack_superblock(sb):
unpack_fat = unpack_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):
def __init__(self, length):
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 & (DF_FILE | DF_DIR | DF_EXISTS)))
ent[0] = mode
if new_ent[1] != None:
ent[1] = new_ent[1]
if new_ent[3] != None:
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]
for i in [1, 3, 6, 7, 8]: # ???, created, modifed, attr
if new_ent[i] != None:
ent[i] = new_ent[i]
self.write_raw_ent(index, ent, False)
def close(self):
@ -1155,6 +1161,9 @@ class ps2mc(object):
def create_dir_entry(self, parent_dirloc, name, mode):
"""Create a new directory entry in a directory."""
if name == "":
raise file_not_found, name
# print "@@@ create_dir_ent", parent_dirloc, name
dir_ent = self._dirloc_to_ent(parent_dirloc)
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
pathname's parent directory, if that exists otherwise
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
a directory."""
components = pathname.split("/")
if len(components) < 1:
# could return curdir
# print "@@@ path_search", repr(pathname)
if pathname == "":
return (None, None, False)
dirloc = self.curdir
if components[0] == "":
(components, relative, is_dir) = pathname_split(pathname)
dirloc = (0, 0)
if relative:
dirloc = self.curdir
tmpname = "<path_search temp>"
_directory = self._directory
if dirloc == (0, 0):
rootent = self.read_allocatable_cluster(0)
ent = unpack_dirent(rootent[:PS2MC_DIRENT_LENGTH])
dir_cluster = 0
dir = self._directory(dirloc, dir_cluster, ent[2],
name = "<path_search temp>")
dir = _directory(dirloc, dir_cluster, ent[2],
name = tmpname)
else:
ent = self._dirloc_to_ent(dirloc)
dir = self._directory(dirloc, ent[4], ent[2],
name = "<path_search temp>")
dir = _directory(dirloc, ent[4], ent[2],
name = tmpname)
for s in components:
# print "@@@", dirloc, repr(s), dir == None, ent
if s == "":
continue
if dir == None:
# tried to traverse a file or a
# 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
if s == "..":
dotent = dir[0]
dir.close()
dirloc = (dotent[4], dotent[5])
ent = self._dirloc_to_ent(dirloc)
dir = self._directory(dirloc, ent[4], ent[2],
name
= "<path_search temp>")
dir = _directory(dirloc, ent[4], ent[2],
name = tmpname)
continue
dir_cluster = ent[4]
@ -1317,29 +1331,34 @@ class ps2mc(object):
dirloc = (dir_cluster, i)
if ent[0] & DF_DIR:
dir = self._directory(dirloc, ent[4], ent[2],
name
= "<path_search temp>")
dir = _directory(dirloc, ent[4], ent[2],
name = tmpname)
if dir != None:
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"):
"""Open a file, returning a new file-like object for it."""
(dirloc, ent, is_dir) = self.path_search(filename)
# print "@@@ open", (dirloc, ent)
if dirloc == None or (ent == None and is_dir):
if dirloc == None:
raise path_not_found, filename
if is_dir:
raise io_error, (EISDIR, "not a regular file",
filename)
if ent == None:
if ent[0] == 0:
if mode[0] not in "wa":
raise file_not_found, filename
name = filename.split("/")[-1]
name = ent[8]
(dirloc, ent) = self.create_dir_entry(dirloc, name,
DF_FILE | DF_RWX
| DF_0400);
@ -1354,7 +1373,7 @@ class ps2mc(object):
(dirloc, ent, is_dir) = self.path_search(filename)
if dirloc == None:
raise path_not_found, filename
if ent == None:
if ent[0] == 0:
raise dir_not_found, filename
if not is_dir:
raise io_error, (ENOTDIR, "not a directory", filename)
@ -1364,12 +1383,9 @@ class ps2mc(object):
(dirloc, ent, is_dir) = self.path_search(filename)
if dirloc == None:
raise path_not_found, filename
if ent != None:
if ent[0] != 0:
raise io_error, (EEXIST, "directory exists", filename)
a = filename.split("/")
name = a.pop()
while name == "":
name = a.pop()
name = ent[8]
self.create_dir_entry(dirloc, name, DF_DIR | DF_RWX | DF_0400)
self.flush()
@ -1392,7 +1408,7 @@ class ps2mc(object):
(dirloc, ent, is_dir) = self.path_search(filename)
if dirloc == None:
raise path_not_found, filename
if ent == None:
if ent[0] == 0:
raise file_not_found, filename
if is_dir:
if ent[4] == 0:
@ -1410,7 +1426,7 @@ class ps2mc(object):
(dirloc, ent, is_dir) = self.path_search(filename)
if dirloc == None:
raise path_not_found, filename
if ent == None:
if ent[0] == 0:
raise dir_not_found, filename
if not is_dir:
raise io_error, (ENOTDIR, "not a directory", filename)
@ -1423,7 +1439,7 @@ class ps2mc(object):
throwing a error."""
(dirloc, ent, is_dir) = self.path_search(filename)
if ent == None:
if ent[0] == 0:
return None
return ent[0]
@ -1433,7 +1449,7 @@ class ps2mc(object):
(dirloc, ent, is_dir) = self.path_search(filename)
if dirloc == None:
raise path_not_found, filename
if ent == None:
if ent[0] == 0:
raise file_not_found, filename
return ent
@ -1446,16 +1462,101 @@ class ps2mc(object):
(dirloc, ent, is_dir) = self.path_search(filename)
if dirloc == None:
raise path_not_found, filename
if ent == None:
if ent[0] == 0:
raise file_not_found, filename
dir = self._opendir_parent_dirloc(dirloc)
dir = self._opendir_parent_dirloc(dirloc, "r+b")
try:
new_ent = list(new_ent)
new_ent[8] = None
dir[dirloc[1]] = new_ent
finally:
dir.close()
self.flush()
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):
"""Copy the contents a ps2_save_file object to a directory.
@ -1468,30 +1569,20 @@ class ps2mc(object):
dir_ent = sf.get_directory()
if dirname == None:
dir_ent_name = 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)
if root_dirloc == None:
raise path_not_found, dirname
if ent != None:
if ent[0] != 0:
if ignore_existing:
return False
raise io_error, (EEXIST, "directory exists", dirname)
name = ent[8]
mode = DF_DIR | (dir_ent[0] & ~DF_FILE)
(dir_dirloc, ent) = self.create_dir_entry(root_dirloc,
dir_ent_name,
mode)
name, mode)
try:
assert dirname != "/"
dirname = dirname + "/"
@ -1541,7 +1632,9 @@ class ps2mc(object):
dir = self._opendir_dirloc(root_dirloc, "r+b")
try:
dir[dir_dirloc[1]] = dir_ent
a = dir_ent[:]
a[8] = None # don't change the name
dir[dir_dirloc[1]] = a
finally:
dir.close()
@ -1552,7 +1645,7 @@ class ps2mc(object):
(dir_dirloc, dirent, is_dir) = self.path_search(filename)
if dir_dirloc == None:
raise path_not_found, filename
if dirent == None:
if dirent[0] == 0:
raise dir_not_found, filename
if not is_dir:
raise io_error, (ENOTDIR, "not a directory", filename)
@ -1619,7 +1712,7 @@ class ps2mc(object):
(dirloc, ent, is_dir) = self.path_search(dirname)
if dirloc == None:
raise path_not_found, dirname
if ent == None:
if ent[0] == 0:
raise dir_not_found, dirname
if not is_dir:
raise io_error, (ENOTDIR, "not a directory", dirname)
@ -1740,24 +1833,33 @@ class ps2mc(object):
return ret
def _glob(self, dirname, components):
def _globdir(self, dirname, components, is_dir):
pattern = components[0]
if len(components) == 1:
if pattern == "":
return [dirname]
if dirname == "":
dir = self.dir_open(".")
else:
dir = self.dir_open(dirname)
try:
return [dirname + ent[8]
for ent in dir
if ((ent[0] & DF_EXISTS)
and (not is_dir or (ent[8] & DF_DIR))
and (ent[8] not in [".", ".."]
or ent[8] == pattern)
and fnmatch.fnmatchcase(ent[8],
pattern))]
finally:
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 == "":
dir = self.dir_open(".")
else:
@ -1774,18 +1876,28 @@ class ps2mc(object):
continue
elif not fnmatch.fnmatchcase(name, pattern):
continue
ret += self._glob(dirname + name + "/",
components[1:])
ret += _glob(dirname + name + "/",
components, is_dir)
finally:
dir.close()
return ret
def glob(self, pattern):
if pattern == "":
return []
ret = self._glob("", pattern.split("/"))
return [""]
(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
return self._glob("", pattern.split("/"))
return ret
def get_icon_sys(self, dirname):
"""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."""
_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 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.
"""
_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

View File

@ -7,7 +7,7 @@
# 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 os
@ -142,6 +142,8 @@ char_substs = {
u'\u254b': u"+",
u'\u25a0': u"#",
u'\u25a1': u"#",
u'\u2605': u"*",
u'\u2606': u"*",
u'\u3001': u",",
u'\u3002': u".",
u'\u3003': u'"',
@ -279,7 +281,7 @@ class ps2_save_file(object):
self.file_data[i] = data
def get_directory(self):
return self.dirent
return self.dirent[:]
def get_file(self, i):
if self._defer_load_max:
@ -589,10 +591,10 @@ _bad_filename_chars = ("".join(map(chr, range(32)))
_bad_filename_repl = "_" * len(_bad_filename_chars)
if os.name in ["nt", "os2", "ce"]:
_bad_filename_chars += '<>:"/\\|'
_bad_filename_repl += "()_'___"
_bad_filename_chars2 = _bad_filename_chars + "?* "
_bad_filename_repl2 = _bad_filename_repl + "___"
_bad_filename_chars += '<>:"/\\|?*'
_bad_filename_repl += "()_'_____"
_bad_filename_chars2 = _bad_filename_chars + " "
_bad_filename_repl2 = _bad_filename_repl + "_"
else:
_bad_filename_chars += "/"
_bad_filename_repl += "_"

View File

@ -7,7 +7,7 @@
# 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):
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'''