Package smart.updater

Source Code of smart.updater.Updater

/**
*  Copyright 2010 by Benjamin J. Land (a.k.a. BenLand100)
*
*  This file is part of the SMART Minimizing Autoing Resource Thing (SMART)
*
*  SMART is free software: you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation, either version 3 of the License, or
*  (at your option) any later version.
*
*  SMART is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with SMART. If not, see <http://www.gnu.org/licenses/>.
*/

package smart.updater;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map.Entry;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.generic.*;

/**
* Updater is the core of the updater. To add a new search, put its class name
* in the SEARCHES field, and ensure its .class file is in the correct package.
* Usage for this program is as follows:
*
* java smart.updater.Updater
*     Simply runs the updater on a freshly downloaded runescape.jar and
*     writes everything to STDOUT
*
* java smart.updater.Updater [outputfile]
*     Runs the updater on a freshly downloaded runescape.jar and generates a
*     SMART compatible pascal file in the provided file name, overwriting any
*     previous data.
*
* java smart.updater.Updater [downloadedjar] [outputfile]
*     Runs the updater on the specified jar file (without downloading a new)
*     runescape.jar, and generates a SMART compatible pascal file in the
*     provided file name, overwriting any previous data.
*
* @author benland100
*/
public class Updater {

    /**
     * Searches to run go here. Must be in the smart.updater.searches package.
     * Searches are run in the order given, but may be deferred if required data
     * is not avaliable when run.
     */
    public static final String[] SEARCHES = new String[]{
        "LoginIndex", "BaseAnimableXY", "NPC", "NPCDefName", "NPCNode", "NPCIndexArray", "NPCNodes",
        "NPCCount", "GroundPlane", "RSInteractable", "Toolkit", "Viewport", "StandardDetail",
        "MinimapAngle", "Animation", "QueueXY", "Camera", "MenuOptionCount", "MenuXY",
        "MenuNodeList", "NodeListHead", "NodeNext", "MenuOption", "CharacterHeight", "NPCLevel",
        "LoopCycle", "LoopCycleStatus", "HPRatio", "Interacting", "PlayerName", "PlayerIndexArray",
        "GetPlayers", "PlayerDef"
    };

    /**
     * See the class description for usage information.
     *
     * @param args
     */
    public static void main(String[] args) {
        Updater updater;
        RSClient data;
        switch (args.length) {
            case 1:
                updater = new Updater(download("http://world" + Math.round(Math.random() * 169) + ".runescape.com/runescape.jar"));
                data = updater.runSearches();
                System.out.println(data);
                saveFile(args[1],data.smartFile().getBytes());
            case 2:
                updater = new Updater(readFile(args[0]));
                data = updater.runSearches();
                System.out.println(data);
                saveFile(args[1],data.smartFile().getBytes());
                break;
            case 0:
            default:
                updater = new Updater(download("http://world" + Math.round(Math.random() * 169) + ".runescape.com/runescape.jar"));
                data = updater.runSearches();
                System.out.println(data);
                System.out.println(data.smartFile());
        }
    }

