#!/usr/bin/python # Copyright (c) 1999-2002 Thomas Wouters # All rights reserved import sys, string builtin_attrnames = { "1": "OSUCC", "2": "OFAIL", "3": "FAIL", "4": "SUCC", "5": "PASS", "6": "DESC", "7": "SEX", "8": "ODROP", "9": "DROP", "10": "OKILL", "11": "KILL", "12": "ASUCC", "13": "AFAIL", "14": "ADROP", "15": "AKILL", "16": "AUSE", "17": "CHARGES", "18": "RUNOUT", "19": "STARTUP", "20": "ACLONE", "21": "APAY", "22": "OPAY", "23": "PAY", "24": "COST", "25": "MONEY", "26": "LISTEN", "27": "AAHEAR", "28": "AMHEAR", "29": "AHEAR", "30": "LAST", "31": "QUEUEMAX", "32": "IDESC", "33": "ENTER", "34": "OXENTER", "35": "AENTER", "36": "ADESC", "37": "ODESC", "38": "RQUOTA", "39": "ACONNECT", "40": "ADISCONNECT", "41": "ALLOWANCE", "42": "LOCK", "43": "NAME", "44": "COMMENT", "45": "USE", "46": "OUSE", "47": "SEMAPHORE", "48": "TIMEOUT", "49": "QUOTA", "50": "LEAVE", "51": "OLEAVE", "52": "ALEAVE", "53": "OENTER", "54": "OXLEAVE", "55": "MOVE", "56": "OMOVE", "57": "AMOVE", "58": "ALIAS", "59": "LENTER", "60": "LLEAVE", "61": "LPAGE", "62": "LUSE", "63": "LGIVE", "64": "EALIAS", "65": "LALIAS", "66": "EFAIL", "67": "OEFAIL", "68": "AEFAIL", "69": "LFAIL", "70": "OLFAIL", "71": "ALFAIL", "72": "REJECT", "73": "AWAY", "74": "IDLE", "75": "UFAIL", "76": "OUFAIL", "77": "AUFAIL", "78": "PFAIL", "79": "TPORT", "80": "OTPORT", "81": "OXTPORT", "82": "ATPORT", "83": "PRIVS", "84": "LOGINDATA", "85": "LTPORT", "86": "LDROP", "87": "LRECEIVE", "88": "LASTSITE", "89": "INPREFIX", "90": "PREFIX", "91": "INFILTER", "92": "FILTER", "93": "LLINK", "94": "LTELOUT", "95": "FORWARDLIST", "96": "MAILFOLDERS", "97": "LUSER", "98": "LPARENT", "100": "VA", "101": "VB", "102": "VC", "103": "VD", "104": "VE", "105": "VF", "106": "VG", "107": "VH", "108": "VI", "109": "VJ", "110": "VK", "111": "VL", "112": "VM", "113": "VN", "114": "VO", "115": "VP", "116": "VQ", "117": "VR", "118": "VS", "119": "VT", "120": "VU", "121": "VV", "122": "VW", "123": "VX", "124": "VY", "125": "VZ", "129": "GFAIL", "130": "OGFAIL", "131": "AGFAIL", "132": "RFAIL", "133": "ORFAIL", "134": "ARFAIL", "135": "DFAIL", "136": "ODFAIL", "137": "ADFAIL", "138": "TFAIL", "139": "OTFAIL", "140": "ATFAIL", "141": "TOFAIL", "142": "OTOFAIL", "143": "ATOFAIL", "144": "LASTNAME", "145": "HEATCHARS", "146": "MECHPREFID", "200": "LASTPAGE", "201": "MAIL", "202": "AMAIL", "203": "SIGNATURE", "204": "DAILY", "205": "MAILTO", "206": "MAILMSG", "207": "MAILSUB", "208": "MAILCURF", "209": "LSPEECH", "210": "PROGCMD", "211": "MAILFLAGS", "212": "DESTROYER", "213": "LUCK", "214": "MECHSKILLS", "215": "XTYPE", "216": "TACHEIGHT", "217": "LRSHEIGHT", "218": "CONTACTOPT", "219": "MECHNAME", "220": "MECHTYPE", "221": "MECHDESC", "222": "MECHSTATUS", "229": "MWTEMPLATE", "230": "FACTION", "231": "JOB", "232": "RANKNUM", "233": "HEALTH", "234": "ATTRS", "235": "BUILDLINKS", "236": "BUILDENTRANCE", "237": "BUILDCOORD", "238": "ADVS", "239": "PILOTNUM", "240": "MAPVIS", "241": "TZ", "242": "TECHTIME", "243": "ECONPARTS", "244": "SKILLS", "245": "PCEQUIP", "246": "HOURLY", "247": "HISTORY", "250": "VRML_URL", "251": "HTDESC" } class MUXDBLoadError(Exception): "Something went wrong with loading the DB" pass class MUXFlatfileDB: def __init__(self, fp=None): self.db = {} self.dbtop = 0 self.player_record = 0 self.version = 0 self.attrnames = builtin_attrnames.copy() if fp: self.readdb(fp) def readdb(self, fp): self.fp = fp version = self.fp.readline() if not version or version[:2] <> "+X": # Version starts with +X raise MUXDBLoadError, \ "Not a valid DB file (no first line or it doesn't start with '+X')" if version[2:-1] <> "992001": sys.stderr.write("flatfiledb: Warning: possibly wrong flatfile version" "(%d insteas of %s)\n"%( version[2:-1], "992001")) self.version = int(version[2:-1]) nextline = self.fp.readline() if nextline and nextline[:2] == "+S": self.dbtop = int(nextline[2:-1]) nextline = self.fp.readline() if nextline and nextline[:2] == "+N": self.nextattr = int(nextline[2:-1]) nextline = self.fp.readline() if nextline and nextline[:2] == "-R": self.player_record = int(nextline[2:-1]) nextline = self.fp.readline() while nextline and nextline[:2] == "+A": # Attribute defn, next line is the attribute name attr = self.fp.readline() if attr[0] <> '"' or attr[-2] <> '"': sys.stderr.write("Warning: broken +A lines:\n%s%s"%(nextline, attr)) nextline = self.fp.readline() continue # The attribute name is really "flags:name", but we don't care about flags yet attrname = string.split(attr[1:-2], ":", maxsplit=1)[1] # sys.stderr.write("debug: adding attr num %s (%s)\n"%(nextline[2:-1], nextline)) self.attrnames[nextline[2:-1]] = attrname nextline = self.fp.readline() while nextline and nextline[0] == "!": # Next object. nextline = self.readobject(int(nextline[1:-1])) if not nextline or nextline <> "***END OF DUMP***\n": sys.stderr.write("Didn't find ***END OF DUMP***\n") if nextline: sys.stderr.write("The line read was: %s"%nextline) return def _readint(self): line = self.fp.readline()[:-1] try: return int(line) except: sys.stderr.write("warning: something went wrong with reading int: %s\n"%line) return -1 def _readstr(self): return self.fp.readline()[1:-2] def _readattr(self): # If the line doesn't start with '"', it's broken # If the line doesn't *end* with '"', it's continued on the next line line = self.fp.readline()[:-1] # Strip the newline if line[0] <> '"': sys.stderr.write("flatfiledb: Warning: not a valid attr line: %s\n"%line) while line[-1] <> '"': line = line + self.fp.readline()[:-1] return line[1:-1] def readobject(self, objnum): obj = MUXDBObject(objnum) self.db[objnum] = obj # if not vlags & V_ATRNAME obj.name = self._readstr() obj.attrs["NAME"] = obj.name obj.location = self._readint() # if flags & V_ZONE) obj.zone = self._readint() obj.contents = self._readint() obj.exits = self._readint() # if flags & V_LINK) obj.link = self._readint() obj.next = self._readint() # if not flags & V_ATRKEY # Lock attribute... treat as string, even though it should be specially handled obj.lock = self._readstr() obj.attrs["LOCK"] = obj.lock # Ugly hack to work around silly db restriction nextline = self.fp.readline() if string.strip(nextline): obj.owner = int(nextline[:-1]) else: obj.owner = self._readint() # if flags & V_PARENT obj.parent = self._readint() # if not flags & V_ATRMONEY obj.money = self._readint() obj.flags = self._readint() # if flags & V_XFLAGS obj.flags2 = self._readint() # if flags & V_3FLAGS obj.flags3 = self._readint() # if flags & V_POWERS obj.powers = self._readint() obj.powers2 = self._readint() # Read the attributes # This is really 'if not flags & V_GDBM' but we don't do GDBM db's (yet?) nextline = self.fp.readline() while nextline and nextline[0] == ">": attrnum = nextline[1:-1] obj.attrs[self.attrnames[attrnum]] = self._readattr() nextline = self.fp.readline() if nextline <> "<\n": sys.stderr.write("flatfiledb: Warning: attrlist ended with: %s"%nextline) return self.fp.readline() def attr_search(self, str): res = [] for obj in self.db.values(): res.extend(obj.attr_search(str)) return res class MUXDBObject: def __init__(self, objnum): self.objnum = objnum self.attrs = {} def attr_search(self, str): res = [] for attr in self.attrs.keys(): if string.find(self.attrs[attr], str) <> -1: res.append((self.objnum, attr, self.attrs[attr])) return res if __name__ == "__main__": import sys if len(sys.argv) <> 2: print "Usage: python -i flatfiledb.py <flatfile>" sys.exit() db = MUXFlatfileDB(open(sys.argv[1]))