#!/usr/bin/env python import os, re, struct import cksum, arclib, fsutil, ndscodes from ndsheader import NdsHeader """The parse_* filenames are ugly hacks and should never be used. I am seriously thinking of removing them and using CRC only w/ fallback on header information (both nds and gba have somewhat wellknown UID's in the headers.""" def parse_clean_name(filename, extension='', group='', region='', number=''): filename = filename.replace(extension, '') filename = filename.strip('.').strip() if number: if isinstance(number, int): filename = filename.replace('%04d' % number, '') else: filename = filename.replace(number, '') filename = filename.strip().strip('-').strip() filename = filename.replace('(%s)' % group, '') filename = filename.replace('(%s)' % region, '') filename = filename.strip() return filename def parse_region(filename): """Parse the region out of a meta/file name.""" rre = re.compile('\((?P('+ndscodes.region_keys+'))\).*?(\((?P[^\)]+)\))?') m = rre.search(filename) if m and m.groupdict().has_key('region'): return m.group('region') return '' def parse_num(filename): """Parse the number out of a meta/file name.""" nre = re.compile(r'^(?P(\d+)|x{4})') m = nre.search(filename) if m and m.groupdict().has_key('num'): try: return int(m.group('num')) except: return m.group('num') return '' def parse_group(filename): """Parse the release group out of a meta/file name.""" gre = re.compile('\((?P('+ndscodes.region_keys+'))\).*?(\((?P[^\)]+)\))?') m = gre.search(filename) if m and m.groupdict().has_key('group'): return m.group('group') return '' class Rom: def __init__(self, path): self.path = fsutil.normalize_path(path) self.dirpath = os.path.dirname(path) self.filename = os.path.basename(self.path) self.number = parse_num(self.filename) self.region = parse_region(self.filename) self.group = parse_group(self.filename) self.extension = fsutil.extension_of(self.filename) self.clean_name = parse_clean_name(self.filename, self.extension, group=self.group, region=self.region, number=self.number) self.name = self.clean_name self.crc = None self.header = None def get_crc_from_header(self): # if the file type was 'zip' or 'rar', we can get the # crc32 of the file from the header of the zip/rar file info = arclib.get_info(self.path, '*.nds') if not info: return '' return arclib.crc(info[0]) def get_crc_and_header(self): f = self.get_file() if f: self.crc = cksum.CheckSum(f).getfilecrc() f.seek(0) self.header = NdsHeader(f) f.close() del f def get_crc(self): if self.crc: return self.crc if self.extension.lower() in ['zip', 'rar']: self.crc = self.get_crc_from_header() return self.crc f = self.get_file() if f: self.crc = cksum.CheckSum(f).getfilecrc() f.close() del f return self.crc def get_header(self): if self.header: return self.header f = self.get_file() if f: self.header = NdsHeader(f) f.close() del f return self.header def get_file(self, mode='rb'): # NOTE: mode of os.tmpfile() is *always* 'wb' if self.extension in ('gba', 'nds'): return file(self.path, mode) elif self.extension in arclib.supported_extensions: return arclib.extract(self.path, '*.nds')[0] else: print 'unrecognized filetype: %s (%s)' % (self.path, self.extension) return False def __str__(self): s = "rom file \"%s\"\n\tname: %s\n\trelease no.: %s\n\tclean: %s\n\tformat: %s" % (self.filename, self.clean_name, self.number, self.clean_name, self.extension) if self.crc: s += "\n\tcrc: %s" % (self.crc) return s def __repr__(self): return "" % self.filename