    /**
     * Saves data to a file, erasing all previous information.
     *
     * @param file Path to file
     * @param data Data to save
     */
    public static void saveFile(String file, byte[] data) {
        try {
            File f = new File(file);
            if (f.exists()) {
                f.delete();
            }
            f.createNewFile();
            FileOutputStream out = new FileOutputStream(f);
            out.write(data);
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Reads data from a file and returns the bytes
     *
     * @param file Path to file
     * @return Data read
     */
    public static byte[] readFile(String file) {
        try {
            FileInputStream in = new FileInputStream(new File(file));
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len;
            while ((len = in.read(buffer, 0, 1024)) > -1) {
                out.write(buffer, 0, len);
            }
            in.close();
            out.close();
            return out.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * Reads data from a URL and returns the bytes
     *
     * @param address Valid URL
     * @return Data read
     */
    public static byte[] download(String address) {
        ByteArrayOutputStream out = null;
        InputStream in = null;
        try {
            URL url = new URL(address);
            URLConnection urlc = url.openConnection();
            urlc.setConnectTimeout(1000);
            urlc.setReadTimeout(1000);
            out = new ByteArrayOutputStream();
            in = urlc.getInputStream();
            byte[] buffer = new byte[1024];
            int numRead;
            while ((numRead = in.read(buffer)) != -1) {
                out.write(buffer, 0, numRead);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
            }
        }
        if (out != null) {
            return out.toByteArray();
        }
        return null;
    }

    /**
     * HashMap of raw binary class data by class name, just in case.
     */
    private HashMap<String, byte[]> rawclasses = new HashMap<String, byte[]>();

    /**
     * HashMap of ClassGens by class name, for use in the Searches.
     */
    private HashMap<String, ClassGen> javaclasses = new HashMap<String, ClassGen>();

    /**
     * Creates an Updater instance by parsing the classes out of a byte[] from
     * a runescape.jar. This constructor does not do any bytecode searching, it
     * simply parses classes.
     *
     * @param jar byte[] from a runescape.jar
     */
    public Updater(byte[] jar) {
        try {
            ZipInputStream in = new ZipInputStream(new ByteArrayInputStream(jar));
            ZipEntry entry = in.getNextEntry();
            byte[] buffer = new byte[1024];
            while (entry != null) {
                String entryName = entry.getName();
                if (entryName.endsWith(".class")) {
                    ByteArrayOutputStream data = new ByteArrayOutputStream();
                    int len;
                    while ((len = in.read(buffer, 0, 1024)) > -1) {
                        data.write(buffer, 0, len);
                    }
                    rawclasses.put(entryName.replaceAll("\\\\", ".").replace(".class", ""), data.toByteArray());
                    data.close();
                }
                in.closeEntry();
                entry = in.getNextEntry();
            }
            in.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        try {
            for (Entry<String, byte[]> entry : rawclasses.entrySet()) {
                ByteArrayInputStream in = new ByteArrayInputStream(entry.getValue());
                ClassParser parser = new ClassParser(in, entry.getKey());
                javaclasses.put(entry.getKey(), new ClassGen(parser.parse()));
                in.close();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Searches the client class for the version. Usually works fine.
     *
     * @return Client version
     */
    public int getVersion() {
        ClassGen client = javaclasses.get("client");
        if (client == null)
            return -1;
        for (Method m : client.getMethods()) {
            if (m.getName().equals("main")) {
                MethodGen gen = new MethodGen(m, client.getClassName(), client.getConstantPool());
                InstructionList il = gen.getInstructionList();
                InstructionHandle i = il.getStart();
                do {
                    if (i.getInstruction() instanceof SIPUSH) {
                        int value = ((SIPUSH) i.getInstruction()).getValue().intValue();
                        if (value >= 400 && value <= 800 && value != 503 && value != 768) {
                            return value;
                        }
                    }
                } while ((i = i.getNext()) != null);
            }
        }
        return -1;
    }

    /**
     * Runs all the specified searches deferring as necessary and prints out
     * some nice debug information.
     *
     * @return RSClient instance containing the hooks found.
     */
    public RSClient runSearches() {
        long start = System.currentTimeMillis();
        System.out.println("=== SMART Public Updater by BenLand100 ===");
        System.out.println();
        int version = getVersion();
        if (version == -1) System.out.println("Warning: version not found, hooks may fail");
        System.out.println("Preparing to run searches on:");
        System.out.println("  * " + rawclasses.size() + " class files");
        System.out.println("  * From client version: " + version);
        System.out.println();
        RSClient data = new RSClient(version);
        LinkedList<Search> deferred = new LinkedList<Search>();
        for (String searchName : SEARCHES) {
            Search search = null;
            try {
                search = (Search) Class.forName("smart.updater.searches." + searchName).newInstance();
                System.out.print(searchName + "... ");
                switch (search.run(data, javaclasses)) {
                    case Success:
                        System.out.println(" completed successfully");
                        break;
                    case Failure:
                        System.out.println(" failed to find its hooks");
                        break;
                    case MissingInfo:
                        System.out.println(" needs to be deferred");
                        deferred.add(search);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        int lastsize = deferred.size();
        while (deferred.size() > 0) {
            System.out.println("Running deferred searches");
            for (Search search : deferred) {
                System.out.print(search.getClass().getSimpleName() + "... ");
                switch (search.run(data, javaclasses)) {
                    case Success:
                        System.out.println(" completed after deferring");
                        deferred.remove(search);
                        break;
                    case Failure:
                        System.out.println(" failed to find its hooks");
                        deferred.remove(search);
                        break;
                    case MissingInfo:
                        System.out.println(" needs to be deferred again");
                }
            }
            if (lastsize == deferred.size()) {
                break;
            }
            lastsize = deferred.size();
        }
        for (Search search : deferred) {
            System.out.println(search.getClass().getSimpleName() + " failed to find its hooks");
        }
        System.out.println();
        System.out.println("Finished after " + (System.currentTimeMillis() - start) + "ms");
        System.out.println();
        return data;
    }
}
TOP

Related Classes of smart.updater.Updater

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.