forked from 2009Scape/Server
* Fixes Fixed #11 and implemented a beta command for testing (stops the need to go into database and manually change when debugging, very slow, now one command in game, very fast) * Space to continue Does what it says on the tin! * Fixes + more What I've done this update: - Fixed tutorial island's chef giving infinite amounts of buckets and water to players - Fixed fishing without a tool. - Added the wilderness teleport lever to Edgeville south of the bank (as some have requested) - Added some useful tools for editing cache. Enjoy!
446 lines
13 KiB
Java
446 lines
13 KiB
Java
package com.alex.store;
|
|
|
|
import com.alex.io.InputStream;
|
|
import com.alex.io.OutputStream;
|
|
import com.alex.util.crc32.CRC32HGenerator;
|
|
import com.alex.util.whirlpool.Whirlpool;
|
|
import com.alex.utils.Constants;
|
|
import com.alex.utils.Utils;
|
|
|
|
public final class Index {
|
|
|
|
private MainFile mainFile;
|
|
private MainFile index255;
|
|
private ReferenceTable table;
|
|
private byte[][][] cachedFiles;
|
|
private int crc;
|
|
private byte[] whirlpool;
|
|
|
|
protected Index(MainFile index255, MainFile mainFile, int[] keys) {
|
|
this.mainFile = mainFile;
|
|
this.index255 = index255;
|
|
byte[] archiveData = index255.getArchiveData(getId());
|
|
if (archiveData == null)
|
|
return;
|
|
crc = CRC32HGenerator.getHash(archiveData);
|
|
whirlpool = Whirlpool.getHash(archiveData, 0, archiveData.length);
|
|
Archive archive = new Archive(getId(), archiveData, keys);
|
|
table = new ReferenceTable(archive);
|
|
resetCachedFiles();
|
|
}
|
|
|
|
public void resetCachedFiles() {
|
|
cachedFiles = new byte[getLastArchiveId() + 1][][];
|
|
}
|
|
|
|
public int getLastFileId(int archiveId) {
|
|
if (!archiveExists(archiveId))
|
|
return -1;
|
|
return table.getArchives()[archiveId].getFiles().length - 1;
|
|
}
|
|
|
|
public int getLastArchiveId() {
|
|
return table.getArchives().length - 1;
|
|
}
|
|
|
|
public int getValidArchivesCount() {
|
|
return table.getValidArchiveIds().length;
|
|
}
|
|
|
|
public int getValidFilesCount(int archiveId) {
|
|
if (!archiveExists(archiveId))
|
|
return -1;
|
|
return table.getArchives()[archiveId].getValidFileIds().length;
|
|
}
|
|
|
|
public boolean archiveExists(int archiveId) {
|
|
if(archiveId < 0)
|
|
return false;
|
|
ArchiveReference[] archives = table.getArchives();
|
|
return archives.length > archiveId && archives[archiveId] != null;
|
|
}
|
|
|
|
public boolean fileExists(int archiveId, int fileId) {
|
|
if (!archiveExists(archiveId))
|
|
return false;
|
|
FileReference[] files = table.getArchives()[archiveId].getFiles();
|
|
return files.length > fileId && files[fileId] != null;
|
|
}
|
|
|
|
public int getArchiveId(String name) {
|
|
int nameHash = Utils.getNameHash(name);
|
|
ArchiveReference[] archives = table.getArchives();
|
|
int[] validArchiveIds = table.getValidArchiveIds();
|
|
for (int archiveId : validArchiveIds) {
|
|
if (archives[archiveId].getNameHash() == nameHash)
|
|
return archiveId;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
public int getFileId(int archiveId, String name) {
|
|
if (!archiveExists(archiveId))
|
|
return -1;
|
|
int nameHash = Utils.getNameHash(name);
|
|
FileReference[] files = table.getArchives()[archiveId].getFiles();
|
|
int[] validFileIds = table.getArchives()[archiveId].getValidFileIds();
|
|
for (int index = 0; index < validFileIds.length; index++) {
|
|
int fileId = validFileIds[index];
|
|
if (files[fileId].getNameHash() == nameHash)
|
|
return fileId;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
public byte[] getFile(int archiveId) {
|
|
if (!archiveExists(archiveId))
|
|
return null;
|
|
return getFile(archiveId,
|
|
table.getArchives()[archiveId].getValidFileIds()[0]);
|
|
}
|
|
|
|
public byte[] getFile(int archiveId, int fileId) {
|
|
return getFile(archiveId, fileId, null);
|
|
}
|
|
|
|
public byte[] getFile(int archiveId, int fileId, int[] keys) {
|
|
try {
|
|
if (!fileExists(archiveId, fileId)) {
|
|
return null;
|
|
}
|
|
if (cachedFiles[archiveId] == null || cachedFiles[archiveId][fileId] == null) cacheArchiveFiles(archiveId, keys);
|
|
byte[] file = cachedFiles[archiveId][fileId];
|
|
cachedFiles[archiveId][fileId] = null;
|
|
return file;
|
|
} catch (Throwable e) {
|
|
e.printStackTrace();
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public boolean packIndex(Store originalStore) {
|
|
return packIndex(originalStore, false);
|
|
}
|
|
|
|
public boolean packIndex(Store originalStore, boolean checkCRC) {
|
|
try {
|
|
return packIndex(getId(), originalStore, checkCRC);
|
|
}catch (Exception e) {
|
|
|
|
}
|
|
return packIndex(getId(), originalStore, checkCRC);
|
|
}
|
|
|
|
public boolean packIndex(int id, Store originalStore, boolean checkCRC) {
|
|
try {
|
|
Index originalIndex = originalStore.getIndexes()[id];
|
|
for (int archiveId : originalIndex.table.getValidArchiveIds()) {
|
|
if (checkCRC
|
|
&& archiveExists(archiveId)
|
|
&& originalIndex.table.getArchives()[archiveId]
|
|
.getCRC() == table.getArchives()[archiveId]
|
|
.getCRC())
|
|
continue;
|
|
if (!putArchive(id, archiveId, originalStore, false, false))
|
|
return false;
|
|
}
|
|
if (!rewriteTable())
|
|
return false;
|
|
resetCachedFiles();
|
|
return true;
|
|
} catch (Exception e) {
|
|
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public boolean putArchive(int archiveId, Store originalStore) {
|
|
return putArchive(getId(), archiveId, originalStore, true, true);
|
|
}
|
|
public boolean putArchive(int archiveId, Store originalStore,
|
|
boolean rewriteTable, boolean resetCache) {
|
|
return putArchive(getId(), archiveId, originalStore, rewriteTable, resetCache);
|
|
}
|
|
|
|
|
|
public boolean putArchive(int id, int archiveId, Store originalStore,
|
|
boolean rewriteTable, boolean resetCache) {
|
|
try {
|
|
Index originalIndex = originalStore.getIndexes()[id];
|
|
byte[] data = originalIndex.getMainFile().getArchiveData(archiveId);
|
|
if (data == null)
|
|
return false;
|
|
if (!archiveExists(archiveId))
|
|
table.addEmptyArchiveReference(archiveId);
|
|
ArchiveReference reference = table.getArchives()[archiveId];
|
|
reference.updateRevision();
|
|
ArchiveReference originalReference = originalIndex.table.getArchives()[archiveId];
|
|
reference.copyHeader(originalReference);
|
|
int revision = reference.getRevision();
|
|
data[data.length - 2] = (byte) (revision >> 8);
|
|
data[data.length - 1] = (byte) revision;
|
|
if (!mainFile.putArchiveData(archiveId, data))
|
|
return false;
|
|
if (rewriteTable && !rewriteTable())
|
|
return false;
|
|
if (resetCache)
|
|
resetCachedFiles();
|
|
return true;
|
|
} catch (Exception e) {
|
|
e.printStackTrace();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean putFile(int archiveId, int fileId, byte[] data) {
|
|
return putFile(archiveId, fileId, Constants.GZIP_COMPRESSION, data,
|
|
null, true, true, -1, -1);
|
|
}
|
|
|
|
public boolean removeFile(int archiveId, int fileId) {
|
|
return removeFile(archiveId, fileId, Constants.GZIP_COMPRESSION, null);
|
|
}
|
|
|
|
public boolean removeFile(int archiveId, int fileId, int compression,
|
|
int[] keys) {
|
|
if (!fileExists(archiveId, fileId))
|
|
return false;
|
|
cacheArchiveFiles(archiveId, keys);
|
|
ArchiveReference reference = table.getArchives()[archiveId];
|
|
reference.removeFileReference(fileId);
|
|
int filesCount = getValidFilesCount(archiveId);
|
|
byte[] archiveData;
|
|
if (filesCount == 1)
|
|
archiveData = getFile(archiveId, reference.getValidFileIds()[0],
|
|
keys);
|
|
else {
|
|
int[] filesSize = new int[filesCount];
|
|
OutputStream stream = new OutputStream();
|
|
for (int index = 0; index < filesCount; index++) {
|
|
int id = reference.getValidFileIds()[index];
|
|
byte[] fileData = getFile(archiveId, id, keys);
|
|
filesSize[index] = fileData.length;
|
|
stream.writeBytes(fileData);
|
|
}
|
|
for (int index = 0; index < filesSize.length; index++) {
|
|
int offset = filesSize[index];
|
|
if (index != 0)
|
|
offset -= filesSize[index - 1];
|
|
stream.writeInt(offset);
|
|
}
|
|
stream.writeByte(1); // 1loop
|
|
archiveData = new byte[stream.getOffset()];
|
|
stream.setOffset(0);
|
|
stream.getBytes(archiveData, 0, archiveData.length);
|
|
}
|
|
reference.updateRevision();
|
|
Archive archive = new Archive(archiveId, compression,
|
|
reference.getRevision(), archiveData);
|
|
byte[] closedArchive = archive.compress();
|
|
reference.setCrc(CRC32HGenerator.getHash(closedArchive, 0,
|
|
closedArchive.length - 2));
|
|
reference.setWhirpool(Whirlpool.getHash(closedArchive, 0,
|
|
closedArchive.length - 2));
|
|
if (!mainFile.putArchiveData(archiveId, closedArchive))
|
|
return false;
|
|
if (!rewriteTable())
|
|
return false;
|
|
resetCachedFiles();
|
|
return true;
|
|
}
|
|
|
|
public boolean putFile(int archiveId, int fileId, int compression,
|
|
byte[] data, int[] keys, boolean rewriteTable, boolean resetCache,
|
|
int archiveName, int fileName) {
|
|
if (!archiveExists(archiveId)) {
|
|
table.addEmptyArchiveReference(archiveId);
|
|
resetCachedFiles();
|
|
cachedFiles[archiveId] = new byte[1][];
|
|
} else {
|
|
cacheArchiveFiles(archiveId, keys);
|
|
}
|
|
ArchiveReference reference = table.getArchives()[archiveId];
|
|
if (!fileExists(archiveId, fileId))
|
|
reference.addEmptyFileReference(fileId);
|
|
reference.sortFiles();
|
|
int filesCount = getValidFilesCount(archiveId);
|
|
byte[] archiveData;
|
|
if (filesCount == 1)
|
|
archiveData = data;
|
|
else {
|
|
int[] filesSize = new int[filesCount];
|
|
OutputStream stream = new OutputStream();
|
|
for (int index = 0; index < filesCount; index++) {
|
|
int id = reference.getValidFileIds()[index];
|
|
byte[] fileData;
|
|
if (id == fileId)
|
|
fileData = data;
|
|
else
|
|
fileData = getFile(archiveId, id, keys);
|
|
filesSize[index] = fileData.length;
|
|
stream.writeBytes(fileData);
|
|
}
|
|
for (int index = 0; index < filesCount; index++) {
|
|
int offset = filesSize[index];
|
|
if (index != 0)
|
|
offset -= filesSize[index - 1];
|
|
stream.writeInt(offset);
|
|
}
|
|
stream.writeByte(1); // 1loop
|
|
archiveData = new byte[stream.getOffset()];
|
|
stream.setOffset(0);
|
|
stream.getBytes(archiveData, 0, archiveData.length);
|
|
}
|
|
reference.updateRevision();
|
|
Archive archive = new Archive(archiveId, compression,
|
|
reference.getRevision(), archiveData);
|
|
|
|
//Fixed packing maps on 498
|
|
archive.setKeys(keys);
|
|
|
|
byte[] closedArchive = archive.compress();
|
|
reference.setCrc(CRC32HGenerator.getHash(closedArchive, 0,
|
|
closedArchive.length - 2));
|
|
reference.setWhirpool(Whirlpool.getHash(closedArchive, 0,
|
|
closedArchive.length - 2));
|
|
if (archiveName != -1)
|
|
reference.setNameHash(archiveName);
|
|
if (fileName != -1)
|
|
reference.getFiles()[fileId].setNameHash(fileName);
|
|
if (!mainFile.putArchiveData(archiveId, closedArchive))
|
|
return false;
|
|
if (rewriteTable && !rewriteTable())
|
|
return false;
|
|
if (resetCache)
|
|
resetCachedFiles();
|
|
return true;
|
|
}
|
|
|
|
public boolean encryptArchive(int archiveId, int[] keys) {
|
|
return encryptArchive(archiveId, null, keys, true, true);
|
|
}
|
|
|
|
public boolean encryptArchive(int archiveId, int[] oldKeys, int[] keys, boolean rewriteTable, boolean resetCache) {
|
|
if (!archiveExists(archiveId))
|
|
return false;
|
|
Archive archive = mainFile.getArchive(archiveId, oldKeys);
|
|
if (archive == null)
|
|
return false;
|
|
ArchiveReference reference = table.getArchives()[archiveId];
|
|
if(reference.getRevision() != archive.getRevision())
|
|
throw new RuntimeException("ERROR REVISION");
|
|
reference.updateRevision();
|
|
archive.setRevision(reference.getRevision());
|
|
archive.setKeys(keys);
|
|
byte[] closedArchive = archive.compress();
|
|
reference.setCrc(CRC32HGenerator.getHash(closedArchive, 0,
|
|
closedArchive.length - 2));
|
|
reference.setWhirpool(Whirlpool.getHash(closedArchive, 0,
|
|
closedArchive.length - 2));
|
|
if (!mainFile.putArchiveData(archiveId, closedArchive))
|
|
return false;
|
|
if (rewriteTable && !rewriteTable())
|
|
return false;
|
|
if (resetCache)
|
|
resetCachedFiles();
|
|
return true;
|
|
|
|
}
|
|
|
|
public boolean rewriteTable() {
|
|
table.updateRevision();
|
|
table.sortTable();
|
|
Object[] hashes = table.encodeHeader(index255);
|
|
if (hashes == null)
|
|
return false;
|
|
//crc = (int) hashes[0];
|
|
whirlpool = (byte[]) hashes[1];
|
|
return true;
|
|
}
|
|
|
|
public void setKeys(int[] keys) {
|
|
table.setKeys(keys);
|
|
}
|
|
|
|
public int[] getKeys() {
|
|
return table.getKeys();
|
|
}
|
|
|
|
private void cacheArchiveFiles(int archiveId, int[] keys) {
|
|
Archive archive = getArchive(archiveId, keys);
|
|
int lastFileId = getLastFileId(archiveId);
|
|
cachedFiles[archiveId] = new byte[lastFileId + 1][];
|
|
if (archive == null)
|
|
return;
|
|
byte[] data = archive.getData();
|
|
if (data == null)
|
|
return;
|
|
int filesCount = getValidFilesCount(archiveId);
|
|
if (filesCount == 1)
|
|
cachedFiles[archiveId][lastFileId] = data;
|
|
else {
|
|
int readPosition = data.length;
|
|
int amtOfLoops = data[--readPosition] & 0xff;
|
|
readPosition -= amtOfLoops * (filesCount * 4);
|
|
InputStream stream = new InputStream(data);
|
|
stream.setOffset(readPosition);
|
|
int filesSize[] = new int[filesCount];
|
|
for (int loop = 0; loop < amtOfLoops; loop++) {
|
|
int offset = 0;
|
|
for (int i = 0; i < filesCount; i++)
|
|
filesSize[i] += offset += stream.readInt();
|
|
}
|
|
byte[][] filesData = new byte[filesCount][];
|
|
for (int i = 0; i < filesCount; i++) {
|
|
filesData[i] = new byte[filesSize[i]];
|
|
filesSize[i] = 0;
|
|
}
|
|
stream.setOffset(readPosition);
|
|
int sourceOffset = 0;
|
|
for (int loop = 0; loop < amtOfLoops; loop++) {
|
|
int dataRead = 0;
|
|
for (int i = 0; i < filesCount; i++) {
|
|
dataRead += stream.readInt();
|
|
System.arraycopy(data, sourceOffset, filesData[i],
|
|
filesSize[i], dataRead);
|
|
sourceOffset += dataRead;
|
|
filesSize[i] += dataRead;
|
|
}
|
|
}
|
|
int count = 0;
|
|
for (int fileId : table.getArchives()[archiveId].getValidFileIds())
|
|
cachedFiles[archiveId][fileId] = filesData[count++];
|
|
}
|
|
}
|
|
|
|
public int getId() {
|
|
return mainFile.getId();
|
|
}
|
|
|
|
public ReferenceTable getTable() {
|
|
return table;
|
|
}
|
|
|
|
public MainFile getMainFile() {
|
|
return mainFile;
|
|
}
|
|
|
|
public Archive getArchive(int id) {
|
|
return mainFile.getArchive(id, null);
|
|
}
|
|
|
|
public Archive getArchive(int id, int[] keys) {
|
|
return mainFile.getArchive(id, keys);
|
|
}
|
|
|
|
public int getCRC() {
|
|
return crc;
|
|
}
|
|
|
|
public byte[] getWhirlpool() {
|
|
return whirlpool;
|
|
}
|
|
}
|