Skip to content

Commit

Permalink
Work on parsing, implemented prototypes
Browse files Browse the repository at this point in the history
  • Loading branch information
djspiewak committed Apr 9, 2010
1 parent 5fe0640 commit b1b5d04
Show file tree
Hide file tree
Showing 19 changed files with 339 additions and 143 deletions.
2 changes: 2 additions & 0 deletions .classpath
@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="test"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
<classpathentry kind="output" path="bin"/>
</classpath>
66 changes: 43 additions & 23 deletions src/com/googlecode/jbencode/Parser.java
Expand Up @@ -5,67 +5,87 @@

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

import com.googlecode.jbencode.factories.DictionaryValueFactory;
import com.googlecode.jbencode.factories.IntegerValueFactory;
import com.googlecode.jbencode.factories.ListValueFactory;
import com.googlecode.jbencode.factories.StringValueFactory;
import com.googlecode.jbencode.factories.ValueFactory;
import com.googlecode.jbencode.composite.DictionaryValue;
import com.googlecode.jbencode.composite.ListValue;
import com.googlecode.jbencode.primitive.IntegerValue;
import com.googlecode.jbencode.primitive.StringValue;

/**
* @author Daniel Spiewak
*/
public final class Parser {
private final Map<Byte, ValueFactory<?>> factories;
private final ValueFactory<StringValue> stringFactory = new StringValueFactory();
private final Map<Byte, Class<? extends Value<?>>> valueTypes;

public Parser() {
factories = new HashMap<Byte, ValueFactory<?>>();
valueTypes = new HashMap<Byte, Class<? extends Value<?>>>();

addFactory(new IntegerValueFactory());
addFactory(new ListValueFactory());
addFactory(new DictionaryValueFactory());
addType(IntegerValue.class);
addType(ListValue.class);
addType(DictionaryValue.class);
}

public void addFactory(ValueFactory<?> factory) {
factories.put(factory.getPrefix(), factory);
private final void addType(Class<? extends Value<?>> type) {
valueTypes.put(type.getAnnotation(Prefix.class).value(), type);
}

public Value<?> parse(InputStream is) throws IOException {
public Class<? extends Value<?>> getValueType(byte b) {
return valueTypes.get(b);
}

public final Value<?> parse(InputStream is) throws IOException {
int i = is.read();

if (i < 255) {
if (i >= 0) {
byte b = (byte) i;
ValueFactory<?> factory = factories.get(b);
Class<? extends Value<?>> valueType = getValueType(b);

if (factory != null) {
return factory.createValue(is);
if (valueType != null) {
return createValue(valueType, this, is);
} else if (b > '0' && b < '9') {
return readString(is, b - '0');
} else if (b == ' ' || b == '\n' || b == '\r' || b == '\t') {
return parse(is); // loop state
} else {
throw new IOException("Unexpected character in the parse stream: " + Character.forDigit(i, 10));
}
}

throw new IOException("Unexpected character in the parse stream: " + Character.forDigit(i, 10));
throw new IOException("Unexpected end of stream durring parse");
}

private StringValue readString(InputStream is, long length) throws IOException {
private final StringValue readString(InputStream is, long length) throws IOException {
int i = is.read();

if (i < 255) {
if (i >= 0) {
byte b = (byte) i;

if (b == ':') {
return stringFactory.createValue(new SubStream(is, length));
return createValue(StringValue.class, this, new SubStream(is, length));
} else if (b > '0' && b < '9') {
return readString(is, (length * 10) + b - '0');
} else {
throw new IOException("Unexpected character in string value: " + Character.forDigit(i, 10));
}
}

throw new IOException("Unexpected character in the parse stream: " + Character.forDigit(i, 10));
throw new IOException("Unexpected end of stream in string value");
}

public static final <T extends Value<?>> T createValue(Class<T> type, Parser p, InputStream is) {
try {
return type.getConstructor(Parser.class, InputStream.class).newInstance(p, is);
} catch (IllegalArgumentException e) {
} catch (SecurityException e) {
} catch (InstantiationException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
} catch (NoSuchMethodException e) {
}

return null;
}
}
18 changes: 18 additions & 0 deletions src/com/googlecode/jbencode/Prefix.java
@@ -0,0 +1,18 @@
/*
* Created on Apr 2, 2008
*/
package com.googlecode.jbencode;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* @author Daniel Spiewak
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Prefix {
byte value();
}
2 changes: 1 addition & 1 deletion src/com/googlecode/jbencode/SubStream.java
Expand Up @@ -9,7 +9,7 @@
/**
* @author Daniel Spiewak
*/
class SubStream extends InputStream {
public class SubStream extends InputStream {
private final InputStream is;
private final long length;

Expand Down
4 changes: 3 additions & 1 deletion src/com/googlecode/jbencode/Value.java
Expand Up @@ -3,9 +3,11 @@
*/
package com.googlecode.jbencode;

import java.io.IOException;

/**
* @author Daniel Spiewak
*/
public interface Value<T> {
public T resolve();
public T resolve() throws IOException;
}
9 changes: 9 additions & 0 deletions src/com/googlecode/jbencode/composite/DictionaryValue.java
Expand Up @@ -3,10 +3,19 @@
*/
package com.googlecode.jbencode.composite;

import java.io.InputStream;

import com.googlecode.jbencode.Parser;
import com.googlecode.jbencode.Prefix;

/**
* @author Daniel Spiewak
*/
@Prefix('d')
public class DictionaryValue extends CompositeValue<DictionaryValue, EntryPair> {

DictionaryValue(Parser p, InputStream is) {
}

public DictionaryValue resolve() {
return this;
Expand Down
110 changes: 107 additions & 3 deletions src/com/googlecode/jbencode/composite/ListValue.java
Expand Up @@ -3,22 +3,126 @@
*/
package com.googlecode.jbencode.composite;

import java.io.IOException;
import java.io.InputStream;

import com.googlecode.jbencode.Parser;
import com.googlecode.jbencode.Prefix;
import com.googlecode.jbencode.SubStream;
import com.googlecode.jbencode.Value;
import com.googlecode.jbencode.primitive.StringValue;
import com.googlecode.jbencode.util.None;
import com.googlecode.jbencode.util.Option;
import com.googlecode.jbencode.util.Some;

/**
* @author Daniel Spiewak
*/
@Prefix('l')
public class ListValue extends CompositeValue<ListValue, Value<?>> {
private final Parser parser;
private final InputStream is;

private boolean resolved = false;
private Option<Byte> readAhead;

ListValue(Parser parser, InputStream is) {
this.parser = parser;
this.is = is;

readAhead = new None<Byte>();
}

public ListValue resolve() {
public ListValue resolve() throws IOException {
if (resolved) {
throw new IOException("Value already resolved");
}
resolved = true;

for (Value<?> value : this) {
value.resolve();
}

return this;
}

public boolean hasNext() {
return false;
if (readAhead instanceof Some && readAhead.value() == 'e') {
return false;
}

try {
byte b = read();

if (b < 0) {
return false;
}

readAhead = new Some<Byte>(b);

if (b == 'e') {
return false;
}

return true;
} catch (IOException e) {
throw new RuntimeException(e);
}
}

public Value<?> next() {
return null;
try {
return parse();
} catch (IOException e) {
throw new RuntimeException(e);
}
}

private final Value<?> parse() throws IOException {
byte b = -1;
if (readAhead instanceof Some) {
b = readAhead.value();
readAhead = new None<Byte>();
} else {
b = read();
}

if (b >= 0) {
Class<? extends Value<?>> valueType = parser.getValueType(b);

if (valueType != null) {
return Parser.createValue(valueType, parser, is);
} else if (b > '0' && b < '9') {
return readString(b - '0');
} else if (b == ' ' || b == '\n' || b == '\r' || b == '\t') {
return parse(); // loop state
} else {
throw new IOException("Unexpected character in the parse stream: " + Character.forDigit(b, 10));
}
}

throw new IOException("Unexpected end of stream in list value");
}

private final StringValue readString(long length) throws IOException {
int i = is.read();

if (i >= 0) {
byte b = (byte) i;

if (b == ':') {
return Parser.createValue(StringValue.class, parser, new SubStream(is, length));
} else if (b > '0' && b < '9') {
return readString((length * 10) + b - '0');
} else {
throw new IOException("Unexpected character in string value: " + Character.forDigit(i, 10));
}
}

throw new IOException("Unexpected end of stream in string value");
}

private final byte read() throws IOException {
return (byte) is.read();
}
}
22 changes: 0 additions & 22 deletions src/com/googlecode/jbencode/factories/DictionaryValueFactory.java

This file was deleted.

22 changes: 0 additions & 22 deletions src/com/googlecode/jbencode/factories/IntegerValueFactory.java

This file was deleted.

22 changes: 0 additions & 22 deletions src/com/googlecode/jbencode/factories/ListValueFactory.java

This file was deleted.

0 comments on commit b1b5d04

Please sign in to comment.