diff --git a/src/main/java/net/runelite/cache/fs/Archive.java b/src/main/java/net/runelite/cache/fs/Archive.java new file mode 100644 index 0000000000..61ce08be90 --- /dev/null +++ b/src/main/java/net/runelite/cache/fs/Archive.java @@ -0,0 +1,61 @@ +package net.runelite.cache.fs; + +import java.util.ArrayList; +import java.util.List; + +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; + } + + 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; + } +} diff --git a/src/main/java/net/runelite/cache/fs/DataFile.java b/src/main/java/net/runelite/cache/fs/DataFile.java index d44024d3a6..66fb3d177c 100644 --- a/src/main/java/net/runelite/cache/fs/DataFile.java +++ b/src/main/java/net/runelite/cache/fs/DataFile.java @@ -33,13 +33,14 @@ public class DataFile implements Closeable /** * + * @param indexId * @param archiveId * @param sector sector to start reading at * @param size expected size of file * @return * @throws IOException */ - public synchronized ByteBuffer read(int indexId, int archiveId, int sector, int size) throws IOException + public synchronized byte[] read(int indexId, int archiveId, int sector, int size) throws IOException { if (sector <= 0L || dat.length() / 520L < (long) sector) { @@ -122,11 +123,13 @@ public class DataFile implements Closeable ++part; } - return buffer; + buffer.flip(); + return buffer.array(); } /** * + * @param indexId * @param archiveId archive to write to * @param data data to write * @return the sector the data starts at diff --git a/src/main/java/net/runelite/cache/fs/File.java b/src/main/java/net/runelite/cache/fs/File.java new file mode 100644 index 0000000000..4f45d9e414 --- /dev/null +++ b/src/main/java/net/runelite/cache/fs/File.java @@ -0,0 +1,8 @@ +package net.runelite.cache.fs; + +public class File +{ + private Archive archive; + private int fileId; + private int nameHash; +} diff --git a/src/main/java/net/runelite/cache/fs/Index.java b/src/main/java/net/runelite/cache/fs/Index.java new file mode 100644 index 0000000000..ca2ff830f1 --- /dev/null +++ b/src/main/java/net/runelite/cache/fs/Index.java @@ -0,0 +1,201 @@ +package net.runelite.cache.fs; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import net.runelite.cache.fs.io.InputStream; +import net.runelite.cache.fs.util.bzip2.BZip2Decompressor; +import net.runelite.cache.fs.util.gzip.GZipDecompressor; + +public class Index +{ + private final IndexFile index; + private final int id; + private int compression; + private boolean named, usesWhirpool; + private int revision; + private int crc; + private byte[] whirlpool; + private List archives = new ArrayList<>(); + + public Index(IndexFile index, int id) throws IOException + { + this.index = index; + this.id = id; + + // read data from index255 + Store store = index.getStore(); + DataFile dataFile = store.getData(); + IndexFile index255 = store.getIndex255(); + + IndexEntry entry = index255.read(id); + byte[] b = dataFile.read(id, entry.getId(), entry.getSector(), entry.getLength()); + + InputStream stream = new InputStream(b); + + //XTEA decrypt here + + this.compression = stream.readUnsignedByte(); + int compressedLength = stream.readInt(); + if (compressedLength < 0 || compressedLength > 1000000) + throw new RuntimeException("Invalid archive header"); + + byte[] data; + switch (compression) + { + case 0: + data = new byte[compressedLength]; + this.checkRevision(stream, compressedLength); + stream.readBytes(data, 0, compressedLength); + break; + case 1: + { + int length = stream.readInt(); + data = new byte[length]; + this.checkRevision(stream, compressedLength); + BZip2Decompressor.decompress(data, b, compressedLength, 9); + break; + } + default: + { + int length = stream.readInt(); + data = new byte[length]; + this.checkRevision(stream, compressedLength); + GZipDecompressor.decompress(stream, data); + } + } + + readIndexData(data); + } + + private void checkRevision(InputStream stream, int compressedLength) + { + int offset = stream.getOffset(); + if (stream.getLength() - (compressedLength + stream.getOffset()) >= 2) { + stream.setOffset(stream.getLength() - 2); + this.revision = stream.readUnsignedShort(); + stream.setOffset(offset); + } + else { + this.revision = -1; + } + + } + + private void readIndexData(byte[] data) + { + InputStream stream = new InputStream(data); + int protocol = stream.readUnsignedByte(); + if (protocol >= 5 && protocol <= 7) { + if (protocol >= 6) { + not the right rev + this.revision = stream.readInt(); + } + + int hash = stream.readUnsignedByte(); + this.named = (1 & hash) != 0; + this.usesWhirpool = (2 & hash) != 0; + int validArchivesCount = protocol >= 7 ? stream.readBigSmart() : stream.readUnsignedShort(); +// this.validArchiveIds = new int[validArchivesCount]; +// int lastArchiveId = 0; +// int biggestArchiveId = 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 (archive > biggestArchiveId) { +// biggestArchiveId = archive; +// } +// +// this.validArchiveIds[index] = archive; + } + + //this.archives = new ArchiveReference[biggestArchiveId + 1]; + + for (index = 0; index < validArchivesCount; ++index) { + Archive a = this.archives.get(index); + //this.archives[this.validArchiveIds[index]] = new ArchiveReference(); + } + + if (this.named) { + for (index = 0; index < validArchivesCount; ++index) { + int nameHash = stream.readInt(); + Archive a = this.archives.get(index); + a.setNameHash(nameHash); + //this.archives[this.validArchiveIds[index]].setNameHash(stream.readInt()); + } + } + + if (this.usesWhirpool) { + for (index = 0; index < validArchivesCount; ++index) { + byte[] var13 = new byte[64]; + stream.getBytes(var13, 0, 64); + + Archive a = this.archives.get(index); + a.setWhirlpool(var13); + //this.archives[this.validArchiveIds[index]].setWhirpool(var13); + } + } + + for (index = 0; index < validArchivesCount; ++index) { + int crc = stream.readInt(); + + Archive a = this.archives.get(index); + a.setCrc(crc); + //this.archives[this.validArchiveIds[index]].setCrc(stream.readInt()); + } + + for (index = 0; index < validArchivesCount; ++index) { + int revision = stream.readInt(); + + Archive a = this.archives.get(index); + a.setRevision(revision); + //this.archives[this.validArchiveIds[index]].setRevision(stream.readInt()); + } + + int[] numberOfFiles = new int[validArchivesCount]; + for (index = 0; index < validArchivesCount; ++index) { + int num = protocol >= 7 ? stream.readBigSmart() : stream.readUnsignedShort(); + numberOfFiles[index] = num; + //this.archives[this.validArchiveIds[index]].setValidFileIds(new int[protocol >= 7 ? stream.readBigSmart() : stream.readUnsignedShort()]); + } + + int index2; + for (index = 0; index < validArchivesCount; ++index) { + archive = 0; + index2 = 0; + ArchiveReference archive1 = this.archives[this.validArchiveIds[index]]; + + int index21; + for (index21 = 0; index21 < archive1.getValidFileIds().length; ++index21) { + int fileId = archive += protocol >= 7 ? stream.readBigSmart() : stream.readUnsignedShort(); + if (fileId > index2) { + index2 = fileId; + } + + archive1.getValidFileIds()[index21] = fileId; + } + + archive1.setFiles(new FileReference[index2 + 1]); + + for (index21 = 0; index21 < archive1.getValidFileIds().length; ++index21) { + archive1.getFiles()[archive1.getValidFileIds()[index21]] = new FileReference(); + } + } + + if (this.named) { + for (index = 0; index < validArchivesCount; ++index) { + ArchiveReference var14 = this.archives[this.validArchiveIds[index]]; + + for (index2 = 0; index2 < var14.getValidFileIds().length; ++index2) { + var14.getFiles()[var14.getValidFileIds()[index2]].setNameHash(stream.readInt()); + } + } + } + } + } +} diff --git a/src/main/java/net/runelite/cache/fs/IndexFile.java b/src/main/java/net/runelite/cache/fs/IndexFile.java index 633371bb8d..07c95be57d 100644 --- a/src/main/java/net/runelite/cache/fs/IndexFile.java +++ b/src/main/java/net/runelite/cache/fs/IndexFile.java @@ -30,6 +30,16 @@ public class IndexFile implements Closeable { idx.close(); } + + public Store getStore() + { + return store; + } + + public int getIndexFileId() + { + return indexFileId; + } public synchronized void write(IndexEntry entry) throws IOException { diff --git a/src/main/java/net/runelite/cache/fs/Store.java b/src/main/java/net/runelite/cache/fs/Store.java index cca81beeb4..2f0acb9942 100644 --- a/src/main/java/net/runelite/cache/fs/Store.java +++ b/src/main/java/net/runelite/cache/fs/Store.java @@ -33,4 +33,14 @@ public class Store implements Closeable for (IndexFile i : indexFiles) i.close(); } + + public DataFile getData() + { + return data; + } + + public IndexFile getIndex255() + { + return index255; + } } diff --git a/src/main/java/net/runelite/cache/fs/io/InputStream.java b/src/main/java/net/runelite/cache/fs/io/InputStream.java new file mode 100644 index 0000000000..840289d77a --- /dev/null +++ b/src/main/java/net/runelite/cache/fs/io/InputStream.java @@ -0,0 +1,252 @@ +package net.runelite.cache.fs.io; + +import net.runelite.cache.fs.io.Stream; + +public final class InputStream extends Stream { + private static final int[] BIT_MASK = new int[]{0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, '\uffff', 131071, 262143, 524287, 1048575, 2097151, 4194303, 8388607, 16777215, 33554431, 67108863, 134217727, 268435455, 536870911, 1073741823, Integer.MAX_VALUE, -1}; + + public void initBitAccess() { + this.bitPosition = this.offset * 8; + } + + public void finishBitAccess() { + this.offset = (7 + this.bitPosition) / 8; + } + + public int readBits(int bitOffset) { + int bytePos = this.bitPosition >> 1779819011; + int i_8_ = -(7 & this.bitPosition) + 8; + this.bitPosition += bitOffset; + + int value; + for(value = 0; ~bitOffset < ~i_8_; i_8_ = 8) { + value += (BIT_MASK[i_8_] & this.buffer[bytePos++]) << -i_8_ + bitOffset; + bitOffset -= i_8_; + } + + if(~i_8_ == ~bitOffset) { + value += this.buffer[bytePos] & BIT_MASK[i_8_]; + } else { + value += this.buffer[bytePos] >> -bitOffset + i_8_ & BIT_MASK[bitOffset]; + } + + return value; + } + + public InputStream(int capacity) { + this.buffer = new byte[capacity]; + } + + public InputStream(byte[] buffer) { + this.buffer = buffer; + this.length = buffer.length; + } + + public void checkCapacity(int length) { + if(this.offset + length >= this.buffer.length) { + byte[] newBuffer = new byte[(this.offset + length) * 2]; + System.arraycopy(this.buffer, 0, newBuffer, 0, this.buffer.length); + this.buffer = newBuffer; + } + + } + + public int read24BitInt() { + return (this.readUnsignedByte() << 16) + (this.readUnsignedByte() << 8) + this.readUnsignedByte(); + } + + public void skip(int length) { + this.offset += length; + } + + public void setLength(int length) { + this.length = length; + } + + public void setOffset(int offset) { + this.offset = offset; + } + + public int getRemaining() { + return this.offset < this.length?this.length - this.offset:0; + } + + public void addBytes(byte[] b, int offset, int length) { + this.checkCapacity(length - offset); + System.arraycopy(b, offset, this.buffer, this.offset, length); + this.length += length - offset; + } + + public int readPacket() { + return this.readUnsignedByte(); + } + + public int readByte() { + return this.getRemaining() > 0?this.buffer[this.offset++]:0; + } + + public void readBytes(byte[] buffer, int off, int len) { + for(int k = off; k < len + off; ++k) { + buffer[k] = (byte)this.readByte(); + } + + } + + public void readBytes(byte[] buffer) { + this.readBytes(buffer, 0, buffer.length); + } + + public int readSmart2() { + int i = 0; + + int i_33_; + for(i_33_ = this.readUnsignedSmart(); ~i_33_ == -32768; i += 32767) { + i_33_ = this.readUnsignedSmart(); + } + + i += i_33_; + return i; + } + + public int readUnsignedByte() { + return this.readByte() & 255; + } + + public int readByte128() { + return (byte)(this.readByte() - 128); + } + + public int readByteC() { + return (byte)(-this.readByte()); + } + + public int read128Byte() { + return (byte)(128 - this.readByte()); + } + + public int readUnsignedByte128() { + return this.readUnsignedByte() - 128 & 255; + } + + public int readUnsignedByteC() { + return -this.readUnsignedByte() & 255; + } + + public int readUnsigned128Byte() { + return 128 - this.readUnsignedByte() & 255; + } + + public int readShortLE() { + int i = this.readUnsignedByte() + (this.readUnsignedByte() << 8); + if(i > 32767) { + i -= 65536; + } + + return i; + } + + public int readShort128() { + int i = (this.readUnsignedByte() << 8) + (this.readByte() - 128 & 255); + if(i > 32767) { + i -= 65536; + } + + return i; + } + + public int readShortLE128() { + int i = (this.readByte() - 128 & 255) + (this.readUnsignedByte() << 8); + if(i > 32767) { + i -= 65536; + } + + return i; + } + + public int read128ShortLE() { + int i = (128 - this.readByte() & 255) + (this.readUnsignedByte() << 8); + if(i > 32767) { + i -= 65536; + } + + return i; + } + + public int readShort() { + int i = (this.readUnsignedByte() << 8) + this.readUnsignedByte(); + if(i > 32767) { + i -= 65536; + } + + return i; + } + + public int readUnsignedShortLE() { + return this.readUnsignedByte() + (this.readUnsignedByte() << 8); + } + + public int readUnsignedShort() { + return (this.readUnsignedByte() << 8) + this.readUnsignedByte(); + } + + public int readUnsignedShort128() { + return (this.readUnsignedByte() << 8) + (this.readByte() - 128 & 255); + } + + public int readUnsignedShortLE128() { + return (this.readByte() - 128 & 255) + (this.readUnsignedByte() << 8); + } + + public int readInt() { + return (this.readUnsignedByte() << 24) + (this.readUnsignedByte() << 16) + (this.readUnsignedByte() << 8) + this.readUnsignedByte(); + } + + public int readIntV1() { + return (this.readUnsignedByte() << 8) + this.readUnsignedByte() + (this.readUnsignedByte() << 24) + (this.readUnsignedByte() << 16); + } + + public int readIntV2() { + return (this.readUnsignedByte() << 16) + (this.readUnsignedByte() << 24) + this.readUnsignedByte() + (this.readUnsignedByte() << 8); + } + + public int readIntLE() { + return this.readUnsignedByte() + (this.readUnsignedByte() << 8) + (this.readUnsignedByte() << 16) + (this.readUnsignedByte() << 24); + } + + public long readLong() { + long l = (long)this.readInt() & 4294967295L; + long l1 = (long)this.readInt() & 4294967295L; + return (l << 32) + l1; + } + + public String readString() { + String s; + int b; + for(s = ""; (b = this.readByte()) != 0; s = s + (char)b) { + ; + } + + return s; + } + + public String readJagString() { + this.readByte(); + + String s; + int b; + for(s = ""; (b = this.readByte()) != 0; s = s + (char)b) { + ; + } + + return s; + } + + public int readBigSmart() { + return this.buffer[this.offset] >= 0?this.readUnsignedShort():Integer.MAX_VALUE & this.readInt(); + } + + public int readUnsignedSmart() { + int i = 255 & this.buffer[this.offset]; + return i >= 128?-32768 + this.readUnsignedShort():this.readUnsignedByte(); + } +} diff --git a/src/main/java/net/runelite/cache/fs/io/OutputStream.java b/src/main/java/net/runelite/cache/fs/io/OutputStream.java new file mode 100644 index 0000000000..66eda169e1 --- /dev/null +++ b/src/main/java/net/runelite/cache/fs/io/OutputStream.java @@ -0,0 +1,327 @@ +package net.runelite.cache.fs.io; + +import net.runelite.cache.fs.io.Stream; +import java.math.BigInteger; + +public final class OutputStream extends Stream { + private static final int[] BIT_MASK = new int[32]; + private int opcodeStart = 0; + + static { + for(int i = 0; i < 32; ++i) { + BIT_MASK[i] = (1 << i) - 1; + } + + } + + public OutputStream(int capacity) { + this.setBuffer(new byte[capacity]); + } + + public OutputStream() { + this.setBuffer(new byte[16]); + } + + public OutputStream(byte[] buffer) { + this.setBuffer(buffer); + this.offset = buffer.length; + this.length = buffer.length; + } + + public OutputStream(int[] buffer) { + this.setBuffer(new byte[buffer.length]); + int[] var5 = buffer; + int var4 = buffer.length; + + for(int var3 = 0; var3 < var4; ++var3) { + int value = var5[var3]; + this.writeByte(value); + } + + } + + public void checkCapacityPosition(int position) { + if(position >= this.getBuffer().length) { + byte[] newBuffer = new byte[position + 16]; + System.arraycopy(this.getBuffer(), 0, newBuffer, 0, this.getBuffer().length); + this.setBuffer(newBuffer); + } + + } + + public void skip(int length) { + this.setOffset(this.getOffset() + length); + } + + public void setOffset(int offset) { + this.offset = offset; + } + + public void writeBytes(byte[] b, int offset, int length) { + this.checkCapacityPosition(this.getOffset() + length - offset); + System.arraycopy(b, offset, this.getBuffer(), this.getOffset(), length); + this.setOffset(this.getOffset() + (length - offset)); + } + + public void writeBytes(byte[] b) { + byte offset = 0; + int length = b.length; + this.checkCapacityPosition(this.getOffset() + length - offset); + System.arraycopy(b, offset, this.getBuffer(), this.getOffset(), length); + this.setOffset(this.getOffset() + (length - offset)); + } + + public void addBytes128(byte[] data, int offset, int len) { + for(int k = offset; k < len; ++k) { + this.writeByte((byte)(data[k] + 128)); + } + + } + + public void addBytesS(byte[] data, int offset, int len) { + for(int k = offset; k < len; ++k) { + this.writeByte((byte)(-128 + data[k])); + } + + } + + public void addBytes_Reverse(byte[] data, int offset, int len) { + for(int i = len - 1; i >= 0; --i) { + this.writeByte(data[i]); + } + + } + + public void addBytes_Reverse128(byte[] data, int offset, int len) { + for(int i = len - 1; i >= 0; --i) { + this.writeByte((byte)(data[i] + 128)); + } + + } + + public void writeByte(int i) { + this.writeByte(i, this.offset++); + } + + public void writeNegativeByte(int i) { + this.writeByte(-i, this.offset++); + } + + public void writeByte(int i, int position) { + this.checkCapacityPosition(position); + this.getBuffer()[position] = (byte)i; + } + + public void writeByte128(int i) { + this.writeByte(i + 128); + } + + public void writeByteC(int i) { + this.writeByte(-i); + } + + public void write3Byte(int i) { + this.writeByte(i >> 16); + this.writeByte(i >> 8); + this.writeByte(i); + } + + public void write128Byte(int i) { + this.writeByte(128 - i); + } + + public void writeShortLE128(int i) { + this.writeByte(i + 128); + this.writeByte(i >> 8); + } + + public void writeShort128(int i) { + this.writeByte(i >> 8); + this.writeByte(i + 128); + } + + public void writeBigSmart(int value) { + if(value >= 65536) { + this.writeByte(-1); + this.writeInt(Integer.MAX_VALUE & value); + } else { + this.writeShort(value); + } + } + + public void writeSmart(int i) { + if(i >= 128) { + this.writeShort(i + '\u8000'); + } else { + this.writeByte(i); + } + + } + + public void writeShort(int i) { + this.writeByte(i >> 8); + this.writeByte(i); + } + + public void writeShortLE(int i) { + this.writeByte(i); + this.writeByte(i >> 8); + } + + public void write24BitInt(int i) { + this.writeByte(i >> 16); + this.writeByte(i >> 8); + this.writeByte(i); + } + + public void writeInt(int i) { + this.writeByte(i >> 24); + this.writeByte(i >> 16); + this.writeByte(i >> 8); + this.writeByte(i); + } + + public void writeIntV1(int i) { + this.writeByte(i >> 8); + this.writeByte(i); + this.writeByte(i >> 24); + this.writeByte(i >> 16); + } + + public void writeIntV2(int i) { + this.writeByte(i >> 16); + this.writeByte(i >> 24); + this.writeByte(i); + this.writeByte(i >> 8); + } + + public void writeIntLE(int i) { + this.writeByte(i); + this.writeByte(i >> 8); + this.writeByte(i >> 16); + this.writeByte(i >> 24); + } + + public void writeLong(long l) { + this.writeByte((int)(l >> 56)); + this.writeByte((int)(l >> 48)); + this.writeByte((int)(l >> 40)); + this.writeByte((int)(l >> 32)); + this.writeByte((int)(l >> 24)); + this.writeByte((int)(l >> 16)); + this.writeByte((int)(l >> 8)); + this.writeByte((int)l); + } + + public void writePSmarts(int i) { + if(i < 128) { + this.writeByte(i); + } else if(i < '\u8000') { + this.writeShort('\u8000' + i); + } else { + System.out.println("Error psmarts out of range:"); + } + } + + public void writeString(String s) { + this.checkCapacityPosition(this.getOffset() + s.length() + 1); + System.arraycopy(s.getBytes(), 0, this.getBuffer(), this.getOffset(), s.length()); + this.setOffset(this.getOffset() + s.length()); + this.writeByte(0); + } + + public void writeGJString(String s) { + this.writeByte(0); + this.writeString(s); + } + + public void putGJString3(String s) { + this.writeByte(0); + this.writeString(s); + this.writeByte(0); + } + + public void writePacket(int id) { + this.writeByte(id); + } + + public void writePacketVarByte(int id) { + this.writePacket(id); + this.writeByte(0); + this.opcodeStart = this.getOffset() - 1; + } + + public void writePacketVarShort(int id) { + this.writePacket(id); + this.writeShort(0); + this.opcodeStart = this.getOffset() - 2; + } + + public void endPacketVarByte() { + this.writeByte(this.getOffset() - (this.opcodeStart + 2) + 1, this.opcodeStart); + } + + public void endPacketVarShort() { + int size = this.getOffset() - (this.opcodeStart + 2); + this.writeByte(size >> 8, this.opcodeStart++); + this.writeByte(size, this.opcodeStart); + } + + public void initBitAccess() { + this.bitPosition = this.getOffset() * 8; + } + + public void finishBitAccess() { + this.setOffset((this.bitPosition + 7) / 8); + } + + public int getBitPos(int i) { + return 8 * i - this.bitPosition; + } + + public void writeBits(int numBits, int value) { + int bytePos = this.bitPosition >> 3; + int bitOffset = 8 - (this.bitPosition & 7); + + byte[] var10000; + for(this.bitPosition += numBits; numBits > bitOffset; bitOffset = 8) { + this.checkCapacityPosition(bytePos); + var10000 = this.getBuffer(); + var10000[bytePos] = (byte)(var10000[bytePos] & ~BIT_MASK[bitOffset]); + var10000 = this.getBuffer(); + int var10001 = bytePos++; + var10000[var10001] = (byte)(var10000[var10001] | value >> numBits - bitOffset & BIT_MASK[bitOffset]); + numBits -= bitOffset; + } + + this.checkCapacityPosition(bytePos); + if(numBits == bitOffset) { + var10000 = this.getBuffer(); + var10000[bytePos] = (byte)(var10000[bytePos] & ~BIT_MASK[bitOffset]); + var10000 = this.getBuffer(); + var10000[bytePos] = (byte)(var10000[bytePos] | value & BIT_MASK[bitOffset]); + } else { + var10000 = this.getBuffer(); + var10000[bytePos] = (byte)(var10000[bytePos] & ~(BIT_MASK[numBits] << bitOffset - numBits)); + var10000 = this.getBuffer(); + var10000[bytePos] = (byte)(var10000[bytePos] | (value & BIT_MASK[numBits]) << bitOffset - numBits); + } + + } + + public void setBuffer(byte[] buffer) { + this.buffer = buffer; + } + + public final void rsaEncode(BigInteger key, BigInteger modulus) { + int length = this.offset; + this.offset = 0; + byte[] data = new byte[length]; + this.getBytes(data, 0, length); + BigInteger biginteger2 = new BigInteger(data); + BigInteger biginteger3 = biginteger2.modPow(key, modulus); + byte[] out = biginteger3.toByteArray(); + this.offset = 0; + this.writeBytes(out, 0, out.length); + } +} diff --git a/src/main/java/net/runelite/cache/fs/io/Stream.java b/src/main/java/net/runelite/cache/fs/io/Stream.java new file mode 100644 index 0000000000..c140af5fd1 --- /dev/null +++ b/src/main/java/net/runelite/cache/fs/io/Stream.java @@ -0,0 +1,67 @@ +package net.runelite.cache.fs.io; + +public abstract class Stream { + protected int offset; + protected int length; + protected byte[] buffer; + protected int bitPosition; + + public int getLength() { + return this.length; + } + + public byte[] getBuffer() { + return this.buffer; + } + + public int getOffset() { + return this.offset; + } + + public void decodeXTEA(int[] keys) { + this.decodeXTEA(keys, 5, this.length); + } + + public void decodeXTEA(int[] keys, int start, int end) { + int l = this.offset; + this.offset = start; + int i1 = (end - start) / 8; + + for(int j1 = 0; j1 < i1; ++j1) { + int k1 = this.readInt(); + int l1 = this.readInt(); + int sum = -957401312; + int delta = -1640531527; + + for(int k2 = 32; k2-- > 0; k1 -= (l1 >>> 5 ^ l1 << 4) + l1 ^ keys[sum & 3] + sum) { + l1 -= keys[(sum & 7300) >>> 11] + sum ^ (k1 >>> 5 ^ k1 << 4) + k1; + sum -= delta; + } + + this.offset -= 8; + this.writeInt(k1); + this.writeInt(l1); + } + + this.offset = l; + } + + private final int readInt() { + this.offset += 4; + return ((255 & this.buffer[-3 + this.offset]) << 16) + ((255 & this.buffer[-4 + this.offset]) << 24) + ((this.buffer[-2 + this.offset] & 255) << 8) + (this.buffer[-1 + this.offset] & 255); + } + + public void writeInt(int value) { + this.buffer[this.offset++] = (byte)(value >> 24); + this.buffer[this.offset++] = (byte)(value >> 16); + this.buffer[this.offset++] = (byte)(value >> 8); + this.buffer[this.offset++] = (byte)value; + } + + public final void getBytes(byte[] data, int off, int len) { + for(int k = off; k < len + off; ++k) { + data[k] = this.buffer[this.offset++]; + } + + } +} diff --git a/src/main/java/net/runelite/cache/fs/util/bzip2/BZip2BlockEntry.java b/src/main/java/net/runelite/cache/fs/util/bzip2/BZip2BlockEntry.java new file mode 100644 index 0000000000..e799b3f51f --- /dev/null +++ b/src/main/java/net/runelite/cache/fs/util/bzip2/BZip2BlockEntry.java @@ -0,0 +1,36 @@ +package net.runelite.cache.fs.util.bzip2; + +public class BZip2BlockEntry { + boolean[] aBooleanArray2205 = new boolean[16]; + boolean[] aBooleanArray2213 = new boolean[256]; + byte aByte2201; + byte[] aByteArray2204 = new byte[4096]; + byte[] aByteArray2211 = new byte[256]; + byte[] aByteArray2212; + byte[] aByteArray2214 = new byte[18002]; + byte[] aByteArray2219 = new byte[18002]; + byte[] aByteArray2224; + byte[][] aByteArrayArray2229 = new byte[6][258]; + int anInt2202; + int anInt2203 = 0; + int anInt2206; + int anInt2207; + int anInt2208; + int anInt2209 = 0; + int anInt2215; + int anInt2216; + int anInt2217; + int anInt2221; + int anInt2222; + int anInt2223; + int anInt2225; + int anInt2227; + int anInt2232; + int[] anIntArray2200 = new int[6]; + int[] anIntArray2220 = new int[257]; + int[] anIntArray2226 = new int[16]; + int[] anIntArray2228 = new int[256]; + int[][] anIntArrayArray2210 = new int[6][258]; + int[][] anIntArrayArray2218 = new int[6][258]; + int[][] anIntArrayArray2230 = new int[6][258]; +} diff --git a/src/main/java/net/runelite/cache/fs/util/bzip2/BZip2Decompressor.java b/src/main/java/net/runelite/cache/fs/util/bzip2/BZip2Decompressor.java new file mode 100644 index 0000000000..f1e4ca855a --- /dev/null +++ b/src/main/java/net/runelite/cache/fs/util/bzip2/BZip2Decompressor.java @@ -0,0 +1,583 @@ +package net.runelite.cache.fs.util.bzip2; + +import net.runelite.cache.fs.util.bzip2.BZip2BlockEntry; + +public class BZip2Decompressor { + private static int[] anIntArray257; + private static BZip2BlockEntry entryInstance = new BZip2BlockEntry(); + + public static final void decompress(byte[] decompressedData, byte[] packedData, int containerSize, int blockSize) { + BZip2BlockEntry var4 = entryInstance; + synchronized(entryInstance) { + entryInstance.aByteArray2224 = packedData; + entryInstance.anInt2209 = blockSize; + entryInstance.aByteArray2212 = decompressedData; + entryInstance.anInt2203 = 0; + entryInstance.anInt2206 = decompressedData.length; + entryInstance.anInt2232 = 0; + entryInstance.anInt2207 = 0; + entryInstance.anInt2217 = 0; + entryInstance.anInt2216 = 0; + method1793(entryInstance); + entryInstance.aByteArray2224 = null; + entryInstance.aByteArray2212 = null; + } + } + + private static final void method1785(BZip2BlockEntry entry) { + entry.anInt2215 = 0; + + for(int i = 0; i < 256; ++i) { + if(entry.aBooleanArray2213[i]) { + entry.aByteArray2211[entry.anInt2215] = (byte)i; + ++entry.anInt2215; + } + } + + } + + private static final void method1786(int[] ai, int[] ai1, int[] ai2, byte[] abyte0, int i, int j, int k) { + int l = 0; + + int i3; + int k2; + for(i3 = i; i3 <= j; ++i3) { + for(k2 = 0; k2 < k; ++k2) { + if(abyte0[k2] == i3) { + ai2[l] = k2; + ++l; + } + } + } + + for(i3 = 0; i3 < 23; ++i3) { + ai1[i3] = 0; + } + + for(i3 = 0; i3 < k; ++i3) { + ++ai1[abyte0[i3] + 1]; + } + + for(i3 = 1; i3 < 23; ++i3) { + ai1[i3] += ai1[i3 - 1]; + } + + for(i3 = 0; i3 < 23; ++i3) { + ai[i3] = 0; + } + + i3 = 0; + + for(k2 = i; k2 <= j; ++k2) { + i3 += ai1[k2 + 1] - ai1[k2]; + ai[k2] = i3 - 1; + i3 <<= 1; + } + + for(k2 = i + 1; k2 <= j; ++k2) { + ai1[k2] = (ai[k2 - 1] + 1 << 1) - ai1[k2]; + } + + } + + private static final void method1787(BZip2BlockEntry entry) { + byte byte4 = entry.aByte2201; + int i = entry.anInt2222; + int j = entry.anInt2227; + int k = entry.anInt2221; + int[] ai = anIntArray257; + int l = entry.anInt2208; + byte[] abyte0 = entry.aByteArray2212; + int i1 = entry.anInt2203; + int j1 = entry.anInt2206; + int l1 = entry.anInt2225 + 1; + + label65: + while(true) { + if(i > 0) { + while(true) { + if(j1 == 0) { + break label65; + } + + if(i == 1) { + if(j1 == 0) { + i = 1; + break label65; + } + + abyte0[i1] = byte4; + ++i1; + --j1; + break; + } + + abyte0[i1] = byte4; + --i; + ++i1; + --j1; + } + } + + boolean flag = true; + + byte byte1; + while(flag) { + flag = false; + if(j == l1) { + i = 0; + break label65; + } + + byte4 = (byte)k; + l = ai[l]; + byte1 = (byte)(l & 255); + l >>= 8; + ++j; + if(byte1 != k) { + k = byte1; + if(j1 == 0) { + i = 1; + break label65; + } + + abyte0[i1] = byte4; + ++i1; + --j1; + flag = true; + } else if(j == l1) { + if(j1 == 0) { + i = 1; + break label65; + } + + abyte0[i1] = byte4; + ++i1; + --j1; + flag = true; + } + } + + i = 2; + l = ai[l]; + byte1 = (byte)(l & 255); + l >>= 8; + ++j; + if(j != l1) { + if(byte1 != k) { + k = byte1; + } else { + i = 3; + l = ai[l]; + byte byte2 = (byte)(l & 255); + l >>= 8; + ++j; + if(j != l1) { + if(byte2 != k) { + k = byte2; + } else { + l = ai[l]; + byte byte3 = (byte)(l & 255); + l >>= 8; + ++j; + i = (byte3 & 255) + 4; + l = ai[l]; + k = (byte)(l & 255); + l >>= 8; + ++j; + } + } + } + } + } + + entry.anInt2216 += j1 - j1; + entry.aByte2201 = byte4; + entry.anInt2222 = i; + entry.anInt2227 = j; + entry.anInt2221 = k; + anIntArray257 = ai; + entry.anInt2208 = l; + entry.aByteArray2212 = abyte0; + entry.anInt2203 = i1; + entry.anInt2206 = j1; + } + + private static final byte method1788(BZip2BlockEntry entry) { + return (byte)method1790(1, entry); + } + + private static final byte method1789(BZip2BlockEntry entry) { + return (byte)method1790(8, entry); + } + + private static final int method1790(int i, BZip2BlockEntry entry) { + while(entry.anInt2232 < i) { + entry.anInt2207 = entry.anInt2207 << 8 | entry.aByteArray2224[entry.anInt2209] & 255; + entry.anInt2232 += 8; + ++entry.anInt2209; + ++entry.anInt2217; + } + + int k = entry.anInt2207 >> entry.anInt2232 - i & (1 << i) - 1; + entry.anInt2232 -= i; + return k; + } + + public static void clearBlockEntryInstance() { + entryInstance = null; + } + + private static final void method1793(BZip2BlockEntry entry) { + int j8 = 0; + int[] ai = (int[])null; + int[] ai1 = (int[])null; + int[] ai2 = (int[])null; + entry.anInt2202 = 1; + if(anIntArray257 == null) { + anIntArray257 = new int[entry.anInt2202 * 100000]; + } + + boolean flag18 = true; + + while(true) { + while(flag18) { + byte byte0 = method1789(entry); + if(byte0 == 23) { + return; + } + + byte0 = method1789(entry); + byte0 = method1789(entry); + byte0 = method1789(entry); + byte0 = method1789(entry); + byte0 = method1789(entry); + byte0 = method1789(entry); + byte0 = method1789(entry); + byte0 = method1789(entry); + byte0 = method1789(entry); + byte0 = method1788(entry); + entry.anInt2223 = 0; + byte0 = method1789(entry); + entry.anInt2223 = entry.anInt2223 << 8 | byte0 & 255; + byte0 = method1789(entry); + entry.anInt2223 = entry.anInt2223 << 8 | byte0 & 255; + byte0 = method1789(entry); + entry.anInt2223 = entry.anInt2223 << 8 | byte0 & 255; + + int i4; + for(i4 = 0; i4 < 16; ++i4) { + byte j4 = method1788(entry); + if(j4 == 1) { + entry.aBooleanArray2205[i4] = true; + } else { + entry.aBooleanArray2205[i4] = false; + } + } + + for(i4 = 0; i4 < 256; ++i4) { + entry.aBooleanArray2213[i4] = false; + } + + int var28; + for(i4 = 0; i4 < 16; ++i4) { + if(entry.aBooleanArray2205[i4]) { + for(var28 = 0; var28 < 16; ++var28) { + byte k4 = method1788(entry); + if(k4 == 1) { + entry.aBooleanArray2213[i4 * 16 + var28] = true; + } + } + } + } + + method1785(entry); + i4 = entry.anInt2215 + 2; + var28 = method1790(3, entry); + int var29 = method1790(15, entry); + + int l4; + byte i5; + for(int abyte0 = 0; abyte0 < var29; ++abyte0) { + l4 = 0; + + while(true) { + i5 = method1788(entry); + if(i5 == 0) { + entry.aByteArray2214[abyte0] = (byte)l4; + break; + } + + ++l4; + } + } + + byte[] var30 = new byte[6]; + + for(byte var31 = 0; var31 < var28; var30[var31] = var31++) { + ; + } + + byte j5; + for(l4 = 0; l4 < var29; ++l4) { + i5 = entry.aByteArray2214[l4]; + + for(j5 = var30[i5]; i5 > 0; --i5) { + var30[i5] = var30[i5 - 1]; + } + + var30[0] = j5; + entry.aByteArray2219[l4] = j5; + } + + int var32; + int var33; + for(l4 = 0; l4 < var28; ++l4) { + var32 = method1790(5, entry); + + for(var33 = 0; var33 < i4; ++var33) { + while(true) { + byte i9 = method1788(entry); + if(i9 == 0) { + entry.aByteArrayArray2229[l4][var33] = (byte)var32; + break; + } + + i9 = method1788(entry); + if(i9 == 0) { + ++var32; + } else { + --var32; + } + } + } + } + + int var35; + for(l4 = 0; l4 < var28; ++l4) { + i5 = 32; + j5 = 0; + + for(var35 = 0; var35 < i4; ++var35) { + if(entry.aByteArrayArray2229[l4][var35] > j5) { + j5 = entry.aByteArrayArray2229[l4][var35]; + } + + if(entry.aByteArrayArray2229[l4][var35] < i5) { + i5 = entry.aByteArrayArray2229[l4][var35]; + } + } + + method1786(entry.anIntArrayArray2230[l4], entry.anIntArrayArray2218[l4], entry.anIntArrayArray2210[l4], entry.aByteArrayArray2229[l4], i5, j5, i4); + entry.anIntArray2200[l4] = i5; + } + + l4 = entry.anInt2215 + 1; + var32 = -1; + byte var34 = 0; + + for(var35 = 0; var35 <= 255; ++var35) { + entry.anIntArray2228[var35] = 0; + } + + var35 = 4095; + + int l5; + int l6; + for(l5 = 15; l5 >= 0; --l5) { + for(l6 = 15; l6 >= 0; --l6) { + entry.aByteArray2204[var35] = (byte)(l5 * 16 + l6); + --var35; + } + + entry.anIntArray2226[l5] = var35 + 1; + } + + l5 = 0; + if(var34 == 0) { + ++var32; + var34 = 50; + byte var36 = entry.aByteArray2219[var32]; + j8 = entry.anIntArray2200[var36]; + ai = entry.anIntArrayArray2230[var36]; + ai2 = entry.anIntArrayArray2210[var36]; + ai1 = entry.anIntArrayArray2218[var36]; + } + + var33 = var34 - 1; + l6 = j8; + + int k7; + byte byte9; + for(k7 = method1790(j8, entry); k7 > ai[l6]; k7 = k7 << 1 | byte9) { + ++l6; + byte9 = method1788(entry); + } + + int l2 = ai2[k7 - ai1[l6]]; + + while(true) { + while(l2 != l4) { + int byte7; + byte j7; + int i8; + byte byte11; + int var38; + if(l2 != 0 && l2 != 1) { + byte7 = l2 - 1; + byte var37; + if(byte7 < 16) { + var38 = entry.anIntArray2226[0]; + + for(var37 = entry.aByteArray2204[var38 + byte7]; byte7 > 3; byte7 -= 4) { + i8 = var38 + byte7; + entry.aByteArray2204[i8] = entry.aByteArray2204[i8 - 1]; + entry.aByteArray2204[i8 - 1] = entry.aByteArray2204[i8 - 2]; + entry.aByteArray2204[i8 - 2] = entry.aByteArray2204[i8 - 3]; + entry.aByteArray2204[i8 - 3] = entry.aByteArray2204[i8 - 4]; + } + + while(byte7 > 0) { + entry.aByteArray2204[var38 + byte7] = entry.aByteArray2204[var38 + byte7 - 1]; + --byte7; + } + + entry.aByteArray2204[var38] = var37; + } else { + var38 = byte7 / 16; + i8 = byte7 % 16; + int var40 = entry.anIntArray2226[var38] + i8; + + for(var37 = entry.aByteArray2204[var40]; var40 > entry.anIntArray2226[var38]; --var40) { + entry.aByteArray2204[var40] = entry.aByteArray2204[var40 - 1]; + } + + ++entry.anIntArray2226[var38]; + + while(var38 > 0) { + --entry.anIntArray2226[var38]; + entry.aByteArray2204[entry.anIntArray2226[var38]] = entry.aByteArray2204[entry.anIntArray2226[var38 - 1] + 16 - 1]; + --var38; + } + + --entry.anIntArray2226[0]; + entry.aByteArray2204[entry.anIntArray2226[0]] = var37; + if(entry.anIntArray2226[0] == 0) { + int l9 = 4095; + + for(int j9 = 15; j9 >= 0; --j9) { + for(int k9 = 15; k9 >= 0; --k9) { + entry.aByteArray2204[l9] = entry.aByteArray2204[entry.anIntArray2226[j9] + k9]; + --l9; + } + + entry.anIntArray2226[j9] = l9 + 1; + } + } + } + + ++entry.anIntArray2228[entry.aByteArray2211[var37 & 255] & 255]; + anIntArray257[l5] = entry.aByteArray2211[var37 & 255] & 255; + ++l5; + if(var33 == 0) { + ++var32; + var33 = 50; + j7 = entry.aByteArray2219[var32]; + j8 = entry.anIntArray2200[j7]; + ai = entry.anIntArrayArray2230[j7]; + ai2 = entry.anIntArrayArray2210[j7]; + ai1 = entry.anIntArrayArray2218[j7]; + } + + --var33; + var38 = j8; + + for(i8 = method1790(j8, entry); i8 > ai[var38]; i8 = i8 << 1 | byte11) { + ++var38; + byte11 = method1788(entry); + } + + l2 = ai2[i8 - ai1[var38]]; + } else { + byte7 = -1; + int byte6 = 1; + + do { + if(l2 == 0) { + byte7 += byte6; + } else if(l2 == 1) { + byte7 += 2 * byte6; + } + + byte6 *= 2; + if(var33 == 0) { + ++var32; + var33 = 50; + j7 = entry.aByteArray2219[var32]; + j8 = entry.anIntArray2200[j7]; + ai = entry.anIntArrayArray2230[j7]; + ai2 = entry.anIntArrayArray2210[j7]; + ai1 = entry.anIntArrayArray2218[j7]; + } + + --var33; + var38 = j8; + + for(i8 = method1790(j8, entry); i8 > ai[var38]; i8 = i8 << 1 | byte11) { + ++var38; + byte11 = method1788(entry); + } + + l2 = ai2[i8 - ai1[var38]]; + } while(l2 == 0 || l2 == 1); + + ++byte7; + j7 = entry.aByteArray2211[entry.aByteArray2204[entry.anIntArray2226[0]] & 255]; + + for(entry.anIntArray2228[j7 & 255] += byte7; byte7 > 0; --byte7) { + anIntArray257[l5] = j7 & 255; + ++l5; + } + } + } + + entry.anInt2222 = 0; + entry.aByte2201 = 0; + entry.anIntArray2220[0] = 0; + + for(l2 = 1; l2 <= 256; ++l2) { + entry.anIntArray2220[l2] = entry.anIntArray2228[l2 - 1]; + } + + for(l2 = 1; l2 <= 256; ++l2) { + entry.anIntArray2220[l2] += entry.anIntArray2220[l2 - 1]; + } + + for(l2 = 0; l2 < l5; ++l2) { + byte var39 = (byte)(anIntArray257[l2] & 255); + anIntArray257[entry.anIntArray2220[var39 & 255]] |= l2 << 8; + ++entry.anIntArray2220[var39 & 255]; + } + + entry.anInt2208 = anIntArray257[entry.anInt2223] >> 8; + entry.anInt2227 = 0; + entry.anInt2208 = anIntArray257[entry.anInt2208]; + entry.anInt2221 = (byte)(entry.anInt2208 & 255); + entry.anInt2208 >>= 8; + ++entry.anInt2227; + entry.anInt2225 = l5; + method1787(entry); + if(entry.anInt2227 == entry.anInt2225 + 1 && entry.anInt2222 == 0) { + flag18 = true; + break; + } + + flag18 = false; + break; + } + } + + return; + } + } +} diff --git a/src/main/java/net/runelite/cache/fs/util/crc32/CRC32HGenerator.java b/src/main/java/net/runelite/cache/fs/util/crc32/CRC32HGenerator.java new file mode 100644 index 0000000000..d95fbc49b2 --- /dev/null +++ b/src/main/java/net/runelite/cache/fs/util/crc32/CRC32HGenerator.java @@ -0,0 +1,21 @@ +package net.runelite.cache.fs.util.crc32; + +import java.util.zip.CRC32; + +public final class CRC32HGenerator { + public static final CRC32 CRC32Instance = new CRC32(); + + public static int getHash(byte[] data) { + return getHash(data, 0, data.length); + } + + public static int getHash(byte[] data, int offset, int length) { + CRC32 var3 = CRC32Instance; + synchronized(CRC32Instance) { + CRC32Instance.update(data, offset, length); + int hash = (int)CRC32Instance.getValue(); + CRC32Instance.reset(); + return hash; + } + } +} diff --git a/src/main/java/net/runelite/cache/fs/util/gzip/GZipCompressor.java b/src/main/java/net/runelite/cache/fs/util/gzip/GZipCompressor.java new file mode 100644 index 0000000000..df1110630e --- /dev/null +++ b/src/main/java/net/runelite/cache/fs/util/gzip/GZipCompressor.java @@ -0,0 +1,22 @@ +package net.runelite.cache.fs.util.gzip; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.zip.GZIPOutputStream; + +public class GZipCompressor { + public static final byte[] compress(byte[] data) { + ByteArrayOutputStream compressedBytes = new ByteArrayOutputStream(); + + try { + GZIPOutputStream e = new GZIPOutputStream(compressedBytes); + e.write(data); + e.finish(); + e.close(); + return compressedBytes.toByteArray(); + } catch (IOException var3) { + var3.printStackTrace(); + return null; + } + } +} diff --git a/src/main/java/net/runelite/cache/fs/util/gzip/GZipDecompressor.java b/src/main/java/net/runelite/cache/fs/util/gzip/GZipDecompressor.java new file mode 100644 index 0000000000..0640d612ba --- /dev/null +++ b/src/main/java/net/runelite/cache/fs/util/gzip/GZipDecompressor.java @@ -0,0 +1,27 @@ +package net.runelite.cache.fs.util.gzip; + +import net.runelite.cache.fs.io.Stream; +import java.util.zip.Inflater; + +public class GZipDecompressor { + private static final Inflater inflaterInstance = new Inflater(true); + + public static final void decompress(Stream stream, byte[] data) { + Inflater var2 = inflaterInstance; + synchronized(inflaterInstance) { + if(stream.getBuffer()[stream.getOffset()] == 31 && stream.getBuffer()[stream.getOffset() + 1] == -117) { + try { + inflaterInstance.setInput(stream.getBuffer(), stream.getOffset() + 10, -stream.getOffset() - 18 + stream.getBuffer().length); + inflaterInstance.inflate(data); + } catch (Exception var4) { + inflaterInstance.reset(); + data = (byte[])null; + } + + inflaterInstance.reset(); + } else { + data = (byte[])null; + } + } + } +} diff --git a/src/main/java/net/runelite/cache/fs/util/whirlpool/Whirlpool.java b/src/main/java/net/runelite/cache/fs/util/whirlpool/Whirlpool.java new file mode 100644 index 0000000000..2687afed7b --- /dev/null +++ b/src/main/java/net/runelite/cache/fs/util/whirlpool/Whirlpool.java @@ -0,0 +1,250 @@ +package net.runelite.cache.fs.util.whirlpool; + +import java.util.Arrays; + +public class Whirlpool { + public static final int DIGESTBITS = 512; + public static final int DIGESTBYTES = 64; + protected static final int R = 10; + private static final String sbox = "\u1823\uc6e8\u87b8\u014f\u36a6\ud2f5\u796f\u9152\u60bc\u9b8e\ua30c\u7b35\u1de0\ud7c2\u2e4b\ufe57\u1577\u37e5\u9ff0\u4ada\u58c9\u290a\ub1a0\u6b85\ubd5d\u10f4\ucb3e\u0567\ue427\u418b\ua77d\u95d8\ufbee\u7c66\udd17\u479e\uca2d\ubf07\uad5a\u8333\u6302\uaa71\uc819\u49d9\uf2e3\u5b88\u9a26\u32b0\ue90f\ud580\ubecd\u3448\uff7a\u905f\u2068\u1aae\ub454\u9322\u64f1\u7312\u4008\uc3ec\udba1\u8d3d\u9700\ucf2b\u7682\ud61b\ub5af\u6a50\u45f3\u30ef\u3f55\ua2ea\u65ba\u2fc0\ude1c\ufd4d\u9275\u068a\ub2e6\u0e1f\u62d4\ua896\uf9c5\u2559\u8472\u394c\u5e78\u388c\ud1a5\ue261\ub321\u9c1e\u43c7\ufc04\u5199\u6d0d\ufadf\u7e24\u3bab\uce11\u8f4e\ub7eb\u3c81\u94f7\ub913\u2cd3\ue76e\uc403\u5644\u7fa9\u2abb\uc153\udc0b\u9d6c\u3174\uf646\uac89\u14e1\u163a\u6909\u70b6\ud0ed\ucc42\u98a4\u285c\uf886"; + private static long[][] C = new long[8][256]; + private static long[] rc = new long[11]; + protected byte[] bitLength = new byte[32]; + protected byte[] buffer = new byte[64]; + protected int bufferBits = 0; + protected int bufferPos = 0; + protected long[] hash = new long[8]; + protected long[] K = new long[8]; + protected long[] L = new long[8]; + protected long[] block = new long[8]; + protected long[] state = new long[8]; + + static { + int r; + for(r = 0; r < 256; ++r) { + char i = "\u1823\uc6e8\u87b8\u014f\u36a6\ud2f5\u796f\u9152\u60bc\u9b8e\ua30c\u7b35\u1de0\ud7c2\u2e4b\ufe57\u1577\u37e5\u9ff0\u4ada\u58c9\u290a\ub1a0\u6b85\ubd5d\u10f4\ucb3e\u0567\ue427\u418b\ua77d\u95d8\ufbee\u7c66\udd17\u479e\uca2d\ubf07\uad5a\u8333\u6302\uaa71\uc819\u49d9\uf2e3\u5b88\u9a26\u32b0\ue90f\ud580\ubecd\u3448\uff7a\u905f\u2068\u1aae\ub454\u9322\u64f1\u7312\u4008\uc3ec\udba1\u8d3d\u9700\ucf2b\u7682\ud61b\ub5af\u6a50\u45f3\u30ef\u3f55\ua2ea\u65ba\u2fc0\ude1c\ufd4d\u9275\u068a\ub2e6\u0e1f\u62d4\ua896\uf9c5\u2559\u8472\u394c\u5e78\u388c\ud1a5\ue261\ub321\u9c1e\u43c7\ufc04\u5199\u6d0d\ufadf\u7e24\u3bab\uce11\u8f4e\ub7eb\u3c81\u94f7\ub913\u2cd3\ue76e\uc403\u5644\u7fa9\u2abb\uc153\udc0b\u9d6c\u3174\uf646\uac89\u14e1\u163a\u6909\u70b6\ud0ed\ucc42\u98a4\u285c\uf886".charAt(r / 2); + long v1 = (long)((r & 1) == 0?i >>> 8:i & 255); + long v2 = v1 << 1; + if(v2 >= 256L) { + v2 ^= 285L; + } + + long v4 = v2 << 1; + if(v4 >= 256L) { + v4 ^= 285L; + } + + long v5 = v4 ^ v1; + long v8 = v4 << 1; + if(v8 >= 256L) { + v8 ^= 285L; + } + + long v9 = v8 ^ v1; + C[0][r] = v1 << 56 | v1 << 48 | v4 << 40 | v1 << 32 | v8 << 24 | v5 << 16 | v2 << 8 | v9; + + for(int t = 1; t < 8; ++t) { + C[t][r] = C[t - 1][r] >>> 8 | C[t - 1][r] << 56; + } + } + + rc[0] = 0L; + + for(r = 1; r <= 10; ++r) { + int var15 = 8 * (r - 1); + rc[r] = C[0][var15] & -72057594037927936L ^ C[1][var15 + 1] & 71776119061217280L ^ C[2][var15 + 2] & 280375465082880L ^ C[3][var15 + 3] & 1095216660480L ^ C[4][var15 + 4] & 4278190080L ^ C[5][var15 + 5] & 16711680L ^ C[6][var15 + 6] & 65280L ^ C[7][var15 + 7] & 255L; + } + + } + + public static byte[] getHash(byte[] data, int off, int len) { + byte[] source; + if(off <= 0) { + source = data; + } else { + source = new byte[len]; + + for(int whirlpool = 0; whirlpool < len; ++whirlpool) { + source[whirlpool] = data[off + whirlpool]; + } + } + + Whirlpool var6 = new Whirlpool(); + var6.NESSIEinit(); + var6.NESSIEadd(source, (long)(len * 8)); + byte[] digest = new byte[64]; + var6.NESSIEfinalize(digest); + return digest; + } + + protected void processBuffer() { + int i = 0; + + int i1; + for(i1 = 0; i < 8; i1 += 8) { + this.block[i] = (long)this.buffer[i1] << 56 ^ ((long)this.buffer[i1 + 1] & 255L) << 48 ^ ((long)this.buffer[i1 + 2] & 255L) << 40 ^ ((long)this.buffer[i1 + 3] & 255L) << 32 ^ ((long)this.buffer[i1 + 4] & 255L) << 24 ^ ((long)this.buffer[i1 + 5] & 255L) << 16 ^ ((long)this.buffer[i1 + 6] & 255L) << 8 ^ (long)this.buffer[i1 + 7] & 255L; + ++i; + } + + for(i = 0; i < 8; ++i) { + this.state[i] = this.block[i] ^ (this.K[i] = this.hash[i]); + } + + for(i = 1; i <= 10; ++i) { + int t; + int s; + for(i1 = 0; i1 < 8; ++i1) { + this.L[i1] = 0L; + t = 0; + + for(s = 56; t < 8; s -= 8) { + this.L[i1] ^= C[t][(int)(this.K[i1 - t & 7] >>> s) & 255]; + ++t; + } + } + + for(i1 = 0; i1 < 8; ++i1) { + this.K[i1] = this.L[i1]; + } + + this.K[0] ^= rc[i]; + + for(i1 = 0; i1 < 8; ++i1) { + this.L[i1] = this.K[i1]; + t = 0; + + for(s = 56; t < 8; s -= 8) { + this.L[i1] ^= C[t][(int)(this.state[i1 - t & 7] >>> s) & 255]; + ++t; + } + } + + for(i1 = 0; i1 < 8; ++i1) { + this.state[i1] = this.L[i1]; + } + } + + for(i = 0; i < 8; ++i) { + this.hash[i] ^= this.state[i] ^ this.block[i]; + } + + } + + public void NESSIEinit() { + Arrays.fill(this.bitLength, (byte)0); + this.bufferBits = this.bufferPos = 0; + this.buffer[0] = 0; + Arrays.fill(this.hash, 0L); + } + + public void NESSIEadd(byte[] source, long sourceBits) { + int sourcePos = 0; + int sourceGap = 8 - ((int)sourceBits & 7) & 7; + int bufferRem = this.bufferBits & 7; + long value = sourceBits; + int i = 31; + + for(int carry = 0; i >= 0; --i) { + carry += (this.bitLength[i] & 255) + ((int)value & 255); + this.bitLength[i] = (byte)carry; + carry >>>= 8; + value >>>= 8; + } + + int b; + while(sourceBits > 8L) { + b = source[sourcePos] << sourceGap & 255 | (source[sourcePos + 1] & 255) >>> 8 - sourceGap; + if(b < 0 || b >= 256) { + throw new RuntimeException("LOGIC ERROR"); + } + + byte[] var10000 = this.buffer; + int var10001 = this.bufferPos++; + var10000[var10001] = (byte)(var10000[var10001] | b >>> bufferRem); + this.bufferBits += 8 - bufferRem; + if(this.bufferBits == 512) { + this.processBuffer(); + this.bufferBits = this.bufferPos = 0; + } + + this.buffer[this.bufferPos] = (byte)(b << 8 - bufferRem & 255); + this.bufferBits += bufferRem; + sourceBits -= 8L; + ++sourcePos; + } + + if(sourceBits > 0L) { + b = source[sourcePos] << sourceGap & 255; + this.buffer[this.bufferPos] = (byte)(this.buffer[this.bufferPos] | b >>> bufferRem); + } else { + b = 0; + } + + if((long)bufferRem + sourceBits < 8L) { + this.bufferBits = (int)((long)this.bufferBits + sourceBits); + } else { + ++this.bufferPos; + this.bufferBits += 8 - bufferRem; + sourceBits -= (long)(8 - bufferRem); + if(this.bufferBits == 512) { + this.processBuffer(); + this.bufferBits = this.bufferPos = 0; + } + + this.buffer[this.bufferPos] = (byte)(b << 8 - bufferRem & 255); + this.bufferBits += (int)sourceBits; + } + + } + + public void NESSIEfinalize(byte[] digest) { + this.buffer[this.bufferPos] = (byte)(this.buffer[this.bufferPos] | 128 >>> (this.bufferBits & 7)); + ++this.bufferPos; + if(this.bufferPos > 32) { + while(true) { + if(this.bufferPos >= 64) { + this.processBuffer(); + this.bufferPos = 0; + break; + } + + this.buffer[this.bufferPos++] = 0; + } + } + + while(this.bufferPos < 32) { + this.buffer[this.bufferPos++] = 0; + } + + System.arraycopy(this.bitLength, 0, this.buffer, 32, 32); + this.processBuffer(); + int i = 0; + + for(int j = 0; i < 8; j += 8) { + long h = this.hash[i]; + digest[j] = (byte)((int)(h >>> 56)); + digest[j + 1] = (byte)((int)(h >>> 48)); + digest[j + 2] = (byte)((int)(h >>> 40)); + digest[j + 3] = (byte)((int)(h >>> 32)); + digest[j + 4] = (byte)((int)(h >>> 24)); + digest[j + 5] = (byte)((int)(h >>> 16)); + digest[j + 6] = (byte)((int)(h >>> 8)); + digest[j + 7] = (byte)((int)h); + ++i; + } + + } + + public void NESSIEadd(String source) { + if(source.length() > 0) { + byte[] data = new byte[source.length()]; + + for(int i = 0; i < source.length(); ++i) { + data[i] = (byte)source.charAt(i); + } + + this.NESSIEadd(data, (long)(8 * data.length)); + } + + } +} diff --git a/src/test/java/net/runelite/cache/fs/DataFileTest.java b/src/test/java/net/runelite/cache/fs/DataFileTest.java index 2bc6b763e1..00bd7904aa 100644 --- a/src/test/java/net/runelite/cache/fs/DataFileTest.java +++ b/src/test/java/net/runelite/cache/fs/DataFileTest.java @@ -20,8 +20,8 @@ public class DataFileTest Store store = new Store(folder.getRoot()); DataFile df = new DataFile(store, file); int sector = df.write(42, 3, ByteBuffer.wrap("test".getBytes())); - ByteBuffer buf = df.read(42, 3, sector, 4); - String str = new String(buf.array()); + byte[] buf = df.read(42, 3, sector, 4); + String str = new String(buf); Assert.assertEquals("test", str); file.delete(); } @@ -36,8 +36,8 @@ public class DataFileTest Store store = new Store(folder.getRoot()); DataFile df = new DataFile(store, file); int sector = df.write(42, 0x1FFFF, ByteBuffer.wrap(b)); - ByteBuffer buf = df.read(42, 0x1FFFF, sector, b.length); - Assert.assertArrayEquals(b, buf.array()); + byte[] buf = df.read(42, 0x1FFFF, sector, b.length); + Assert.assertArrayEquals(b, buf); file.delete(); } }