diff --git a/cache/pom.xml b/cache/pom.xml new file mode 100644 index 0000000000..9b4eefa2d0 --- /dev/null +++ b/cache/pom.xml @@ -0,0 +1,121 @@ + + + + 4.0.0 + + + net.runelite + runelite-parent + 1.1.0-SNAPSHOT + + + net.runelite + cache + 1.1.0-SNAPSHOT + Cache + + + + net.runelite.rs + api + 1.0.1-SNAPSHOT + + + + com.google.guava + guava + 18.0 + + + org.slf4j + slf4j-api + 1.7.12 + + + org.slf4j + slf4j-simple + 1.7.12 + + + org.apache.commons + commons-compress + 1.10 + + + com.google.code.gson + gson + 2.4 + + + org.gnu + gnu-crypto + 2.0.1 + + + + junit + junit + 4.12 + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.16 + + true + -Xmx1024m + + + + maven-assembly-plugin + + + jar-with-dependencies + + + + + make-assembly + package + + single + + + + + + + diff --git a/cache/src/main/java/net/runelite/cache/ConfigType.java b/cache/src/main/java/net/runelite/cache/ConfigType.java new file mode 100644 index 0000000000..1b9099230d --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/ConfigType.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache; + +public enum ConfigType +{ + // types from https://github.com/im-frizzy/OpenRS/blob/master/source/net/openrs/cache/type/ConfigArchive.java + UNDERLAY(1), + IDENTKIT(3), + OVERLAY(4), + INV(5), + OBJECT(6), + ENUM(8), + NPC(9), + ITEM(10), + SEQUENCE(12), + SPOTANIM(13), + VARBIT(14), + VARCLIENT(19), + VARCLIENTSTRING(15), + VARPLAYER(16); + + private final int id; + + ConfigType(int id) + { + this.id = id; + } + + public int getId() + { + return id; + } +} diff --git a/cache/src/main/java/net/runelite/cache/IndexType.java b/cache/src/main/java/net/runelite/cache/IndexType.java new file mode 100644 index 0000000000..e1f381b0d9 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/IndexType.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache; + +public enum IndexType +{ + // names from https://github.com/im-frizzy/OpenRS/blob/master/source/net/openrs/cache/type/CacheIndex.java + SKINS(1), + CONFIGS(2), + INTERFACES(3), + SOUNDEFFECTS(4), + LANDSCAPES(5), + TRACK1(6), + MODELS(7), + SPRITES(8), + TEXTURES(9), + BINARY(10), + TRACK2(11), + CLIENTSCRIPT(12), + FONTS(13), + VORBIS(14), + INSTRUMENTS(15); + + private int id; + + IndexType(int id) + { + this.id = id; + } + + public int getNumber() + { + return id; + } +} \ No newline at end of file diff --git a/cache/src/main/java/net/runelite/cache/ItemDumper.java b/cache/src/main/java/net/runelite/cache/ItemDumper.java new file mode 100644 index 0000000000..7a4c84986f --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/ItemDumper.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashSet; +import java.util.Set; +import net.runelite.cache.definitions.ItemDefinition; +import net.runelite.cache.definitions.loaders.ItemLoader; +import net.runelite.cache.fs.Archive; +import net.runelite.cache.fs.Index; +import net.runelite.cache.fs.Store; +import net.runelite.cache.io.InputStream; + +public class ItemDumper +{ + private final File cache, out, java; + private final Gson gson; + private ItemLoader loader; + + public ItemDumper(File cache, File out, File java) + { + this.cache = cache; + this.out = out; + this.java = java; + + GsonBuilder builder = new GsonBuilder() + .setPrettyPrinting(); + gson = builder.create(); + } + + public static void main(String[] args) throws IOException + { + if (args.length < 3) + System.exit(1); + + File cache = new File(args[0]); + File out = new File(args[1]); + File java = new File(args[2]); + + ItemDumper dumper = new ItemDumper(cache, out, java); + dumper.load(); + dumper.dump(); + dumper.java(); + } + + public void load() throws IOException + { + loader = new ItemLoader(); + + try (Store store = new Store(cache)) + { + store.load(); + + Index index = store.getIndex(IndexType.CONFIGS); + Archive archive = index.getArchive(ConfigType.ITEM.getId()); + + for (net.runelite.cache.fs.File f : archive.getFiles()) + { + loader.load(f.getFileId(), new InputStream(f.getContents())); + } + } + } + + public void dump() throws IOException + { + for (ItemDefinition def : loader.getItems()) + { + out.mkdirs(); + java.io.File targ = new java.io.File(out, def.id + ".json"); + try (FileWriter fw = new FileWriter(targ)) + { + fw.write(gson.toJson(def)); + } + } + } + + public void java() throws IOException + { + java.mkdirs(); + java.io.File targ = new java.io.File(java, "ItemID.java"); + try (PrintWriter fw = new PrintWriter(targ)) + { + Set used = new HashSet<>(); + + fw.println("/* This file is automatically generated. Do not edit. */"); + fw.println("package net.runelite.api;"); + fw.println(""); + fw.println("public final class ItemID {"); + for (ItemDefinition def : loader.getItems()) + { + if (def.name.equalsIgnoreCase("NULL")) + continue; + + String name = name(def.name); + if (name == null) + continue; + + String suffix = ""; + while (used.contains(name + suffix)) + { + if (suffix.isEmpty()) + suffix = "_2"; + else + suffix = "_" + (Integer.parseInt(suffix.substring(1)) + 1); + } + name += suffix; + + used.add(name); + + fw.println(" public static final int " + name + " = " + def.id + ";"); + } + fw.println("}"); + } + } + + private static String name(String in) + { + String s = in.toUpperCase() + .replace(' ', '_') + .replaceAll("[^a-zA-Z0-9_]", ""); + if (s.isEmpty()) + return null; + if (Character.isDigit(s.charAt(0))) + return "_" + s; + else + return s; + } +} diff --git a/cache/src/main/java/net/runelite/cache/NpcDumper.java b/cache/src/main/java/net/runelite/cache/NpcDumper.java new file mode 100644 index 0000000000..c18ec8e556 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/NpcDumper.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashSet; +import java.util.Set; +import net.runelite.cache.definitions.NpcDefinition; +import net.runelite.cache.definitions.loaders.NpcLoader; +import net.runelite.cache.fs.Archive; +import net.runelite.cache.fs.Index; +import net.runelite.cache.fs.Store; +import net.runelite.cache.io.InputStream; + +public class NpcDumper +{ + private final File cache, out, java; + private final Gson gson; + private NpcLoader loader; + + public NpcDumper(File cache, File out, File java) + { + this.cache = cache; + this.out = out; + this.java = java; + + GsonBuilder builder = new GsonBuilder() + .setPrettyPrinting(); + gson = builder.create(); + } + + public static void main(String[] args) throws IOException + { + if (args.length < 3) + System.exit(1); + + File cache = new File(args[0]); + File out = new File(args[1]); + File java = new File(args[2]); + + ItemDumper dumper = new ItemDumper(cache, out, java); + dumper.load(); + dumper.dump(); + dumper.java(); + } + + public void load() throws IOException + { + loader = new NpcLoader(); + + try (Store store = new Store(cache)) + { + store.load(); + + Index index = store.getIndex(IndexType.CONFIGS); + Archive archive = index.getArchive(ConfigType.NPC.getId()); + + for (net.runelite.cache.fs.File f : archive.getFiles()) + { + loader.load(f.getFileId(), new InputStream(f.getContents())); + } + } + } + + public void dump() throws IOException + { + for (NpcDefinition def : loader.getNpcs()) + { + out.mkdirs(); + java.io.File targ = new java.io.File(out, def.id + ".json"); + try (FileWriter fw = new FileWriter(targ)) + { + fw.write(gson.toJson(def)); + } + } + } + + public void java() throws IOException + { + java.mkdirs(); + java.io.File targ = new java.io.File(java, "NpcID.java"); + try (PrintWriter fw = new PrintWriter(targ)) + { + Set used = new HashSet<>(); + + fw.println("/* This file is automatically generated. Do not edit. */"); + fw.println("package net.runelite.api;"); + fw.println(""); + fw.println("public final class NpcID {"); + for (NpcDefinition def : loader.getNpcs()) + { + if (def.name.equalsIgnoreCase("NULL")) + continue; + + String name = name(def.name); + if (name == null) + continue; + + String suffix = ""; + while (used.contains(name + suffix)) + { + if (suffix.isEmpty()) + suffix = "_2"; + else + suffix = "_" + (Integer.parseInt(suffix.substring(1)) + 1); + } + name += suffix; + + used.add(name); + + fw.println(" public static final int " + name + " = " + def.id + ";"); + } + fw.println("}"); + } + } + + private static String name(String in) + { + String s = in.toUpperCase() + .replace(' ', '_') + .replaceAll("[^a-zA-Z0-9_]", ""); + if (s.isEmpty()) + return null; + if (Character.isDigit(s.charAt(0))) + return "_" + s; + else + return s; + } +} diff --git a/cache/src/main/java/net/runelite/cache/ObjectDumper.java b/cache/src/main/java/net/runelite/cache/ObjectDumper.java new file mode 100644 index 0000000000..14397c0a03 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/ObjectDumper.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import net.runelite.cache.definitions.ObjectDefinition; +import net.runelite.cache.definitions.loaders.ObjectLoader; +import net.runelite.cache.fs.Archive; +import net.runelite.cache.fs.Index; +import net.runelite.cache.fs.Store; + +public class ObjectDumper +{ + private final File cache, out, java; + private final Gson gson; + private ObjectLoader loader; + private final List objects = new ArrayList<>(); + + public ObjectDumper(File cache, File out, File java) + { + this.cache = cache; + this.out = out; + this.java = java; + + GsonBuilder builder = new GsonBuilder() + .setPrettyPrinting(); + gson = builder.create(); + } + + public static void main(String[] args) throws IOException + { + if (args.length < 3) + System.exit(1); + + File cache = new File(args[0]); + File out = new File(args[1]); + File java = new File(args[2]); + + ObjectDumper dumper = new ObjectDumper(cache, out, java); + dumper.load(); + dumper.dump(); + dumper.java(); + } + + public void load() throws IOException + { + loader = new ObjectLoader(); + + try (Store store = new Store(cache)) + { + store.load(); + + Index index = store.getIndex(IndexType.CONFIGS); + Archive archive = index.getArchive(ConfigType.OBJECT.getId()); + + for (net.runelite.cache.fs.File f : archive.getFiles()) + { + ObjectDefinition def = loader.load(f.getFileId(), f.getContents()); + objects.add(def); + } + } + } + + public void dump() throws IOException + { + for (ObjectDefinition def : objects) + { + out.mkdirs(); + java.io.File targ = new java.io.File(out, def.getId() + ".json"); + try (FileWriter fw = new FileWriter(targ)) + { + fw.write(gson.toJson(def)); + } + } + } + + public void java() throws IOException + { + java.mkdirs(); + java.io.File targ = new java.io.File(java, "ObjectID.java"); + try (PrintWriter fw = new PrintWriter(targ)) + { + Set used = new HashSet<>(); + + fw.println("/* This file is automatically generated. Do not edit. */"); + fw.println("package net.runelite.api;"); + fw.println(""); + fw.println("public final class ObjectID {"); + for (ObjectDefinition def : objects) + { + if (def.getName().equalsIgnoreCase("NULL")) + continue; + + String name = name(def.getName()); + if (name == null) + continue; + + String suffix = ""; + while (used.contains(name + suffix)) + { + if (suffix.isEmpty()) + suffix = "_2"; + else + suffix = "_" + (Integer.parseInt(suffix.substring(1)) + 1); + } + name += suffix; + + used.add(name); + + fw.println(" public static final int " + name + " = " + def.getId() + ";"); + } + fw.println("}"); + } + } + + private static String name(String in) + { + String s = in.toUpperCase() + .replace(' ', '_') + .replaceAll("[^a-zA-Z0-9_]", ""); + if (s.isEmpty()) + return null; + if (Character.isDigit(s.charAt(0))) + return "_" + s; + else + return s; + } +} diff --git a/cache/src/main/java/net/runelite/cache/definitions/EnumDefinition.java b/cache/src/main/java/net/runelite/cache/definitions/EnumDefinition.java new file mode 100644 index 0000000000..10cf714bec --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/definitions/EnumDefinition.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.definitions; + +public class EnumDefinition +{ + private int id; + private int[] intVals; + private char keyType; + private char valType; + private String defaultString = "null"; + private int defaultInt; + private int size; + private int[] keys; + private String[] stringVals; + + public int getId() + { + return id; + } + + public void setId(int id) + { + this.id = id; + } + + public int[] getIntVals() + { + return intVals; + } + + public void setIntVals(int[] intVals) + { + this.intVals = intVals; + } + + public char getKeyType() + { + return keyType; + } + + public void setKeyType(char keyType) + { + this.keyType = keyType; + } + + public char getValType() + { + return valType; + } + + public void setValType(char valType) + { + this.valType = valType; + } + + public String getDefaultString() + { + return defaultString; + } + + public void setDefaultString(String defaultString) + { + this.defaultString = defaultString; + } + + public int getDefaultInt() + { + return defaultInt; + } + + public void setDefaultInt(int defaultInt) + { + this.defaultInt = defaultInt; + } + + public int getSize() + { + return size; + } + + public void setSize(int size) + { + this.size = size; + } + + public int[] getKeys() + { + return keys; + } + + public void setKeys(int[] keys) + { + this.keys = keys; + } + + public String[] getStringVals() + { + return stringVals; + } + + public void setStringVals(String[] stringVals) + { + this.stringVals = stringVals; + } +} diff --git a/cache/src/main/java/net/runelite/cache/definitions/ItemDefinition.java b/cache/src/main/java/net/runelite/cache/definitions/ItemDefinition.java new file mode 100644 index 0000000000..1b039e26b2 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/definitions/ItemDefinition.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.definitions; + +public class ItemDefinition +{ + public int id; + public int resizeY; + public int xan2d = 0; + public int cost = 1; + public int inventoryModel; + public int resizeZ; + public short[] colorFind; + public short[] colorReplace; + public short[] textureFind; + public String name = "null"; + public int zoom2d = 200000; + public int yan2d = 0; + public int zan2d = 0; + public int maleOffset; + public int yOffset2d = 0; + public int stackable = 0; + public int[] countCo; + public boolean members = false; + public String[] options; + public String[] interfaceOptions; + public int maleModel0; + public int maleModel1; + public short[] textureReplace; + public int femaleModel1; + public int femaleOffset; + public int maleModel2; + public int xOffset2d = 0; + public int maleHeadModel; + public int maleHeadModel2; + public int femaleHeadModel; + public int femaleHeadModel2; + public int[] countObj; + public int femaleModel2; + public int notedID; + public int femaleModel0; + public int resizeX; + public int notedTemplate; + public int ambient; + public int contrast; + public int team; + + public ItemDefinition(int definitionID) + { + this.id = definitionID; + this.options = new String[] + { + null, null, "Take", null, null + }; + this.interfaceOptions = new String[] + { + null, null, null, null, "Drop" + }; + this.maleModel0 = -1; + this.maleModel1 = -1; + this.maleOffset = 0; + this.femaleModel0 = -1; + this.femaleModel1 = -1; + this.femaleOffset = 0; + this.maleModel2 = -1; + this.femaleModel2 = -1; + this.maleHeadModel = -1; + this.maleHeadModel2 = -1; + this.femaleHeadModel = -1; + this.femaleHeadModel2 = -1; + this.notedID = -1; + this.notedTemplate = -1; + this.resizeX = 0; + this.resizeY = 0; + this.resizeZ = 0; + this.ambient = 0; + this.contrast = 0; + this.team = 0; + } +} diff --git a/cache/src/main/java/net/runelite/cache/definitions/ModelDefinition.java b/cache/src/main/java/net/runelite/cache/definitions/ModelDefinition.java new file mode 100644 index 0000000000..eff96f563b --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/definitions/ModelDefinition.java @@ -0,0 +1,45 @@ +package net.runelite.cache.definitions; + +public class ModelDefinition +{ + public short[] texTriangleX; + public int[] vertexX; + public byte[] faceRenderPriorities; + public int[] vertexY; + public int triangleFaceCount; + public int[] trianglePointsX; + public int[] vertexSkins; + public int[] trianglePointsZ; + public int anInt2562; + public int[] trianglePointsY; + public byte[] faceAlphas; + public short aShort2565; + public byte[] faceRenderType; + public short[] faceTextures; + public byte priority; + public int anInt2569; + public byte[] textureRenderTypes; + public short[] texTriangleY; + public short[] texTriangleZ; + public short[] aShortArray2574; + public short[] aShortArray2575; + public short[] aShortArray2577; + public short[] aShortArray2578; + boolean aBool2579; + public byte[] aByteArray2580; + public byte[] textureCoords; + public int[] triangleSkinValues; + public int[][] anIntArrayArray2583; + public int[][] anIntArrayArray2584; + public short[] aShortArray2586; + public short aShort2589; + public short[] faceColor; + public int shadowIntensity; + public int anInt2592; + public int anInt2593; + public int[] vertexZ; + public int anInt2595; + public int vertexCount = 0; + public short[] texturePrimaryColor; + +} diff --git a/cache/src/main/java/net/runelite/cache/definitions/NpcDefinition.java b/cache/src/main/java/net/runelite/cache/definitions/NpcDefinition.java new file mode 100644 index 0000000000..f942cc6f1e --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/definitions/NpcDefinition.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.definitions; + +public class NpcDefinition +{ + + public int id; + public short[] recolorToFind; + public int anInt2156 = 32; + public String name = "null"; + public short[] recolorToReplace; + public int[] models; + public int[] models_2; + public int stanceAnimation = -1; + public int anInt2165 = -1; + public int tileSpacesOccupied = 1; + public int walkAnimation = -1; + public short[] retextureToReplace; + public int rotate90RightAnimation = -1; + public boolean aBool2170 = true; + public int resizeX = 128; + public int contrast = 0; + public int rotate180Animation = -1; + public int anInt2174 = -1; + public String[] options = new String[5]; + public boolean renderOnMinimap = true; + public int combatLevel = -1; + public int rotate90LeftAnimation = -1; + public int resizeY = 128; + public boolean hasRenderPriority = false; + public int ambient = 0; + public int headIcon = -1; + public int anInt2184 = 30; + public int[] anIntArray2185; + public short[] retextureToFind; + public int anInt2187 = -1; + public boolean isClickable = true; + public int anInt2189 = -1; + public boolean aBool2190 = false; + + public NpcDefinition(int definitionID) + { + this.id = definitionID; + } +} diff --git a/cache/src/main/java/net/runelite/cache/definitions/ObjectDefinition.java b/cache/src/main/java/net/runelite/cache/definitions/ObjectDefinition.java new file mode 100644 index 0000000000..3cb0407fed --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/definitions/ObjectDefinition.java @@ -0,0 +1,508 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.definitions; + +public class ObjectDefinition +{ + private int id; + private short[] retextureToFind; + private int anInt2069 = 16; + private boolean isSolid = false; + private String name = "null"; + private int[] objectModels; + private int[] objectTypes; + private short[] recolorToFind; + private int mapIconID = -1; + private short[] textureToReplace; + private int sizeX = 1; + private int sizeY = 1; + private int anInt2083 = 0; + private int[] anIntArray2084; + private int offsetX = 0; + private boolean nonFlatShading = false; + private int anInt2088 = -1; + private int animationID = -1; + private int varpID = -1; + private int ambient = 0; + private int contrast = 0; + private String[] actions = new String[5]; + private int anInt2094 = 2; + private int mapSceneID = -1; + private short[] recolorToReplace; + private boolean aBool2097 = true; + private int modelSizeX = 128; + private int modelSizeHeight = 128; + private int modelSizeY = 128; + private int objectID; + private int offsetHeight = 0; + private int offsetY = 0; + private boolean aBool2104 = false; + private int anInt2105 = -1; + private int anInt2106 = -1; + private int[] configChangeDest; + private boolean aBool2108 = false; + private int configId = -1; + private int anInt2110 = -1; + private boolean aBool2111 = false; + private int anInt2112 = 0; + private int anInt2113 = 0; + private boolean aBool2114 = true; + + public int getId() + { + return id; + } + + public void setId(int id) + { + this.id = id; + } + + public short[] getRetextureToFind() + { + return retextureToFind; + } + + public void setRetextureToFind(short[] retextureToFind) + { + this.retextureToFind = retextureToFind; + } + + public int getAnInt2069() + { + return anInt2069; + } + + public void setAnInt2069(int anInt2069) + { + this.anInt2069 = anInt2069; + } + + public boolean isIsSolid() + { + return isSolid; + } + + public void setIsSolid(boolean isSolid) + { + this.isSolid = isSolid; + } + + public String getName() + { + return name; + } + + public void setName(String name) + { + this.name = name; + } + + public int[] getObjectModels() + { + return objectModels; + } + + public void setObjectModels(int[] objectModels) + { + this.objectModels = objectModels; + } + + public int[] getObjectTypes() + { + return objectTypes; + } + + public void setObjectTypes(int[] objectTypes) + { + this.objectTypes = objectTypes; + } + + public short[] getRecolorToFind() + { + return recolorToFind; + } + + public void setRecolorToFind(short[] recolorToFind) + { + this.recolorToFind = recolorToFind; + } + + public int getMapIconID() + { + return mapIconID; + } + + public void setMapIconID(int mapIconID) + { + this.mapIconID = mapIconID; + } + + public short[] getTextureToReplace() + { + return textureToReplace; + } + + public void setTextureToReplace(short[] textureToReplace) + { + this.textureToReplace = textureToReplace; + } + + public int getSizeX() + { + return sizeX; + } + + public void setSizeX(int sizeX) + { + this.sizeX = sizeX; + } + + public int getSizeY() + { + return sizeY; + } + + public void setSizeY(int sizeY) + { + this.sizeY = sizeY; + } + + public int getAnInt2083() + { + return anInt2083; + } + + public void setAnInt2083(int anInt2083) + { + this.anInt2083 = anInt2083; + } + + public int[] getAnIntArray2084() + { + return anIntArray2084; + } + + public void setAnIntArray2084(int[] anIntArray2084) + { + this.anIntArray2084 = anIntArray2084; + } + + public int getOffsetX() + { + return offsetX; + } + + public void setOffsetX(int offsetX) + { + this.offsetX = offsetX; + } + + public boolean isNonFlatShading() + { + return nonFlatShading; + } + + public void setNonFlatShading(boolean nonFlatShading) + { + this.nonFlatShading = nonFlatShading; + } + + public int getAnInt2088() + { + return anInt2088; + } + + public void setAnInt2088(int anInt2088) + { + this.anInt2088 = anInt2088; + } + + public int getAnimationID() + { + return animationID; + } + + public void setAnimationID(int animationID) + { + this.animationID = animationID; + } + + public int getVarpID() + { + return varpID; + } + + public void setVarpID(int varpID) + { + this.varpID = varpID; + } + + public int getAmbient() + { + return ambient; + } + + public void setAmbient(int ambient) + { + this.ambient = ambient; + } + + public int getContrast() + { + return contrast; + } + + public void setContrast(int contrast) + { + this.contrast = contrast; + } + + public String[] getActions() + { + return actions; + } + + public void setActions(String[] actions) + { + this.actions = actions; + } + + public int getAnInt2094() + { + return anInt2094; + } + + public void setAnInt2094(int anInt2094) + { + this.anInt2094 = anInt2094; + } + + public int getMapSceneID() + { + return mapSceneID; + } + + public void setMapSceneID(int mapSceneID) + { + this.mapSceneID = mapSceneID; + } + + public short[] getRecolorToReplace() + { + return recolorToReplace; + } + + public void setRecolorToReplace(short[] recolorToReplace) + { + this.recolorToReplace = recolorToReplace; + } + + public boolean isaBool2097() + { + return aBool2097; + } + + public void setaBool2097(boolean aBool2097) + { + this.aBool2097 = aBool2097; + } + + public int getModelSizeX() + { + return modelSizeX; + } + + public void setModelSizeX(int modelSizeX) + { + this.modelSizeX = modelSizeX; + } + + public int getModelSizeHeight() + { + return modelSizeHeight; + } + + public void setModelSizeHeight(int modelSizeHeight) + { + this.modelSizeHeight = modelSizeHeight; + } + + public int getModelSizeY() + { + return modelSizeY; + } + + public void setModelSizeY(int modelSizeY) + { + this.modelSizeY = modelSizeY; + } + + public int getObjectID() + { + return objectID; + } + + public void setObjectID(int objectID) + { + this.objectID = objectID; + } + + public int getOffsetHeight() + { + return offsetHeight; + } + + public void setOffsetHeight(int offsetHeight) + { + this.offsetHeight = offsetHeight; + } + + public int getOffsetY() + { + return offsetY; + } + + public void setOffsetY(int offsetY) + { + this.offsetY = offsetY; + } + + public boolean isaBool2104() + { + return aBool2104; + } + + public void setaBool2104(boolean aBool2104) + { + this.aBool2104 = aBool2104; + } + + public int getAnInt2105() + { + return anInt2105; + } + + public void setAnInt2105(int anInt2105) + { + this.anInt2105 = anInt2105; + } + + public int getAnInt2106() + { + return anInt2106; + } + + public void setAnInt2106(int anInt2106) + { + this.anInt2106 = anInt2106; + } + + public int[] getConfigChangeDest() + { + return configChangeDest; + } + + public void setConfigChangeDest(int[] configChangeDest) + { + this.configChangeDest = configChangeDest; + } + + public boolean isaBool2108() + { + return aBool2108; + } + + public void setaBool2108(boolean aBool2108) + { + this.aBool2108 = aBool2108; + } + + public int getConfigId() + { + return configId; + } + + public void setConfigId(int configId) + { + this.configId = configId; + } + + public int getAnInt2110() + { + return anInt2110; + } + + public void setAnInt2110(int anInt2110) + { + this.anInt2110 = anInt2110; + } + + public boolean isaBool2111() + { + return aBool2111; + } + + public void setaBool2111(boolean aBool2111) + { + this.aBool2111 = aBool2111; + } + + public int getAnInt2112() + { + return anInt2112; + } + + public void setAnInt2112(int anInt2112) + { + this.anInt2112 = anInt2112; + } + + public int getAnInt2113() + { + return anInt2113; + } + + public void setAnInt2113(int anInt2113) + { + this.anInt2113 = anInt2113; + } + + public boolean isaBool2114() + { + return aBool2114; + } + + public void setaBool2114(boolean aBool2114) + { + this.aBool2114 = aBool2114; + } +} diff --git a/cache/src/main/java/net/runelite/cache/definitions/ScriptDefinition.java b/cache/src/main/java/net/runelite/cache/definitions/ScriptDefinition.java new file mode 100644 index 0000000000..bc75a9efe4 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/definitions/ScriptDefinition.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.definitions; + +public class ScriptDefinition +{ + private int id; + private int anInt2269; + private int[] instructions; + private int[] intOperands; + private String[] aStringArray2272; + private int localStringCount; + private int anInt2276; + private int localIntCount; + + public int getId() + { + return id; + } + + public void setId(int id) + { + this.id = id; + } + + public int getAnInt2269() + { + return anInt2269; + } + + public void setAnInt2269(int anInt2269) + { + this.anInt2269 = anInt2269; + } + + public int[] getInstructions() + { + return instructions; + } + + public void setInstructions(int[] instructions) + { + this.instructions = instructions; + } + + public int[] getIntOperands() + { + return intOperands; + } + + public void setIntOperands(int[] intOperands) + { + this.intOperands = intOperands; + } + + public String[] getaStringArray2272() + { + return aStringArray2272; + } + + public void setaStringArray2272(String[] aStringArray2272) + { + this.aStringArray2272 = aStringArray2272; + } + + public int getLocalStringCount() + { + return localStringCount; + } + + public void setLocalStringCount(int localStringCount) + { + this.localStringCount = localStringCount; + } + + public int getAnInt2276() + { + return anInt2276; + } + + public void setAnInt2276(int anInt2276) + { + this.anInt2276 = anInt2276; + } + + public int getLocalIntCount() + { + return localIntCount; + } + + public void setLocalIntCount(int localIntCount) + { + this.localIntCount = localIntCount; + } +} diff --git a/cache/src/main/java/net/runelite/cache/definitions/SpriteDefinition.java b/cache/src/main/java/net/runelite/cache/definitions/SpriteDefinition.java new file mode 100644 index 0000000000..4f0163ff5c --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/definitions/SpriteDefinition.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.definitions; + +import net.runelite.cache.definitions.loaders.SpriteLoader; + +public class SpriteDefinition +{ + private SpriteLoader loader; + private int offsetX; + private int offsetY; + private int width; + private int height; + private byte[] pixels; + private int maxWidth; + private int maxHeight; + + public SpriteDefinition(SpriteLoader loader) + { + this.loader = loader; + } + + public SpriteLoader getLoader() + { + return loader; + } + + public void setLoader(SpriteLoader loader) + { + this.loader = loader; + } + + public int getOffsetX() + { + return offsetX; + } + + public void setOffsetX(int offsetX) + { + this.offsetX = offsetX; + } + + public int getOffsetY() + { + return offsetY; + } + + public void setOffsetY(int offsetY) + { + this.offsetY = offsetY; + } + + public int getWidth() + { + return width; + } + + public void setWidth(int width) + { + this.width = width; + } + + public int getHeight() + { + return height; + } + + public void setHeight(int height) + { + this.height = height; + } + + public byte[] getPixels() + { + return pixels; + } + + public void setPixels(byte[] pixels) + { + this.pixels = pixels; + } + + public int getMaxWidth() + { + return maxWidth; + } + + public void setMaxWidth(int maxWidth) + { + this.maxWidth = maxWidth; + } + + public int getMaxHeight() + { + return maxHeight; + } + + public void setMaxHeight(int maxHeight) + { + this.maxHeight = maxHeight; + } + + +} diff --git a/cache/src/main/java/net/runelite/cache/definitions/loaders/EnumLoader.java b/cache/src/main/java/net/runelite/cache/definitions/loaders/EnumLoader.java new file mode 100644 index 0000000000..b8f5e155c1 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/definitions/loaders/EnumLoader.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.cache.definitions.loaders; + +import net.runelite.cache.definitions.EnumDefinition; +import net.runelite.cache.io.InputStream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class EnumLoader +{ + private static final Logger logger = LoggerFactory.getLogger(EnumLoader.class); + + public EnumDefinition load(int id, byte[] b) + { + EnumDefinition def = new EnumDefinition(); + InputStream is = new InputStream(b); + + def.setId(id); + + for (;;) + { + int opcode = is.readUnsignedByte(); + if (opcode == 0) + { + break; + } + + processOp(opcode, def, is); + } + + return def; + } + + private void processOp(int opcode, EnumDefinition def, InputStream is) + { + switch (opcode) + { + case 1: + def.setKeyType((char) is.readUnsignedByte()); + break; + case 2: + def.setValType((char) is.readUnsignedByte()); + break; + case 3: + def.setDefaultString(is.readString()); + break; + case 4: + def.setDefaultInt(is.readInt()); + break; + case 5: + { + int size = is.readUnsignedShort(); + int[] keys = new int[size]; + String[] stringVals = new String[size]; + for (int index = 0; index < size; ++index) + { + keys[index] = is.readInt(); + stringVals[index] = is.readString(); + } + def.setKeys(keys); + def.setStringVals(stringVals); + break; + } + case 6: + { + int size = is.readUnsignedShort(); + int[] keys = new int[size]; + int[] intVals = new int[size]; + for (int index = 0; index < size; ++index) + { + keys[index] = is.readInt(); + intVals[index] = is.readInt(); + } + def.setKeys(keys); + def.setIntVals(intVals); + break; + } + default: + logger.warn("Unrecognized opcode {}", opcode); + break; + } + } +} diff --git a/cache/src/main/java/net/runelite/cache/definitions/loaders/ItemLoader.java b/cache/src/main/java/net/runelite/cache/definitions/loaders/ItemLoader.java new file mode 100644 index 0000000000..7b8f6aca36 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/definitions/loaders/ItemLoader.java @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.definitions.loaders; + +import java.util.ArrayList; +import java.util.List; +import net.runelite.cache.definitions.ItemDefinition; +import net.runelite.cache.io.InputStream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ItemLoader +{ + private static final Logger logger = LoggerFactory.getLogger(ItemLoader.class); + private final List items = new ArrayList<>(); + + public List getItems() + { + return items; + } + + public void load(int id, InputStream stream) + { + ItemDefinition def = new ItemDefinition(id); + + while (true) + { + int opcode = stream.readUnsignedByte(); + if (opcode == 0) + { + break; + } + + this.decodeValues(opcode, def, stream); + } + + items.add(def); + } + + private void decodeValues(int opcode, ItemDefinition def, InputStream stream) + { + if (opcode == 1) + { + def.inventoryModel = stream.readUnsignedShort(); + } + else if (opcode == 2) + { + def.name = stream.readString(); + } + else if (opcode == 4) + { + def.zoom2d = stream.readUnsignedShort(); + } + else if (opcode == 5) + { + def.xan2d = stream.readUnsignedShort(); + } + else if (opcode == 6) + { + def.yan2d = stream.readUnsignedShort(); + } + else if (7 == opcode) + { + def.xOffset2d = stream.readUnsignedShort(); + if (def.xOffset2d > 32767) + { + def.xOffset2d -= 65536; + } + } + else if (8 == opcode) + { + def.yOffset2d = stream.readUnsignedShort(); + if (def.yOffset2d > 32767) + { + def.yOffset2d -= 65536; + } + } + else if (11 == opcode) + { + def.stackable = 1; + } + else if (opcode == 12) + { + def.cost = stream.readInt(); + } + else if (16 == opcode) + { + def.members = true; + } + else if (opcode == 23) + { + def.maleModel0 = stream.readUnsignedShort(); + def.maleOffset = stream.readUnsignedByte(); + } + else if (opcode == 24) + { + def.maleModel1 = stream.readUnsignedShort(); + } + else if (25 == opcode) + { + def.femaleModel0 = stream.readUnsignedShort(); + def.femaleOffset = stream.readUnsignedByte(); + } + else if (26 == opcode) + { + def.femaleModel1 = stream.readUnsignedShort(); + } + else if (opcode >= 30 && opcode < 35) + { + def.options[opcode - 30] = stream.readString(); + if (def.options[opcode - 30].equalsIgnoreCase("Hidden")) + { + def.options[opcode - 30] = null; + } + } + else if (opcode >= 35 && opcode < 40) + { + def.interfaceOptions[opcode - 35] = stream.readString(); + } + else if (opcode == 40) + { + int var5 = stream.readUnsignedByte(); + def.colorFind = new short[var5]; + def.colorReplace = new short[var5]; + + for (int var4 = 0; var4 < var5; ++var4) + { + def.colorFind[var4] = (short) stream.readUnsignedShort(); + def.colorReplace[var4] = (short) stream.readUnsignedShort(); + } + + } + else if (opcode == 78) + { + def.maleModel2 = stream.readUnsignedShort(); + } + else if (opcode == 79) + { + def.femaleModel2 = stream.readUnsignedShort(); + } + else if (90 == opcode) + { + def.maleHeadModel = stream.readUnsignedShort(); + } + else if (91 == opcode) + { + def.femaleHeadModel = stream.readUnsignedShort(); + } + else if (92 == opcode) + { + def.maleHeadModel2 = stream.readUnsignedShort(); + } + else if (opcode == 93) + { + def.femaleHeadModel2 = stream.readUnsignedShort(); + } + else if (opcode == 95) + { + def.zan2d = stream.readUnsignedShort(); + } + else if (97 == opcode) + { + def.notedID = stream.readUnsignedShort(); + } + else if (98 == opcode) + { + def.notedTemplate = stream.readUnsignedShort(); + } + else if (opcode >= 100 && opcode < 110) + { + if (def.countObj == null) + { + def.countObj = new int[10]; + def.countCo = new int[10]; + } + + def.countObj[opcode - 100] = stream.readUnsignedShort(); + def.countCo[opcode - 100] = stream.readUnsignedShort(); + } + else if (110 == opcode) + { + def.resizeX = stream.readUnsignedShort(); + } + else if (opcode == 111) + { + def.resizeY = stream.readUnsignedShort(); + } + else if (opcode == 112) + { + def.resizeZ = stream.readUnsignedShort(); + } + else if (opcode == 113) + { + def.ambient = stream.readByte(); + } + else if (114 == opcode) + { + def.contrast = stream.readByte(); + } + else if (115 == opcode) + { + def.team = stream.readUnsignedByte(); + } + else if (opcode == 41) + { + int var5 = stream.readUnsignedByte(); + def.textureFind = new short[var5]; + def.textureReplace = new short[var5]; + + for (int var4 = 0; var4 < var5; ++var4) + { + def.textureFind[var4] = (short) stream.readUnsignedShort(); + def.textureReplace[var4] = (short) stream.readUnsignedShort(); + } + + } + else if (opcode == 148) + { + stream.readUnsignedShort(); + } + else if (opcode == 65) + { + + } + else if (opcode == 139) + { + stream.readUnsignedShort(); + } + else if (opcode == 140) + { + + } + else + { + logger.warn("Unrecognized opcode {}", opcode); + } + } +} diff --git a/cache/src/main/java/net/runelite/cache/definitions/loaders/ModelLoader.java b/cache/src/main/java/net/runelite/cache/definitions/loaders/ModelLoader.java new file mode 100644 index 0000000000..b613a8837b --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/definitions/loaders/ModelLoader.java @@ -0,0 +1,741 @@ +package net.runelite.cache.definitions.loaders; + +import net.runelite.cache.definitions.ModelDefinition; +import net.runelite.cache.io.InputStream; + +public class ModelLoader extends ModelDefinition +{ + public void load(byte[] var1) + { + if (var1[var1.length - 1] == -1 && var1[var1.length - 2] == -1) + { + this.load1(var1); + } + else + { + this.load2(var1); + } + } + + private void load1(byte[] var1) + { + InputStream var2 = new InputStream(var1); + InputStream var24 = new InputStream(var1); + InputStream var3 = new InputStream(var1); + InputStream var28 = new InputStream(var1); + InputStream var6 = new InputStream(var1); + InputStream var55 = new InputStream(var1); + InputStream var51 = new InputStream(var1); + var2.setOffset(var1.length - 23); + int verticeCount = var2.readUnsignedShort(); + int triangleCount = var2.readUnsignedShort(); + int textureTriangleCount = var2.readUnsignedByte(); + int var13 = var2.readUnsignedByte(); + int modelPriority = var2.readUnsignedByte(); + int var50 = var2.readUnsignedByte(); + int var17 = var2.readUnsignedByte(); + int modelTexture = var2.readUnsignedByte(); + int modelVertexSkins = var2.readUnsignedByte(); + int var20 = var2.readUnsignedShort(); + int var21 = var2.readUnsignedShort(); + int var42 = var2.readUnsignedShort(); + int var22 = var2.readUnsignedShort(); + int var38 = var2.readUnsignedShort(); + int textureAmount = 0; + int var7 = 0; + int var29 = 0; + int position; + if (textureTriangleCount > 0) + { + this.textureRenderTypes = new byte[textureTriangleCount]; + var2.setOffset(0); + + for (position = 0; position < textureTriangleCount; ++position) + { + byte renderType = this.textureRenderTypes[position] = var2.readByte(); + if (renderType == 0) + { + ++textureAmount; + } + + if (renderType >= 1 && renderType <= 3) + { + ++var7; + } + + if (renderType == 2) + { + ++var29; + } + } + } + + position = textureTriangleCount + verticeCount; + int renderTypePos = position; + if (var13 == 1) + { + position += triangleCount; + } + + int var49 = position; + position += triangleCount; + int priorityPos = position; + if (modelPriority == 255) + { + position += triangleCount; + } + + int triangleSkinPos = position; + if (var17 == 1) + { + position += triangleCount; + } + + int var35 = position; + if (modelVertexSkins == 1) + { + position += verticeCount; + } + + int alphaPos = position; + if (var50 == 1) + { + position += triangleCount; + } + + int var11 = position; + position += var22; + int texturePos = position; + if (modelTexture == 1) + { + position += triangleCount * 2; + } + + int textureCoordPos = position; + position += var38; + int colorPos = position; + position += triangleCount * 2; + int var40 = position; + position += var20; + int var41 = position; + position += var21; + int var8 = position; + position += var42; + int var43 = position; + position += textureAmount * 6; + int var37 = position; + position += var7 * 6; + int var48 = position; + position += var7 * 6; + int var56 = position; + position += var7 * 2; + int var45 = position; + position += var7; + int var46 = position; + position += var7 * 2 + var29 * 2; + this.vertexCount = verticeCount; + this.triangleFaceCount = triangleCount; + this.anInt2569 = textureTriangleCount; + this.vertexX = new int[verticeCount]; + this.vertexY = new int[verticeCount]; + this.vertexZ = new int[verticeCount]; + this.trianglePointsX = new int[triangleCount]; + this.trianglePointsY = new int[triangleCount]; + this.trianglePointsZ = new int[triangleCount]; + if (modelVertexSkins == 1) + { + this.vertexSkins = new int[verticeCount]; + } + + if (var13 == 1) + { + this.faceRenderType = new byte[triangleCount]; + } + + if (modelPriority == 255) + { + this.faceRenderPriorities = new byte[triangleCount]; + } + else + { + this.priority = (byte) modelPriority; + } + + if (var50 == 1) + { + this.faceAlphas = new byte[triangleCount]; + } + + if (var17 == 1) + { + this.triangleSkinValues = new int[triangleCount]; + } + + if (modelTexture == 1) + { + this.faceTextures = new short[triangleCount]; + } + + if (modelTexture == 1 && textureTriangleCount > 0) + { + this.textureCoords = new byte[triangleCount]; + } + + this.faceColor = new short[triangleCount]; + if (textureTriangleCount > 0) + { + this.texTriangleX = new short[textureTriangleCount]; + this.texTriangleY = new short[textureTriangleCount]; + this.texTriangleZ = new short[textureTriangleCount]; + if (var7 > 0) + { + this.aShortArray2574 = new short[var7]; + this.aShortArray2575 = new short[var7]; + this.aShortArray2586 = new short[var7]; + this.aShortArray2577 = new short[var7]; + this.aByteArray2580 = new byte[var7]; + this.aShortArray2578 = new short[var7]; + } + + if (var29 > 0) + { + this.texturePrimaryColor = new short[var29]; + } + } + + var2.setOffset(textureTriangleCount); + var24.setOffset(var40); + var3.setOffset(var41); + var28.setOffset(var8); + var6.setOffset(var35); + int vX = 0; + int vY = 0; + int vZ = 0; + + int vertexZOffset; + int var10; + int vertexYOffset; + int var15; + int point; + for (point = 0; point < verticeCount; ++point) + { + int vertexFlags = var2.readUnsignedByte(); + int vertexXOffset = 0; + if ((vertexFlags & 1) != 0) + { + vertexXOffset = var24.readShortSmart(); + } + + vertexYOffset = 0; + if ((vertexFlags & 2) != 0) + { + vertexYOffset = var3.readShortSmart(); + } + + vertexZOffset = 0; + if ((vertexFlags & 4) != 0) + { + vertexZOffset = var28.readShortSmart(); + } + + this.vertexX[point] = vX + vertexXOffset; + this.vertexY[point] = vY + vertexYOffset; + this.vertexZ[point] = vZ + vertexZOffset; + vX = this.vertexX[point]; + vY = this.vertexY[point]; + vZ = this.vertexZ[point]; + if (modelVertexSkins == 1) + { + this.vertexSkins[point] = var6.readUnsignedByte(); + } + } + + var2.setOffset(colorPos); + var24.setOffset(renderTypePos); + var3.setOffset(priorityPos); + var28.setOffset(alphaPos); + var6.setOffset(triangleSkinPos); + var55.setOffset(texturePos); + var51.setOffset(textureCoordPos); + + for (point = 0; point < triangleCount; ++point) + { + this.faceColor[point] = (short) var2.readUnsignedShort(); + if (var13 == 1) + { + this.faceRenderType[point] = var24.readByte(); + } + + if (modelPriority == 255) + { + this.faceRenderPriorities[point] = var3.readByte(); + } + + if (var50 == 1) + { + this.faceAlphas[point] = var28.readByte(); + } + + if (var17 == 1) + { + this.triangleSkinValues[point] = var6.readUnsignedByte(); + } + + if (modelTexture == 1) + { + this.faceTextures[point] = (short) (var55.readUnsignedShort() - 1); + } + + if (this.textureCoords != null && this.faceTextures[point] != -1) + { + this.textureCoords[point] = (byte) (var51.readUnsignedByte() - 1); + } + } + + var2.setOffset(var11); + var24.setOffset(var49); + int trianglePointX = 0; + int trianglePointY = 0; + int trianglePointZ = 0; + vertexYOffset = 0; + + int var16; + for (vertexZOffset = 0; vertexZOffset < triangleCount; ++vertexZOffset) + { + int numFaces = var24.readUnsignedByte(); + if (numFaces == 1) + { + trianglePointX = var2.readShortSmart() + vertexYOffset; + trianglePointY = var2.readShortSmart() + trianglePointX; + trianglePointZ = var2.readShortSmart() + trianglePointY; + vertexYOffset = trianglePointZ; + this.trianglePointsX[vertexZOffset] = trianglePointX; + this.trianglePointsY[vertexZOffset] = trianglePointY; + this.trianglePointsZ[vertexZOffset] = trianglePointZ; + } + + if (numFaces == 2) + { + trianglePointY = trianglePointZ; + trianglePointZ = var2.readShortSmart() + vertexYOffset; + vertexYOffset = trianglePointZ; + this.trianglePointsX[vertexZOffset] = trianglePointX; + this.trianglePointsY[vertexZOffset] = trianglePointY; + this.trianglePointsZ[vertexZOffset] = trianglePointZ; + } + + if (numFaces == 3) + { + trianglePointX = trianglePointZ; + trianglePointZ = var2.readShortSmart() + vertexYOffset; + vertexYOffset = trianglePointZ; + this.trianglePointsX[vertexZOffset] = trianglePointX; + this.trianglePointsY[vertexZOffset] = trianglePointY; + this.trianglePointsZ[vertexZOffset] = trianglePointZ; + } + + if (numFaces == 4) + { + int var57 = trianglePointX; + trianglePointX = trianglePointY; + trianglePointY = var57; + trianglePointZ = var2.readShortSmart() + vertexYOffset; + vertexYOffset = trianglePointZ; + this.trianglePointsX[vertexZOffset] = trianglePointX; + this.trianglePointsY[vertexZOffset] = var57; + this.trianglePointsZ[vertexZOffset] = trianglePointZ; + } + } + + var2.setOffset(var43); + var24.setOffset(var37); + var3.setOffset(var48); + var28.setOffset(var56); + var6.setOffset(var45); + var55.setOffset(var46); + + for (int texIndex = 0; texIndex < textureTriangleCount; ++texIndex) + { + int type = this.textureRenderTypes[texIndex] & 255; + if (type == 0) + { + this.texTriangleX[texIndex] = (short) var2.readUnsignedShort(); + this.texTriangleY[texIndex] = (short) var2.readUnsignedShort(); + this.texTriangleZ[texIndex] = (short) var2.readUnsignedShort(); + } + + if (type == 1) + { + this.texTriangleX[texIndex] = (short) var24.readUnsignedShort(); + this.texTriangleY[texIndex] = (short) var24.readUnsignedShort(); + this.texTriangleZ[texIndex] = (short) var24.readUnsignedShort(); + this.aShortArray2574[texIndex] = (short) var3.readUnsignedShort(); + this.aShortArray2575[texIndex] = (short) var3.readUnsignedShort(); + this.aShortArray2586[texIndex] = (short) var3.readUnsignedShort(); + this.aShortArray2577[texIndex] = (short) var28.readUnsignedShort(); + this.aByteArray2580[texIndex] = var6.readByte(); + this.aShortArray2578[texIndex] = (short) var55.readUnsignedShort(); + } + + if (type == 2) + { + this.texTriangleX[texIndex] = (short) var24.readUnsignedShort(); + this.texTriangleY[texIndex] = (short) var24.readUnsignedShort(); + this.texTriangleZ[texIndex] = (short) var24.readUnsignedShort(); + this.aShortArray2574[texIndex] = (short) var3.readUnsignedShort(); + this.aShortArray2575[texIndex] = (short) var3.readUnsignedShort(); + this.aShortArray2586[texIndex] = (short) var3.readUnsignedShort(); + this.aShortArray2577[texIndex] = (short) var28.readUnsignedShort(); + this.aByteArray2580[texIndex] = var6.readByte(); + this.aShortArray2578[texIndex] = (short) var55.readUnsignedShort(); + this.texturePrimaryColor[texIndex] = (short) var55.readUnsignedShort(); + } + + if (type == 3) + { + this.texTriangleX[texIndex] = (short) var24.readUnsignedShort(); + this.texTriangleY[texIndex] = (short) var24.readUnsignedShort(); + this.texTriangleZ[texIndex] = (short) var24.readUnsignedShort(); + this.aShortArray2574[texIndex] = (short) var3.readUnsignedShort(); + this.aShortArray2575[texIndex] = (short) var3.readUnsignedShort(); + this.aShortArray2586[texIndex] = (short) var3.readUnsignedShort(); + this.aShortArray2577[texIndex] = (short) var28.readUnsignedShort(); + this.aByteArray2580[texIndex] = var6.readByte(); + this.aShortArray2578[texIndex] = (short) var55.readUnsignedShort(); + } + } + + var2.setOffset(position); + vertexZOffset = var2.readUnsignedByte(); + if (vertexZOffset != 0) + { + //new Class41(); + var2.readUnsignedShort(); + var2.readUnsignedShort(); + var2.readUnsignedShort(); + var2.readInt(); + } + } + + private void load2(byte[] var1) + { + boolean var2 = false; + boolean var43 = false; + InputStream var5 = new InputStream(var1); + InputStream var39 = new InputStream(var1); + InputStream var26 = new InputStream(var1); + InputStream var9 = new InputStream(var1); + InputStream var3 = new InputStream(var1); + var5.setOffset(var1.length - 18); + int var10 = var5.readUnsignedShort(); + int var11 = var5.readUnsignedShort(); + int var12 = var5.readUnsignedByte(); + int var13 = var5.readUnsignedByte(); + int var14 = var5.readUnsignedByte(); + int var30 = var5.readUnsignedByte(); + int var15 = var5.readUnsignedByte(); + int var28 = var5.readUnsignedByte(); + int var27 = var5.readUnsignedShort(); + int var20 = var5.readUnsignedShort(); + int var36 = var5.readUnsignedShort(); + int var23 = var5.readUnsignedShort(); + byte var16 = 0; + int var46 = var16 + var10; + int var24 = var46; + var46 += var11; + int var25 = var46; + if (var14 == 255) + { + var46 += var11; + } + + int var4 = var46; + if (var15 == 1) + { + var46 += var11; + } + + int var42 = var46; + if (var13 == 1) + { + var46 += var11; + } + + int var37 = var46; + if (var28 == 1) + { + var46 += var10; + } + + int var29 = var46; + if (var30 == 1) + { + var46 += var11; + } + + int var44 = var46; + var46 += var23; + int var17 = var46; + var46 += var11 * 2; + int var32 = var46; + var46 += var12 * 6; + int var34 = var46; + var46 += var27; + int var35 = var46; + var46 += var20; + int var10000 = var46 + var36; + this.vertexCount = var10; + this.triangleFaceCount = var11; + this.anInt2569 = var12; + this.vertexX = new int[var10]; + this.vertexY = new int[var10]; + this.vertexZ = new int[var10]; + this.trianglePointsX = new int[var11]; + this.trianglePointsY = new int[var11]; + this.trianglePointsZ = new int[var11]; + if (var12 > 0) + { + this.textureRenderTypes = new byte[var12]; + this.texTriangleX = new short[var12]; + this.texTriangleY = new short[var12]; + this.texTriangleZ = new short[var12]; + } + + if (var28 == 1) + { + this.vertexSkins = new int[var10]; + } + + if (var13 == 1) + { + this.faceRenderType = new byte[var11]; + this.textureCoords = new byte[var11]; + this.faceTextures = new short[var11]; + } + + if (var14 == 255) + { + this.faceRenderPriorities = new byte[var11]; + } + else + { + this.priority = (byte) var14; + } + + if (var30 == 1) + { + this.faceAlphas = new byte[var11]; + } + + if (var15 == 1) + { + this.triangleSkinValues = new int[var11]; + } + + this.faceColor = new short[var11]; + var5.setOffset(var16); + var39.setOffset(var34); + var26.setOffset(var35); + var9.setOffset(var46); + var3.setOffset(var37); + int var41 = 0; + int var33 = 0; + int var19 = 0; + + int var6; + int var7; + int var8; + int var18; + int var31; + for (var18 = 0; var18 < var10; ++var18) + { + var8 = var5.readUnsignedByte(); + var31 = 0; + if ((var8 & 1) != 0) + { + var31 = var39.readShortSmart(); + } + + var6 = 0; + if ((var8 & 2) != 0) + { + var6 = var26.readShortSmart(); + } + + var7 = 0; + if ((var8 & 4) != 0) + { + var7 = var9.readShortSmart(); + } + + this.vertexX[var18] = var41 + var31; + this.vertexY[var18] = var33 + var6; + this.vertexZ[var18] = var19 + var7; + var41 = this.vertexX[var18]; + var33 = this.vertexY[var18]; + var19 = this.vertexZ[var18]; + if (var28 == 1) + { + this.vertexSkins[var18] = var3.readUnsignedByte(); + } + } + + var5.setOffset(var17); + var39.setOffset(var42); + var26.setOffset(var25); + var9.setOffset(var29); + var3.setOffset(var4); + + for (var18 = 0; var18 < var11; ++var18) + { + this.faceColor[var18] = (short) var5.readUnsignedShort(); + if (var13 == 1) + { + var8 = var39.readUnsignedByte(); + if ((var8 & 1) == 1) + { + this.faceRenderType[var18] = 1; + var2 = true; + } + else + { + this.faceRenderType[var18] = 0; + } + + if ((var8 & 2) == 2) + { + this.textureCoords[var18] = (byte) (var8 >> 2); + this.faceTextures[var18] = this.faceColor[var18]; + this.faceColor[var18] = 127; + if (this.faceTextures[var18] != -1) + { + var43 = true; + } + } + else + { + this.textureCoords[var18] = -1; + this.faceTextures[var18] = -1; + } + } + + if (var14 == 255) + { + this.faceRenderPriorities[var18] = var26.readByte(); + } + + if (var30 == 1) + { + this.faceAlphas[var18] = var9.readByte(); + } + + if (var15 == 1) + { + this.triangleSkinValues[var18] = var3.readUnsignedByte(); + } + } + + var5.setOffset(var44); + var39.setOffset(var24); + var18 = 0; + var8 = 0; + var31 = 0; + var6 = 0; + + int var21; + int var22; + for (var7 = 0; var7 < var11; ++var7) + { + var22 = var39.readUnsignedByte(); + if (var22 == 1) + { + var18 = var5.readShortSmart() + var6; + var8 = var5.readShortSmart() + var18; + var31 = var5.readShortSmart() + var8; + var6 = var31; + this.trianglePointsX[var7] = var18; + this.trianglePointsY[var7] = var8; + this.trianglePointsZ[var7] = var31; + } + + if (var22 == 2) + { + var8 = var31; + var31 = var5.readShortSmart() + var6; + var6 = var31; + this.trianglePointsX[var7] = var18; + this.trianglePointsY[var7] = var8; + this.trianglePointsZ[var7] = var31; + } + + if (var22 == 3) + { + var18 = var31; + var31 = var5.readShortSmart() + var6; + var6 = var31; + this.trianglePointsX[var7] = var18; + this.trianglePointsY[var7] = var8; + this.trianglePointsZ[var7] = var31; + } + + if (var22 == 4) + { + var21 = var18; + var18 = var8; + var8 = var21; + var31 = var5.readShortSmart() + var6; + var6 = var31; + this.trianglePointsX[var7] = var18; + this.trianglePointsY[var7] = var21; + this.trianglePointsZ[var7] = var31; + } + } + + var5.setOffset(var32); + + for (var7 = 0; var7 < var12; ++var7) + { + this.textureRenderTypes[var7] = 0; + this.texTriangleX[var7] = (short) var5.readUnsignedShort(); + this.texTriangleY[var7] = (short) var5.readUnsignedShort(); + this.texTriangleZ[var7] = (short) var5.readUnsignedShort(); + } + + if (this.textureCoords != null) + { + boolean var45 = false; + + for (var22 = 0; var22 < var11; ++var22) + { + var21 = this.textureCoords[var22] & 255; + if (var21 != 255) + { + if ((this.texTriangleX[var21] & '\uffff') == this.trianglePointsX[var22] && (this.texTriangleY[var21] & '\uffff') == this.trianglePointsY[var22] && (this.texTriangleZ[var21] & '\uffff') == this.trianglePointsZ[var22]) + { + this.textureCoords[var22] = -1; + } + else + { + var45 = true; + } + } + } + + if (!var45) + { + this.textureCoords = null; + } + } + + if (!var43) + { + this.faceTextures = null; + } + + if (!var2) + { + this.faceRenderType = null; + } + } + +} diff --git a/cache/src/main/java/net/runelite/cache/definitions/loaders/NpcLoader.java b/cache/src/main/java/net/runelite/cache/definitions/loaders/NpcLoader.java new file mode 100644 index 0000000000..69aa79ac69 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/definitions/loaders/NpcLoader.java @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.definitions.loaders; + +import java.util.ArrayList; +import java.util.List; +import net.runelite.cache.definitions.NpcDefinition; +import net.runelite.cache.io.InputStream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NpcLoader +{ + private static final Logger logger = LoggerFactory.getLogger(NpcLoader.class); + private final List npcs = new ArrayList<>(); + + public List getNpcs() + { + return npcs; + } + + public void load(int id, InputStream stream) + { + NpcDefinition def = new NpcDefinition(id); + while (true) + { + int opcode = stream.readUnsignedByte(); + if (opcode == 0) + { + break; + } + + this.decodeValues(opcode, def, stream); + } + npcs.add(def); + } + + void decodeValues(int opcode, NpcDefinition def, InputStream stream) + { + int length; + int index; + if (1 == opcode) + { + length = stream.readUnsignedByte(); + def.models = new int[length]; + + for (index = 0; index < length; ++index) + { + def.models[index] = stream.readUnsignedShort(); + } + + } + else if (2 == opcode) + { + def.name = stream.readString(); + } + else if (12 == opcode) + { + def.tileSpacesOccupied = stream.readUnsignedByte(); + } + else if (opcode == 13) + { + def.stanceAnimation = stream.readUnsignedShort(); + } + else if (opcode == 14) + { + def.walkAnimation = stream.readUnsignedShort(); + } + else if (15 == opcode) + { + def.anInt2165 = stream.readUnsignedShort(); + } + else if (opcode == 16) + { + def.anInt2189 = stream.readUnsignedShort(); + } + else if (17 == opcode) + { + def.walkAnimation = stream.readUnsignedShort(); + def.rotate180Animation = stream.readUnsignedShort(); + def.rotate90RightAnimation = stream.readUnsignedShort(); + def.rotate90LeftAnimation = stream.readUnsignedShort(); + } + else if (opcode >= 30 && opcode < 35) + { + def.options[opcode - 30] = stream.readString(); + if (def.options[opcode - 30].equalsIgnoreCase("Hidden")) + { + def.options[opcode - 30] = null; + } + } + else if (opcode == 40) + { + length = stream.readUnsignedByte(); + def.recolorToFind = new short[length]; + def.recolorToReplace = new short[length]; + + for (index = 0; index < length; ++index) + { + def.recolorToFind[index] = (short) stream.readUnsignedShort(); + def.recolorToReplace[index] = (short) stream.readUnsignedShort(); + } + + } + else if (opcode == 41) + { + length = stream.readUnsignedByte(); + def.retextureToFind = new short[length]; + def.retextureToReplace = new short[length]; + + for (index = 0; index < length; ++index) + { + def.retextureToFind[index] = (short) stream.readUnsignedShort(); + def.retextureToReplace[index] = (short) stream.readUnsignedShort(); + } + + } + else if (60 == opcode) + { + length = stream.readUnsignedByte(); + def.models_2 = new int[length]; + + for (index = 0; index < length; ++index) + { + def.models_2[index] = stream.readUnsignedShort(); + } + + } + else if (opcode == 93) + { + def.renderOnMinimap = false; + } + else if (95 == opcode) + { + def.combatLevel = stream.readUnsignedShort(); + } + else if (97 == opcode) + { + def.resizeX = stream.readUnsignedShort(); + } + else if (98 == opcode) + { + def.resizeY = stream.readUnsignedShort(); + } + else if (opcode == 99) + { + def.hasRenderPriority = true; + } + else if (100 == opcode) + { + def.ambient = stream.readByte(); + } + else if (101 == opcode) + { + def.contrast = stream.readByte(); + } + else if (opcode == 102) + { + def.headIcon = stream.readUnsignedShort(); + } + else if (103 == opcode) + { + def.anInt2156 = stream.readUnsignedShort(); + } + else if (opcode == 106) + { + def.anInt2174 = stream.readUnsignedShort(); + if ('\uffff' == def.anInt2174) + { + def.anInt2174 = -1; + } + + def.anInt2187 = stream.readUnsignedShort(); + if ('\uffff' == def.anInt2187) + { + def.anInt2187 = -40212193; + } + + length = stream.readUnsignedByte(); + def.anIntArray2185 = new int[length + 1]; + + for (index = 0; index <= length; ++index) + { + def.anIntArray2185[index] = stream.readUnsignedShort(); + if (def.anIntArray2185[index] == '\uffff') + { + def.anIntArray2185[index] = -1; + } + } + + } + else if (107 == opcode) + { + def.isClickable = false; + } + else if (opcode == 109) + { + def.aBool2170 = false; + } + else if (opcode == 111) + { + def.aBool2190 = true; + } + else if (opcode == 112) + { + def.anInt2184 = stream.readUnsignedByte(); + } + else + { + logger.warn("Unrecognized opcode {}", opcode); + } + } +} diff --git a/cache/src/main/java/net/runelite/cache/definitions/loaders/ObjectLoader.java b/cache/src/main/java/net/runelite/cache/definitions/loaders/ObjectLoader.java new file mode 100644 index 0000000000..22023175d8 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/definitions/loaders/ObjectLoader.java @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.cache.definitions.loaders; + +import net.runelite.cache.definitions.ObjectDefinition; +import net.runelite.cache.io.InputStream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ObjectLoader +{ + private static final Logger logger = LoggerFactory.getLogger(ObjectLoader.class); + + public ObjectDefinition load(int id, byte[] b) + { + ObjectDefinition def = new ObjectDefinition(); + InputStream is = new InputStream(b); + + def.setId(id); + + for (;;) + { + int opcode = is.readUnsignedByte(); + if (opcode == 0) + { + break; + } + + processOp(opcode, def, is); + } + + return def; + } + + private void processOp(int opcode, ObjectDefinition def, InputStream is) + { + if (1 == opcode) + { + int length = is.readUnsignedByte(); + if (length > 0) + { + int[] objectTypes = new int[length]; + int[] objectModels = new int[length]; + + for (int index = 0; index < length; ++index) + { + objectModels[index] = is.readUnsignedShort(); + objectTypes[index] = is.readUnsignedByte(); + } + + def.setObjectTypes(objectTypes); + def.setObjectModels(objectModels); + } + } + else if (opcode == 2) + { + def.setName(is.readString()); + } + else if (opcode == 5) + { + int length = is.readUnsignedByte(); + if (length > 0) + { + def.setObjectTypes(null); + int[] objectModels = new int[length]; + + for (int index = 0; index < length; ++index) + { + objectModels[index] = is.readUnsignedShort(); + } + + def.setObjectModels(objectModels); + } + } + else if (opcode == 14) + { + def.setSizeX(is.readUnsignedByte()); + } + else if (15 == opcode) + { + def.setSizeY(is.readUnsignedByte()); + } + else if (opcode == 17) + { + def.setAnInt2094(0); + def.setaBool2114(false); + } + else if (opcode == 18) + { + def.setaBool2114(false); + } + else if (opcode == 19) + { + def.setAnInt2088(is.readUnsignedByte()); + } + else if (opcode == 21) + { + def.setAnInt2105(0); + } + else if (22 == opcode) + { + def.setNonFlatShading(false); + } + else if (opcode == 23) + { + def.setaBool2111(true); + } + else if (24 == opcode) + { + def.setAnimationID(is.readUnsignedShort()); + if (def.getAnimationID() == 0xFFFF) + { + def.setAnimationID(-1); + } + } + else if (opcode == 27) + { + def.setAnInt2094(1); + } + else if (opcode == 28) + { + def.setAnInt2069(is.readUnsignedByte()); + } + else if (opcode == 29) + { + def.setAmbient(is.readByte()); + } + else if (opcode == 39) + { + def.setContrast(is.readByte()); + } + else if (opcode >= 30 && opcode < 35) + { + String[] actions = def.getActions(); + actions[opcode - 30] = is.readString(); + if (actions[opcode - 30].equalsIgnoreCase("Hidden")) + { + actions[opcode - 30] = null; + } + } + else if (opcode == 40) + { + int length = is.readUnsignedByte(); + short[] recolorToFind = new short[length]; + short[] recolorToReplace = new short[length]; + + for (int index = 0; index < length; ++index) + { + recolorToFind[index] = is.readShort(); + recolorToReplace[index] = is.readShort(); + } + + def.setRecolorToFind(recolorToFind); + def.setRecolorToReplace(recolorToReplace); + } + else if (opcode == 41) + { + int length = is.readUnsignedByte(); + short[] retextureToFind = new short[length]; + short[] textureToReplace = new short[length]; + + for (int index = 0; index < length; ++index) + { + retextureToFind[index] = is.readShort(); + textureToReplace[index] = is.readShort(); + } + + def.setRetextureToFind(retextureToFind); + def.setTextureToReplace(textureToReplace); + } + else if (opcode == 60) + { + def.setMapIconID(is.readUnsignedShort()); + } + else if (62 == opcode) + { + def.setaBool2108(true); + } + else if (opcode == 64) + { + def.setaBool2097(false); + } + else if (opcode == 65) + { + def.setModelSizeX(is.readUnsignedShort()); + } + else if (opcode == 66) + { + def.setModelSizeHeight(is.readUnsignedShort()); + } + else if (67 == opcode) + { + def.setModelSizeY(is.readUnsignedShort()); + } + else if (opcode == 68) + { + def.setMapSceneID(is.readUnsignedShort()); + } + else if (opcode == 69) + { + is.readByte(); + } + else if (70 == opcode) + { + def.setOffsetX(is.readUnsignedShort()); + } + else if (opcode == 71) + { + def.setOffsetHeight(is.readUnsignedShort()); + } + else if (opcode == 72) + { + def.setOffsetY(is.readUnsignedShort()); + } + else if (73 == opcode) + { + def.setaBool2104(true); + } + else if (74 == opcode) + { + def.setIsSolid(true); + } + else if (opcode == 75) + { + def.setAnInt2106(is.readUnsignedByte()); + } + else if (opcode == 77) + { + int varpID = is.readUnsignedShort(); + if (varpID == 0xFFFF) + { + varpID = -1; + } + def.setVarpID(varpID); + + int configId = is.readUnsignedShort(); + if (configId == 0xFFFF) + { + configId = -1; + } + def.setConfigId(configId); + + int length = is.readUnsignedByte(); + int[] configChangeDest = new int[length + 1]; + + for (int index = 0; index <= length; ++index) + { + configChangeDest[index] = is.readUnsignedShort(); + if (0xFFFF == configChangeDest[index]) + { + configChangeDest[index] = -1; + } + } + + def.setConfigChangeDest(configChangeDest); + } + else if (opcode == 78) + { + def.setAnInt2110(is.readUnsignedShort()); + def.setAnInt2083(is.readUnsignedByte()); + } + else if (opcode == 79) + { + def.setAnInt2112(is.readUnsignedShort()); + def.setAnInt2113(is.readUnsignedShort()); + def.setAnInt2083(is.readUnsignedByte()); + int length = is.readUnsignedByte(); + int[] anIntArray2084 = new int[length]; + + for (int index = 0; index < length; ++index) + { + anIntArray2084[index] = is.readUnsignedShort(); + } + + def.setAnIntArray2084(anIntArray2084); + } + else if (opcode == 81) + { + def.setAnInt2105(is.readUnsignedByte()); + } + else + { + logger.warn("Unrecognized opcode {}", opcode); + } + } +} diff --git a/cache/src/main/java/net/runelite/cache/definitions/loaders/ScriptLoader.java b/cache/src/main/java/net/runelite/cache/definitions/loaders/ScriptLoader.java new file mode 100644 index 0000000000..419a550482 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/definitions/loaders/ScriptLoader.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.cache.definitions.loaders; + +import net.runelite.cache.definitions.ScriptDefinition; +import net.runelite.cache.io.InputStream; + +public class ScriptLoader +{ + public ScriptDefinition load(int id, byte[] b) + { + ScriptDefinition def = new ScriptDefinition(); + InputStream in = new InputStream(b); + + in.setOffset(in.getLength() - 12); + int paramCount = in.readInt(); + int localIntCount = in.readUnsignedShort(); + int localStringCount = in.readUnsignedShort(); + int anInt2269 = in.readUnsignedShort(); + int anInt2276 = in.readUnsignedShort(); + + def.setLocalIntCount(localIntCount); + def.setLocalStringCount(localStringCount); + def.setAnInt2269(anInt2269); + def.setAnInt2276(anInt2276); + + in.setOffset(0); + in.readStringOrNull(); + + int[] instructions = new int[paramCount]; + int[] intOperands = new int[paramCount]; + String[] aStringArray2272 = new String[paramCount]; + + def.setInstructions(instructions); + def.setIntOperands(intOperands); + def.setaStringArray2272(aStringArray2272); + + int var3; + for (int var6 = 0; in.getOffset() < in.getLength() - 12; instructions[var6++] = var3) + { + var3 = in.readUnsignedShort(); + if (var3 == 3) + { + aStringArray2272[var6] = in.readString(); + } + else if (var3 < 100 && 21 != var3 && 38 != var3 && 39 != var3) + { + intOperands[var6] = in.readInt(); + } + else + { + intOperands[var6] = in.readUnsignedByte(); + } + } + + return def; + } +} diff --git a/cache/src/main/java/net/runelite/cache/definitions/loaders/SpriteLoader.java b/cache/src/main/java/net/runelite/cache/definitions/loaders/SpriteLoader.java new file mode 100644 index 0000000000..00c2ca5339 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/definitions/loaders/SpriteLoader.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.definitions.loaders; + +import net.runelite.cache.definitions.SpriteDefinition; +import net.runelite.cache.io.InputStream; + +public class SpriteLoader +{ + private SpriteDefinition[] sprites; + + private int[] loadedPalette; + private int loadedSpriteMaxWidth; + private int loadedSpriteMaxHeight; + + public void load(InputStream stream) + { + stream.setOffset(stream.getLength() - 2); + int paletteChildCount = stream.readUnsignedShort(); + sprites = new SpriteDefinition[paletteChildCount]; + for (int i = 0; i < paletteChildCount; ++i) + { + sprites[i] = new SpriteDefinition(this); + } + stream.setOffset(stream.getLength() - 7 - paletteChildCount * 8); + loadedSpriteMaxWidth = stream.readUnsignedShort(); + loadedSpriteMaxHeight = stream.readUnsignedShort(); + int var3 = (stream.readUnsignedByte() & 255) + 1; + + int spriteIndex; + for (spriteIndex = 0; spriteIndex < paletteChildCount; ++spriteIndex) + { + sprites[spriteIndex].setOffsetX(stream.readUnsignedShort()); + } + + for (spriteIndex = 0; spriteIndex < paletteChildCount; ++spriteIndex) + { + sprites[spriteIndex].setOffsetY(stream.readUnsignedShort()); + } + + for (spriteIndex = 0; spriteIndex < paletteChildCount; ++spriteIndex) + { + sprites[spriteIndex].setWidth(stream.readUnsignedShort()); + } + + for (spriteIndex = 0; spriteIndex < paletteChildCount; ++spriteIndex) + { + sprites[spriteIndex].setHeight(stream.readUnsignedShort()); + } + + stream.setOffset(stream.getLength() - 7 - paletteChildCount * 8 - (var3 - 1) * 3); + loadedPalette = new int[var3]; + + for (spriteIndex = 1; spriteIndex < var3; ++spriteIndex) + { + loadedPalette[spriteIndex] = stream.read24BitInt(); + if (0 == loadedPalette[spriteIndex]) + { + loadedPalette[spriteIndex] = 1; + } + } + + stream.setOffset(0); + + for (spriteIndex = 0; spriteIndex < paletteChildCount; ++spriteIndex) + { + SpriteDefinition def = sprites[spriteIndex]; + int width = def.getWidth(); + int height = def.getHeight(); + int dimmension = width * height; + byte[] loadPixels = new byte[dimmension]; + int var4 = stream.readUnsignedByte(); + int var5; + if (var4 == 0) + { + for (var5 = 0; var5 < dimmension; ++var5) + { + loadPixels[var5] = (byte) stream.readByte(); + } + } + else if (1 == var4) + { + for (var5 = 0; var5 < width; ++var5) + { + for (int var8 = 0; var8 < height; ++var8) + { + loadPixels[width * var8 + var5] = (byte) stream.readByte(); + } + } + } + def.setPixels(loadPixels); + } + } + + public SpriteDefinition[] getSprites() + { + return sprites; + } + + public int[] getLoadedPalette() + { + return loadedPalette; + } +} diff --git a/cache/src/main/java/net/runelite/cache/fs/Archive.java b/cache/src/main/java/net/runelite/cache/fs/Archive.java new file mode 100644 index 0000000000..e4c8ddbed1 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/fs/Archive.java @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.fs; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import net.runelite.cache.io.InputStream; + +public class Archive +{ + private Index index; // member of this index + private int archiveId; + private int nameHash; + private byte[] whirlpool; + private int crc; + private int revision; + private List files = new ArrayList<>(); + + public Archive(Index index, int id) + { + this.index = index; + this.archiveId = id; + } + + @Override + public int hashCode() + { + int hash = 7; + hash = 47 * hash + this.archiveId; + hash = 47 * hash + this.nameHash; + hash = 47 * hash + this.revision; + hash = 47 * hash + Objects.hashCode(this.files); + return hash; + } + + @Override + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + if (getClass() != obj.getClass()) + { + return false; + } + final Archive other = (Archive) obj; + if (this.archiveId != other.archiveId) + { + return false; + } + if (this.nameHash != other.nameHash) + { + return false; + } + // crc is of the file data, we always rewrite in one loop, so iti is different + if (this.revision != other.revision) + { + return false; + } + if (!Objects.equals(this.files, other.files)) + { + return false; + } + return true; + } + + public File addFile(int id) + { + File file = new File(this, id); + this.files.add(file); + return file; + } + + public void load(InputStream stream, int numberOfFiles, int protocol) + { + int archive = 0; + + for (int i = 0; i < numberOfFiles; ++i) + { + int fileId = archive += protocol >= 7 ? stream.readBigSmart() : stream.readUnsignedShort(); + + File file = new File(this, fileId); + this.files.add(file); + } + } + + public void loadNames(InputStream stream, int numberOfFiles) + { + for (int i = 0; i < numberOfFiles; ++i) + { + File file = this.files.get(i); + int name = stream.readInt(); + file.setNameHash(name); + } + } + + public int getArchiveId() + { + return archiveId; + } + + public int getNameHash() + { + return nameHash; + } + + public void setNameHash(int nameHash) + { + this.nameHash = nameHash; + } + + public byte[] getWhirlpool() + { + return whirlpool; + } + + public void setWhirlpool(byte[] whirlpool) + { + this.whirlpool = whirlpool; + } + + public int getCrc() + { + return crc; + } + + public void setCrc(int crc) + { + this.crc = crc; + } + + public int getRevision() + { + return revision; + } + + public void setRevision(int revision) + { + this.revision = revision; + } + + public List getFiles() + { + return files; + } +} diff --git a/cache/src/main/java/net/runelite/cache/fs/CompressionType.java b/cache/src/main/java/net/runelite/cache/fs/CompressionType.java new file mode 100644 index 0000000000..74ec84fa1a --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/fs/CompressionType.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.cache.fs; + +public class CompressionType +{ + public static final int NONE = 0; + public static final int BZ2 = 1; + public static final int GZ = 2; +} diff --git a/cache/src/main/java/net/runelite/cache/fs/DataFile.java b/cache/src/main/java/net/runelite/cache/fs/DataFile.java new file mode 100644 index 0000000000..a292a34049 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/fs/DataFile.java @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.fs; + +import java.io.Closeable; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.ByteBuffer; +import net.runelite.cache.fs.util.BZip2; +import net.runelite.cache.io.InputStream; +import net.runelite.cache.io.OutputStream; +import net.runelite.cache.fs.util.CRC32HGenerator; +import net.runelite.cache.fs.util.GZip; +import net.runelite.cache.fs.util.Whirlpool; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DataFile implements Closeable +{ + private static final Logger logger = LoggerFactory.getLogger(DataFile.class); + + private static final int SECTOR_SIZE = 520; + + private final Store store; + private final File file; + private final RandomAccessFile dat; + private final byte[] readCachedBuffer = new byte[SECTOR_SIZE]; + + public DataFile(Store store, File file) throws FileNotFoundException + { + this.file = file; + this.store = store; + dat = new RandomAccessFile(file, "rw"); + } + + @Override + public void close() throws IOException + { + dat.close(); + } + + /** + * + * @param indexId + * @param archiveId + * @param sector sector to start reading at + * @param size expected size of file + * @return + * @throws IOException + */ + public synchronized DataFileReadResult read(int indexId, int archiveId, int sector, int size) throws IOException + { + if (sector <= 0L || dat.length() / 520L < (long) sector) + { + logger.warn("bad read, dat length {}, requested sector {}", dat.length(), sector); + return null; + } + + ByteBuffer buffer = ByteBuffer.allocate(size); + + for (int part = 0, readBytesCount = 0, nextSector; + size > readBytesCount; + sector = nextSector) + { + if (sector == 0) + { + logger.warn("sector == 0"); + return null; + } + + dat.seek(SECTOR_SIZE * sector); + + int dataBlockSize = size - readBytesCount; + byte headerSize; + int currentIndex; + int currentPart; + int currentArchive; + if (0xFFFF < archiveId) + { + headerSize = 10; + if (dataBlockSize > SECTOR_SIZE - headerSize) + { + dataBlockSize = SECTOR_SIZE - headerSize; + } + + int i = dat.read(this.readCachedBuffer, 0, headerSize + dataBlockSize); + if (i != headerSize + dataBlockSize) + { + logger.warn("short read"); + return null; + } + + currentArchive = ((this.readCachedBuffer[1] & 255) << 16) + ((this.readCachedBuffer[0] & 255) << 24) + (('\uff00' & this.readCachedBuffer[2] << 8) - -(this.readCachedBuffer[3] & 255)); + currentPart = ((this.readCachedBuffer[4] & 255) << 8) + (255 & this.readCachedBuffer[5]); + nextSector = (this.readCachedBuffer[8] & 255) + ('\uff00' & this.readCachedBuffer[7] << 8) + ((255 & this.readCachedBuffer[6]) << 16); + currentIndex = this.readCachedBuffer[9] & 255; + } + else + { + headerSize = 8; + if (dataBlockSize > SECTOR_SIZE - headerSize) + { + dataBlockSize = SECTOR_SIZE - headerSize; + } + + int i = dat.read(this.readCachedBuffer, 0, headerSize + dataBlockSize); + if (i != headerSize + dataBlockSize) + { + logger.warn("short read"); + return null; + } + + currentArchive = (255 & this.readCachedBuffer[1]) + ('\uff00' & this.readCachedBuffer[0] << 8); + currentPart = ((this.readCachedBuffer[2] & 255) << 8) + (255 & this.readCachedBuffer[3]); + nextSector = (this.readCachedBuffer[6] & 255) + ('\uff00' & this.readCachedBuffer[5] << 8) + ((255 & this.readCachedBuffer[4]) << 16); + currentIndex = this.readCachedBuffer[7] & 255; + } + + if (archiveId != currentArchive || currentPart != part || indexId != currentIndex) + { + logger.warn("data mismatch {} != {}, {} != {}, {} != {}", + archiveId, currentArchive, + part, currentPart, + indexId, currentIndex); + return null; + } + + if (nextSector < 0 || dat.length() / SECTOR_SIZE < (long) nextSector) + { + logger.warn("Invalid next sector"); + return null; + } + + buffer.put(readCachedBuffer, headerSize, dataBlockSize); + readBytesCount += dataBlockSize; + + ++part; + } + + buffer.flip(); + + //XTEA decrypt here? + + return this.decompress(buffer.array()); + } + + public synchronized DataFileWriteResult write(int indexId, int archiveId, ByteBuffer data, int compression, int revision) throws IOException + { + int sector; + int startSector; + + byte[] compressedData = this.compress(data.array(), compression, revision); + data = ByteBuffer.wrap(compressedData); + + //XTEA encrypt here? + + sector = (int) ((dat.length() + (long) (SECTOR_SIZE - 1)) / (long) SECTOR_SIZE); + if (sector == 0) + { + sector = 1; + } + startSector = sector; + + for (int part = 0; data.hasRemaining(); ++part) + { + int nextSector = 0; + int dataToWrite; + + if (nextSector == 0) + { + nextSector = (int) ((dat.length() + (long) (SECTOR_SIZE - 1)) / (long) SECTOR_SIZE); + if (nextSector == 0) + { + ++nextSector; + } + + if (nextSector == sector) + { + ++nextSector; + } + } + + + if (0xFFFF < archiveId) + { + if (data.remaining() <= 510) + { + nextSector = 0; + } + + this.readCachedBuffer[0] = (byte) (archiveId >> 24); + this.readCachedBuffer[1] = (byte) (archiveId >> 16); + this.readCachedBuffer[2] = (byte) (archiveId >> 8); + this.readCachedBuffer[3] = (byte) archiveId; + this.readCachedBuffer[4] = (byte) (part >> 8); + this.readCachedBuffer[5] = (byte) part; + this.readCachedBuffer[6] = (byte) (nextSector >> 16); + this.readCachedBuffer[7] = (byte) (nextSector >> 8); + this.readCachedBuffer[8] = (byte) nextSector; + this.readCachedBuffer[9] = (byte) indexId; + dat.seek(SECTOR_SIZE * sector); + dat.write(this.readCachedBuffer, 0, 10); + + dataToWrite = data.remaining(); + if (dataToWrite > 510) + { + dataToWrite = 510; + } + } + else + { + if (data.remaining() <= 512) + { + nextSector = 0; + } + + this.readCachedBuffer[0] = (byte) (archiveId >> 8); + this.readCachedBuffer[1] = (byte) archiveId; + this.readCachedBuffer[2] = (byte) (part >> 8); + this.readCachedBuffer[3] = (byte) part; + this.readCachedBuffer[4] = (byte) (nextSector >> 16); + this.readCachedBuffer[5] = (byte) (nextSector >> 8); + this.readCachedBuffer[6] = (byte) nextSector; + this.readCachedBuffer[7] = (byte) indexId; + dat.seek(SECTOR_SIZE * sector); + dat.write(this.readCachedBuffer, 0, 8); + + dataToWrite = data.remaining(); + if (dataToWrite > 512) + { + dataToWrite = 512; + } + } + + data.get(readCachedBuffer, 0, dataToWrite); + dat.write(readCachedBuffer, 0, dataToWrite); + sector = nextSector; + } + + DataFileWriteResult res = new DataFileWriteResult(); + res.sector = startSector; + res.compressedLength = compressedData.length; + res.crc = CRC32HGenerator.getHash(compressedData, compressedData.length - 2); + res.whirlpool = Whirlpool.getHash(compressedData, compressedData.length - 2); + return res; + } + + private DataFileReadResult decompress(byte[] b) + { + InputStream stream = new InputStream(b); + + int compression = stream.readUnsignedByte(); + int compressedLength = stream.readInt(); + if (compressedLength < 0 || compressedLength > 1000000) + throw new RuntimeException("Invalid data"); + + byte[] data; + int revision; + switch (compression) + { + case CompressionType.NONE: + data = new byte[compressedLength]; + revision = this.checkRevision(stream, compressedLength); + stream.readBytes(data, 0, compressedLength); + break; + case CompressionType.BZ2: + { + int length = stream.readInt(); + revision = this.checkRevision(stream, compressedLength); + data = BZip2.decompress(stream.getRemaining()); + assert data.length == length; + break; + } + case CompressionType.GZ: + { + int length = stream.readInt(); + revision = this.checkRevision(stream, compressedLength); + data = GZip.decompress(stream.getRemaining()); + assert data.length == length; + break; + } + default: + throw new RuntimeException("Unknown decompression type"); + } + + DataFileReadResult res = new DataFileReadResult(); + res.data = data; + res.revision = revision; + res.crc = CRC32HGenerator.getHash(b, b.length - 2); + res.whirlpool = Whirlpool.getHash(b, b.length - 2); + return res; + } + + private byte[] compress(byte[] data, int compression, int revision) throws IOException + { + OutputStream stream = new OutputStream(); + stream.writeByte(compression); + byte[] compressedData; + switch (compression) + { + case CompressionType.NONE: + compressedData = data; + stream.writeInt(data.length); + break; + case CompressionType.BZ2: + compressedData = BZip2.compress(data); + + stream.writeInt(compressedData.length); + stream.writeInt(data.length); + break; + case CompressionType.GZ: + compressedData = GZip.compress(data); + + stream.writeInt(compressedData.length); + stream.writeInt(data.length); + break; + default: + throw new RuntimeException("Unknown compression type"); + } + + stream.writeBytes(compressedData); + stream.writeShort(revision); + + return stream.flip(); + } + + private int checkRevision(InputStream stream, int compressedLength) + { + int offset = stream.getOffset(); + int revision; + if (stream.getLength() - (compressedLength + stream.getOffset()) >= 2) + { + stream.setOffset(stream.getLength() - 2); + revision = stream.readUnsignedShort(); + stream.setOffset(offset); + } + else + { + revision = -1; + } + return revision; + } +} diff --git a/cache/src/main/java/net/runelite/cache/fs/DataFileReadResult.java b/cache/src/main/java/net/runelite/cache/fs/DataFileReadResult.java new file mode 100644 index 0000000000..0a2d7e47b3 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/fs/DataFileReadResult.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.fs; + +public class DataFileReadResult +{ + public byte[] data; + public int revision; + public int crc; // crc of compressed data + public byte[] whirlpool; +} diff --git a/cache/src/main/java/net/runelite/cache/fs/DataFileWriteResult.java b/cache/src/main/java/net/runelite/cache/fs/DataFileWriteResult.java new file mode 100644 index 0000000000..b45b4fc23b --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/fs/DataFileWriteResult.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.fs; + +public class DataFileWriteResult +{ + public int sector, compressedLength; + public int crc; // crc of compressed data + public byte[] whirlpool; +} diff --git a/cache/src/main/java/net/runelite/cache/fs/File.java b/cache/src/main/java/net/runelite/cache/fs/File.java new file mode 100644 index 0000000000..b4ee24c550 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/fs/File.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.fs; + +import java.util.Arrays; + +public class File +{ + private Archive archive; + private int fileId; + private int nameHash; + private byte[] contents; + + public File(Archive archive, int fileId) + { + this.archive = archive; + this.fileId = fileId; + } + + @Override + public int hashCode() + { + int hash = 7; + hash = 97 * hash + this.fileId; + hash = 97 * hash + this.nameHash; + hash = 97 * hash + Arrays.hashCode(this.contents); + return hash; + } + + @Override + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + if (getClass() != obj.getClass()) + { + return false; + } + final File other = (File) obj; + if (this.fileId != other.fileId) + { + return false; + } + if (this.nameHash != other.nameHash) + { + return false; + } + if (!Arrays.equals(this.contents, other.contents)) + { + return false; + } + return true; + } + + public Archive getArchive() + { + return archive; + } + + public int getFileId() + { + return fileId; + } + + public int getNameHash() + { + return nameHash; + } + + public void setNameHash(int nameHash) + { + this.nameHash = nameHash; + } + + public byte[] getContents() + { + return contents; + } + + public void setContents(byte[] contents) + { + this.contents = contents; + } + + public int getSize() + { + return contents.length; + } +} diff --git a/cache/src/main/java/net/runelite/cache/fs/Index.java b/cache/src/main/java/net/runelite/cache/fs/Index.java new file mode 100644 index 0000000000..fbe6948736 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/fs/Index.java @@ -0,0 +1,533 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.fs; + +import java.io.Closeable; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import net.runelite.cache.fs.util.Djb2; +import net.runelite.cache.io.InputStream; +import net.runelite.cache.io.OutputStream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Index implements Closeable +{ + private static final Logger logger = LoggerFactory.getLogger(Index.class); + + private final Store store; + private final IndexFile index; + private final int id; + private int revision; + private final List archives = new ArrayList<>(); + + public Index(Store store, IndexFile index, int id) + { + this.store = store; + this.index = index; + this.id = id; + } + + @Override + public void close() throws IOException + { + index.close(); + } + + @Override + public int hashCode() + { + int hash = 3; + hash = 97 * hash + this.id; + hash = 97 * hash + this.revision; + hash = 97 * hash + Objects.hashCode(this.archives); + return hash; + } + + @Override + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + if (getClass() != obj.getClass()) + { + return false; + } + final Index other = (Index) obj; + if (this.id != other.id) + { + return false; + } + if (this.revision != other.revision) + { + return false; + } + if (!Objects.equals(this.archives, other.archives)) + { + return false; + } + return true; + } + + public int getId() + { + return id; + } + + public IndexFile getIndex() + { + return index; + } + + public List getArchives() + { + return archives; + } + + public Archive addArchive(int id) + { + Archive archive = new Archive(this, id); + this.archives.add(archive); + return archive; + } + + public Archive getArchive(int id) + { + for (Archive a : archives) + if (a.getArchiveId() == id) + return a; + return null; + } + + public Archive findArchiveByName(String name) + { + int hash = Djb2.hash(name); + for (Archive a : archives) + if (a.getNameHash() == hash) + return a; + return null; + } + + public void load() throws IOException + { + DataFile dataFile = store.getData(); + IndexFile index255 = store.getIndex255(); + + IndexEntry entry = index255.read(id); + DataFileReadResult res = dataFile.read(index255.getIndexFileId(), entry.getId(), entry.getSector(), entry.getLength()); + byte[] data = res.data; + + archives.clear(); + + readIndexData(data); + + this.loadFiles(); + } + + public void save() throws IOException + { + saveFiles(); + + byte[] data = this.writeIndexData(); + + DataFile dataFile = store.getData(); + IndexFile index255 = store.getIndex255(); + + DataFileWriteResult res = dataFile.write(index255.getIndexFileId(), this.id, ByteBuffer.wrap(data), 0, this.revision); + index255.write(new IndexEntry(index255, id, res.sector, res.compressedLength)); + } + + private void readIndexData(byte[] data) + { + InputStream stream = new InputStream(data); + int protocol = stream.readUnsignedByte(); + if (protocol >= 5 && protocol <= 7) + { + if (protocol >= 6) + { + this.revision = stream.readInt(); + } + + int hash = stream.readUnsignedByte(); + boolean named = (1 & hash) != 0; + boolean usesWhirpool = (2 & hash) != 0; + int validArchivesCount = protocol >= 7 ? stream.readBigSmart() : stream.readUnsignedShort(); + int lastArchiveId = 0; + + int index; + int archive; + for (index = 0; index < validArchivesCount; ++index) + { + archive = lastArchiveId += protocol >= 7 ? stream.readBigSmart() : stream.readUnsignedShort(); + Archive a = new Archive(this, archive); + this.archives.add(a); + } + + if (named) + { + for (index = 0; index < validArchivesCount; ++index) + { + int nameHash = stream.readInt(); + Archive a = this.archives.get(index); + a.setNameHash(nameHash); + } + } + + if (usesWhirpool) + { + for (index = 0; index < validArchivesCount; ++index) + { + byte[] var13 = new byte[64]; + stream.readBytes(var13); + + Archive a = this.archives.get(index); + a.setWhirlpool(var13); + } + } + + for (index = 0; index < validArchivesCount; ++index) + { + int crc = stream.readInt(); + + Archive a = this.archives.get(index); + a.setCrc(crc); + } + + for (index = 0; index < validArchivesCount; ++index) + { + int revision = stream.readInt(); + + Archive a = this.archives.get(index); + a.setRevision(revision); + } + + int[] numberOfFiles = new int[validArchivesCount]; + for (index = 0; index < validArchivesCount; ++index) + { + int num = protocol >= 7 ? stream.readBigSmart() : stream.readUnsignedShort(); + numberOfFiles[index] = num; + } + + for (index = 0; index < validArchivesCount; ++index) + { + archive = 0; + + Archive a = this.archives.get(index); + a.load(stream, numberOfFiles[index], protocol); + } + + if (named) + { + for (index = 0; index < validArchivesCount; ++index) + { + Archive a = this.archives.get(index); + a.loadNames(stream, numberOfFiles[index]); + } + } + } + } + + private void loadFiles() throws IOException + { + // get data from index file + for (Archive a : archives) + { + IndexEntry entry = this.index.read(a.getArchiveId()); + if (entry == null) + { + logger.debug("can't read archive " + a.getArchiveId() + " from index " + this.id); + continue; + } + + assert this.index.getIndexFileId() == this.id; + assert entry.getId() == a.getArchiveId(); + DataFileReadResult res = store.getData().read(this.id, entry.getId(), entry.getSector(), entry.getLength()); + byte[] data = res.data; + + if (a.getCrc() != res.crc) + { + logger.warn("crc mismatch for archive {}", a); + } + + if (a.getWhirlpool() != null && !Arrays.equals(a.getWhirlpool(), res.whirlpool)) + { + logger.warn("whirlpool mismatch for archive {}", a); + } + + if (a.getFiles().size() == 1) + { + a.getFiles().get(0).setContents(data); + continue; + } + + final int filesCount = a.getFiles().size(); + + int readPosition = data.length; + --readPosition; + int amtOfLoops = data[readPosition] & 255; + readPosition -= amtOfLoops * filesCount * 4; + InputStream stream = new InputStream(data); + stream.setOffset(readPosition); + int[] filesSize = new int[filesCount]; + + int sourceOffset; + int count; + for (int filesData = 0; filesData < amtOfLoops; ++filesData) + { + sourceOffset = 0; + + for (count = 0; count < filesCount; ++count) + { + filesSize[count] += sourceOffset += stream.readInt(); + } + } + + byte[][] var18 = new byte[filesCount][]; + + for (sourceOffset = 0; sourceOffset < filesCount; ++sourceOffset) + { + var18[sourceOffset] = new byte[filesSize[sourceOffset]]; + filesSize[sourceOffset] = 0; + } + + stream.setOffset(readPosition); + sourceOffset = 0; + + int fileId; + int i; + for (count = 0; count < amtOfLoops; ++count) + { + fileId = 0; + + for (i = 0; i < filesCount; ++i) + { + fileId += stream.readInt(); + System.arraycopy(data, sourceOffset, var18[i], filesSize[i], fileId); + sourceOffset += fileId; + filesSize[i] += fileId; + } + } + + for (i = 0; i < filesCount; ++i) + { + File f = a.getFiles().get(i); + f.setContents(var18[i]); + } + } + } + + public void saveFiles() throws IOException + { + for (Archive a : archives) + { + OutputStream stream = new OutputStream(); + + int sourceOffset = 0; + final int filesCount = a.getFiles().size(); + + if (filesCount == 1) + { + File file = a.getFiles().get(0); + stream.writeBytes(file.getContents()); + } + else + { + for (int i = 0; i < filesCount; ++i) + { + File file = a.getFiles().get(i); + stream.writeBytes(file.getContents()); + } + + for (int count = 0; count < filesCount; ++count) + { + File file = a.getFiles().get(count); + + int sz = file.getSize() - sourceOffset; + sourceOffset = file.getSize(); + stream.writeInt(sz); + } + + stream.writeByte(1); // number of loops + } + + byte[] fileData = stream.flip(); + + assert this.index.getIndexFileId() == this.id; + DataFile data = store.getData(); + + // XXX old data is just left there in the file? + DataFileWriteResult res = data.write(this.id, a.getArchiveId(), ByteBuffer.wrap(fileData), 0, this.revision); + this.index.write(new IndexEntry(this.index, a.getArchiveId(), res.sector, res.compressedLength)); + + a.setCrc(res.crc); + a.setWhirlpool(res.whirlpool); + } + } + + public byte[] writeIndexData() + { + OutputStream stream = new OutputStream(); + int protocol = 7;//this.getProtocol(); + stream.writeByte(protocol); + if (protocol >= 6) + { + stream.writeInt(this.revision); + } + + boolean named = true, usesWhirpool = false; + stream.writeByte((named ? 1 : 0) | (usesWhirpool ? 2 : 0)); + if (protocol >= 7) + { + stream.writeBigSmart(this.archives.size()); + } + else + { + stream.writeShort(this.archives.size()); + } + + int data; + for (data = 0; data < this.archives.size(); ++data) + { + Archive a = this.archives.get(data); + int archive = a.getArchiveId(); + + if (data != 0) + { + Archive prev = this.archives.get(data - 1); + archive -= prev.getArchiveId(); + } + + if (protocol >= 7) + { + stream.writeBigSmart(archive); + } + else + { + stream.writeShort(archive); + } + } + + if (named) + { + for (data = 0; data < this.archives.size(); ++data) + { + Archive a = this.archives.get(data); + stream.writeInt(a.getNameHash()); + } + } + + if (usesWhirpool) + { + for (data = 0; data < this.archives.size(); ++data) + { + Archive a = this.archives.get(data); + stream.writeBytes(a.getWhirlpool()); + } + } + + for (data = 0; data < this.archives.size(); ++data) + { + Archive a = this.archives.get(data); + stream.writeInt(a.getCrc()); + } + + for (data = 0; data < this.archives.size(); ++data) + { + Archive a = this.archives.get(data); + stream.writeInt(a.getRevision()); + } + + for (data = 0; data < this.archives.size(); ++data) + { + Archive a = this.archives.get(data); + + int len = a.getFiles().size(); + + if (protocol >= 7) + { + stream.writeBigSmart(len); + } + else + { + stream.writeShort(len); + } + } + + int index2; + for (data = 0; data < this.archives.size(); ++data) + { + Archive a = this.archives.get(data); + + for (index2 = 0; index2 < a.getFiles().size(); ++index2) + { + File file = a.getFiles().get(index2); + int offset = file.getFileId(); + + if (index2 != 0) + { + File prev = a.getFiles().get(index2 - 1); + offset -= prev.getFileId(); + } + + if (protocol >= 7) + { + stream.writeBigSmart(offset); + } + else + { + stream.writeShort(offset); + } + } + } + + if (named) + { + for (data = 0; data < this.archives.size(); ++data) + { + Archive a = this.archives.get(data); + + for (index2 = 0; index2 < a.getFiles().size(); ++index2) + { + File file = a.getFiles().get(index2); + stream.writeInt(file.getNameHash()); + } + } + } + + return stream.flip(); + } +} diff --git a/cache/src/main/java/net/runelite/cache/fs/IndexEntry.java b/cache/src/main/java/net/runelite/cache/fs/IndexEntry.java new file mode 100644 index 0000000000..a103c11fbf --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/fs/IndexEntry.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.fs; + +import java.util.Objects; + +public class IndexEntry +{ + private final IndexFile indexFile; + private final int id, sector, length; + + public IndexEntry(IndexFile indexFile, int id, int sector, int length) + { + this.indexFile = indexFile; + this.id = id; + this.sector = sector; + this.length = length; + } + + public IndexFile getIndexFile() + { + return indexFile; + } + + public int getId() + { + return id; + } + + public int getSector() + { + return sector; + } + + public int getLength() + { + return length; + } + + @Override + public int hashCode() + { + int hash = 7; + hash = 19 * hash + Objects.hashCode(this.indexFile); + hash = 19 * hash + this.id; + hash = 19 * hash + this.sector; + hash = 19 * hash + this.length; + return hash; + } + + @Override + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + if (getClass() != obj.getClass()) + { + return false; + } + final IndexEntry other = (IndexEntry) obj; + if (!Objects.equals(this.indexFile, other.indexFile)) + { + return false; + } + if (this.id != other.id) + { + return false; + } + if (this.sector != other.sector) + { + return false; + } + if (this.length != other.length) + { + return false; + } + return true; + } +} diff --git a/cache/src/main/java/net/runelite/cache/fs/IndexFile.java b/cache/src/main/java/net/runelite/cache/fs/IndexFile.java new file mode 100644 index 0000000000..2b0a43a75d --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/fs/IndexFile.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.fs; + +import java.io.Closeable; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.Objects; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class IndexFile implements Closeable +{ + private static final Logger logger = LoggerFactory.getLogger(IndexFile.class); + private static final int INDEX_ENTRY_LEN = 6; + + private final Store store; + private final int indexFileId; + private final File file; + private final RandomAccessFile idx; + private final byte[] buffer = new byte[INDEX_ENTRY_LEN]; + + public IndexFile(Store store, int indexFileId, File file) throws FileNotFoundException + { + this.store = store; + this.indexFileId = indexFileId; + this.file = file; + this.idx = new RandomAccessFile(file, "rw"); + } + + @Override + public void close() throws IOException + { + idx.close(); + } + + @Override + public int hashCode() + { + int hash = 3; + hash = 41 * hash + Objects.hashCode(this.file); + return hash; + } + + @Override + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + if (getClass() != obj.getClass()) + { + return false; + } + final IndexFile other = (IndexFile) obj; + if (!Objects.equals(this.file, other.file)) + { + return false; + } + return true; + } + + public Store getStore() + { + return store; + } + + public int getIndexFileId() + { + return indexFileId; + } + + public synchronized void write(IndexEntry entry) throws IOException + { + idx.seek(entry.getId() * INDEX_ENTRY_LEN); + + buffer[0] = (byte) (entry.getLength() >> 16); + buffer[1] = (byte) (entry.getLength() >> 8); + buffer[2] = (byte) entry.getLength(); + + buffer[3] = (byte) (entry.getSector() >> 16); + buffer[4] = (byte) (entry.getSector() >> 8); + buffer[5] = (byte) entry.getSector(); + + idx.write(buffer); + } + + public synchronized IndexEntry read(int id) throws IOException + { + idx.seek(id * INDEX_ENTRY_LEN); + int i = idx.read(buffer); + if (i != INDEX_ENTRY_LEN) + { + logger.warn("short read for id {} on index {}: {}", id, indexFileId, i); + return null; + } + + int length = ((buffer[0] & 0xFF) << 16) | ((buffer[1] & 0xFF) << 8) | (buffer[2] & 0xFF); + int sector = ((buffer[3] & 0xFF) << 16) | ((buffer[4] & 0xFF) << 8) | (buffer[5] & 0xFF); + + if (length <= 0 || sector <= 0) + { + logger.debug("invalid length or sector {}/{}", length, sector); + return null; + } + + return new IndexEntry(this, id, sector, length); + } + + public synchronized int getIndexCount() throws IOException + { + return (int)(idx.length() / INDEX_ENTRY_LEN); + } +} diff --git a/cache/src/main/java/net/runelite/cache/fs/Store.java b/cache/src/main/java/net/runelite/cache/fs/Store.java new file mode 100644 index 0000000000..399a600986 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/fs/Store.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.fs; + +import java.io.Closeable; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import net.runelite.cache.IndexType; + +public class Store implements Closeable +{ + private static final String MAIN_FILE_CACHE_DAT = "main_file_cache.dat2"; + private static final String MAIN_FILE_CACHE_IDX = "main_file_cache.idx"; + + private final File folder; + private final DataFile data; + private final IndexFile index255; + private final List indexes = new ArrayList<>(); + + public Store(File folder) throws IOException + { + this.folder = folder; + + data = new DataFile(this, new File(folder, MAIN_FILE_CACHE_DAT)); + index255 = new IndexFile(this, 255, new File(folder, MAIN_FILE_CACHE_IDX + "255")); + + for (int i = 0; i < index255.getIndexCount(); ++i) + { + this.addIndex(i); + } + } + + @Override + public void close() throws IOException + { + data.close(); + index255.close(); + for (Index i : indexes) + i.close(); + } + + @Override + public int hashCode() + { + int hash = 5; + hash = 79 * hash + Objects.hashCode(this.indexes); + return hash; + } + + @Override + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + if (getClass() != obj.getClass()) + { + return false; + } + final Store other = (Store) obj; + if (!Objects.equals(this.indexes, other.indexes)) + { + return false; + } + return true; + } + + public final Index addIndex(int id) throws FileNotFoundException + { + for (Index i : indexes) + if (i.getIndex().getIndexFileId() == id) + throw new IllegalArgumentException("index " + id + " already exists"); + + IndexFile indexFile = new IndexFile(this, id, new File(folder, MAIN_FILE_CACHE_IDX + id)); + Index index = new Index(this, indexFile, id); + + this.indexes.add(index); + + return index; + } + + public void load() throws IOException + { + for (Index i : indexes) + { + int id = i.getIndex().getIndexFileId(); + if (id == 5) // XXX maps, XTEA encrypted, can't decompress + continue; + if (id == 6 || id == 14) + continue; // XXX I get more Indexes than there is length of the index file for these + i.load(); + } + } + + public void save() throws IOException + { + for (Index i : indexes) + i.save(); + } + + public DataFile getData() + { + return data; + } + + public IndexFile getIndex255() + { + return index255; + } + + public List getIndexes() + { + return indexes; + } + + public Index getIndex(IndexType type) + { + return indexes.get(type.getNumber()); + } +} diff --git a/cache/src/main/java/net/runelite/cache/fs/util/BZip2.java b/cache/src/main/java/net/runelite/cache/fs/util/BZip2.java new file mode 100644 index 0000000000..2cca0b6f56 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/fs/util/BZip2.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.fs.util; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Arrays; +import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream; +import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream; +import org.apache.commons.compress.utils.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BZip2 +{ + private static final Logger logger = LoggerFactory.getLogger(BZip2.class); + + private static final byte[] BZIP_HEADER = new byte[] { + 'B', 'Z', // magic + 'h', // 'h' for Bzip2 ('H'uffman coding) + '1' // block size + }; + + public static byte[] compress(byte[] bytes) + { + try + { + InputStream is = new ByteArrayInputStream(bytes); + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + try (OutputStream os = new BZip2CompressorOutputStream(bout)) + { + IOUtils.copy(is, os); + } + + byte[] out = bout.toByteArray(); + return Arrays.copyOfRange(out, BZIP_HEADER.length, out.length); // remove header.. + } + catch (IOException ex) + { + logger.warn(null, ex); + return null; + } + } + + public static byte[] decompress(byte[] bytes) + { + try + { + byte[] data = new byte[bytes.length + BZIP_HEADER.length]; + + // add header + System.arraycopy(BZIP_HEADER, 0, data, 0, BZIP_HEADER.length); + System.arraycopy(bytes, 0, data, BZIP_HEADER.length, bytes.length); + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + + try (InputStream is = new BZip2CompressorInputStream(new ByteArrayInputStream(data))) + { + IOUtils.copy(is, os); + } + + return os.toByteArray(); + } + catch (IOException ex) + { + logger.warn(null, ex); + return null; + } + } +} diff --git a/cache/src/main/java/net/runelite/cache/fs/util/CRC32HGenerator.java b/cache/src/main/java/net/runelite/cache/fs/util/CRC32HGenerator.java new file mode 100644 index 0000000000..130ff67055 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/fs/util/CRC32HGenerator.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.fs.util; + +import java.util.zip.CRC32; + +public final class CRC32HGenerator +{ + public static final CRC32 CRC32Instance = new CRC32(); + + public static synchronized int getHash(byte[] data, int len) + { + CRC32Instance.update(data, 0, len); + try + { + return (int) CRC32Instance.getValue(); + } + finally + { + CRC32Instance.reset(); + } + } +} diff --git a/cache/src/main/java/net/runelite/cache/fs/util/Djb2.java b/cache/src/main/java/net/runelite/cache/fs/util/Djb2.java new file mode 100644 index 0000000000..4cd490423a --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/fs/util/Djb2.java @@ -0,0 +1,28 @@ +package net.runelite.cache.fs.util; + +/** + * An implementation of the {@code djb2} hash function. + * + * @author Graham + * @author `Discardedx2 + */ +public final class Djb2 +{ + /** + * An implementation of Dan Bernstein's {@code djb2} hash function which + * is slightly modified. Instead of the initial hash being 5381, it is + * zero. + * + * @param str The string to hash. + * @return The hash code. + */ + public static int hash(String str) + { + int hash = 0; + for (int i = 0; i < str.length(); i++) + { + hash = str.charAt(i) + ((hash << 5) - hash); + } + return hash; + } +} diff --git a/cache/src/main/java/net/runelite/cache/fs/util/GZip.java b/cache/src/main/java/net/runelite/cache/fs/util/GZip.java new file mode 100644 index 0000000000..9b6adbb76c --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/fs/util/GZip.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.fs.util; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; +import org.apache.commons.compress.utils.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class GZip +{ + private static final Logger logger = LoggerFactory.getLogger(GZip.class); + + public static byte[] compress(byte[] bytes) + { + InputStream is = new ByteArrayInputStream(bytes); + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + + try (OutputStream os = new GZIPOutputStream(bout)) + { + IOUtils.copy(is, os); + } + catch (IOException ex) + { + logger.warn(null, ex); + return null; + } + + return bout.toByteArray(); + } + + public static byte[] decompress(byte[] bytes) + { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + + try (InputStream is = new GZIPInputStream(new ByteArrayInputStream(bytes))) + { + IOUtils.copy(is, os); + } + catch (IOException ex) + { + logger.warn(null, ex); + return null; + } + + return os.toByteArray(); + } +} diff --git a/cache/src/main/java/net/runelite/cache/fs/util/Whirlpool.java b/cache/src/main/java/net/runelite/cache/fs/util/Whirlpool.java new file mode 100644 index 0000000000..a380819276 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/fs/util/Whirlpool.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.fs.util; + +public class Whirlpool { + private static gnu.crypto.hash.Whirlpool whirlpool = new gnu.crypto.hash.Whirlpool(); + + public static synchronized byte[] getHash(byte[] data, int len) + { + whirlpool.update(data, 0, len); + try + { + return whirlpool.digest(); + } + finally + { + whirlpool.reset(); + } + } +} diff --git a/cache/src/main/java/net/runelite/cache/io/InputStream.java b/cache/src/main/java/net/runelite/cache/io/InputStream.java new file mode 100644 index 0000000000..af76b73859 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/io/InputStream.java @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.cache.io; + +import java.io.IOException; +import java.nio.ByteBuffer; + +public class InputStream extends java.io.InputStream +{ + private static final char[] CHARACTERS = new char[] + { + '\u20ac', '\u0000', '\u201a', '\u0192', '\u201e', '\u2026', + '\u2020', '\u2021', '\u02c6', '\u2030', '\u0160', '\u2039', + '\u0152', '\u0000', '\u017d', '\u0000', '\u0000', '\u2018', + '\u2019', '\u201c', '\u201d', '\u2022', '\u2013', '\u2014', + '\u02dc', '\u2122', '\u0161', '\u203a', '\u0153', '\u0000', + '\u017e', '\u0178' + }; + + private final ByteBuffer buffer; + + public InputStream(byte[] buffer) + { + this.buffer = ByteBuffer.wrap(buffer); + } + + public int read24BitInt() + { + return (this.readUnsignedByte() << 16) + (this.readUnsignedByte() << 8) + this.readUnsignedByte(); + } + + public void skip(int length) + { + int pos = buffer.position(); + pos += length; + buffer.position(pos); + } + + public void setOffset(int offset) + { + buffer.position(offset); + } + + public int getOffset() + { + return buffer.position(); + } + + public int getLength() + { + return buffer.limit(); + } + + public byte readByte() + { + return buffer.get(); + } + + public void readBytes(byte[] buffer, int off, int len) + { + this.buffer.get(buffer, off, len); + } + + public void readBytes(byte[] buffer) + { + this.buffer.get(buffer); + } + + public int readUnsignedByte() + { + return this.readByte() & 0xFF; + } + + public int readUnsignedShort() + { + return buffer.getShort() & 0xFFFF; + } + + public short readShort() + { + return buffer.getShort(); + } + + public int readInt() + { + return buffer.getInt(); + } + + public byte peek() + { + int position = buffer.position(); + try + { + return buffer.get(); + } + finally + { + buffer.position(position); + } + } + + public int readBigSmart() + { + return peek() >= 0 ? this.readUnsignedShort() : Integer.MAX_VALUE & this.readInt(); + } + + public int readShortSmart() + { + int var2 = this.peek() & 0xFF; + return var2 < 128 ? this.readUnsignedByte() - 64 : this.readUnsignedShort() - 0xc000; + } + + public String readString() + { + StringBuilder sb = new StringBuilder(); + + for (;;) + { + int ch = this.readByte(); + + if (ch == 0) + break; + + if (ch >= 128 && ch < 160) + { + char var7 = CHARACTERS[ch - 128]; + if (0 == var7) + { + var7 = 63; + } + + ch = var7; + } + + sb.append((char) ch); + } + return sb.toString(); + } + + + public String readStringOrNull() + { + if (this.peek() != 0) + { + return readString(); + } + else + { + this.readByte(); // discard + return null; + } + } + + public byte[] getRemaining() + { + byte[] b = new byte[buffer.remaining()]; + buffer.get(b); + return b; + } + + @Override + public int read() throws IOException + { + return this.readUnsignedByte(); + } +} diff --git a/cache/src/main/java/net/runelite/cache/io/OutputStream.java b/cache/src/main/java/net/runelite/cache/io/OutputStream.java new file mode 100644 index 0000000000..ee6e41a2ea --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/io/OutputStream.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.cache.io; + +import java.io.IOException; +import java.nio.ByteBuffer; + +public final class OutputStream extends java.io.OutputStream +{ + private ByteBuffer buffer; + + public OutputStream(int capacity) + { + buffer = ByteBuffer.allocate(capacity); + } + + public OutputStream() + { + this(16); + } + + private void ensureRemaining(int remaining) + { + while (remaining > buffer.remaining()) + { + int newCapacity = buffer.capacity() * 2; + + ByteBuffer old = buffer; + old.flip(); + + buffer = ByteBuffer.allocate(newCapacity); + + buffer.put(old); + } + } + + public void skip(int length) + { + int pos = buffer.position(); + pos += length; + buffer.position(pos); + } + + public void setOffset(int offset) + { + buffer.position(offset); + } + + public void writeBytes(byte[] b) + { + ensureRemaining(b.length); + buffer.put(b); + } + + public void writeByte(int i) + { + ensureRemaining(1); + buffer.put((byte) i); + } + + public void writeBigSmart(int value) + { + if (value >= 65536) + { + ensureRemaining(5); + this.writeByte(-1); + this.writeInt(Integer.MAX_VALUE & value); + } + else + { + ensureRemaining(2); + this.writeShort(value); + } + } + + public void writeShort(int i) + { + ensureRemaining(2); + buffer.putShort((short) i); + } + + public void writeInt(int i) + { + ensureRemaining(4); + buffer.putInt(i); + } + + public byte[] flip() + { + buffer.flip(); + byte[] b = new byte[buffer.limit()]; + buffer.get(b); + return b; + } + + @Override + public void write(int b) throws IOException + { + buffer.put((byte) b); + } + +} diff --git a/cache/src/main/java/net/runelite/cache/renderable/RGBSprite.java b/cache/src/main/java/net/runelite/cache/renderable/RGBSprite.java new file mode 100644 index 0000000000..2c21d4bb3c --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/renderable/RGBSprite.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.renderable; + +import java.awt.*; +import java.awt.image.*; +import net.runelite.cache.definitions.SpriteDefinition; + +public class RGBSprite +{ + private int offsetY; + private int spriteWidth; + private int spriteHeight; + private int offsetX; + private int maxHeight; + private int maxWidth; + private int[] pixels; + + RGBSprite() + { + } + + public int getOffsetY() + { + return offsetY; + } + + public int getSpriteWidth() + { + return spriteWidth; + } + + public int getSpriteHeight() + { + return spriteHeight; + } + + public int getOffsetX() + { + return offsetX; + } + + public int getMaxHeight() + { + return maxHeight; + } + + public int getMaxWidth() + { + return maxWidth; + } + + public int[] getPixels() + { + return pixels; + } + + public static RGBSprite fromSpriteDefinition(SpriteDefinition def) + { + RGBSprite sprite = new RGBSprite(); + + sprite.maxWidth = def.getMaxWidth(); + sprite.maxHeight = def.getMaxHeight(); + sprite.offsetX = def.getOffsetX(); + sprite.offsetY = def.getOffsetY(); + sprite.spriteWidth = def.getWidth(); + sprite.spriteHeight = def.getHeight(); + + int dimmension = sprite.spriteWidth * sprite.spriteHeight; + byte[] pixels = def.getPixels(); + int[] palette = def.getLoader().getLoadedPalette(); + + sprite.pixels = new int[dimmension]; + + for (int pos = 0; pos < dimmension; ++pos) + { + sprite.pixels[pos] = palette[pixels[pos] & 255]; + } + + return sprite; + } + + public BufferedImage getBufferedImage() + { + BufferedImage bi = new BufferedImage(spriteWidth, spriteHeight, BufferedImage.TYPE_INT_RGB); + bi.setRGB(0, 0, spriteWidth, spriteHeight, pixels, 0, spriteWidth); + Image img = makeColorTransparent(bi, new Color(0, 0, 0)); + BufferedImage trans = imageToBufferedImage(img); + return trans; + } + + private static Image makeColorTransparent(BufferedImage im, final Color color) + { + final int markerRGB = color.getRGB() | 0xFF000000; + + RGBImageFilter filter = new RGBImageFilter() + { + @Override + public final int filterRGB(int x, int y, int rgb) + { + if ((rgb | 0xFF000000) == markerRGB) + { + return 0x00FFFFFF & rgb; + } + else + { + return rgb; + } + } + }; + + ImageProducer ip = new FilteredImageSource(im.getSource(), filter); + return Toolkit.getDefaultToolkit().createImage(ip); + } + + private static BufferedImage imageToBufferedImage(Image image) + { + BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB); + Graphics2D g2 = bufferedImage.createGraphics(); + g2.drawImage(image, 0, 0, null); + g2.dispose(); + return bufferedImage; + } +} diff --git a/cache/src/test/java/net/runelite/cache/EnumDumperTest.java b/cache/src/test/java/net/runelite/cache/EnumDumperTest.java new file mode 100644 index 0000000000..9a31945fb2 --- /dev/null +++ b/cache/src/test/java/net/runelite/cache/EnumDumperTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache; + +import com.google.common.io.Files; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import net.runelite.cache.definitions.EnumDefinition; +import net.runelite.cache.definitions.loaders.EnumLoader; +import net.runelite.cache.fs.Archive; +import net.runelite.cache.fs.Index; +import net.runelite.cache.fs.Store; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class EnumDumperTest +{ + private static final Logger logger = LoggerFactory.getLogger(EnumDumperTest.class); + + private Gson gson = new GsonBuilder().setPrettyPrinting().create(); + + @Rule + public TemporaryFolder folder = StoreLocation.getTemporaryFolder(); + + @Test + public void test() throws IOException + { + File dumpDir = folder.newFolder(); + int count = 0; + + try (Store store = new Store(StoreLocation.LOCATION)) + { + store.load(); + + Index index = store.getIndex(IndexType.CONFIGS); + Archive archive = index.getArchive(ConfigType.ENUM.getId()); + + EnumLoader loader = new EnumLoader(); + + for (net.runelite.cache.fs.File file : archive.getFiles()) + { + byte[] b = file.getContents(); + + EnumDefinition def = loader.load(file.getFileId(), b); + + Files.write(gson.toJson(def), new File(dumpDir, file.getFileId() + ".json"), Charset.defaultCharset()); + ++count; + } + } + + logger.info("Dumped {} enums to {}", count, dumpDir); + } +} diff --git a/cache/src/test/java/net/runelite/cache/ItemDumperTest.java b/cache/src/test/java/net/runelite/cache/ItemDumperTest.java new file mode 100644 index 0000000000..989c8ef7b1 --- /dev/null +++ b/cache/src/test/java/net/runelite/cache/ItemDumperTest.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache; + +import java.io.File; +import java.io.IOException; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ItemDumperTest +{ + private static final Logger logger = LoggerFactory.getLogger(ItemDumperTest.class); + + @Rule + public TemporaryFolder folder = StoreLocation.getTemporaryFolder(); + + @Test + public void test() throws IOException + { + File dumpDir = folder.newFolder(), + javaDir = folder.newFolder(); + + ItemDumper dumper = new ItemDumper( + StoreLocation.LOCATION, + dumpDir, + javaDir + ); + dumper.load(); + dumper.dump(); + dumper.java(); + + logger.info("Dumped to {}, java {}", dumpDir, javaDir); + } + +} diff --git a/cache/src/test/java/net/runelite/cache/ModelDumperTest.java b/cache/src/test/java/net/runelite/cache/ModelDumperTest.java new file mode 100644 index 0000000000..717c14984c --- /dev/null +++ b/cache/src/test/java/net/runelite/cache/ModelDumperTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache; + + +import com.google.common.io.Files; +import com.google.gson.Gson; +import java.io.IOException; +import net.runelite.cache.definitions.loaders.ModelLoader; +import net.runelite.cache.fs.Archive; +import net.runelite.cache.fs.File; +import net.runelite.cache.fs.Index; +import net.runelite.cache.fs.Store; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ModelDumperTest +{ + private static final Logger logger = LoggerFactory.getLogger(ModelDumperTest.class); + + private Gson gson = new Gson(); + + @Rule + public TemporaryFolder folder = StoreLocation.getTemporaryFolder(); + + @Test + public void test() throws IOException + { + java.io.File modelDir = folder.newFolder("models"); + int count = 0; + + try (Store store = new Store(StoreLocation.LOCATION)) + { + store.load(); + + Index index = store.getIndex(IndexType.MODELS); + + for (Archive archive : index.getArchives()) + { + assert archive.getFiles().size() == 1; + + File file = archive.getFiles().get(0); + byte[] contents = file.getContents(); + + ModelLoader loader = new ModelLoader(); + loader.load(contents); + + Files.write(contents, new java.io.File(modelDir, archive.getArchiveId() + ".model")); + //Files.write(gson.toJson(loader), new java.io.File(modelDir, archive.getArchiveId() + ".json"), Charset.defaultCharset()); + ++count; + } + } + + logger.info("Dumped {} models to {}", count, modelDir); + } +} diff --git a/cache/src/test/java/net/runelite/cache/NpcDumperTest.java b/cache/src/test/java/net/runelite/cache/NpcDumperTest.java new file mode 100644 index 0000000000..99fa877ed3 --- /dev/null +++ b/cache/src/test/java/net/runelite/cache/NpcDumperTest.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache; + +import java.io.File; +import java.io.IOException; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NpcDumperTest +{ + private static final Logger logger = LoggerFactory.getLogger(NpcDumperTest.class); + + @Rule + public TemporaryFolder folder = StoreLocation.getTemporaryFolder(); + + @Test + public void test() throws IOException + { + File dumpDir = folder.newFolder(), + javaDir = folder.newFolder(); + + NpcDumper dumper = new NpcDumper( + StoreLocation.LOCATION, + dumpDir, + javaDir + ); + dumper.load(); + dumper.dump(); + dumper.java(); + + logger.info("Dumped to {}, java {}", dumpDir, javaDir); + } + +} diff --git a/cache/src/test/java/net/runelite/cache/ObjectDumperTest.java b/cache/src/test/java/net/runelite/cache/ObjectDumperTest.java new file mode 100644 index 0000000000..cce14cc3ec --- /dev/null +++ b/cache/src/test/java/net/runelite/cache/ObjectDumperTest.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.cache; + +import java.io.File; +import java.io.IOException; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ObjectDumperTest +{ + private static final Logger logger = LoggerFactory.getLogger(ObjectDumperTest.class); + + @Rule + public TemporaryFolder folder = StoreLocation.getTemporaryFolder(); + + @Test + public void test() throws IOException + { + File dumpDir = folder.newFolder(), + javaDir = folder.newFolder(); + + ObjectDumper dumper = new ObjectDumper( + StoreLocation.LOCATION, + dumpDir, + javaDir + ); + dumper.load(); + dumper.dump(); + dumper.java(); + + logger.info("Dumped to {}, java {}", dumpDir, javaDir); + } + +} diff --git a/cache/src/test/java/net/runelite/cache/ScriptDumperTest.java b/cache/src/test/java/net/runelite/cache/ScriptDumperTest.java new file mode 100644 index 0000000000..403b9d8496 --- /dev/null +++ b/cache/src/test/java/net/runelite/cache/ScriptDumperTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache; + +import com.google.common.io.Files; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import java.io.IOException; +import net.runelite.cache.definitions.ScriptDefinition; +import net.runelite.cache.definitions.loaders.ScriptLoader; +import net.runelite.cache.fs.Archive; +import net.runelite.cache.fs.File; +import net.runelite.cache.fs.Index; +import net.runelite.cache.fs.Store; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ScriptDumperTest +{ + private static final Logger logger = LoggerFactory.getLogger(ScriptDumperTest.class); + + private Gson gson = new GsonBuilder().setPrettyPrinting().create(); + + @Rule + public TemporaryFolder folder = StoreLocation.getTemporaryFolder(); + + @Test + public void test() throws IOException + { + java.io.File outDir = folder.newFolder(); + int count = 0; + + try (Store store = new Store(StoreLocation.LOCATION)) + { + store.load(); + + Index index = store.getIndex(IndexType.CLIENTSCRIPT); + ScriptLoader loader = new ScriptLoader(); + + for (Archive archive : index.getArchives()) + { + assert archive.getFiles().size() == 1; + + File file = archive.getFiles().get(0); + byte[] contents = file.getContents(); + + ScriptDefinition script = loader.load(file.getFileId(), contents); + + Files.write(contents, new java.io.File(outDir, archive.getArchiveId() + ".script")); + ++count; + } + } + + logger.info("Dumped {} scripts to {}", count, outDir); + } +} diff --git a/cache/src/test/java/net/runelite/cache/StoreLocation.java b/cache/src/test/java/net/runelite/cache/StoreLocation.java new file mode 100644 index 0000000000..caf9bf2832 --- /dev/null +++ b/cache/src/test/java/net/runelite/cache/StoreLocation.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache; + +import java.io.File; +import java.net.URISyntaxException; +import org.junit.rules.TemporaryFolder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class StoreLocation +{ + private static final Logger logger = LoggerFactory.getLogger(StoreLocation.class); + + public static File LOCATION; + + static + { + try + { + LOCATION = new File(StoreLocation.class.getResource("/cache").toURI()); + } + catch (URISyntaxException ex) + { + logger.error(null, ex); + } + + File tmp = new File("d:/temp"); + if (tmp.exists() || tmp.mkdir()) + System.setProperty("java.io.tmpdir", "d:/temp"); + } + + public static TemporaryFolder getTemporaryFolder() + { + return new TemporaryFolder(); + } +} \ No newline at end of file diff --git a/cache/src/test/java/net/runelite/cache/fs/DataFileTest.java b/cache/src/test/java/net/runelite/cache/fs/DataFileTest.java new file mode 100644 index 0000000000..ea5ac06d91 --- /dev/null +++ b/cache/src/test/java/net/runelite/cache/fs/DataFileTest.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.fs; + +import java.io.File; +import java.io.IOException; +import java.nio.ByteBuffer; +import net.runelite.cache.StoreLocation; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +public class DataFileTest +{ + @Rule + public TemporaryFolder folder = StoreLocation.getTemporaryFolder(); + + @Test + public void test1() throws IOException + { + File file = folder.newFile(); + Store store = new Store(folder.getRoot()); + DataFile df = new DataFile(store, file); + DataFileWriteResult res = df.write(42, 3, ByteBuffer.wrap("test".getBytes()), CompressionType.NONE, 0); + DataFileReadResult res2 = df.read(42, 3, res.sector, res.compressedLength); + byte[] buf = res2.data; + String str = new String(buf); + Assert.assertEquals("test", str); + file.delete(); + } + + @Test + public void test2() throws IOException + { + byte[] b = new byte[1024]; + for (int i = 0; i < 1024; ++i) + b[i] = (byte) i; + + File file = folder.newFile(); + Store store = new Store(folder.getRoot()); + DataFile df = new DataFile(store, file); + DataFileWriteResult res = df.write(42, 0x1FFFF, ByteBuffer.wrap(b), CompressionType.NONE, 0); + DataFileReadResult res2 = df.read(42, 0x1FFFF, res.sector, res.compressedLength); + byte[] buf = res2.data; + Assert.assertArrayEquals(b, buf); + file.delete(); + } + + @Test + public void testGZipCompression() throws IOException + { + try (Store store = new Store(folder.getRoot())) + { + DataFile df = new DataFile(store, folder.newFile()); + DataFileWriteResult res = df.write(41, 4, ByteBuffer.wrap("test".getBytes()), CompressionType.GZ, 0); + DataFileReadResult res2 = df.read(41, 4, res.sector, res.compressedLength); + byte[] buf = res2.data; + String str = new String(buf); + Assert.assertEquals("test", str); + } + } + + @Test + public void testBZip2Compression() throws IOException + { + try (Store store = new Store(folder.getRoot())) + { + DataFile df = new DataFile(store, folder.newFile()); + DataFileWriteResult res = df.write(41, 4, ByteBuffer.wrap("test".getBytes()), CompressionType.BZ2, 0); + DataFileReadResult res2 = df.read(41, 4, res.sector, res.compressedLength); + byte[] buf = res2.data; + String str = new String(buf); + Assert.assertEquals("test", str); + } + } +} diff --git a/cache/src/test/java/net/runelite/cache/fs/IndexFileTest.java b/cache/src/test/java/net/runelite/cache/fs/IndexFileTest.java new file mode 100644 index 0000000000..fa9a17b603 --- /dev/null +++ b/cache/src/test/java/net/runelite/cache/fs/IndexFileTest.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.fs; + +import java.io.File; +import java.io.IOException; +import net.runelite.cache.StoreLocation; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +public class IndexFileTest +{ + @Rule + public TemporaryFolder folder = StoreLocation.getTemporaryFolder(); + + @Test + public void test1() throws IOException + { + File file = folder.newFile(); + Store store = new Store(folder.getRoot()); + IndexFile index = new IndexFile(store, 5, file); + IndexEntry entry = new IndexEntry(index, 7, 8, 9); + index.write(entry); + IndexEntry entry2 = index.read(7); + Assert.assertEquals(entry, entry2); + } +} diff --git a/cache/src/test/java/net/runelite/cache/fs/StoreLoadTest.java b/cache/src/test/java/net/runelite/cache/fs/StoreLoadTest.java new file mode 100644 index 0000000000..0e56fe384a --- /dev/null +++ b/cache/src/test/java/net/runelite/cache/fs/StoreLoadTest.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.fs; + +import com.google.common.io.Files; +import java.io.FileOutputStream; +import java.io.IOException; +import net.runelite.cache.StoreLocation; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +public class StoreLoadTest +{ + @Rule + public TemporaryFolder folder = StoreLocation.getTemporaryFolder(); + + @Test + public void testLoad() throws IOException + { + Store store = new Store(StoreLocation.LOCATION); + store.load(); + System.out.println(store); + } + + @Test + public void testSave() throws IOException + { + Store store = new Store(StoreLocation.LOCATION); + store.load(); + + java.io.File testStoreFile = folder.newFolder(); + for (java.io.File f : StoreLocation.LOCATION.listFiles()) + Files.copy(f, new java.io.File(testStoreFile, f.getName())); + + Store testStore = new Store(testStoreFile); + testStore.load(); + + Assert.assertTrue(store.equals(testStore)); + + testStore.save(); + testStore.load(); + + Assert.assertTrue(store.equals(testStore)); + } + + //@Test + public void unpackStore() throws IOException + { + java.io.File base = StoreLocation.LOCATION; + try (Store store = new Store(base)) + { + store.load(); + + for (Index i : store.getIndexes()) + { + java.io.File ifile = new java.io.File(folder.newFolder(), "" + i.getId()); + ifile.mkdir(); + + for (Archive a : i.getArchives()) + { + java.io.File afile = new java.io.File(ifile, "" + a.getArchiveId()); + afile.mkdir(); + + for (File f : a.getFiles()) + { + java.io.File ffile = new java.io.File(afile, "" + f.getFileId()); + try (FileOutputStream fout = new FileOutputStream(ffile)) + { + if (f.getContents() != null) + { + fout.write(f.getContents()); + } + } + } + } + } + } + } +} diff --git a/cache/src/test/java/net/runelite/cache/fs/StoreTest.java b/cache/src/test/java/net/runelite/cache/fs/StoreTest.java new file mode 100644 index 0000000000..03a4f6ed2a --- /dev/null +++ b/cache/src/test/java/net/runelite/cache/fs/StoreTest.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.fs; + +import java.io.IOException; +import java.util.Random; +import net.runelite.cache.StoreLocation; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +public class StoreTest +{ + @Rule + public TemporaryFolder folder = StoreLocation.getTemporaryFolder(); + + @Test + public void testOneFile() throws IOException + { + try (Store store = new Store(folder.getRoot())) + { + Index index = store.addIndex(0); + Archive archive = index.addArchive(0); + File file = archive.addFile(0); + file.setNameHash(7); + file.setContents("test".getBytes()); + + store.save(); + + try (Store store2 = new Store(folder.getRoot())) + { + store2.load(); + + Assert.assertEquals(store, store2); + } + } + } + + private static final int NUMBER_OF_FILES = 1024; + + @Test + public void testManyFiles() throws IOException + { + Random random = new Random(42L); + + try (Store store = new Store(folder.getRoot())) + { + Index index = store.addIndex(0); + Archive archive = index.addArchive(0); + archive.setNameHash(random.nextInt()); + + for (int i = 0; i < NUMBER_OF_FILES; ++i) + { + File file = archive.addFile(i); + file.setNameHash(random.nextInt()); + byte[] data = new byte[random.nextInt(1024)]; + random.nextBytes(data); + file.setContents(data); + } + + store.save(); + + try (Store store2 = new Store(folder.getRoot())) + { + store2.load(); + + Assert.assertEquals(store, store2); + } + } + } + + @Test + public void testMultipleArchives() throws IOException + { + Random random = new Random(43L); + + try (Store store = new Store(folder.getRoot())) + { + Index index = store.addIndex(0); + Index index2 = store.addIndex(1); + + Archive archive = index.addArchive(0); + archive.setNameHash(random.nextInt()); + + Archive archive2 = index.addArchive(1); + + Archive archive3 = index2.addArchive(0); + + for (int i = 0; i < NUMBER_OF_FILES; ++i) + { + File file = archive.addFile(i); + file.setNameHash(random.nextInt()); + byte[] data = new byte[random.nextInt(1024)]; + random.nextBytes(data); + file.setContents(data); + } + + for (int i = 0; i < NUMBER_OF_FILES; ++i) + { + File file = archive2.addFile(i); + file.setNameHash(random.nextInt()); + byte[] data = new byte[random.nextInt(1024)]; + random.nextBytes(data); + file.setContents(data); + } + + for (int i = 0; i < NUMBER_OF_FILES; ++i) + { + File file = archive3.addFile(i); + file.setNameHash(random.nextInt()); + byte[] data = new byte[random.nextInt(1024)]; + random.nextBytes(data); + file.setContents(data); + } + + store.save(); + + try (Store store2 = new Store(folder.getRoot())) + { + store2.load(); + + Assert.assertEquals(store, store2); + } + } + } +} diff --git a/cache/src/test/java/net/runelite/cache/loaders/SpriteLoaderTest.java b/cache/src/test/java/net/runelite/cache/loaders/SpriteLoaderTest.java new file mode 100644 index 0000000000..b8180359c2 --- /dev/null +++ b/cache/src/test/java/net/runelite/cache/loaders/SpriteLoaderTest.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.loaders; + +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.util.List; +import javax.imageio.ImageIO; +import net.runelite.cache.IndexType; +import net.runelite.cache.StoreLocation; +import net.runelite.cache.definitions.SpriteDefinition; +import net.runelite.cache.definitions.loaders.SpriteLoader; +import net.runelite.cache.fs.Archive; +import net.runelite.cache.fs.File; +import net.runelite.cache.fs.Index; +import net.runelite.cache.fs.Store; +import net.runelite.cache.io.InputStream; +import net.runelite.cache.renderable.RGBSprite; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SpriteLoaderTest +{ + private static final Logger logger = LoggerFactory.getLogger(SpriteLoaderTest.class); + + @Rule + public TemporaryFolder folder = StoreLocation.getTemporaryFolder(); + + @Test + public void extract() throws IOException + { + java.io.File base = StoreLocation.LOCATION, + outDir = folder.newFolder(); + + try (Store store = new Store(base)) + { + store.load(); + + Index index = store.getIndex(IndexType.SPRITES); + + for (Archive a : index.getArchives()) + { + List files = a.getFiles(); + + Assert.assertEquals(1, files.size()); + + File file = files.get(0); + byte[] contents = file.getContents(); + + SpriteLoader loader = new SpriteLoader(); + loader.load(new InputStream(contents)); + + SpriteDefinition[] defs = loader.getSprites(); + + for (int i = 0; i < defs.length; ++i) + { + RGBSprite sp = RGBSprite.fromSpriteDefinition(defs[i]); + + // I don't know why this happens + if (sp.getSpriteHeight() <= 0 || sp.getSpriteWidth() <= 0) + continue; + + BufferedImage image = sp.getBufferedImage(); + java.io.File targ = new java.io.File(outDir, a.getArchiveId() + "-" + i + ".png"); + targ.mkdirs(); + ImageIO.write(image, "png", targ); + } + } + } + + logger.info("Dumped to {}", outDir); + } +} diff --git a/cache/src/test/java/net/runelite/cache/loaders/TitleDumper.java b/cache/src/test/java/net/runelite/cache/loaders/TitleDumper.java new file mode 100644 index 0000000000..3ca8ca00d5 --- /dev/null +++ b/cache/src/test/java/net/runelite/cache/loaders/TitleDumper.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2016, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Adam BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.cache.loaders; + +import java.io.IOException; +import java.nio.file.Files; +import net.runelite.cache.IndexType; +import net.runelite.cache.StoreLocation; +import net.runelite.cache.fs.Archive; +import net.runelite.cache.fs.File; +import net.runelite.cache.fs.Index; +import net.runelite.cache.fs.Store; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TitleDumper +{ + private static final Logger logger = LoggerFactory.getLogger(TitleDumper.class); + + @Rule + public TemporaryFolder folder = StoreLocation.getTemporaryFolder(); + + @Test + public void extract() throws IOException + { + java.io.File base = StoreLocation.LOCATION, + outFile = folder.newFile(); + + try (Store store = new Store(base)) + { + store.load(); + + Index index = store.getIndex(IndexType.BINARY); + Archive a = index.findArchiveByName("title.jpg"); + File file = a.getFiles().get(0); + + Files.write(outFile.toPath(), file.getContents()); + } + + logger.info("Dumped to {}", outFile); + } +} diff --git a/model-viewer/pom.xml b/model-viewer/pom.xml index a52ce360d7..4e7c36d330 100644 --- a/model-viewer/pom.xml +++ b/model-viewer/pom.xml @@ -45,7 +45,7 @@ net.runelite - deob + cache 1.1.0-SNAPSHOT diff --git a/pom.xml b/pom.xml index 3551ac75d6..fe8008d5b7 100644 --- a/pom.xml +++ b/pom.xml @@ -71,6 +71,7 @@ runelite-client runelite-api model-viewer + cache