package fr.inria.diversify.sosie.logger;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
/**
* A reader to read binary log files
*
* Created by marodrig on 17/07/2014.
*/
public class BinaryLogReader {
public class LogChunk {
private LogChunk(DataInputStream stream) throws IOException {
}
public LogChunk() {}
}
/**
* A class representing a test chunk
*/
public class TestChunk extends LogChunk {
private String name;
public String getName() { return name; }
private TestChunk(DataInputStream stream) throws IOException {
name = stream.readUTF();
}
}
public class MethodCallChunk extends LogChunk {
private int id;
private String signature;
private int currentDepth;
public int getId() { return id; }
public String getSignature() { return signature; }
public int getCurrentDepth() { return currentDepth; }
private MethodCallChunk(byte optByte, DataInputStream stream) throws IOException {
int sizeID = (optByte >> 3) & 0x3;
int depthID = (optByte >> 5) & 0x3;
boolean newSignature = ((optByte >> 7) & 0x1) == 1;
if ( newSignature ) {
signature = stream.readUTF();
id = readVariableSizeInt(stream, sizeID);
}
else {
id = stream.readInt();
signature = methodMap.get(id);
}
currentDepth = readVariableSizeInt(stream, depthID);
}
}
public class VariableChunk extends LogChunk {
private VariableChunk(DataInputStream stream) throws IOException {
}
}
public class ExceptionChunk extends LogChunk {
private ExceptionChunk(DataInputStream stream) throws IOException {
super(stream);
}
}
public class CatchChunk extends LogChunk {
private CatchChunk(DataInputStream stream) throws IOException {
super(stream);
}
}
public class AssertChunk extends LogChunk {
private AssertChunk(DataInputStream stream) throws IOException {
super(stream);
}
}
private int readVariableSizeInt(DataInputStream stream, int size) throws IOException {
byte[] bytes = new byte[size];
stream.read(bytes);
int result = 0;
for ( int i = 0; i < size; i++ ) {
result |= bytes[i] >> (i * 8);
}
return result;
}
private DataInputStream stream;
private boolean eof;
//Map bein readed
protected Map<Integer, String> idMap;
//Map with the name of the methods
protected Map<Integer, String> methodMap;
public BinaryLogReader(File file) throws FileNotFoundException {
this(new DataInputStream(new BufferedInputStream(new FileInputStream(file))));
eof = false;
}
public BinaryLogReader(DataInputStream stream) {
idMap = new HashMap<>();
methodMap = new HashMap<>();
this.stream = stream;
eof = false;
}
/**
* Reads the next chunk of the trace.
* @return The log chunk readed
* @throws IOException In case we are unable to read from the stream
*/
public LogChunk next() throws IOException {
byte optByte = stream.readByte();
//Only the first 3 bits of the optByte are the magic number
byte magic = (byte)(optByte & 7);
switch (magic) {
case InstruBinaryLog.LOG_TEST:
return new TestChunk(stream);
case InstruBinaryLog.LOG_METHOD:
return new MethodCallChunk(optByte, stream);
case InstruBinaryLog.LOG_VAR:
throw new NotImplementedException();
case InstruBinaryLog.LOG_EXCEPTION:
throw new NotImplementedException();
case InstruBinaryLog.LOG_CATCH:
throw new NotImplementedException();
case InstruBinaryLog.LOG_ASSERT:
throw new NotImplementedException();
case InstruBinaryLog.LOG_CLOSE:
eof = true;
return null;
default:
throw new IOException("Unknown magic number, File is corrupted or not proper format");
}
}
/**
* Reads a chunk of the signatures map
*
* @param stream
*/
private void readSignatureChunk(DataInputStream stream) throws IOException {
int size = stream.readInt();
for (int i = 0; i < size; i++) {
String id = stream.readUTF();
int key = stream.readInt();
idMap.put(key, id);
}
}
public boolean eof() {
return this.eof;
}
}