mirror of
https://github.com/DieReicheErethons/Brewery.git
synced 2024-06-28 10:44:48 +02:00
f431c13100
Remember all used Scramble seeds to unscramble potions
104 lines
2.9 KiB
Java
104 lines
2.9 KiB
Java
package com.dre.brewery.lore;
|
|
|
|
import java.io.FilterOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.OutputStream;
|
|
import java.util.Random;
|
|
|
|
/**
|
|
* A Scramble Stream that uses XOR operations to scramble an outputstream.
|
|
* a byte generator feeded with the seed is used as xor source
|
|
* The resulting data can be unscrambled by the XORUnscrambleStream
|
|
*/
|
|
public class XORScrambleStream extends FilterOutputStream {
|
|
|
|
private final long seed;
|
|
private SeedInputStream xorStream;
|
|
private boolean running;
|
|
|
|
/**
|
|
* Create a new instance of an XORScrambler, scrambling the given outputstream
|
|
*
|
|
* @param out The Outputstream to be scrambled
|
|
* @param seed The seed used for scrambling
|
|
*/
|
|
public XORScrambleStream(OutputStream out, long seed) {
|
|
super(out);
|
|
this.seed = seed;
|
|
}
|
|
|
|
/**
|
|
* To start the scrambling process this has to be called before writing any data to this stream.
|
|
* Before starting the scrambler, any data will just be passed through unscrambled to the underlying stream.
|
|
* The Scrambling can be started and stopped arbitrarily at any point, allowing for parts of unscrambled data in the stream.
|
|
*
|
|
* @throws IOException IOException
|
|
*/
|
|
public void start() throws IOException {
|
|
running = true;
|
|
if (xorStream == null) {
|
|
short id = 0;
|
|
while (id == 0) {
|
|
id = (short) new Random().nextInt();
|
|
}
|
|
xorStream = new SeedInputStream(seed ^ id);
|
|
out.write((byte) (id >> 8));
|
|
out.write((byte) id);
|
|
write((int) (seed >> 48) & 0xFF); // parity/sanity
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Stop the scrambling, any following data will be passed through unscrambled.
|
|
* The scrambling can be started again at any point after calling this
|
|
*/
|
|
public void stop() {
|
|
running = false;
|
|
}
|
|
|
|
/**
|
|
* Mark the stream as unscrambled, any effort of unscrambing the data later will automatically read the already unscrambled data
|
|
* Useful if a stream may be scrambled or unscrambled, the unscrambler will automatically identify either way.
|
|
*
|
|
* @throws IOException IOException
|
|
* @throws IllegalStateException If the Scrambler was started in normal scrambling mode before
|
|
*/
|
|
public void startUnscrambled() throws IOException, IllegalStateException {
|
|
if (xorStream != null) throw new IllegalStateException("The Scrambler was started in scrambling mode before");
|
|
short id = 0;
|
|
out.write((byte) (id >> 8));
|
|
out.write((byte) id);
|
|
}
|
|
|
|
@Override
|
|
public void write(int b) throws IOException {
|
|
if (!running) {
|
|
out.write(b);
|
|
return;
|
|
}
|
|
out.write(b ^ xorStream.read());
|
|
}
|
|
|
|
@Override
|
|
public void write(byte[] b, int off, int len) throws IOException {
|
|
if (!running) {
|
|
out.write(b, off, len);
|
|
return;
|
|
}
|
|
byte[] xored = new byte[len];
|
|
xorStream.read(xored);
|
|
int j = off;
|
|
for (int i = 0; i < len; i++) {
|
|
xored[i] ^= b[j++];
|
|
}
|
|
out.write(xored);
|
|
}
|
|
|
|
@Override
|
|
public void close() throws IOException {
|
|
running = false;
|
|
xorStream = null;
|
|
super.close();
|
|
}
|
|
}
|