diff --git a/README.md b/README.md
index ad08ed2..fc37d69 100644
--- a/README.md
+++ b/README.md
@@ -8,23 +8,19 @@
- Creating an object
- Arrays
- Named lists
-- Saving classes
-- Implementation details
+- Human readable representation
+- Special notes
### Overview
-Binary Data Format (or BDF) is designed to store data in a tree-like binary structure,
-like Notch's NBT format, but also open source and free like JSON. The format is
-fast and allows multiple data types. It uses 32-bit integers, so BDF files can
-be fast and work well on 32-bit systems, but have a maximum size of 2 GB.
-BDF allows human readable serialization to see what is going on for debugging
-purposes, but it currently can't parse the human readable serialized string to an object.
-
+Binary Data Format (BDF) is a statically typed data representation
+format. It was made to be free, fast, compact, and seamlessly
+convertable between its human readable and binary representations.
### Languages
-- Java
- C++
+- Java
### Data types
@@ -70,8 +66,15 @@ int v = bdf.getInteger();
// Set an integer
bdf.setInteger(5);
-// Set a "smart" integer
-bdf.setSmartInteger(53);
+// Set an integer with an automatic type
+bdf.setAutoInt(53);
+
+// Set a primitive array of ints
+int intArray[] = {3, 4, 5, 6};
+bdf.setIntegerArray(intArray);
+
+// Get a byte array
+byte[] byteArray = bdf.getByteArray();
// Get the type of variable of the object
int type = bdf.getType();
@@ -83,38 +86,27 @@ if(type == BdfTypes.INTEGER)
}
// Serialize the BDF object
-IBdfDatabase data = bdf.serialize();
+byte[] data = bdf->serialize(&data, &data_size);
-// Load another BDF object with the serialized bytes
-BdfObject bdf2 = new BdfObject(new BdfDatabase(data));
+// Load another reader object from the serialized bytes
+BdfReader reader2 = new BdfReader(data);
-```
+/*
+ A reader object can be serialized to the human readable
+ representation as a string or sent over a stream
+*/
+reader2.serializeHumanReadable(System.out, new BdfIndent("\t", "\n"));
+String data_hr = reader2.serializeHumanReadable(new BdfIndent("\t", "\n"));
-A file manager instance can be used in the same way as a reader object,
-but it also needs a String parameter for the path of the file. The file
-manager instance also has the capacity to use compression (by default this
-uses the GZIP compression algorithm).
-
-```java
-
-// Open a file with compression enabled
-BdfFileManager reader = new BdfFileManager("file.bdf", true);
-
-// Save the database
-reader.saveDatabase();
-
-// The file can be casted to a BdfReader
-BdfReader reader2 = (BdfReader) reader;
-
-// Can be used just as any reader instance
-BdfObject bdf = reader.getObject();
+// A reader object can be loaded from a human readable object
+BdfReader reader3 = new BdfReaderHuman(data_hr);
```
### Arrays
-Arrays can be used to store lists of information, they hold instances of
-BdfObject. Arrays have support for Iterators and are an instance of Iterable.
+Arrays can be used to store chunks of information, they hold instances of
+BdfObject. Arrays can also be iterated over just like any other array.
```java
@@ -134,17 +126,11 @@ array.remove(3);
array.set(4, bdf.newObject().setString("A String"));
// Add an object to an array
-array.add(bdf.newObject().setByte(53));
+array.add(bdf.newObject().setByte((byte)53));
// Set the array to the bdf object
bdf.setArray(array);
-// Iterate over an array
-for(BdfObject o : array)
-{
-
-}
-
```
### Named lists
@@ -156,26 +142,26 @@ can be created similar to an array.
```java
BdfReader reader = new BdfReader();
-BdfObject bdf = new BdfObject();
+BdfObject bdf = reader.getObject();
// New named list
-BdfNamedList nl = bdf.newNamedList();
+BdfNamedList list = bdf.newNamedList();
// Set an element to the named list
-nl.set("key1", bdf.newObject().setInteger(5));
+list.set("key1", bdf.newObject().setInteger(5));
// Use ids instead of strings for optimisation
// if set/get is being called multiple times
// on the same key.
-int key2 = nl.getKeyLocation("key2");
-nl.set(key2, bdf.newObject().setFloat(42.0F));
+int key2 = bdf.getKeyLocation("key2");
+list.set(key2, bdf.newObject().setFloat(42.0F));
// Get an elements value
int v = list.get("key1").getInteger();
// Check if an element exists
-boolean has_key = list.contains("key1");
+bool has_key = list.contains("key1");
// Get the lists keys
int[] keys = list.getKeys();
@@ -184,64 +170,132 @@ int[] keys = list.getKeys();
for(int key : keys)
{
// Get the keys name
- String key_name = nl.getKeyName(key);
+ String key_name = bdf.getKeyName(key);
}
```
-### Further optimisations
+### Human readable representation
+A big part of binary data format is the human readable
+representation. It has a JSON-like syntax.
+This can be used with config files and to modify/view
+binaries. A big advantage to using the human readable
+representation in configuration files is its support
+for comments.
-### Implementation details
+```hbdf
-All integer data types are in the Big Endian layout.
+/*
+ A Named List is represented
+ by an opening tag and a closing
+ tag { }
+*/
+{
+ /*
+ A key value pair can be stored
+ within a Named List with a string
+ property
+ */
+ "hello": "world",
-**Flags (1 unsigned byte)**
-This holds 3 values:
-- Type (0-17)
-- Size type (0-2)
-- Parent payload (0-2)
+ /*
+ Integers can be stored here too.
+ They have a character at the end
+ to say what type they are.
+
+ The tag at the end can be:
+ - I: Integer - a value between -2^31 and 2^31 - 1
+ - S: Short - a value between -32768 and 32767
+ - L: Long - a value between -2^63 and 2^63 - 1
+ - B: Byte - a value between -128 and 127
+ - D: Double - has 15 decimal digits of precision
+ - F: Float - has 7 decimal digits of precision
+ */
+ "number": 42I,
+ "byte": -23B,
+ "decimal": 73.5D,
-**Type**
-```
-0: UNDEFINED (0 bytes)
+ /*
+ This is a boolean. It can
+ be true or false.
+ */
+ "boolTest": false,
-1: BOOLEAN (1 byte, 0x00 or 0x01)
-2: INTEGER (4 bytes)
-3: LONG (8 bytes)
-4: SHORT (2 bytes)
-5: BYTE (1 byte)
-6: DOUBLE (8 bytes)
-7: FLOAT (4 bytes)
+ /*
+ Primitive arrays are represented
+ by a type, an opening tag, and a
+ closing tag. They are like an array
+ but they contain only 1 data type.
-8: STRING
-9: ARRAY
-10: NAMED_LIST
+ The tag at the start can be:
+ - int
+ - short
+ - long
+ - byte
+ - double
+ - float
+ - bool
+ */
+ "intArray": int (
+ 64I, 42I, 63I,
+ 22I, 96I, -12I,
+ ),
-11: ARRAY_BOOLEAN
-12: ARRAY_INTEGER
-13: ARRAY_LONG
-14: ARRAY_SHORT
-15: ARRAY_BYTE
-16: ARRAY_DOUBLE
-17: ARRAY_FLOAT
+ /*
+ The double and float types support
+ Infinity, -Infinity, and NaN.
+
+ They also support both really
+ high and really low value numbers.
+ */
+ "doubleArray": double (
+ 42.5D, -20D, 400D,
+ NaND, -InfinityD, InfinityD,
+ 5.3e-200F, 4e+500F, 2.2e200F,
+ )
+
+ /*
+ Arrays are enclosed by an opening
+ tag and a closing tag [ ]
+
+ Like the Named List, it can hold
+ any data type.
+ */
+ "people": [
+ {"name": "foo", "age": 60B},
+ {"name": "bar", "age": 21B},
+ ],
+
+ // This is a single-line comment
+
+ /* This is a multi-line comment */
+}
```
-**Size Type**
-This value holds info for how big the size of
-the size of the payload is, in bytes. The purpose
-of this is to reduce the size as much as possible
-by throwing out unneccicary zeros.
+### Special notes
-**Object**
-- Flags (unsigned byte, 1 byte)
-- Size (variable length)
-- Payload (Any type, variable length)
+Don't mix bdf types between different
+readers, this will cause problems.
-**NamedList**
-- Key ID (variable length)
-- Payload (Object, variable length)
+```java
+
+BdfReader reader1 = new BdfReader();
+BdfReader reader2 = new BdfReader();
+
+BdfObject bdf1 = reader1.getObject();
+BdfObject bdf2 = reader2.getObject();
+
+// Don't do this
+bdf1.setNamedList(bdf2.newNamedList());
+
+// Or this
+bdf1.setArray(bdf2.newArray());
+
+// Or this
+BdfNamedList nl = bdf1.newArray();
+nl.set("illegal", bdf2.newObject().setString("action"));
+
+```
-**Array**
-- Payload (Object, variable length)
diff --git a/src/bdf/classes/IBdfClassManager.java b/src/bdf/classes/IBdfClassManager.java
deleted file mode 100755
index 68a0f5d..0000000
--- a/src/bdf/classes/IBdfClassManager.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package bdf.classes;
-
-import bdf.types.BdfObject;
-
-public interface IBdfClassManager
-{
- public void BdfClassLoad(BdfObject bdf);
- public void BdfClassSave(BdfObject bdf);
-}
diff --git a/src/bdf/data/BdfStringPointer.java b/src/bdf/data/BdfStringPointer.java
index 1efee1e..f62c5d0 100644
--- a/src/bdf/data/BdfStringPointer.java
+++ b/src/bdf/data/BdfStringPointer.java
@@ -7,6 +7,11 @@ public class BdfStringPointer
char[] data;
int offset;
+ public BdfStringPointer(char[] data, int offset) {
+ this.data = data;
+ this.offset = offset;
+ }
+
public BdfStringPointer getPointer(int offset) {
return new BdfStringPointer(data, this.offset + offset);
}
@@ -45,11 +50,6 @@ public class BdfStringPointer
public char[] getCharArray(int length) {
return getCharArray(0, length);
}
-
- public BdfStringPointer(char[] data, int offset) {
- this.data = data;
- this.offset = offset;
- }
public char getChar(int i) {
return data[offset + i];
@@ -61,7 +61,7 @@ public class BdfStringPointer
public void ignoreBlanks()
{
- while(true)
+ for(;;)
{
if(offset >= data.length) {
throw BdfError.createError(BdfError.ERROR_END_OF_FILE, this);
@@ -69,7 +69,54 @@ public class BdfStringPointer
char c = getChar();
- if(!(c == '\n' || c == '\t' || c == ' ')) {
+ // Comments
+ if(c == '/' && offset < data.length)
+ {
+ char c2 = getChar(1);
+
+ // Line comment
+ if(c2 == '/')
+ {
+ for(;;)
+ {
+ if(offset + 1 >= data.length) {
+ break;
+ }
+
+ increment();
+ c = getChar();
+
+ if(c == '\n') {
+ break;
+ }
+ }
+ }
+
+ // Multi-line comment
+ else if(c2 == '*')
+ {
+ for(;;)
+ {
+ if(offset + 1 >= data.length) {
+ throw BdfError.createError(BdfError.ERROR_UNESCAPED_COMMENT, getPointer(-1));
+ }
+
+ increment();
+ c = getChar();
+
+ if(c == '*' && offset < data.length && getChar(1) == '/') {
+ increment();
+ break;
+ }
+ }
+ }
+
+ else {
+ return;
+ }
+ }
+
+ else if(!(c == '\n' || c == '\t' || c == ' ')) {
return;
}
@@ -87,10 +134,10 @@ public class BdfStringPointer
increment();
String str = "";
- while(true)
+ for(;;)
{
if(offset >= data.length) {
- throw BdfError.createError(BdfError.ERROR_END_OF_FILE, this);
+ throw BdfError.createError(BdfError.ERROR_UNESCAPED_STRING, this);
}
char c = getChar();
@@ -98,27 +145,35 @@ public class BdfStringPointer
// Check for back slashes
if(c == '\\')
{
- increment(1);
+ increment();
c = getChar();
switch(c)
{
case 'n':
str += "\n";
+ increment();
break;
case 't':
str += "\t";
+ increment();
break;
case '"':
str += "\"";
+ increment();
break;
case '\\':
str += "\\";
+ increment();
+ break;
+ case '\n':
+ str += "\n";
+ increment();
break;
case 'u': // \u0000
{
if(offset + 5 >= data.length) {
- throw BdfError.createError(BdfError.ERROR_END_OF_FILE, getPointer(1));
+ throw BdfError.createError(BdfError.ERROR_UNESCAPED_STRING, getPointer(1));
}
char[] hex = getCharArray(1, 4);
@@ -154,6 +209,10 @@ public class BdfStringPointer
}
}
+ else if(c == '\n') {
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, this);
+ }
+
else if(c == '"') {
increment();
break;
@@ -170,16 +229,12 @@ public class BdfStringPointer
public boolean isNext(String check)
{
- if(check.length() + offset >= data.length) {
+ if(check.length() + offset > data.length) {
return false;
}
for(int i=0;i= data.length) {
- throw BdfError.createError(BdfError.ERROR_END_OF_FILE, this);
- }
-
char c = getChar(i);
c = (char)((c >= 'A' && c <= 'Z') ? (c + 32) : c);
@@ -219,6 +274,8 @@ public class BdfStringPointer
continue;
case '.':
continue;
+ case '-':
+ continue;
}
if(c >= '0' && c <= '9') {
diff --git a/src/bdf/file/.gitignore b/src/bdf/file/.gitignore
deleted file mode 100644
index 097f6c7..0000000
--- a/src/bdf/file/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/BdfFileManager.class
diff --git a/src/bdf/file/BdfFileManager.java b/src/bdf/file/BdfFileManager.java
deleted file mode 100644
index 0a78daa..0000000
--- a/src/bdf/file/BdfFileManager.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package bdf.file;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.zip.DeflaterOutputStream;
-import java.util.zip.GZIPOutputStream;
-
-import bdf.data.BdfDatabase;
-import bdf.types.BdfObject;
-import bdf.types.BdfReader;
-import bdf.util.FileHelpers;
-
-public class BdfFileManager extends BdfReader
-{
- protected String path;
- private boolean compressed;
-
- private static BdfDatabase init(String path, boolean compressed)
- {
- // Get the file
- File file = new File(path);
-
- // Does the file have read access
- if(file.canRead())
- {
- if(compressed)
- {
- // Return the files contents as a database
- return new BdfDatabase(FileHelpers.readAllCompressedIgnoreErrors(path));
- }
-
- else
- {
- // Return the files contents as a database
- return new BdfDatabase(FileHelpers.readAllIgnoreErrors(path));
- }
- }
-
- // Return an empty database if there is no read access
- return new BdfDatabase(0);
- }
-
- public BdfFileManager(String path, boolean compressed) {
- super(init(path, compressed));
- this.compressed = compressed;
- this.path = path;
- }
-
- public BdfFileManager(String path) {
- this(path, false);
- }
-
- public void saveDatabase(String path)
- {
- try
- {
- // Get the file handler
- File file = new File(path);
-
- // Create the parent directories
- file.getAbsoluteFile().getParentFile().mkdirs();
-
- // Get the database file for output
- OutputStream out = new FileOutputStream(path);
-
- if(compressed) {
- out = new GZIPOutputStream(out);
- }
-
- // Write the database to the file
- BdfDatabase db = this.serialize();
- db.writeToStream(out);
-
- // Close the file output stream
- out.close();
- }
-
- catch(IOException e) {
- return;
- }
- }
-
- public void saveDatabase() {
- this.saveDatabase(this.path);
- }
-}
diff --git a/src/bdf/types/BdfArray.java b/src/bdf/types/BdfArray.java
index 72e27a8..ca24133 100644
--- a/src/bdf/types/BdfArray.java
+++ b/src/bdf/types/BdfArray.java
@@ -8,16 +8,13 @@ import java.util.Iterator;
import bdf.data.BdfStringPointer;
import bdf.data.IBdfDatabase;
import bdf.util.BdfError;
-import bdf.util.DataHelpers;
public class BdfArray implements IBdfType, Iterable
{
protected ArrayList elements;
- protected BdfLookupTable lookupTable;
BdfArray(BdfLookupTable lookupTable, BdfStringPointer ptr)
{
- this.lookupTable = lookupTable;
this.elements = new ArrayList();
ptr.increment();
@@ -55,7 +52,6 @@ public class BdfArray implements IBdfType, Iterable
BdfArray(BdfLookupTable lookupTable, int size)
{
- this.lookupTable = lookupTable;
this.elements = new ArrayList(size);
for(int i=0;i
BdfArray(BdfLookupTable lookupTable, IBdfDatabase data)
{
- this.lookupTable = lookupTable;
this.elements = new ArrayList();
// Create an iterator value to loop over the data
@@ -77,6 +72,10 @@ public class BdfArray implements IBdfType, Iterable
// Get the size of the object
int size = BdfObject.getSize(data.getPointer(i));
+ if(size <= 0 || i + size > data.size()) {
+ return;
+ }
+
// Get the object
BdfObject object = new BdfObject(lookupTable, data.getPointer(i, size));
diff --git a/src/bdf/types/BdfLookupTable.java b/src/bdf/types/BdfLookupTable.java
index 9ef285f..d599389 100644
--- a/src/bdf/types/BdfLookupTable.java
+++ b/src/bdf/types/BdfLookupTable.java
@@ -1,11 +1,7 @@
package bdf.types;
-import java.io.IOException;
import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
import bdf.data.IBdfDatabase;
import bdf.util.DataHelpers;
@@ -31,6 +27,10 @@ class BdfLookupTable implements IBdfType
int key_size = 0xff & database.getByte(i);
i += 1;
+ if(i + key_size > database.size()) {
+ return;
+ }
+
keys.add(database.getBytes(i, key_size));
i += key_size;
@@ -50,6 +50,10 @@ class BdfLookupTable implements IBdfType
return keys.size() - 1;
}
+ boolean hasLocation(int location) {
+ return location >= 0 && location < keys.size();
+ }
+
byte[] getName(int location) {
return keys.get(location);
}
diff --git a/src/bdf/types/BdfNamedList.java b/src/bdf/types/BdfNamedList.java
index 8b07efd..bc6d3a4 100644
--- a/src/bdf/types/BdfNamedList.java
+++ b/src/bdf/types/BdfNamedList.java
@@ -3,7 +3,6 @@ package bdf.types;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import bdf.data.BdfStringPointer;
@@ -94,6 +93,11 @@ public class BdfNamedList implements IBdfType
IBdfDatabase flag_ptr = data.getPointer(i);
int object_size = BdfObject.getSize(flag_ptr);
byte key_size_bytes = BdfObject.getParentFlags(flag_ptr);
+
+ if(object_size <= 0 || i + object_size >= data.size()) {
+ return;
+ }
+
BdfObject object = new BdfObject(lookupTable, data.getPointer(i, object_size));
i += object_size;
@@ -127,6 +131,10 @@ public class BdfNamedList implements IBdfType
break;
}
+ if(!lookupTable.hasLocation(key)) {
+ return;
+ }
+
i += key_size;
// Create a new element and save some data to it
diff --git a/src/bdf/types/BdfObject.java b/src/bdf/types/BdfObject.java
index 49d4c8c..57fcd43 100644
--- a/src/bdf/types/BdfObject.java
+++ b/src/bdf/types/BdfObject.java
@@ -1,6 +1,5 @@
package bdf.types;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
@@ -10,7 +9,6 @@ import bdf.data.BdfStringPointer;
import bdf.data.IBdfDatabase;
import bdf.util.BdfError;
import bdf.util.DataHelpers;
-import tests.Tests;
public class BdfObject implements IBdfType
{
@@ -42,10 +40,25 @@ public class BdfObject implements IBdfType
database = database.getPointer(size_bytes);
}
+ if(database.size() < 0) {
+ database = new BdfDatabase(0);
+ type = BdfTypes.UNDEFINED;
+ return;
+ }
+
// Set the object variable if there is an object specified
- if(type == BdfTypes.STRING) object = database.getString();
- if(type == BdfTypes.ARRAY) object = new BdfArray(lookupTable, database);
- if(type == BdfTypes.NAMED_LIST) object = new BdfNamedList(lookupTable, database);
+ switch(type)
+ {
+ case BdfTypes.STRING:
+ object = database.getString();
+ break;
+ case BdfTypes.ARRAY:
+ object = new BdfArray(lookupTable, database);
+ break;
+ case BdfTypes.NAMED_LIST:
+ object = new BdfNamedList(lookupTable, database);
+ break;
+ }
if(object != null) {
database = null;
@@ -73,6 +86,7 @@ public class BdfObject implements IBdfType
return;
}
+ boolean isDecimalArray = false;
boolean isPrimitiveArray = false;
byte type = 0;
@@ -104,11 +118,13 @@ public class BdfObject implements IBdfType
else if(ptr.isNext("double")) {
type = BdfTypes.ARRAY_DOUBLE;
isPrimitiveArray = true;
+ isDecimalArray = true;
}
else if(ptr.isNext("float")) {
type = BdfTypes.ARRAY_FLOAT;
isPrimitiveArray = true;
+ isDecimalArray = true;
}
// Deserialize a primitive array
@@ -131,7 +147,17 @@ public class BdfObject implements IBdfType
for(;;)
{
- if(ptr2.isNext("true") || ptr2.isNext("false")) {
+ if(ptr2.getChar() == ')') {
+ ptr2.increment();
+ break;
+ }
+
+ if(
+ ptr2.isNext("true") || ptr2.isNext("false") ||
+ ptr2.isNext("infinityd") || ptr2.isNext("-infinityd") ||
+ ptr2.isNext("infinityf") || ptr2.isNext("-infinityf") ||
+ ptr2.isNext("nand") || ptr2.isNext("nanf"))
+ {
size += 1;
}
@@ -139,9 +165,17 @@ public class BdfObject implements IBdfType
{
for(;;)
{
+ if(ptr2.getDataLocation() >= ptr2.getDataLength()) {
+ throw BdfError.createError(BdfError.ERROR_END_OF_FILE, ptr2.getPointer(-1));
+ }
+
c = ptr2.getChar();
- if(c >= '0' && c <= '9' || c == '.' || c == 'e' || c == 'E' || c == '-') {
+ if(c >= 'a' && c <= 'z') {
+ c -= 32;
+ }
+
+ if(c >= '0' && c <= '9' || ((c == '.' || c == 'E') && isDecimalArray) || c == '+' || c == '-') {
ptr2.increment();
continue;
}
@@ -198,6 +232,11 @@ public class BdfObject implements IBdfType
for(int i=0;;i++)
{
+ if(ptr.getChar() == ')') {
+ ptr.increment();
+ break;
+ }
+
if(ptr.isNext("true"))
{
if(type != BdfTypes.ARRAY_BOOLEAN) {
@@ -218,6 +257,66 @@ public class BdfObject implements IBdfType
a[i] = false;
}
+ else if(ptr.isNext("infinityd"))
+ {
+ if(type != BdfTypes.ARRAY_DOUBLE) {
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, ptr);
+ }
+
+ double[] a = (double[]) array;
+ a[i] = Double.POSITIVE_INFINITY;
+ }
+
+ else if(ptr.isNext("-infinityd"))
+ {
+ if(type != BdfTypes.ARRAY_DOUBLE) {
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, ptr);
+ }
+
+ double[] a = (double[]) array;
+ a[i] = Double.NEGATIVE_INFINITY;
+ }
+
+ else if(ptr.isNext("nand"))
+ {
+ if(type != BdfTypes.ARRAY_DOUBLE) {
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, ptr);
+ }
+
+ double[] a = (double[]) array;
+ a[i] = Double.NaN;
+ }
+
+ else if(ptr.isNext("infinityf"))
+ {
+ if(type != BdfTypes.ARRAY_FLOAT) {
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, ptr);
+ }
+
+ float[] a = (float[]) array;
+ a[i] = Float.POSITIVE_INFINITY;
+ }
+
+ else if(ptr.isNext("-infinityf"))
+ {
+ if(type != BdfTypes.ARRAY_FLOAT) {
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, ptr);
+ }
+
+ float[] a = (float[]) array;
+ a[i] = Float.NEGATIVE_INFINITY;
+ }
+
+ else if(ptr.isNext("nanf"))
+ {
+ if(type != BdfTypes.ARRAY_FLOAT) {
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, ptr);
+ }
+
+ float[] a = (float[]) array;
+ a[i] = Float.NaN;
+ }
+
else
{
// Parse a number
@@ -227,11 +326,15 @@ public class BdfObject implements IBdfType
{
c = ptr.getChar();
+ if(c >= 'a' && c <= 'z') {
+ c -= 32;
+ }
+
if(ptr.getDataLocation() > ptr.getDataLength()) {
throw BdfError.createError(BdfError.ERROR_END_OF_FILE, ptr);
}
- if(c >= '0' && c <= '9' || c == '.' || c == 'e' || c == 'E' || c == '-') {
+ if(c >= '0' && c <= '9' || ((c == '.' || c == 'E') && isDecimalArray) || c == '+' || c == '-') {
ptr.increment();
number += c;
continue;
@@ -372,50 +475,103 @@ public class BdfObject implements IBdfType
return;
}
+ if(ptr.isNext("infinityd")) {
+ setDouble(Double.POSITIVE_INFINITY);
+ return;
+ }
+
+ if(ptr.isNext("-infinityd")) {
+ setDouble(Double.NEGATIVE_INFINITY);
+ return;
+ }
+
+ if(ptr.isNext("nand")) {
+ setDouble(Double.NaN);
+ return;
+ }
+
+ if(ptr.isNext("infinityf")) {
+ setFloat(Float.POSITIVE_INFINITY);
+ return;
+ }
+
+ if(ptr.isNext("-infinityf")) {
+ setFloat(Float.NEGATIVE_INFINITY);
+ return;
+ }
+
+ if(ptr.isNext("nanf")) {
+ setFloat(Float.NaN);
+ return;
+ }
+
if(ptr.isNext("undefined")) {
+ database = new BdfDatabase(0);
return;
}
// Parse a number
String number = "";
+ boolean isDecimal = false;
for(;;)
{
c = ptr.getChar();
ptr.increment();
+ if(c >= 'a' && c <= 'z') {
+ c -= 32;
+ }
+
if(ptr.getDataLocation() > ptr.getDataLength()) {
throw BdfError.createError(BdfError.ERROR_END_OF_FILE, ptr);
}
- if(c >= '0' && c <= '9' || c == '.' || c == 'e' || c == 'E' || c == '-') {
+ if(c == '.' || c == 'E') {
+ isDecimal = true;
number += c;
continue;
}
- switch(c)
- {
- case 'D':
- setDouble(Double.parseDouble(number));
- return;
- case 'F':
- setFloat(Float.parseFloat(number));
- return;
- case 'B':
- setByte(Byte.parseByte(number));
- return;
- case 'S':
- setShort(Short.parseShort(number));
- return;
- case 'I':
- setInteger(Integer.parseInt(number));
- return;
- case 'L':
- setLong(Long.parseLong(number));
- return;
+ if(c >= '0' && c <= '9' || c == '+' || c == '-') {
+ number += c;
+ continue;
}
- throw BdfError.createError(BdfError.ERROR_SYNTAX, ptr);
+ if(isDecimal && !(c == 'D' || c == 'F')) {
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, ptr.getPointer(-1));
+ }
+
+ try
+ {
+ switch(c)
+ {
+ case 'D':
+ setDouble(Double.parseDouble(number));
+ return;
+ case 'F':
+ setFloat(Float.parseFloat(number));
+ return;
+ case 'B':
+ setByte(Byte.parseByte(number));
+ return;
+ case 'S':
+ setShort(Short.parseShort(number));
+ return;
+ case 'I':
+ setInteger(Integer.parseInt(number));
+ return;
+ case 'L':
+ setLong(Long.parseLong(number));
+ return;
+ default:
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, ptr);
+ }
+ }
+
+ catch(NumberFormatException e) {
+ throw BdfError.createError(BdfError.ERROR_NUMBER, ptr.getPointer(-number.length()));
+ }
}
}
@@ -673,7 +829,7 @@ public class BdfObject implements IBdfType
break;
case BdfTypes.ARRAY_INTEGER: {
- stream.write(("int(" + calcIndent(indent, it)).getBytes());
+ stream.write("int(".getBytes());
int[] array = this.getIntegerArray();
for(int i=0;i database.size()) {
+ initNew();
+ return;
+ }
+
+ // Get the rest of the data
+ int bdf_size = BdfObject.getSize(flag_ptr);
+
+ if(bdf_size + lookupTable_size_bytes > database.size()) {
+ initNew();
+ return;
+ }
+
+ IBdfDatabase database_bdf = database.getPointer(upto, bdf_size);
+ upto += bdf_size;
+
+ // Get the lookup table
+ ByteBuffer lookupTable_size_buff = DataHelpers.getByteBuffer(database.getPointer(upto, lookupTable_size_bytes));
+ int lookupTable_size = 0;
+
+ switch(lookupTable_size_tag)
+ {
+ case 0:
+ lookupTable_size = lookupTable_size_buff.getInt();
+ break;
+ case 1:
+ lookupTable_size = 0xffff & lookupTable_size_buff.getShort();
+ break;
+ case 2:
+ lookupTable_size = 0xff & lookupTable_size_buff.get();
+ break;
+ }
+
+ if(lookupTable_size + lookupTable_size_bytes + bdf_size > database.size()) {
+ initNew();
+ return;
+ }
+
+ lookupTable = new BdfLookupTable(this, database.getPointer(lookupTable_size_bytes + upto, lookupTable_size));
+ bdf = new BdfObject(lookupTable, database_bdf);
+ }
+
+ catch(IndexOutOfBoundsException e) {
initNew();
- return;
}
-
- int upto = 0;
-
- IBdfDatabase flag_ptr = database.getPointer(upto);
- byte lookupTable_size_tag = BdfObject.getParentFlags(flag_ptr);
- byte lookupTable_size_bytes = 0;
-
- switch(lookupTable_size_tag)
- {
- case 0:
- lookupTable_size_bytes = 4;
- break;
- case 1:
- lookupTable_size_bytes = 2;
- break;
- case 2:
- lookupTable_size_bytes = 1;
- break;
- }
-
- // Get the rest of the data
- int bdf_size = BdfObject.getSize(flag_ptr);
- IBdfDatabase database_bdf = database.getPointer(upto, bdf_size);
- upto += bdf_size;
-
- // Get the lookup table
- ByteBuffer lookupTable_size_buff = DataHelpers.getByteBuffer(database.getPointer(upto, lookupTable_size_bytes));
- int lookupTable_size = 0;
-
- switch(lookupTable_size_tag)
- {
- case 0:
- lookupTable_size = lookupTable_size_buff.getInt();
- break;
- case 1:
- lookupTable_size = 0xffff & lookupTable_size_buff.getShort();
- break;
- case 2:
- lookupTable_size = 0xff & lookupTable_size_buff.get();
- break;
- }
-
- lookupTable = new BdfLookupTable(this, database.getPointer(lookupTable_size_bytes + upto, lookupTable_size));
- bdf = new BdfObject(lookupTable, database_bdf);
- }
-
- public static BdfReader readHumanReadable(String data)
- {
- BdfReader reader = new BdfReader();
- reader.bdf = new BdfObject(reader.lookupTable, new BdfStringPointer(data.toCharArray(), 0));
-
- return reader;
}
public BdfDatabase serialize()
diff --git a/src/bdf/types/BdfReaderHuman.java b/src/bdf/types/BdfReaderHuman.java
new file mode 100644
index 0000000..fe9c73f
--- /dev/null
+++ b/src/bdf/types/BdfReaderHuman.java
@@ -0,0 +1,29 @@
+package bdf.types;
+
+import bdf.data.BdfStringPointer;
+import bdf.util.BdfError;
+
+public class BdfReaderHuman extends BdfReader
+{
+ public BdfReaderHuman(String data)
+ {
+ BdfStringPointer ptr = new BdfStringPointer(data.toCharArray(), 0);
+
+ ptr.ignoreBlanks();
+ bdf = new BdfObject(lookupTable, ptr);
+
+ try {
+ ptr.ignoreBlanks();
+ }
+
+ catch(BdfError e) {
+ if(e.getType() == BdfError.ERROR_END_OF_FILE) {
+ return;
+ } else {
+ throw e;
+ }
+ }
+
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, ptr);
+ }
+}
diff --git a/src/bdf/util/BdfError.java b/src/bdf/util/BdfError.java
index d704313..0007e45 100644
--- a/src/bdf/util/BdfError.java
+++ b/src/bdf/util/BdfError.java
@@ -8,10 +8,16 @@ public class BdfError extends RuntimeException
private static final String[] ERRORS = {
"Syntax error",
"End of file",
+ "Unescaped comment",
+ "Unescaped string",
+ "Number format error",
};
public static final int ERROR_SYNTAX = 0;
public static final int ERROR_END_OF_FILE = 1;
+ public static final int ERROR_UNESCAPED_COMMENT = 2;
+ public static final int ERROR_UNESCAPED_STRING = 3;
+ public static final int ERROR_NUMBER = 4;
public static BdfError createError(int errorID, BdfStringPointer ptr)
{
@@ -33,13 +39,7 @@ public class BdfError extends RuntimeException
continue;
}
- if(array[i] == '\t') {
- at = at / 4 * 4 + 4;
- }
-
- else {
- at += 1;
- }
+ at += 1;
}
int line_size = 0;
@@ -47,16 +47,16 @@ public class BdfError extends RuntimeException
for(int i=start_of_line;i 1000) {
+ System.out.println("" + i + ": " + done);
+ start += 1000;
+ done = 0;
+ i += 1;
+ }
+
+ done += 1;
+
+ rand.read(buffer);
+ new BdfReader(buffer);
}
-
- reader.serializeHumanReadable(System.out);
-
- IBdfDatabase db = reader.serialize();
- displayHex(db);
-
- reader = new BdfReader(db);
-
- reader.serializeHumanReadable(System.out);
}
}