Advertisement
Corosus

Untitled

Sep 25th, 2011
112
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 51.74 KB | None | 0 0
  1. # -*- coding: utf-8 -*-
  2. """
  3. Created on Fri Apr  8 16:36:26 2011
  4.  
  5. @author: ProfMobius & Searge
  6. @version: v1.2
  7. """
  8. import fnmatch
  9. import warnings
  10. warnings.simplefilter('ignore')
  11. import sys
  12. import logging
  13. import os, shutil, zipfile, glob, csv, re, subprocess
  14. import ConfigParser
  15. import urllib, urllib2
  16. from filehandling.srgsexport import writesrgsfromcsvs
  17. from pylibs.annotate_gl_constants import annotate_file
  18. from pylibs.whereis import whereis
  19. from hashlib import md5
  20.  
  21.  
  22. class Commands(object):
  23.     """Contains the commands and initialisation for a full mcp run"""
  24.  
  25.     MCPVersion = '4.3'
  26.     _instance  = None    #Small trick to create a singleton
  27.     _single    = False   #Small trick to create a singleton
  28.     _default_config = 'conf/mcp.cfg'
  29.  
  30.     def __init__(self, conffile=None):
  31.         #HINT: This is for the singleton pattern. If we already did __init__, we skip it
  32.         if     Commands._single:return
  33.         if not Commands._single:Commands._single=True
  34.  
  35.         if sys.version_info[0] == 3:
  36.             print ('ERROR : Python3 is not supported yet.')
  37.             sys.exit(1)
  38.  
  39.         self.conffile = conffile
  40.  
  41.         self.readconf()
  42.         self.checkfolders()
  43.  
  44.         self.startlogger()
  45.  
  46.         self.logger.info('== MCP v%s =='%self.MCPVersion)
  47.  
  48.         if   'linux'  in sys.platform:   self.osname='linux'
  49.         elif 'darwin' in sys.platform:   self.osname='osx'
  50.         elif sys.platform[0:3] == 'win': self.osname='win'
  51.         else :
  52.             self.logger.error('OS not supported : %s'%sys.platform)
  53.             sys.exit(0)
  54.  
  55.         self.logger.debug('OS : %s'%sys.platform)
  56.         self.checkjava()
  57.         self.readcommands()
  58.  
  59.     #HINT: This is for the singleton pattern. We either create a new instance or return the current one
  60.     def __new__(cls, *args, **kwargs):
  61.         if not cls._instance:
  62.             cls._instance = super(Commands, cls).__new__(cls, *args, **kwargs)
  63.         return cls._instance
  64.  
  65.     def readcommands(self):
  66.         self.patcher     = self.config.get('COMMANDS', 'Patcher' ).replace('/',os.sep).replace('\\',os.sep)
  67.         self.jadretro    = self.config.get('COMMANDS', 'JadRetro').replace('/',os.sep).replace('\\',os.sep)
  68.         self.jad         = self.config.get('COMMANDS', 'Jad%s'%self.osname     ).replace('/',os.sep).replace('\\',os.sep)
  69.         self.cmdjad      = self.config.get('COMMANDS', 'CmdJad%s'%self.osname  ).replace('/',os.sep).replace('\\',os.sep)
  70.         self.cmdpatch    = self.config.get('COMMANDS', 'CmdPatch%s'%self.osname).replace('/',os.sep).replace('\\',os.sep)
  71.         self.fernflower  = self.config.get('COMMANDS', 'Fernflower').replace('/',os.sep).replace('\\',os.sep)
  72.         self.exceptor    = self.config.get('COMMANDS', 'Exceptor').replace('/',os.sep).replace('\\',os.sep)
  73.  
  74.         self.cmdrg         = self.config.get('COMMANDS', 'CmdRG',         raw=1)%self.cmdjava
  75.         self.cmdrgreobf    = self.config.get('COMMANDS', 'CmdRGReobf',    raw=1)%self.cmdjava
  76.         self.cmdjadretro   = self.config.get('COMMANDS', 'CmdJadretro',   raw=1)%self.cmdjava
  77.         self.cmdrecompclt  = self.config.get('COMMANDS', 'CmdRecompClt',  raw=1)%self.cmdjavac
  78.         self.cmdrecompsrv  = self.config.get('COMMANDS', 'CmdRecompSrv',  raw=1)%self.cmdjavac
  79.         self.cmdstartsrv   = self.config.get('COMMANDS', 'CmdStartSrv',   raw=1)%self.cmdjava
  80.         self.cmdstartclt   = self.config.get('COMMANDS', 'CmdStartClt',   raw=1)%self.cmdjava
  81.         self.cmdfernflower = self.config.get('COMMANDS', 'CmdFernflower', raw=1)%self.cmdjava
  82.         self.cmdexceptor   = self.config.get('COMMANDS', 'CmdExceptor',   raw=1)%self.cmdjava
  83.  
  84.     def startlogger(self):
  85.         self.logger = logging.getLogger('MCPLog')
  86.         self.logger.setLevel(logging.DEBUG)
  87.         # create file handler which logs even debug messages
  88.         fh = logging.FileHandler(filename=self.mcplogfile, mode='w')
  89.         fh.setLevel(logging.DEBUG)
  90.         # create console handler with a higher log level
  91.         ch = logging.StreamHandler()
  92.         ch.setLevel(logging.INFO)
  93.         #File output of everything Warning or above
  94.         eh = logging.FileHandler(filename=self.mcperrlogfile, mode='w')
  95.         eh.setLevel(logging.WARNING)
  96.         # create formatter and add it to the handlers
  97.         formatterconsole = logging.Formatter('%(message)s')
  98.         ch.setFormatter(formatterconsole)
  99.         formatterfile = logging.Formatter('%(asctime)s - %(module)11s.%(funcName)s - %(levelname)s - %(message)s',datefmt='%Y-%m-%d %H:%M')
  100.         fh.setFormatter(formatterfile)
  101.         eh.setFormatter(formatterfile)
  102.         # add the handlers to logger
  103.         self.logger.addHandler(ch)
  104.         self.logger.addHandler(fh)
  105.         self.logger.addHandler(eh)
  106.  
  107.         #HINT: SECONDARY LOGGER FOR CLIENT & SERVER
  108.         self.loggermc = logging.getLogger('MCRunLog')
  109.         self.loggermc.setLevel(logging.DEBUG)
  110.         chmc = logging.StreamHandler()
  111.         chmc.setLevel(logging.DEBUG)
  112.         formatterconsolemc = logging.Formatter('[%(asctime)s] %(message)s',datefmt='%H:%M')
  113.         chmc.setFormatter(formatterconsolemc)
  114.         # add the handlers to logger
  115.         self.loggermc.addHandler(chmc)
  116.  
  117.     def readconf(self):
  118.         """Read the configuration file to setup some basic paths"""
  119.         config = ConfigParser.SafeConfigParser()
  120.         config.readfp(open(self._default_config))
  121.         if self.conffile is not None:
  122.             config.read(self.conffile)
  123.         self.config = config
  124.  
  125.         #HINT: We read the directories for cleanup
  126.         try:
  127.             self.dirtemp  = config.get('DEFAULT','DirTemp')
  128.             self.dirsrc   = config.get('DEFAULT','DirSrc')
  129.             self.dirlogs  = config.get('DEFAULT','DirLogs')
  130.             self.dirbin   = config.get('DEFAULT','DirBin')
  131.             self.dirjars  = config.get('DEFAULT','DirJars')
  132.             self.dirreobf = config.get('DEFAULT','DirReobf')
  133.             self.dirlib   = config.get('DEFAULT','DirLib')
  134.             self.dirffout = config.get('DEFAULT','DirFFOut')
  135.         except ConfigParser.NoOptionError:
  136.             pass
  137.  
  138.         #HINT: We read the position of the CSV files
  139.         self.csvclasses = config.get('CSV', 'Classes')
  140.         self.csvmethods = config.get('CSV', 'Methods')
  141.         self.csvfields  = config.get('CSV', 'Fields')
  142.  
  143.         #HINT: We read the names of the SRG output
  144.         self.srgsclient = config.get('SRGS', 'Client')
  145.         self.srgsserver = config.get('SRGS', 'Server')
  146.  
  147.         #HINT: We read the position of the jar files
  148.         self.dirnatives = config.get('JAR', 'DirNatives')
  149.         self.jarclient  = config.get('JAR', 'Client')
  150.         self.jarserver  = config.get('JAR', 'Server')
  151.         self.md5jarclt  = config.get('JAR', 'MD5Client')
  152.         self.md5jarsrv  = config.get('JAR', 'MD5Server')
  153.  
  154.         #HINT: We read keys relevant to retroguard
  155.         self.retroguard       = config.get('RETROGUARD', 'Location')
  156.         self.rgconfig         = config.get('RETROGUARD', 'RetroConf')
  157.         self.rgclientconf     = config.get('RETROGUARD', 'ClientConf')
  158.         self.rgserverconf     = config.get('RETROGUARD', 'ServerConf')
  159.         self.rgclientout      = config.get('RETROGUARD', 'ClientOut')
  160.         self.rgserverout      = config.get('RETROGUARD', 'ServerOut')
  161.         self.rgclientlog      = config.get('RETROGUARD', 'ClientLog')
  162.         self.rgserverlog      = config.get('RETROGUARD', 'ServerLog')
  163.         self.rgclientdeoblog  = config.get('RETROGUARD', 'ClientDeobLog')
  164.         self.rgserverdeoblog  = config.get('RETROGUARD', 'ServerDeobLog')
  165.  
  166.         #HINT: We read keys relevant to exceptor
  167.         self.xclientconf = config.get('EXCEPTOR', 'XClientCfg')
  168.         self.xserverconf = config.get('EXCEPTOR', 'XServerCfg')
  169.         self.xclientout  = config.get('EXCEPTOR', 'XClientOut')
  170.         self.xserverout  = config.get('EXCEPTOR', 'XServerOut')
  171.         self.xclientlog  = config.get('EXCEPTOR', 'XClientLog')
  172.         self.xserverlog  = config.get('EXCEPTOR', 'XServerLog')
  173.  
  174.         #HINT: We read keys relevant to fernflower
  175.         self.ffclientconf = config.get('DECOMPILE', 'FFClientConf')
  176.         self.ffserverconf = config.get('DECOMPILE', 'FFServerConf')
  177.         self.ffclientout  = config.get('DECOMPILE', 'FFClientOut')
  178.         self.ffserverout  = config.get('DECOMPILE', 'FFServerOut')
  179.         self.ffclientsrc  = config.get('DECOMPILE', 'FFClientSrc')
  180.         self.ffserversrc  = config.get('DECOMPILE', 'FFServerSrc')
  181.         self.ffsource     = config.get('DECOMPILE', 'FFSource')
  182.  
  183.         #HINT: We read the output directories
  184.         self.binouttmp    = config.get('OUTPUT', 'BinOut')
  185.         self.binclienttmp = config.get('OUTPUT', 'BinClient')
  186.         self.binservertmp = config.get('OUTPUT', 'BinServer')
  187.         self.srcclient    = config.get('OUTPUT', 'SrcClient')
  188.         self.srcserver    = config.get('OUTPUT', 'SrcServer')
  189.  
  190.         #HINT: The packages on the client & server side
  191.         self.pkgclient = config.get('PACKAGES', 'PkgClient').split(',')
  192.         self.pkgserver = config.get('PACKAGES', 'PkgServer').split(',')
  193.  
  194.         #HINT: Patcher related configs
  195.         self.patchclient   = config.get('PATCHES', 'PatchClient')
  196.         self.patchserver   = config.get('PATCHES', 'PatchServer')
  197.         self.patchtemp     = config.get('PATCHES', 'PatchTemp')
  198.         self.ffpatchclient = config.get('PATCHES', 'FFPatchClient')
  199.         self.ffpatchserver = config.get('PATCHES', 'FFPatchServer')
  200.  
  201.         #HINT: Recompilation related configs
  202.         try:
  203.             self.binclient    = config.get('RECOMPILE','BinClient')
  204.             self.binserver    = config.get('RECOMPILE','BinServer')
  205.             self.cpathclient  = config.get('RECOMPILE','ClassPathClient').split(',')
  206.             self.fixesclient  = config.get('RECOMPILE','ClientFixes')
  207.             self.cpathserver  = config.get('RECOMPILE','ClassPathServer').split(',')
  208.         except ConfigParser.NoOptionError:
  209.             pass
  210.  
  211.         #HINT: Reobf related configs
  212.         self.saffxclient    = config.get('REOBF', 'SAFFXClient')
  213.         self.saffxserver    = config.get('REOBF', 'SAFFXServer')
  214.         self.md5client      = config.get('REOBF', 'MD5Client')
  215.         self.md5server      = config.get('REOBF', 'MD5Server')
  216.         self.md5reobfclient = config.get('REOBF', 'MD5PreReobfClient')
  217.         self.md5reobfserver = config.get('REOBF', 'MD5PreReobfServer')
  218.         self.reobsrgclient  = config.get('REOBF', 'ObfSRGClient')
  219.         self.reobsrgserver  = config.get('REOBF', 'ObfSRGServer')
  220.         self.cmpjarclient   = config.get('REOBF', 'RecompJarClient')
  221.         self.cmpjarserver   = config.get('REOBF', 'RecompJarServer')
  222.         self.reobfjarclient = config.get('REOBF', 'ObfJarClient')
  223.         self.reobfjarserver = config.get('REOBF', 'ObfJarServer')
  224.         self.nullpkg        = config.get('REOBF', 'NullPkg')
  225.         self.ignorepkg      = config.get('REOBF', 'IgnorePkg').split(',')
  226.         self.dirreobfclt    = config.get('REOBF', 'ReobfDirClient')
  227.         self.dirreobfsrv    = config.get('REOBF', 'ReobfDirServer')
  228.         self.clientreoblog  = config.get('REOBF', 'ReobfClientLog')
  229.         self.serverreoblog  = config.get('REOBF', 'ReobfServerLog')
  230.         self.fixsound       = config.get('REOBF', 'FixSound')
  231.         self.fixstart       = config.get('REOBF', 'FixStart')
  232.  
  233.         self.mcplogfile     = config.get('MCP', 'LogFile')
  234.         self.mcperrlogfile  = config.get('MCP', 'LogFileErr')
  235.  
  236.         try:
  237.             self.rgreobconfig   = config.get('RETROGUARD', 'RetroReobConf')
  238.             self.rgclientreobconf = config.get('RETROGUARD', 'ClientReobConf')
  239.             self.rgserverreobconf = config.get('RETROGUARD', 'ServerReobConf')
  240.         except ConfigParser.NoOptionError:
  241.             pass
  242.  
  243.     def creatergcfg(self):
  244.         """Create the files necessary for both deobf and obf RetroGuard"""
  245.         self.createsinglergcfg()
  246.         self.createsinglergcfg(True)
  247.  
  248.     def createsinglergcfg(self, reobf=False):
  249.         """Create the files necessary for RetroGuard"""
  250.         if reobf:
  251.             rgout = open(self.rgreobconfig, 'wb')
  252.         else:
  253.             rgout = open(self.rgconfig, 'wb')
  254.         rgout.write('.option Application\n')
  255.         rgout.write('.option Applet\n')
  256.         rgout.write('.option Repackage\n')
  257.  
  258.         rgout.write('.option Annotations\n')
  259.         rgout.write('.option MapClassString\n')
  260.         rgout.write('.attribute LineNumberTable\n')
  261.         rgout.write('.attribute EnclosingMethod\n')
  262.         rgout.write('.attribute Deprecated\n')
  263.  
  264.         if reobf:
  265.             # this is obfuscated in vanilla and breaks the patches
  266.             rgout.write('.attribute SourceFile\n')
  267.  
  268.             # this will mess up the patches with mods:
  269.             rgout.write('.attribute LocalVariableTable\n')
  270.  
  271.             # rg doesn't remap generic signatures:
  272.             rgout.write('.option Generic\n')
  273.             rgout.write('.attribute LocalVariableTypeTable\n')
  274.  
  275.         rgout.close()
  276.  
  277.         if reobf:
  278.             rgout = open(self.rgclientreobconf,'w')
  279.         else:
  280.             rgout = open(self.rgclientconf,'w')
  281.         rgout.write('%s = %s\n'%('startindex', '0'))
  282.         rgout.write('%s = %s\n'%('input', self.jarclient))
  283.         rgout.write('%s = %s\n'%('output', self.rgclientout))
  284.         rgout.write('%s = %s\n'%('reobinput', self.cmpjarclient))
  285.         rgout.write('%s = %s\n'%('reoboutput', self.reobfjarclient))
  286.         if reobf:
  287.             rgout.write('%s = %s\n'%('script', self.rgreobconfig))
  288.         else:
  289.             rgout.write('%s = %s\n'%('script', self.rgconfig))
  290.         rgout.write('%s = %s\n'%('log', self.rgclientlog))
  291.         rgout.write('%s = %s\n'%('packages', self.srgsclient))
  292.         rgout.write('%s = %s\n'%('classes', self.srgsclient))
  293.         rgout.write('%s = %s\n'%('fields', self.srgsclient))
  294.         rgout.write('%s = %s\n'%('methods', self.srgsclient))
  295.         rgout.write('%s = %s\n'%('reob', self.reobsrgclient))
  296.         rgout.write('%s = %s\n'%('nplog', self.rgclientdeoblog))
  297.         rgout.write('%s = %s\n'%('rolog', self.clientreoblog))
  298.         for pkg in self.ignorepkg:
  299.             rgout.write('%s = %s\n'%('protectedpackage', pkg))
  300.         rgout.close()
  301.  
  302.         if reobf:
  303.             rgout = open(self.rgserverreobconf,'w')
  304.         else:
  305.             rgout = open(self.rgserverconf,'w')
  306.         rgout.write('%s = %s\n'%('startindex', '0'))
  307.         rgout.write('%s = %s\n'%('input', self.jarserver))
  308.         rgout.write('%s = %s\n'%('output', self.rgserverout))
  309.         rgout.write('%s = %s\n'%('reobinput', self.cmpjarserver))
  310.         rgout.write('%s = %s\n'%('reoboutput', self.reobfjarserver))
  311.         if reobf:
  312.             rgout.write('%s = %s\n'%('script', self.rgreobconfig))
  313.         else:
  314.             rgout.write('%s = %s\n'%('script', self.rgconfig))
  315.         rgout.write('%s = %s\n'%('log', self.rgserverlog))
  316.         rgout.write('%s = %s\n'%('packages', self.srgsserver))
  317.         rgout.write('%s = %s\n'%('classes', self.srgsserver))
  318.         rgout.write('%s = %s\n'%('fields', self.srgsserver))
  319.         rgout.write('%s = %s\n'%('methods', self.srgsserver))
  320.         rgout.write('%s = %s\n'%('reob', self.reobsrgserver))
  321.         rgout.write('%s = %s\n'%('nplog', self.rgserverdeoblog))
  322.         rgout.write('%s = %s\n'%('rolog', self.serverreoblog))
  323.         for pkg in self.ignorepkg:
  324.             rgout.write('%s = %s\n'%('protectedpackage', pkg))
  325.         rgout.close()
  326.  
  327.     def createsrgs(self, side):
  328.         """Write the srgs files."""
  329.         sidelk = {0:self.srgsclient, 1:self.srgsserver}
  330.         writesrgsfromcsvs(self.csvclasses, self.csvmethods, self.csvfields, sidelk[side], side)
  331.  
  332.     def createsaffx(self, side):
  333.         """Creates the reobfuscation tables"""
  334.         saffxlk = {0:self.saffxclient,    1:self.saffxserver}
  335.  
  336.         ff = open(saffxlk[side], 'w')
  337.  
  338.         ff.write('[OPTIONS]\n')
  339.         ff.write('strip_package net/minecraft/src\n\n')
  340.  
  341.         #HINT: We read the data from the CSVs and dump it in another formating to a SAFFX file
  342.         methodsreader = csv.DictReader(open(self.csvmethods, 'r'), delimiter=',',quotechar='"', quoting=csv.QUOTE_ALL)
  343.         fieldsreader  = csv.DictReader(open(self.csvfields,  'r'), delimiter=',',quotechar='"', quoting=csv.QUOTE_ALL)
  344.         classesreader = csv.DictReader(open(self.csvclasses, 'r'), delimiter=',',quotechar='"', quoting=csv.QUOTE_ALL)
  345.  
  346.         ff.write('[CLASSES]\n')
  347.         for row in classesreader:
  348.             if row['name'] == 'Start': continue
  349.             if int(row['side']) == side:
  350.                 ff.write('%s/%s %s\n'%(row['package'], row['name'], row['notch']))
  351.  
  352.         ff.write('[METHODS]\n')
  353.         for row in methodsreader:
  354.             if row['classname'] == 'Start': continue
  355.             if int(row['side']) == side:
  356.                 ff.write('%s/%s/%s %s %s\n'%(row['package'], row['classname'], row['name'], row['notchsig'], row['notch']))
  357.  
  358.         ff.write('[FIELDS]\n')
  359.         for row in fieldsreader:
  360.             if row['classname'] == 'Start': continue
  361.             if int(row['side']) == side:
  362.                 ff.write('%s/%s/%s %s\n'%(row['package'], row['classname'], row['name'], row['notch']))
  363.  
  364.         ff.close()
  365.  
  366.     def checkjava(self):
  367.         """Check for java and setup the proper directory if needed"""
  368.         results = []
  369.         if self.osname == 'win':
  370.             if subprocess.call('javac.exe 1>NUL 2>NUL', shell=True) == 2:
  371.                 self.cmdjava  = 'java.exe'
  372.                 self.cmdjavac = 'javac.exe'
  373.                 return
  374.             else:
  375.                 import _winreg
  376.                 for flag in [_winreg.KEY_WOW64_64KEY, _winreg.KEY_WOW64_32KEY]:
  377.                     try:
  378.                         k = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, "Software\\JavaSoft\\Java Development Kit", 0, _winreg.KEY_READ | flag)
  379.                         version,_ = _winreg.QueryValueEx(k, "CurrentVersion")
  380.                         k.Close()
  381.                         k = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, "Software\\JavaSoft\\Java Development Kit\\%s" % version, 0, _winreg.KEY_READ | flag)
  382.                         path,_ = _winreg.QueryValueEx(k, "JavaHome")
  383.                         k.Close()
  384.                         if subprocess.call('"%s" 1>NUL 2>NUL' % os.path.join(path, "bin", "javac.exe"), shell=True) == 2:
  385.                             self.cmdjava = '"%s"' % os.path.join(path, "bin", "java.exe")
  386.                             self.cmdjavac = '"%s"' % os.path.join(path, "bin", "javac.exe")
  387.                             return
  388.                     except OSError:
  389.                         pass
  390.  
  391.                 if 'ProgramW6432' in os.environ:
  392.                     results.extend(whereis('javac.exe', os.environ['ProgramW6432']))
  393.                 if 'ProgramFiles' in os.environ:
  394.                     results.extend(whereis('javac.exe', os.environ['ProgramFiles']))
  395.                 if 'ProgramFiles(x86)' in os.environ:
  396.                     results.extend(whereis('javac.exe', os.environ['ProgramFiles(x86)']))
  397.  
  398.         if self.osname  in ['linux','osx']:
  399.             if subprocess.call('javac 1> /dev/null 2> /dev/null', shell=True) == 2:
  400.                 self.cmdjava  = 'java'
  401.                 self.cmdjavac = 'javac'
  402.                 return
  403.             else:
  404.                 results.extend(whereis('javac', '/usr/bin'))
  405.                 results.extend(whereis('javac', '/usr/local/bin'))
  406.                 results.extend(whereis('javac', '/opt'))
  407.  
  408.         if not results:
  409.             self.logger.error('Java SDK is not installed ! Please install java SDK from ???')
  410.             sys.exit(0)
  411.         else:
  412.             if self.osname == 'win':
  413.                 self.cmdjavac = '"%s"'%os.path.join(results[0],'javac.exe')
  414.                 self.cmdjava  = '"%s"'%os.path.join(results[0],'java.exe')
  415.             if self.osname  in ['linux','osx']:
  416.                 self.cmdjavac = os.path.join(results[0],'javac')
  417.                 self.cmdjava  = os.path.join(results[0],'java')
  418.  
  419.     def checkjars(self, side):
  420.         jarlk     = {0:self.jarclient, 1:self.jarserver}
  421.         md5jarlk  = {0:self.md5jarclt, 1:self.md5jarsrv}
  422.  
  423.         if not os.path.exists(jarlk[side]):
  424.             self.logger.warning('!! Missing jar file %s. Aborting !!'%jarlk[side])
  425.             return False
  426.  
  427.         md5jar = md5(open(jarlk[side],'rb').read()).hexdigest()
  428.  
  429.         if not md5jar == md5jarlk[side]:
  430.             self.logger.warn('!! Modified jar detected. Unpredictable results !!')
  431.             self.logger.debug('md5: ' + md5jar)
  432.  
  433.         return True
  434.  
  435.     def checksources(self, side):
  436.         srclk = {0:self.srcclient, 1:self.srcserver}
  437.         if side == 0:
  438.             if not os.path.exists(os.path.join(srclk[side], 'net/minecraft/client/Minecraft.java')):
  439.                 self.logger.warning('!! Can not find client sources !!')
  440.                 return False
  441.             else:
  442.                 return True
  443.  
  444.         if side == 1:
  445.             if not os.path.exists(os.path.join(srclk[side], 'net/minecraft/server/MinecraftServer.java')):
  446.                 self.logger.warning('!! Can not find server sources !!')
  447.                 return False
  448.             else:
  449.                 return True
  450.  
  451.     def checkbins(self, side):
  452.         binlk = {0:self.binclient, 1:self.binserver}
  453.         if side == 0:
  454.             if not os.path.exists(os.path.join(binlk[side], 'net/minecraft/client/Minecraft.class')):
  455.                 self.logger.warning('!! Can not find client bins !!')
  456.                 return False
  457.             else:
  458.                 return True
  459.  
  460.         if side == 1:
  461.             if not os.path.exists(os.path.join(binlk[side], 'net/minecraft/server/MinecraftServer.class')):
  462.                 self.logger.warning('!! Can not find server bins !!')
  463.                 return False
  464.             else:
  465.                 return True
  466.  
  467.     def checkfolders(self):
  468.         try:
  469.             if not os.path.exists(self.dirtemp):
  470.                 os.mkdir(self.dirtemp)
  471.             if not os.path.exists(self.dirsrc):
  472.                 os.mkdir(self.dirsrc)
  473.             if not os.path.exists(self.dirlogs):
  474.                 os.mkdir(self.dirlogs)
  475.             if not os.path.exists(self.dirbin):
  476.                 os.mkdir(self.dirbin)
  477.             if not os.path.exists(self.dirreobf):
  478.                 os.mkdir(self.dirreobf)
  479.             if not os.path.exists(self.dirlib):
  480.                 os.mkdir(self.dirlib)
  481.         except AttributeError:
  482.             pass
  483.  
  484.     def checkupdates(self, silent=False):
  485.         results = []
  486.         #HINT: Each local entry is of the form dict[filename]=(md5,modificationtime)
  487.         md5lcldict = {}
  488.         for path, dirlist, filelist in os.walk('.'):
  489.             for trgfile in filelist:
  490.                 md5lcldict[os.path.join(path,trgfile).replace(os.sep, '/').replace('./','')] = \
  491.                 (md5(open(os.path.join(path,trgfile),'rb').read()).hexdigest(),
  492.                  os.stat(os.path.join(path,trgfile)).st_mtime
  493.                  )
  494.  
  495.         try:
  496.             md5srvlist = urllib.urlopen('http://mcp.ocean-labs.de/files/mcprolling/mcp.md5').readlines()
  497.             md5srvdict = {}
  498.         except IOError:
  499.             return []
  500.  
  501.         #HINT: Each remote entry is of the form dict[filename]=(md5,modificationtime)
  502.         for entry in md5srvlist:
  503.             md5srvdict[entry.split()[0]] = (entry.split()[1], float(entry.split()[2]), entry.split()[3])
  504.  
  505.         for key,value in md5srvdict.items():
  506.             #HINT: If the remote entry is not in the local table, append
  507.             if not key in md5lcldict:
  508.                 results.append([key, value[0], value[1], value[2]])
  509.                 continue
  510.             #HINT: If the remote entry has a different MD5 checksum and modtime is > local entry modtime
  511.             if not md5lcldict[key][0] == value[0] and value[1] > md5lcldict[key][1]:
  512.                 results.append([key, value[0], value[1], value[2]])
  513.  
  514.         if results and not silent:
  515.             self.logger.warning('!! Updates available. Please run updatemcp to get them. !!')
  516.  
  517.         return results
  518.  
  519.     def cleanbindirs(self,side):
  520.         pathbinlk    = {0:self.binclient,    1:self.binserver}
  521.  
  522.         for path, dirlist, filelist in os.walk(pathbinlk[side]):
  523.             for bin_file in glob.glob(os.path.join(path, '*.class')):
  524.                 os.remove(bin_file)
  525.  
  526.     def cleanreobfdir(self, side):
  527.         outpathlk = {0:self.dirreobfclt,    1:self.dirreobfsrv}
  528.         pathbinlk = {0:self.binclient,    1:self.binserver}
  529.         if os.path.exists(outpathlk[side]):
  530.             shutil.rmtree(outpathlk[side], ignore_errors=True)
  531.  
  532.         shutil.copytree(pathbinlk[side], outpathlk[side])
  533.         for path, dirlist, filelist in os.walk(outpathlk[side]):
  534.             for bin_file in glob.glob(os.path.join(path, '*.class')):
  535.                 os.remove(bin_file)
  536.  
  537.         for i in range(4):
  538.             for path, dirlist, filelist in os.walk(outpathlk[side]):
  539.                 if not dirlist and not filelist:
  540.                     shutil.rmtree(path)
  541.  
  542.         if not os.path.exists(outpathlk[side]):
  543.             os.mkdir(outpathlk[side])
  544.  
  545.     def cleantempbin(self, side):
  546.         pathbinlk = {0:self.binclienttmp,    1:self.binservertmp}
  547.  
  548.         if side == 0:
  549.             shutil.rmtree(os.path.join(pathbinlk[side], 'META-INF'), ignore_errors=True)
  550.             shutil.rmtree(os.path.join(pathbinlk[side], 'net'), ignore_errors=True)
  551.             shutil.rmtree(os.path.join(pathbinlk[side], 'com'), ignore_errors=True)
  552.             shutil.rmtree(os.path.join(pathbinlk[side], 'paulscode'), ignore_errors=True)
  553.  
  554.         if side == 1:
  555.             shutil.rmtree(os.path.join(pathbinlk[side], 'META-INF'), ignore_errors=True)
  556.             shutil.rmtree(os.path.join(pathbinlk[side], 'net'), ignore_errors=True)
  557.  
  558.     def applyrg(self, side):
  559.         """Apply rg to the given side"""
  560.  
  561.         # add retroguard.jar to copy of client classpath
  562.         if side == 0:
  563.             rgconf = self.rgclientconf
  564.             rgcp = [self.retroguard] + self.cpathclient
  565.             rgcp = os.pathsep.join(rgcp)
  566.  
  567.         # add retroguard.jar to copy of server classpath
  568.         if side == 1:
  569.             rgconf = self.rgserverconf
  570.             rgcp = [self.retroguard] + self.cpathserver
  571.             rgcp = os.pathsep.join(rgcp)
  572.  
  573.         forkcmd = self.cmdrg.format(classpath=rgcp, conffile=rgconf)
  574.         self.runcmd(forkcmd)
  575.  
  576.     def applyff(self, side):
  577.         """Apply fernflower to the given side"""
  578.  
  579.         if side == 0:
  580.             ffconf = self.ffclientconf
  581.             ffsrc  = self.xclientout
  582.  
  583.         if side == 1:
  584.             ffconf = self.ffserverconf
  585.             ffsrc  = self.xserverout
  586.  
  587.         forkcmd = self.cmdfernflower.format(jarff=self.fernflower, conf=ffconf, jarin=ffsrc, jarout=self.dirffout)
  588.         self.runcmd(forkcmd)
  589.  
  590.     def applyexceptor(self, side):
  591.         """Apply exceptor to the given side"""
  592.         excinput = {0:self.rgclientout,    1:self.rgserverout}
  593.         excoutput = {0:self.xclientout,    1:self.xserverout}
  594.         excconf = {0:self.xclientconf,    1:self.xserverconf}
  595.         exclog = {0:self.xclientlog,    1:self.xserverlog}
  596.  
  597.         forkcmd = self.cmdexceptor.format(jarexc=self.exceptor, input=excinput[side], output=excoutput[side], conf=excconf[side], log=exclog[side])
  598.         self.runcmd(forkcmd)
  599.  
  600.     def applyjadretro(self, side):
  601.         """Apply jadretro to the bin output directory"""
  602.         pathbinlk = {0:self.binclienttmp,   1:self.binservertmp}
  603.         pkglist = []
  604.         for path, dirlist, filelist in os.walk(pathbinlk[side]):
  605.             if glob.glob(os.path.join(path,'*.class')):
  606.                 for pkg in self.ignorepkg:
  607.                     if pkg.replace('\\',os.sep).replace('/',os.sep) in path:
  608.                         break
  609.                 else:
  610.                     pkglist.append(path)
  611.  
  612.         for pkg in pkglist:
  613.             forkcmd = self.cmdjadretro.format(jarjr=self.jadretro, targetdir=pkg)
  614.             self.runcmd(forkcmd)
  615.  
  616.     def applyjad(self, side):
  617.         """Decompile the code using jad"""
  618.         pathbinlk = {0:self.binclienttmp, 1:self.binservertmp}
  619.         pathsrclk = {0:self.srcclient,    1:self.srcserver}
  620.  
  621.         #HINT: We delete the old sources and recreate it
  622.         if os.path.exists(pathsrclk[side]):
  623.             shutil.rmtree(pathsrclk[side])
  624.         os.mkdir(pathsrclk[side])
  625.  
  626.         #HINT: We go throught the packages and apply jad to the directory
  627.         pkglist = []
  628.         for path, dirlist, filelist in os.walk(pathbinlk[side]):
  629.             if glob.glob(os.path.join(path,'*.class')):
  630.                 for pkg in self.ignorepkg:
  631.                     if pkg.replace('\\',os.sep).replace('/',os.sep) in path:
  632.                         break
  633.                 else:
  634.                     pkglist.append(path)
  635.  
  636.         for pkg in pkglist:
  637.             classlist = os.path.join(pkg, '*.class')
  638.  
  639.             forkcmd = self.cmdjad.format(binjad=self.jad, outdir=pathsrclk[side], classes=classlist)
  640.             self.runcmd(forkcmd)
  641.  
  642.     def applypatches(self, side):
  643.         """Applies the patches to the src directory"""
  644.         pathsrclk = {0:self.srcclient,   1:self.srcserver}
  645.         patchlk   = {0:self.patchclient, 1:self.patchserver}
  646.  
  647.         #HINT: Here we transform the patches to match the directory separator of the specific platform
  648.         patch    = open(patchlk[side],'r').read().splitlines()
  649.         outpatch = open(self.patchtemp,'wb')
  650.         for line in patch:
  651.             if line[:3] in ['+++','---', 'Onl', 'dif']:
  652.                  outpatch.write(line.replace('\\',os.sep).replace('/',os.sep) + '\r\n')
  653.             else:
  654.                 outpatch.write(line  + '\r\n')
  655.         outpatch.close()
  656.  
  657.         forkcmd = self.cmdpatch.format(srcdir=pathsrclk[side], patchfile=self.patchtemp)
  658.  
  659.         p = subprocess.Popen(forkcmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
  660.         buffer = []
  661.         errormsgs = []
  662.         retcode = None
  663.         while True:
  664.             o = p.stdout.readline()
  665.             retcode = p.poll()
  666.             if o == '' and retcode is not None:
  667.                 break
  668.             if o != '':
  669.                 buffer.append(o.strip())
  670.  
  671.         if retcode == 0:
  672.             for line in buffer:
  673.                 self.logger.debug(line)
  674.         else:
  675.             self.logger.warn('%s failed.'%forkcmd)
  676.             self.logger.warn('Return code : %d'%retcode)
  677.             for line in buffer:
  678.                 if 'saving rejects' in line:
  679.                     errormsgs.append(line)
  680.                 self.logger.debug(line)
  681.  
  682.             self.logger.warn('')
  683.             self.logger.warn('== ERRORS FOUND ==')
  684.             self.logger.warn('')
  685.             for line in errormsgs:
  686.                 self.logger.warn(line)
  687.             self.logger.warn('==================')
  688.             self.logger.warn('')
  689.  
  690.     def applyffpatches(self, side):
  691.         """Applies the patches to the src directory"""
  692.         pathsrclk = {0:self.srcclient,   1:self.srcserver}
  693.         patchlk   = {0:self.ffpatchclient, 1:self.ffpatchserver}
  694.  
  695.         #HINT: Here we transform the patches to match the directory separator of the specific platform
  696.         patch    = open(patchlk[side],'r').read().splitlines()
  697.         outpatch = open(self.patchtemp,'wb')
  698.         for line in patch:
  699.             if line[:3] in ['+++','---', 'Onl', 'dif']:
  700.                  outpatch.write(line.replace('\\',os.sep).replace('/',os.sep) + '\r\n')
  701.             else:
  702.                 outpatch.write(line  + '\r\n')
  703.         outpatch.close()
  704.  
  705.         forkcmd = self.cmdpatch.format(srcdir=pathsrclk[side], patchfile=self.patchtemp)
  706.  
  707.         p = subprocess.Popen(forkcmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
  708.         buffer = []
  709.         errormsgs = []
  710.         retcode = None
  711.         while True:
  712.             o = p.stdout.readline()
  713.             retcode = p.poll()
  714.             if o == '' and retcode is not None:
  715.                 break
  716.             if o != '':
  717.                 buffer.append(o.strip())
  718.  
  719.         if retcode == 0:
  720.             for line in buffer:
  721.                 self.logger.debug(line)
  722.         else:
  723.             self.logger.warn('%s failed.'%forkcmd)
  724.             self.logger.warn('Return code : %d'%retcode)
  725.             for line in buffer:
  726.                 if 'saving rejects' in line:
  727.                     errormsgs.append(line)
  728.                 self.logger.debug(line)
  729.  
  730.             self.logger.warn('')
  731.             self.logger.warn('== ERRORS FOUND ==')
  732.             self.logger.warn('')
  733.             for line in errormsgs:
  734.                 self.logger.warn(line)
  735.             self.logger.warn('==================')
  736.             self.logger.warn('')
  737.  
  738.     def recompile(self, side):
  739.         """Recompile the sources and produce the final bins"""
  740.         cmdlk     = {0:self.cmdrecompclt, 1:self.cmdrecompsrv}
  741.         pathbinlk = {0:self.binclient,    1:self.binserver}
  742.         pathsrclk = {0:self.srcclient,    1:self.srcserver}
  743.  
  744.         if not os.path.exists(pathbinlk[side]):
  745.             os.mkdir(pathbinlk[side])
  746.  
  747.         #HINT: We create the list of source directories based on the list of packages
  748.         pkglist = ''
  749.         for path, dirlist, filelist in os.walk(pathsrclk[side]):
  750.             if glob.glob(os.path.join(path,'*.java')):
  751.                 pkglist += os.path.join(path,'*.java') + ' '
  752.  
  753.         #HINT: We have to split between client & server because both have different arguments
  754.         forkcmd = ''
  755.         if side == 0:
  756.             cpc = os.pathsep.join(self.cpathclient)
  757.             forkcmd = cmdlk[side].format(classpath=cpc, sourcepath=pathsrclk[side], outpath=pathbinlk[side], pkgs=pkglist, fixes=self.fixesclient)
  758.  
  759.         if side == 1:
  760.             cps = os.pathsep.join(self.cpathserver)
  761.             forkcmd = cmdlk[side].format(classpath=cps, sourcepath=pathsrclk[side], outpath=pathbinlk[side], pkgs=pkglist)
  762.  
  763.         self.logger.debug("recompile: '"+forkcmd+"'")
  764.         p = subprocess.Popen(forkcmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
  765.         buffer = []
  766.         errormsgs = []
  767.         retcode = None
  768.         while True:
  769.             o = p.stdout.readline()
  770.             retcode = p.poll()
  771.             if o == '' and retcode is not None:
  772.                 break
  773.             if o != '':
  774.                 buffer.append(o.strip())
  775.  
  776.         if retcode == 0:
  777.             for line in buffer:
  778.                 self.logger.debug(line)
  779.         else:
  780.             self.logger.error('%s failed.'%forkcmd)
  781.             self.logger.error('Return code : %d'%retcode)
  782.             for line in buffer:
  783.                 if not line.strip(): continue
  784.                 if line[0] != '[' and line[0:4] != 'Note':
  785.                     errormsgs.append(line)
  786.                 self.logger.debug(line)
  787.  
  788.             self.logger.error('')
  789.             self.logger.error('== ERRORS FOUND ==')
  790.             self.logger.error('')
  791.             for line in errormsgs:
  792.                 self.logger.error(line)
  793.                 if '^' in line: self.logger.error('')
  794.             self.logger.error('==================')
  795.             self.logger.error('')
  796.             #sys.exit(1)
  797.  
  798.     def startserver(self):
  799.         cps = ['../'+p for p in self.cpathserver]
  800.         cps.insert(2, '../'+self.binserver)
  801.         cps = os.pathsep.join(cps)
  802.         #self.logger.info("classpath: '"+cps+"'")
  803.  
  804.         os.chdir(self.dirjars)
  805.  
  806.         forkcmd = self.cmdstartsrv.format(classpath=cps)
  807.         self.runmc(forkcmd)
  808.  
  809.     def startclient(self):
  810.         cpc = ['../'+p for p in self.cpathclient]
  811.         cpc.insert(2, '../'+self.binclient)
  812.         cpc = os.pathsep.join(cpc)
  813.         #self.logger.info("classpath: '"+cpc+"'")
  814.  
  815.         os.chdir(self.dirjars)
  816.  
  817.         forkcmd = self.cmdstartclt.format(classpath=cpc, natives='../'+self.dirnatives)
  818.         self.runmc(forkcmd)
  819.  
  820.     def runcmd(self, forkcmd):
  821.         self.logger.debug("runcmd: '"+forkcmd+"'")
  822.         p = subprocess.Popen(forkcmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
  823.         buffer = []
  824.         retcode = None
  825.         while True:
  826.             o = p.stdout.readline()
  827.             retcode = p.poll()
  828.             if o == '' and retcode is not None:
  829.                 break
  830.             if o != '':
  831.                 buffer.append(o.strip())
  832.  
  833.         if retcode == 0:
  834.             for line in buffer:
  835.                 self.logger.debug(line)
  836.         else:
  837.             self.logger.error('%s failed.'%forkcmd)
  838.             self.logger.error('Return code : %d'%retcode)
  839.             for line in buffer:
  840.                 self.logger.error(line)
  841.  
  842.     def runmc(self, forkcmd):
  843.         self.logger.debug("runmc: '"+forkcmd+"'")
  844.         pclient = subprocess.Popen(forkcmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
  845.         msgs        = []
  846.         returnvalue = None
  847.         while True:
  848.             o = pclient.stdout.readline()
  849.             returnvalue = pclient.poll()
  850.             if o == '' and returnvalue is not None:
  851.                 break
  852.             if o != '':
  853.                 self.loggermc.debug(o.strip())
  854.                 msgs.append(o.strip())
  855.  
  856.         if returnvalue != 0:
  857.             for msg in msgs:
  858.                 self.logger.error(msg)
  859.         else:
  860.             for msg in msgs:
  861.                 self.logger.debug(msg)
  862.  
  863.     def extractjar(self, side):
  864.         """Unzip the jar file to the bin directory defined in the config file"""
  865.         pathbinlk = {0:self.binclienttmp,   1:self.binservertmp}
  866.         jarlk     = {0:self.xclientout, 1:self.xserverout}
  867.  
  868.         #HINT: We check if the top output directory exists. If not, we create it
  869.         #We than check if the specific side directory exists. If it does, we delete it and create a new one
  870.         if not os.path.exists(self.binouttmp):
  871.             os.mkdir(self.binouttmp)
  872.         if os.path.exists(pathbinlk[side]):
  873.             shutil.rmtree(pathbinlk[side])
  874.         os.mkdir(pathbinlk[side])
  875.  
  876.         #HINT: We extract the jar to the right location
  877.         zipjar = zipfile.ZipFile(jarlk[side])
  878.         zipjar.extractall(pathbinlk[side])
  879.  
  880.     def extractsrc(self, side):
  881.         """Unzip the source jar file to the src directory defined in the config file"""
  882.         pathbinlk = {0:self.ffclientout,   1:self.ffserverout}
  883.         jarlk     = {0:self.ffclientsrc, 1:self.ffserversrc}
  884.         pathsrclk = {0:self.srcclient,   1:self.srcserver}
  885.  
  886.         #HINT: We check if the top output directory exists. If not, we create it
  887.         if not os.path.exists(pathbinlk[side]):
  888.             os.mkdir(pathbinlk[side])
  889.  
  890.         #HINT: We extract the jar to the right location
  891.         zipjar = zipfile.ZipFile(jarlk[side])
  892.         zipjar.extractall(pathbinlk[side])
  893.  
  894.         self.copyandfixsrc(pathbinlk[side], pathsrclk[side])
  895.  
  896.     def copyandfixsrc(self, src_dir, dest_dir):
  897.         src_dir = os.path.normpath(src_dir)
  898.         dest_dir = os.path.normpath(dest_dir)
  899.  
  900.         for path, dirlist, filelist in os.walk(src_dir):
  901.             sub_dir = os.path.relpath(path, src_dir)
  902.             if sub_dir == '.':
  903.                 sub_dir = ''
  904.  
  905.             for cur_dir in dirlist:
  906.                 if os.path.join(sub_dir, cur_dir).replace(os.sep, '/') in self.ignorepkg:
  907.                     # if the full subdir is in the ignored package list delete it so that we don't descend into it
  908.                     dirlist.remove(cur_dir)
  909.  
  910.             for cur_file in fnmatch.filter(filelist, '*.java'):
  911.                 src_file = os.path.join(src_dir, sub_dir, cur_file)
  912.                 dest_file = os.path.join(dest_dir, sub_dir, cur_file)
  913.  
  914.                 if not os.path.exists(os.path.dirname(dest_file)):
  915.                     os.makedirs(os.path.dirname(dest_file))
  916.  
  917.                 # don't bother fixing line endings in windows
  918.                 if self.osname == 'win':
  919.                     shutil.copyfile(src_file, dest_file)
  920.                 else:
  921.                     # read each line in the file, stripping existing line end and adding dos line end
  922.                     with open(src_file, 'r') as in_file:
  923.                         with open(dest_file, 'wb') as out_file:
  924.                             for line in in_file:
  925.                                 out_file.write(line.rstrip() + '\r\n')
  926.  
  927.     def rename(self, side):
  928.         """Rename the sources using the CSV data"""
  929.         pathsrclk = {0:self.srcclient,    1:self.srcserver}
  930.     print("ASDASDASD")
  931.     return
  932.         #HINT: We read the relevant CSVs
  933.         methodsreader = csv.DictReader(open(self.csvmethods, 'r'), delimiter=',',quotechar='"', quoting=csv.QUOTE_ALL)
  934.         fieldsreader  = csv.DictReader(open(self.csvfields,  'r'), delimiter=',',quotechar='"', quoting=csv.QUOTE_ALL)
  935.  
  936.         methods = {}
  937.         fields  = {}
  938.         for row in methodsreader:
  939.             if int(row['side']) == side:
  940.                 if row['searge'] in methods: self.logger.debug('WTF ? %s'%row['searge'])
  941.                 methods[row['searge']] = row
  942.         for row in fieldsreader:
  943.             if int(row['side']) == side:
  944.                 if row['searge'] in methods: self.logger.debug('WTF ? %s'%row['searge'])
  945.                 fields[row['searge']]  = row
  946.  
  947.         type_hash         = {'methods':'func', 'fields':'field'}
  948.         regexp_searge     = r'%s_[0-9]+_[a-zA-Z]+_?'
  949.  
  950.         #HINT: We pathwalk the sources
  951.         for path, dirlist, filelist in os.walk(pathsrclk[side]):
  952.             for src_file in glob.glob(os.path.join(path, '*.java')):
  953.  
  954.                 ff    = open(src_file, 'r')
  955.                 fftmp = open(src_file + '.tmp', 'w')
  956.  
  957.                 buffer = ff.read()
  958.                 ff.close()
  959.  
  960.                 #HINT: We check if the sources have func_????_? or field_????_? in them.
  961.                 # If yes, we replace with the relevant information
  962.                 for group in ['methods', 'fields']:
  963.                     results = re.findall(regexp_searge%type_hash[group], buffer)
  964.  
  965.                     for result in results:
  966.                         #HINT: It is possible for the csv to contain data from previous version or enums, so we catch those
  967.                         try:
  968.                             buffer = buffer.replace(result, locals()[group][result]['name'])
  969.                         except KeyError as msg:
  970.                             self.logger.debug("Can not replace %s on side %d"%(msg,side))
  971.  
  972.                 fftmp.write(buffer)
  973.                 fftmp.close()
  974.  
  975.                 shutil.move(src_file + '.tmp', src_file)
  976.  
  977.                 #HINT: We annotate the GL constants
  978.                 annotate_file(src_file)
  979.                
  980.     def file_code_rename(self, side, filename):
  981.         pathsrclk = {0:self.srcclient,    1:self.srcserver}
  982.        
  983.         #HINT: We read the relevant CSVs
  984.         methodsreader = csv.DictReader(open(self.csvmethods, 'r'), delimiter=',',quotechar='"', quoting=csv.QUOTE_ALL)
  985.         fieldsreader  = csv.DictReader(open(self.csvfields,  'r'), delimiter=',',quotechar='"', quoting=csv.QUOTE_ALL)
  986.        
  987.         methods = {}
  988.         fields  = {}
  989.         for row in methodsreader:
  990.             if int(row['side']) == side:
  991.                 if row['searge'] in methods: self.logger.debug('WTF ? %s'%row['searge'])
  992.                 methods[row['searge']] = row
  993.         for row in fieldsreader:
  994.             if int(row['side']) == side:
  995.                 if row['searge'] in methods: self.logger.debug('WTF ? %s'%row['searge'])
  996.                 fields[row['searge']]  = row
  997.  
  998.         type_hash         = {'methods':'func', 'fields':'field'}
  999.         regexp_searge     = r'%s_[0-9]+_[a-zA-Z]+_?'
  1000.  
  1001.     print(os.path)
  1002.     src_file = filename
  1003.     ff    = open(src_file, 'r')
  1004.     fftmp = open(src_file + '.tmp', 'w')
  1005.  
  1006.     buffer = ff.read()
  1007.     ff.close()
  1008.  
  1009.     #HINT: We check if the sources have func_????_? or field_????_? in them.
  1010.     # If yes, we replace with the relevant information
  1011.     for group in ['methods', 'fields']:
  1012.         results = re.findall(regexp_searge%type_hash[group], buffer)
  1013.  
  1014.         for result in results:
  1015.             #HINT: It is possible for the csv to contain data from previous version or enums, so we catch those
  1016.             try:
  1017.                 buffer = buffer.replace(result, locals()[group][result]['name'])
  1018.             except KeyError as msg:
  1019.                 self.logger.debug("Can not replace %s on side %d"%(msg,side))
  1020.  
  1021.     fftmp.write(buffer)
  1022.     fftmp.close()
  1023.  
  1024.     shutil.move(src_file + '.tmp', src_file)
  1025.  
  1026.     #HINT: We annotate the GL constants
  1027.     annotate_file(src_file)
  1028.  
  1029.     def renamereobsrg(self, side):
  1030.         deoblk = {0:self.rgclientdeoblog, 1:self.rgserverdeoblog}
  1031.         reoblk = {0:self.reobsrgclient, 1:self.reobsrgserver}
  1032.  
  1033.         deoblog = open(deoblk[side],'r').read()
  1034.         reobsrg = open(reoblk[side],'w')
  1035.  
  1036.         methodsreader = csv.DictReader(open(self.csvmethods, 'r'), delimiter=',',quotechar='"', quoting=csv.QUOTE_ALL)
  1037.         fieldsreader  = csv.DictReader(open(self.csvfields,  'r'), delimiter=',',quotechar='"', quoting=csv.QUOTE_ALL)
  1038.  
  1039.         #TODO: A bit too much brute force and a bit slow.
  1040.         for row in methodsreader:
  1041.             if int(row['side']) == side:
  1042.                 deoblog = deoblog.replace(row['searge'], row['name'])
  1043.         for row in fieldsreader:
  1044.             if int(row['side']) == side:
  1045.                 deoblog = deoblog.replace(row['searge'], row['name'])
  1046.  
  1047.         reobsrg.write(deoblog)
  1048.         reobsrg.close()
  1049.  
  1050.     def gathermd5s(self, side, reobf=False):
  1051.         if not reobf:
  1052.             md5lk     = {0:self.md5client,    1:self.md5server}
  1053.         else:
  1054.             md5lk     = {0:self.md5reobfclient,    1:self.md5reobfserver}
  1055.         pathbinlk = {0:self.binclient,    1:self.binserver}
  1056.  
  1057.         md5file = open(md5lk[side],'w')
  1058.  
  1059.         #HINT: We pathwalk the recompiled classes
  1060.         for path, dirlist, filelist in os.walk(pathbinlk[side]):
  1061.             for bin_file in glob.glob(os.path.join(path, '*.class')):
  1062.                 bin_file_osindep = os.sep.join(bin_file.replace(os.sep,'/').split('/')[2:]).split('.')[0]
  1063.                 md5file.write('%s %s\n'%(bin_file_osindep, md5(open(bin_file,'rb').read()).hexdigest()))
  1064.         md5file.close()
  1065.  
  1066.     def packbin(self, side):
  1067.         jarlk     = {0:self.cmpjarclient, 1:self.cmpjarserver}
  1068.         pathbinlk = {0:self.binclient,    1:self.binserver}
  1069.         pathtmpbinlk = {0:self.binclienttmp,    1:self.binservertmp}
  1070.  
  1071.         #HINT: We create the zipfile and add all the files from the bin directory
  1072.         zipjar = zipfile.ZipFile(jarlk[side], 'w')
  1073.         for path, dirlist, filelist in os.walk(pathbinlk[side]):
  1074.             path = path.replace('/',os.sep)
  1075.             for bin_file in glob.glob(os.path.join(path, '*.class')):
  1076.                 if self.fixsound.replace('/',os.sep).replace('\\',os.sep) in bin_file: continue
  1077.                 if self.fixstart.replace('/',os.sep).replace('\\',os.sep) in bin_file: continue
  1078.                 zipjar.write(bin_file, os.sep.join(bin_file.split(os.sep)[2:]))
  1079.  
  1080.         for pkg in self.ignorepkg:
  1081.             curpath = os.path.join(pathtmpbinlk[0],pkg)
  1082.             for path, dirlist, filelist in os.walk(curpath):
  1083.                 path = path.replace('/',os.sep)
  1084.                 for bin_file in glob.glob(os.path.join(path, '*.class')):
  1085.                     zipjar.write(bin_file, os.sep.join(bin_file.split(os.sep)[3:]))
  1086.  
  1087.         zipjar.close()
  1088.  
  1089.     def reobfuscate(self, side):
  1090.         # add retroguard.jar to copy of client classpath
  1091.         if side == 0:
  1092.             rgconf = self.rgclientreobconf
  1093.             rgcp = [self.retroguard] + self.cpathclient
  1094.             rgcp = os.pathsep.join(rgcp)
  1095.  
  1096.         # add retroguard.jar to copy of server classpath
  1097.         if side == 1:
  1098.             rgconf = self.rgserverreobconf
  1099.             rgcp = [self.retroguard] + self.cpathserver
  1100.             rgcp = os.pathsep.join(rgcp)
  1101.  
  1102.         forkcmd = self.cmdrgreobf.format(classpath=rgcp, conffile=rgconf)
  1103.         self.runcmd(forkcmd)
  1104.  
  1105.     def unpackreobfclasses(self, side):
  1106.         jarlk     = {0:self.reobfjarclient, 1:self.reobfjarserver}
  1107.         md5lk     = {0:self.md5client,      1:self.md5server}
  1108.         md5reoblk = {0:self.md5reobfclient, 1:self.md5reobfserver}
  1109.         outpathlk = {0:self.dirreobfclt,    1:self.dirreobfsrv}
  1110.  
  1111.         #HINT: We need a table for the old md5 and the new ones
  1112.         md5table     = {}
  1113.         md5reobtable = {}
  1114.         for row in open(md5lk[side],'r').read().splitlines():
  1115.             row = row.strip().split()
  1116.             if len(row) == 2:
  1117.                 md5table[row[0].replace(os.sep,'/')] = row[1]
  1118.         for row in open(md5reoblk[side],'r').read().splitlines():
  1119.             row = row.strip().split()
  1120.             if len(row) == 2:
  1121.                 md5reobtable[row[0].replace(os.sep,'/')] = row[1]
  1122.  
  1123.         trgclasses = []
  1124.         for key,value in md5reobtable.items():
  1125.             if not key in md5table:
  1126.                 self.logger.info ('> New class found      : %s'%key)
  1127.                 trgclasses.append(key.split('.')[0])
  1128.                 continue
  1129.             if not md5table[key] == md5reobtable[key]:
  1130.                 trgclasses.append(key.split('.')[0])
  1131.                 self.logger.info ('> Modified class found : %s'%key)
  1132.  
  1133.         classesreader = csv.DictReader(open(self.csvclasses, 'r'), delimiter=',',quotechar='"', quoting=csv.QUOTE_ALL)
  1134.         classes = {}
  1135.         for row in classesreader:
  1136.             if int(row['side']) == side:
  1137.                 #HINT: This pkg equivalence is used to reduce the src pkg to the null one
  1138.                 pkg = row['package'] + '/'
  1139.                 if row['package'] == self.nullpkg: pkg = ''
  1140.                 classes['%s/%s'%(row['package'],row['name'])] = pkg + row['notch']
  1141.  
  1142.         if not os.path.exists(outpathlk[side]):
  1143.             os.mkdir(outpathlk[side])
  1144.  
  1145.         #HINT: We extract the modified class files
  1146.         zipjar = zipfile.ZipFile(jarlk[side], 'r')
  1147.         for i in trgclasses:
  1148.             if i in classes:
  1149.                 zipjar.extract('%s.class'%classes[i], outpathlk[side])
  1150.                 self.logger.info ('> Outputted %s to %s as %s'%(i.ljust(35),outpathlk[side],classes[i]+'.class'))
  1151.             else:
  1152.                 i = i.replace(self.nullpkg, '')
  1153.                 if i[0] == '/': i = i[1:]
  1154.                 zipjar.extract('%s.class'%i, outpathlk[side])
  1155.                 self.logger.info ('> Outputted %s to %s as %s'%(i.ljust(35),outpathlk[side],i+'.class'))
  1156.         zipjar.close()
  1157.  
  1158.     def downloadupdates(self, force=False):
  1159.         newfiles = self.checkupdates(silent=True)
  1160.  
  1161.         if not newfiles:
  1162.             self.logger.info('No new updates found.')
  1163.             return
  1164.  
  1165.         for entry in newfiles:
  1166.             if entry[3] == 'U':
  1167.                 self.logger.info('New version found for : %s'%entry[0])
  1168.             if entry[3] == 'D':
  1169.                 self.logger.info('File tagged for deletion : %s'%entry[0])
  1170.  
  1171.         if 'CHANGELOG' in [i[0] for i in newfiles]:
  1172.             print('')
  1173.             self.logger.info('== CHANGELOG ==')
  1174.             changelog = urllib.urlopen('http://mcp.ocean-labs.de/files/mcprolling/mcp/CHANGELOG').readlines()
  1175.             for line in changelog:
  1176.                 self.logger.info(line.strip())
  1177.                 if not line.strip():
  1178.                     break
  1179.             print('')
  1180.             print('')
  1181.  
  1182.         if not force:
  1183.             print('WARNING:')
  1184.             print('You are going to update MCP')
  1185.             print('Are you sure you want to continue ?')
  1186.             answer = raw_input('If you really want to update, enter "Yes" ')
  1187.             if not answer.lower() in ['yes','y']:
  1188.                 print('You have not entered "Yes", aborting the update process')
  1189.                 sys.exit(0)
  1190.  
  1191.         for entry in newfiles:
  1192.             if entry[3] == 'U':
  1193.                 self.logger.info('Retrieving file from server : %s'%entry[0])
  1194.                 dir = os.path.dirname(entry[0])
  1195.                 if not os.path.isdir(dir):
  1196.                     try:
  1197.                         os.makedirs(dir)
  1198.                     except OSError:
  1199.                         pass
  1200.  
  1201.                 urllib.urlretrieve('http://mcp.ocean-labs.de/files/mcprolling/mcp/'+entry[0], entry[0])
  1202.             if entry[3] == 'D':
  1203.                 self.logger.info('Removing file from local install : %s'%entry[0])
  1204.                 #Remove file here
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement