Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Yggdrasil Cleanup #5408

Merged
merged 9 commits into from
Sep 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions src/main/java/ch/njol/yggdrasil/ClassResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,16 @@ public interface ClassResolver {
* @return The Class object that represents data with the given ID, or null if the ID does not belong to the implementor
*/
@Nullable
public Class<?> getClass(String id);
Class<?> getClass(String id);

/**
* Gets an ID for a Class. The ID is used to identify the type of a saved object.
* Gets an ID for a Class. The ID is used to identify the type of saved object.
* <p>
* // TODO make sure that it's unique
*
* @param c The class to get the ID of
* @param clazz The class to get the ID of
* @return The ID of the given class, or null if this is not a class of the implementor
*/
// TODO make sure that it's unique
@Nullable
public String getID(Class<?> c);
String getID(Class<?> clazz);

}
126 changes: 47 additions & 79 deletions src/main/java/ch/njol/yggdrasil/DefaultYggdrasilInputStream.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,102 +18,90 @@
*/
package ch.njol.yggdrasil;

import static ch.njol.yggdrasil.Tag.T_ARRAY;
import static ch.njol.yggdrasil.Tag.T_REFERENCE;
import ch.njol.util.coll.CollectionUtils;

import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.StreamCorruptedException;
import java.lang.reflect.Array;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.jdt.annotation.NonNull;
import static ch.njol.yggdrasil.Tag.T_ARRAY;
import static ch.njol.yggdrasil.Tag.T_REFERENCE;

//Naming conventions:
// x(): read info & data (e.g. content type, contents) [i.e. no tag]
// _x(): read data only (e.g. contents)

