package de.yogularm.minecraft.itemfinder.region;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.file.Path;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.zip.InflaterInputStream;
public class AnvilReader implements AutoCloseable {
private RandomAccessFile file;
private int chunkCount = 0;
private static final int SECTOR_SIZE = 4096;
/**
* Stores the positions where there are chunks
*/
private SortedSet<Integer> chunkPositions;
public AnvilReader(Path path) throws IOException {
file = new RandomAccessFile(path.toFile(), "r");
readMetadata();
}
private void readMetadata() throws IOException {
chunkPositions = new TreeSet<>();
chunkCount = 0;
for (int i = 0; i < 1024; i++) {
int pos = file.readUnsignedByte() * 0x10000 + file.readUnsignedByte() * 0x100
+ file.readUnsignedByte();
file.readByte(); // length
if (pos > 0) { // 0 means chunk does not exist
chunkPositions.add(pos);
chunkCount++;
}
}
}
public int getChunkCount() {
return chunkCount;
}
public InputStream readChunkColumn() throws IOException {
if (chunkPositions.size() == 0)
throw new IllegalStateException("No more chunks available");
int nextChunkPosition = chunkPositions.first();
chunkPositions.remove(nextChunkPosition);
// skip to next chunk
file.seek((long)nextChunkPosition * SECTOR_SIZE);
// read the raw data
int length = file.readInt() - 1; // one byte for the compression
byte compression = file.readByte();
byte[] rawChunkData = new byte[length];
file.readFully(rawChunkData);
// get a stream for the uncompressed data
InputStream rawChunkStream = new ByteArrayInputStream(rawChunkData);
InputStream chunkStream;
switch (compression) {
case 2:
chunkStream = new BufferedInputStream(new InflaterInputStream(rawChunkStream));
break;
default:
throw new InvalidSaveFormatException(
"Unsupported compression type: " + compression);
}
return chunkStream;
}
public boolean hasMore() {
return chunkPositions.size() > 0;
}
@Override
public void close() throws IOException {
file.close();
}
}