package freenet.crypt;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.Random;
import java.util.TreeSet;
class CorruptingOutputStream extends OutputStream {
private final OutputStream os;
/** Bytes to corrupt, in order */
private final long[] killBytes;
private int ptr;
private long ctr;
private final Random random;
public CorruptingOutputStream(OutputStream os, long from, long to, int errors, Random random) {
this.os = os;
this.random = random;
TreeSet<Long> toKill = new TreeSet<Long>();
for(int i=0;i<errors;i++) {
long offset = from + nextLong(random, to - from);
if(!toKill.add(offset)) {
i--;
continue;
}
}
killBytes = new long[errors];
Iterator<Long> it = toKill.iterator();
for(int i=0;i<errors;i++)
killBytes[i] = it.next();
ptr = 0;
}
public void write(int b) throws IOException {
if(ptr < killBytes.length && ctr++ == killBytes[ptr]) {
b ^= (1 << random.nextInt(7));
ptr++;
}
os.write(b);
}
public void close() throws IOException {
os.close();
}
public long nextLong(Random random, long range) {
long maxFair = (Long.MAX_VALUE / range) * range;
while(true) {
long r = random.nextLong();
if(r < 0) r = -r;
if(r == Long.MIN_VALUE) continue; // Wierd case!
if(r > maxFair) continue;
return r % range;
}
}
}