public final class DefaultYggdrasilInputStream extends YggdrasilInputStream {

@SuppressWarnings("null")
private final static Charset UTF_8 = Charset.forName("UTF-8");

private final InputStream in;
private final short version;

final InputStream in;

public DefaultYggdrasilInputStream(final Yggdrasil y, final InputStream in) throws IOException {
super(y);
public DefaultYggdrasilInputStream(Yggdrasil yggdrasil, InputStream in) throws IOException {
super(yggdrasil);
this.in = in;
final int m = readInt();
if (m != Yggdrasil.MAGIC_NUMBER)
if (readInt() != Yggdrasil.MAGIC_NUMBER)
throw new StreamCorruptedException("Not an Yggdrasil stream");
version = readShort();
if (version <= 0 || version > Yggdrasil.LATEST_VERSION)
throw new StreamCorruptedException("Input was saved using a later version of Yggdrasil");
}

// private

/**
* @throws EOFException If the end of the stream is reached
*/
private int read() throws IOException {
final int b = in.read();
int b = in.read();
if (b < 0)
throw new EOFException();
return b;
}

private void readFully(final byte[] buf) throws IOException {
readFully(buf, 0, buf.length);
private void readFully(byte[] buf) throws IOException {
readFully(buf, buf.length);
}

private void readFully(final byte[] buf, int off, final int len) throws IOException {
int l = len;
while (l > 0) {
final int n = in.read(buf, off, l);
private void readFully(byte[] buf, int startLength) throws IOException {
int offset = 0;
int length = startLength;
while (length > 0) {
int n = in.read(buf, offset, length);
if (n < 0)
throw new EOFException("Expected " + len + " bytes, but could only read " + (len - l));
off += n;
l -= n;
throw new EOFException("Expected " + startLength + " bytes, but could only read " + (startLength - length));
offset += n;
length -= n;
}
}

private final List<String> readShortStrings = new ArrayList<>();

private String readShortString() throws IOException {
final int length = read();
int length = read();
if (length == (T_REFERENCE.tag & 0xFF)) {
final int i = version <= 1 ? readInt() : readUnsignedInt();
int i = version <= 1 ? readInt() : readUnsignedInt();
if (i < 0 || i > readShortStrings.size())
throw new StreamCorruptedException("Invalid short string reference " + i);
return "" + readShortStrings.get(i);
}
final byte[] d = new byte[length];
byte[] d = new byte[length];
readFully(d);
final String s = new String(d, UTF_8);
String s = new String(d, StandardCharsets.UTF_8);
if (length > 4)
readShortStrings.add(s);
return s;
}

// Tag

@Override
protected Tag readTag() throws IOException {
final int t = read();
final Tag tag = Tag.byID(t);
int t = read();
Tag tag = Tag.byID(t);
if (tag == null)
throw new StreamCorruptedException("Invalid tag 0x" + Integer.toHexString(t));
return tag;
}

// Primitives

private byte readByte() throws IOException {
return (byte) read();
}
Expand All @@ -123,7 +111,7 @@ private short readShort() throws IOException {
}

private short readUnsignedShort() throws IOException {
final int b = read();
int b = read();
if ((b & 0x80) != 0)
return (short) (b & ~0x80);
return (short) (b << 8 | read());
Expand All @@ -137,21 +125,17 @@ private int readInt() throws IOException {
}

private int readUnsignedInt() throws IOException {
final int b = read();
int b = read();
if ((b & 0x80) != 0)
return (b & ~0x80) << 8 | read();
return b << 24 | read() << 16 | read() << 8 | read();
}

private long readLong() throws IOException {
kiip1 marked this conversation as resolved.
Show resolved Hide resolved
return (long) read() << 56
| (long) read() << 48
| (long) read() << 40
| (long) read() << 32
| (long) read() << 24
| read() << 16
| read() << 8
| read();
return (long) in.read() << 56 | (long) in.read() << 48
| (long) in.read() << 40 | (long) in.read() << 32
| (long) in.read() << 24 | (long) in.read() << 16
| (long) in.read() << 8 | read();
}

private float readFloat() throws IOException {
Expand All @@ -167,7 +151,7 @@ private char readChar() throws IOException {
}

private boolean readBoolean() throws IOException {
final int r = read();
int r = read();
if (r == 0)
return false;
else if (r == 1)
Expand All @@ -176,7 +160,7 @@ else if (r == 1)
}

@Override
protected Object readPrimitive(final Tag type) throws IOException {
protected Object readPrimitive(Tag type) throws IOException {
switch (type) {
case T_BYTE:
return readByte();
Expand All @@ -194,29 +178,24 @@ protected Object readPrimitive(final Tag type) throws IOException {
return readChar();
case T_BOOLEAN:
return readBoolean();
//$CASES-OMITTED$
default:
throw new YggdrasilException("Internal error; " + type);
}
}

@Override
protected Object readPrimitive_(final Tag type) throws IOException {
protected Object readPrimitive_(Tag type) throws IOException {
return readPrimitive(type);
}

// String

@Override
protected String readString() throws IOException {
final int length = readUnsignedInt();
final byte[] d = new byte[length];
int length = readUnsignedInt();
byte[] d = new byte[length];
readFully(d);
return new String(d, UTF_8);
return new String(d, StandardCharsets.UTF_8);
}

// Array

@Override
protected Class<?> readArrayComponentType() throws IOException {
return readClass();
Expand All @@ -227,8 +206,6 @@ protected int readArrayLength() throws IOException {
return readUnsignedInt();
}

// Enum

@Override
protected Class<?> readEnumType() throws IOException {
return yggdrasil.getClass(readShortString());
Expand All @@ -239,21 +216,18 @@ protected String readEnumID() throws IOException {
return readShortString();
}

// Class

@SuppressWarnings("null")
@Override
protected Class<?> readClass() throws IOException {
Tag type;
int dim = 0;
int dimensions = 0;
while ((type = readTag()) == T_ARRAY)
dim++;
@NonNull
Class<?> c;
dimensions++;
Class<?> clazz;
switch (type) {
case T_OBJECT:
case T_ENUM:
c = yggdrasil.getClass(readShortString());
clazz = yggdrasil.getClass(readShortString());
break;
case T_BOOLEAN:
case T_BOOLEAN_OBJ:
Expand All @@ -273,8 +247,8 @@ protected Class<?> readClass() throws IOException {
case T_SHORT_OBJ:
case T_CLASS:
case T_STRING:
c = type.c;
assert c != null;
assert type.type != null;
clazz = type.type;
break;
case T_NULL:
case T_REFERENCE:
Expand All @@ -283,20 +257,16 @@ protected Class<?> readClass() throws IOException {
default:
throw new YggdrasilException("Internal error; " + type);
}
while (dim-- > 0)
c = Array.newInstance(c, 0).getClass();
return c;
while (dimensions-- > 0)
kiip1 marked this conversation as resolved.
Show resolved Hide resolved
clazz = CollectionUtils.arrayType(clazz);
return clazz;
}

// Reference

@Override
protected int readReference() throws IOException {
return readUnsignedInt();
}

// generic Object

@Override
protected Class<?> readObjectType() throws IOException {
return yggdrasil.getClass(readShortString());
Expand All @@ -312,14 +282,12 @@ protected String readFieldID() throws IOException {
return readShortString();
}

// stream

@Override
public void close() throws IOException {
try {
read();
throw new StreamCorruptedException("Stream still has data, at least " + (1 + in.available()) + " bytes remain");
} catch (final EOFException e) {} finally {
} catch (EOFException ignored) {} finally {
in.close();
}
}
Expand Down
Loading