Begin work on DataFile
This commit is contained in:
11
pom.xml
11
pom.xml
@@ -14,6 +14,17 @@
|
|||||||
<artifactId>guava</artifactId>
|
<artifactId>guava</artifactId>
|
||||||
<version>18.0</version>
|
<version>18.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
<version>1.7.12</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-simple</artifactId>
|
||||||
|
<version>1.7.12</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
|
|||||||
203
src/main/java/net/runelite/cache/fs/DataFile.java
vendored
Normal file
203
src/main/java/net/runelite/cache/fs/DataFile.java
vendored
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
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 org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class DataFile implements Closeable
|
||||||
|
{
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(DataFile.class);
|
||||||
|
|
||||||
|
private static final long SECTOR_SIZE = 520L;
|
||||||
|
|
||||||
|
private final int datafileId;
|
||||||
|
private final RandomAccessFile dat;
|
||||||
|
private final byte[] readCachedBuffer = new byte[520];
|
||||||
|
|
||||||
|
public DataFile(int id, File file) throws FileNotFoundException
|
||||||
|
{
|
||||||
|
this.datafileId = id;
|
||||||
|
dat = new RandomAccessFile(file, "rw");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException
|
||||||
|
{
|
||||||
|
dat.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized ByteBuffer read(int archiveId, int sector, int size) throws IOException
|
||||||
|
{
|
||||||
|
if (sector <= 0L || dat.length() / 520L < (long) sector)
|
||||||
|
{
|
||||||
|
logger.warn("bad read, dat length {}", dat.length());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(size);
|
||||||
|
|
||||||
|
dat.seek(SECTOR_SIZE * (long) sector);
|
||||||
|
|
||||||
|
for (int part = 0, readBytesCount = 0, nextSector;
|
||||||
|
size > readBytesCount;
|
||||||
|
sector = nextSector)
|
||||||
|
{
|
||||||
|
if (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 > 510)
|
||||||
|
{
|
||||||
|
dataBlockSize = 510;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 > 512)
|
||||||
|
{
|
||||||
|
dataBlockSize = 512;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 || this.datafileId != currentIndex)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextSector < 0 || dat.length() / 520L < (long) nextSector)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.put(readCachedBuffer, headerSize, dataBlockSize);
|
||||||
|
readBytesCount += dataBlockSize;
|
||||||
|
|
||||||
|
++part;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized int write(int archiveId, ByteBuffer data) throws IOException
|
||||||
|
{
|
||||||
|
int e;
|
||||||
|
int startSector;
|
||||||
|
|
||||||
|
e = (int) ((this.dat.length() + 519L) / 520L);
|
||||||
|
if (e == 0)
|
||||||
|
{
|
||||||
|
e = 1;
|
||||||
|
}
|
||||||
|
startSector = e;
|
||||||
|
|
||||||
|
for (int part = 0; data.hasRemaining(); ++part)
|
||||||
|
{
|
||||||
|
int nextSector = 0;
|
||||||
|
int dataToWrite;
|
||||||
|
|
||||||
|
if (nextSector == 0)
|
||||||
|
{
|
||||||
|
nextSector = (int) ((dat.length() + 519L) / 520L);
|
||||||
|
if (nextSector == 0)
|
||||||
|
{
|
||||||
|
++nextSector;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextSector == e)
|
||||||
|
{
|
||||||
|
++nextSector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.remaining() <= 512)
|
||||||
|
{
|
||||||
|
nextSector = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0xFFFF < archiveId)
|
||||||
|
{
|
||||||
|
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) this.datafileId;
|
||||||
|
dat.seek(SECTOR_SIZE * (long) e);
|
||||||
|
dat.write(this.readCachedBuffer, 0, 10);
|
||||||
|
|
||||||
|
dataToWrite = data.remaining();
|
||||||
|
if (dataToWrite > 510)
|
||||||
|
{
|
||||||
|
dataToWrite = 510;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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) this.datafileId;
|
||||||
|
dat.seek(SECTOR_SIZE * (long) e);
|
||||||
|
dat.write(this.readCachedBuffer, 0, 8);
|
||||||
|
|
||||||
|
dataToWrite = data.remaining();
|
||||||
|
if (dataToWrite > 512)
|
||||||
|
{
|
||||||
|
dataToWrite = 512;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data.get(readCachedBuffer, 0, dataToWrite);
|
||||||
|
dat.write(readCachedBuffer, 0, dataToWrite);
|
||||||
|
e = nextSector;
|
||||||
|
}
|
||||||
|
|
||||||
|
return startSector;
|
||||||
|
}
|
||||||
|
}
|
||||||
36
src/test/java/net/runelite/cache/fs/DataFileTest.java
vendored
Normal file
36
src/test/java/net/runelite/cache/fs/DataFileTest.java
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package net.runelite.cache.fs;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class DataFileTest
|
||||||
|
{
|
||||||
|
@Test
|
||||||
|
public void test1() throws IOException
|
||||||
|
{
|
||||||
|
File file = new File("d:/rs/07/test/test.dat");
|
||||||
|
DataFile df = new DataFile(42, file);
|
||||||
|
int sector = df.write(3, ByteBuffer.wrap("test".getBytes()));
|
||||||
|
ByteBuffer buf = df.read(3, sector, 4);
|
||||||
|
String str = new String(buf.array());
|
||||||
|
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 = new File("d:/rs/07/test/test.dat");
|
||||||
|
DataFile df = new DataFile(42, file);
|
||||||
|
int sector = df.write(0x1FFFF, ByteBuffer.wrap(b));
|
||||||
|
ByteBuffer buf = df.read(0x1FFFF, sector, b.length);
|
||||||
|
Assert.assertArrayEquals(b, buf.array());
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user