diff --git a/.gitignore b/.gitignore
index 894b6fe..2700323 100755
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
/bin/
/*.bdf
+/*.hbdf
diff --git a/README.md b/README.md
index 42a5636..fc37d69 100644
--- a/README.md
+++ b/README.md
@@ -8,26 +8,23 @@
- 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
+- Undefined
- Boolean
- Integer
- Long
@@ -35,20 +32,33 @@ purposes, but it currently can't parse the human readable serialized string to a
- Byte
- Double
- Float
+- Boolean Array
+- Integer Array
+- Long Array
+- Short Array
+- Byte Array
+- Double Array
+- Float Array
- String
- Array
- Named List
-- Empty
### Creating an object
-You will need to create a new object to store any data, use a `BdfObject` instance.
-You can input serialized data into `BdfObject` via a `BdfDatabase`.
+You will need to generate a BdfObject to serialize anything,
+this can be done by first generating a BdfReader, or generating
+a new object via an existing BdfObject.
```java
-// New BDF object
-BdfObject bdf = new BdfObject();
+// Create a reader object
+BdfReader reader = new BdfReader();
+
+// Get the BdfObject instance
+BdfObject bdf = reader.getObject();
+
+// Generate another BdfObject instance
+BdfObject bdf_new = bdf.newObject();
// Get an integer
int v = bdf.getInteger();
@@ -56,6 +66,16 @@ int v = bdf.getInteger();
// Set an integer
bdf.setInteger(5);
+// 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();
@@ -66,243 +86,216 @@ if(type == BdfTypes.INTEGER)
}
// Serialize the BDF object
-byte[] data = bdf.serialize().getBytes();
+byte[] data = bdf->serialize(&data, &data_size);
+// 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"));
-// Load another BDF object with the serialized bytes
-BdfObject bdf2 = new BdfObject(new BdfDatabase(data));
-
-```
-
-A `BdfFileManager`
-instance can be used in the same way as a `BdfObject`, but it also needs a String parameter
-for the path of the file. The file can be written with `BdfFileManager.saveDatabase()`.
-A `BdfFileManager` is an instance of `BdfObject`, a `BdfFileManager` can be casted to
-a `BdfObject`.
-
-```java
-
-// Open a file
-BdfFileManager bdf = new BdfFileManager("file.bdf");
-
-// Save the database
-bdf.saveDatabase();
-
-// The file can be casted to a BdfObject
-BdfObject bdf2 = (BdfObject) bdf;
-
-// Bdf
-System.out.println(bdf instanceof BdfObject); // true
+// 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 `BdfObject`.
-The array is called with `new BdfArray()`. It can hold information, get
-the size of the array with `BdfArray.size()`, remove elements with
-`BdfArray.remove(index)`, set indexes with `BdfArray.set(index, BdfObject)`,
-and add elements with `BdfArray.add(BdfObject)`. Arrays also
-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
-// New BDF Object
-BdfObject bdf = new BdfObject();
+BdfReader reader = new BdfReader();
+BdfObject bdf = reader.getObject();
-// New BDF Array
-BdfArray array = new BdfArray();
+// Can be created from a bdf object
+BdfArray array = bdf.newArray();
-// Size
+// Get the length of an array
int size = array.size();
-// Remove
-array.remove(3); // Could be any number
+// Remove any index from an array
+array.remove(3);
-// Set - Could be any number with any object
-array.set(4, BdfObject.withString("A String"));
+// Set an object to an index of an array
+array.set(4, bdf.newObject().setString("A String"));
-// Add - Could be any object
-array.add(BdfObject.withByte(53));
+// Add an object to an array
+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
-Named lists can be used to store data under strings,
+Named lists can be used to store data under ids/strings
to be used like variables in a program. A named list
-can be created with `new BdfNamedList()` and it
-has the ability to set with `BdfNamedList.set(String, BdfObject)`,
-remove with `BdfNamedList.remove(String)`, and check
-for a key with `BdfNamedList.contains(String)`. It also has
-features to get all the keys with `BdfNamedList.getKeys()`.
-Named lists also have Iterator support and are an instance of
-`Iterable`.
+can be created similar to an array.
```java
-// New bdf named list
-BdfNamedList list = new BdfNamedList();
+BdfReader reader = new BdfReader();
+BdfObject bdf = reader.getObject();
-// Set an element with a value
-list.set("key1", BdfObject.withInteger(5));
+// New named list
+BdfNamedList list = bdf.newNamedList();
+
+// Set an element to the named list
+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 = 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
-String[] keys = list.getKeys();
+int[] keys = list.getKeys();
// Iterate over the lists keys
-for(String key : keys)
+for(int key : keys)
{
-
+ // Get the keys name
+ String key_name = bdf.getKeyName(key);
}
```
-### Saving classes
+### Human readable representation
-Classes can be saved with `BdfClassManager` and by
-implementing the `IBdfClassManager` interface,
-adding 2 functions `BdfClassLoad` and `BdfClassSave`.
-`BdfClassLoad` is for checking and loading data from
-bdf into the classes variables, while `BdfClassSave`
-is for packing pre-existing variables into bdf format.
-A BdfClassManager can be used to pass the `IBdfClassManager`
-interface into.
+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.
-A class with `IBdfClassManager` to save the data
-could look like this:
-
-```java
-
-class HelloWorld implements IBdfClassManager
-{
- int iterator = 0;
-
- @Override
- public void BdfClassLoad(BdfObject bdf)
- {
- // Load scripts here
-
- // Get the named list
- BdfNamedList nl = bdf.getNamedList();
-
- // Set the iterator stored in bdf
- int iterator = nl.get("iterator").getInteger();
- }
-
- @Override
- public void BdfClassSave(BdfObject bdf)
- {
- // Save scripts here
-
- // Create a named list
- BdfNamedList nl = new BdfNamedList();
-
- // Set the iterator to the named list
- nl.set("iterator", BdfObject.withInteger(iterator));
-
- // Store the named list
- bdf.setNamedList(nl);
- }
-
- public void hello()
- {
- // Increase the iterator by 1
- iterator++;
-
- // Say "Hello, World! Script executed times!"
- System.out.println("Hello, World! Script executed "+iterator+" times!");
- }
-
-}
-
-```
-
-A script to manage this could look something like this:
-
-```java
+```hbdf
/*
- Get a new BdfObject instance, it could be existing,
- or from another file, BdfArray, or BdfNamedList instance.
+ A Named List is represented
+ by an opening tag and a closing
+ tag { }
*/
-BdfObject bdf = new BdfObject();
+{
+ /*
+ A key value pair can be stored
+ within a Named List with a string
+ property
+ */
+ "hello": "world",
-// Create the HelloWorld class
-HelloWorld hello = new HelloWorld();
+ /*
+ 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,
-// Get a new BdfClassManager instance to deal with BDF data
-BdfClassManager manager = new BdfClassManager(hello);
+ /*
+ This is a boolean. It can
+ be true or false.
+ */
+ "boolTest": false,
-// Give the manager an existing BdfObject instance
-manager.setBdf(bdf);
+ /*
+ 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.
-// Load the classes bdf data
-manager.load();
+ The tag at the start can be:
+ - int
+ - short
+ - long
+ - byte
+ - double
+ - float
+ - bool
+ */
+ "intArray": int (
+ 64I, 42I, 63I,
+ 22I, 96I, -12I,
+ ),
-// Call the hello world function
-hello.hello();
+ /*
+ 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,
+ )
-// Save the classes bdf data
-manager.save();
+ /*
+ 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 */
+}
```
-### Implementation details
+### Special notes
-All integer data types used are signed and Big Endian.
+Don't mix bdf types between different
+readers, this will cause problems.
-**Type (1 byte)**
-```
-0: BOOLEAN (1 byte, 0x00 or 0x01)
-1: INTEGER (4 bytes)
-2: LONG (8 bytes)
-3: SHORT (2 bytes)
-4: BYTE (1 byte)
-5: DOUBLE (8 bytes)
-6: FLOAT (4 bytes)
+```java
-7: STRING
-8: ARRAY
-9: NAMED_LIST
+BdfReader reader1 = new BdfReader();
+BdfReader reader2 = new BdfReader();
-10: EMPTY (0 bytes)
+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"));
-11: ARRAY_BOOLEAN
-12: ARRAY_INTEGER
-13: ARRAY_LONG
-14: ARRAY_SHORT
-15: ARRAY_BYTE
-16: ARRAY_DOUBLE
-17: ARRAY_FLOAT
```
-**Object**
-- Type (signed byte, 1 byte)
-- Payload (Any type, variable length)
-
-**NamedList**
-- Key size (signed int, 4 bytes)
-- Key (variable length)
-- Payload size (signed int, 4 bytes)
-- Payload (Object, variable length)
-
-**Array**
-- Payload size (signed int, 4 bytes)
-- Payload (Object, variable length)
diff --git a/src/bdf/classes/BdfClassManager.java b/src/bdf/classes/BdfClassManager.java
deleted file mode 100755
index 28cff0e..0000000
--- a/src/bdf/classes/BdfClassManager.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package bdf.classes;
-
-import bdf.types.BdfObject;
-
-public class BdfClassManager
-{
- protected IBdfClassManager method;
- protected BdfObject object = new BdfObject();
-
- public BdfClassManager(IBdfClassManager method)
- {
- // Save some variables for later
- this.method = method;
- }
-
- public void setBdf(BdfObject bdf) {
- this.object = bdf;
- }
-
- public BdfObject getBdf() {
- return this.object;
- }
-
- public void save(BdfObject bdf) {
- method.BdfClassSave(bdf);
- }
-
- public void load(BdfObject bdf) {
- method.BdfClassLoad(bdf);
- }
-
- public void save() {
- this.save(this.object);
- }
-
- public void load() {
- this.load(this.object);
- }
-}
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/BdfDatabase.java b/src/bdf/data/BdfDatabase.java
index 650dd02..7648f7a 100644
--- a/src/bdf/data/BdfDatabase.java
+++ b/src/bdf/data/BdfDatabase.java
@@ -5,16 +5,12 @@ import java.io.OutputStream;
public class BdfDatabase implements IBdfDatabase
{
- private static final int STREAM_CHUNK_SIZE = 1024*1024;
+ static final int STREAM_CHUNK_SIZE = 1024*1024;
- private byte[] database;
- private int location;
- private int size;
+ byte[] database;
public BdfDatabase(byte[] bytes) {
database = bytes;
- size = bytes.length;
- location = 0;
}
public BdfDatabase(String str) {
@@ -23,28 +19,28 @@ public class BdfDatabase implements IBdfDatabase
public BdfDatabase(int size) {
this.database = new byte[size];
- this.location = 0;
- this.size = size;
- }
-
- private BdfDatabase() {
}
@Override
- public IBdfDatabase getAt(int start, int end)
+ public IBdfDatabase getCopy(int start, int end)
{
byte[] database = new byte[end - start];
for(int i=0;i= data.length) {
+ throw BdfError.createError(BdfError.ERROR_END_OF_FILE, this);
+ }
+
+ char c = getChar();
+
+ // 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;
+ }
+
+ increment();
+ }
+ }
+
+ // In the format "abc\n\t\u0003..."
+ public String getQuotedString()
+ {
+ if(getChar() != '"') {
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, this);
+ }
+
+ increment();
+ String str = "";
+
+ for(;;)
+ {
+ if(offset >= data.length) {
+ throw BdfError.createError(BdfError.ERROR_UNESCAPED_STRING, this);
+ }
+
+ char c = getChar();
+
+ // Check for back slashes
+ if(c == '\\')
+ {
+ 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_UNESCAPED_STRING, getPointer(1));
+ }
+
+ char[] hex = getCharArray(1, 4);
+ char unicode = (char)0;
+ int m = 1;
+
+ for(int j=hex.length-1;j>=0;j--)
+ {
+ c = hex[j];
+
+ if(c >= '0' && c <= '9') {
+ unicode += (char)(m * (c - '0'));
+ }
+
+ else if(c >= 'a' && c <= 'f') {
+ unicode += (char)(m * (c - 'a' + 10));
+ }
+
+ else {
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, getPointer(1 + (hex.length-j-1)));
+ }
+
+ m *= 16;
+ }
+
+ str += unicode;
+ increment(5);
+
+ break;
+ }
+ default:
+ str += "\\" + c;
+ }
+ }
+
+ else if(c == '\n') {
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, this);
+ }
+
+ else if(c == '"') {
+ increment();
+ break;
+ }
+
+ else {
+ increment();
+ str += c;
+ }
+ }
+
+ return str;
+ }
+
+ public boolean isNext(String check)
+ {
+ if(check.length() + offset > data.length) {
+ return false;
+ }
+
+ for(int i=0;i= 'A' && c <= 'Z') ? (c + 32) : c);
+
+ if(c != check.charAt(i)) {
+ return false;
+ }
+ }
+
+ increment(check.length());
+
+ return true;
+ }
+
+ public boolean isInteger()
+ {
+ for(int i=offset;i= '0' && c <= '9') {
+ continue;
+ }
+
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, new BdfStringPointer(data, i));
+ }
+
+ throw BdfError.createError(BdfError.ERROR_END_OF_FILE, new BdfStringPointer(data, data.length - 1));
+ }
+}
diff --git a/src/bdf/data/IBdfDatabase.java b/src/bdf/data/IBdfDatabase.java
index 30cd911..8ca3658 100644
--- a/src/bdf/data/IBdfDatabase.java
+++ b/src/bdf/data/IBdfDatabase.java
@@ -5,7 +5,7 @@ import java.io.OutputStream;
public interface IBdfDatabase
{
- public IBdfDatabase getAt(int start, int end);
+ public IBdfDatabase getCopy(int start, int end);
public IBdfDatabase getPointer(int location, int size);
public IBdfDatabase getPointer(int location);
@@ -17,9 +17,18 @@ public interface IBdfDatabase
public byte[] getBytes();
public byte[] getBytes(int start, int size);
+ public byte getByte();
public byte getByte(int i);
public String getString();
- public void setBytes(int pos, byte[] bytes);
+ public void setBytes(byte[] bytes, int offset, int length);
+ public void setBytes(byte[] bytes, int offset);
+ public void setBytes(byte[] bytes);
+
+ public void setBytes(IBdfDatabase bytes, int offset, int length);
+ public void setBytes(IBdfDatabase bytes, int offset);
+ public void setBytes(IBdfDatabase bytes);
+
public void setByte(int pos, byte b);
+ public void setByte(byte b);
}
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 4c46ca9..0000000
--- a/src/bdf/file/BdfFileManager.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package bdf.file;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.zip.DeflaterOutputStream;
-
-import bdf.data.BdfDatabase;
-import bdf.types.BdfObject;
-import bdf.util.FileHelpers;
-
-public class BdfFileManager extends BdfObject
-{
- 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 DeflaterOutputStream(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 5ff46e3..ca24133 100644
--- a/src/bdf/types/BdfArray.java
+++ b/src/bdf/types/BdfArray.java
@@ -5,18 +5,64 @@ import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
+import bdf.data.BdfStringPointer;
import bdf.data.IBdfDatabase;
-import bdf.util.DataHelpers;
+import bdf.util.BdfError;
public class BdfArray implements IBdfType, Iterable
{
- protected ArrayList elements = new ArrayList();
+ protected ArrayList elements;
- public BdfArray() {
+ BdfArray(BdfLookupTable lookupTable, BdfStringPointer ptr)
+ {
+ this.elements = new ArrayList();
+
+ ptr.increment();
+
+ // [..., ...]
+ while(true)
+ {
+ ptr.ignoreBlanks();
+
+ if(ptr.getChar() == ']') {
+ ptr.increment();
+ return;
+ }
+
+ add(new BdfObject(lookupTable, ptr));
+
+ // There should be a comma after this
+ ptr.ignoreBlanks();
+
+ char c = ptr.getChar();
+
+ if(c == ']') {
+ ptr.increment();
+ return;
+ }
+
+ if(c != ',') {
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, ptr);
+ }
+
+ ptr.increment();
+ ptr.ignoreBlanks();
+ }
}
- public BdfArray(IBdfDatabase data)
+ BdfArray(BdfLookupTable lookupTable, int size)
{
+ this.elements = new ArrayList(size);
+
+ for(int i=0;i();
+
// Create an iterator value to loop over the data
int i = 0;
@@ -24,44 +70,42 @@ public class BdfArray implements IBdfType, Iterable
while(i < data.size())
{
// Get the size of the object
- int size = DataHelpers.getByteBuffer(data.getPointer(i, Integer.BYTES)).getInt();
+ int size = BdfObject.getSize(data.getPointer(i));
+
+ if(size <= 0 || i + size > data.size()) {
+ return;
+ }
// Get the object
- BdfObject object = new BdfObject(data.getPointer((i+Integer.BYTES), size));
+ BdfObject object = new BdfObject(lookupTable, data.getPointer(i, size));
// Add the object to the elements list
elements.add(object);
// Increase the iterator by the amount of bytes
- i += Integer.BYTES+size;
+ i += size;
}
}
@Override
- public int serializeSeeker()
+ public int serializeSeeker(int[] locations)
{
int size = 0;
for(BdfObject o : elements) {
- size += o.serializeSeeker();
- size += 4;
+ size += o.serializeSeeker(locations);
}
return size;
}
@Override
- public int serialize(IBdfDatabase database)
+ public int serialize(IBdfDatabase database, int[] locations, byte flags)
{
int pos = 0;
- for(BdfObject o : elements)
- {
- int size = o.serialize(database.getPointer(pos + 4));
- database.setBytes(pos, DataHelpers.serializeInt(size));
-
- pos += size;
- pos += 4;
+ for(BdfObject o : elements) {
+ pos += o.serialize(database.getPointer(pos), locations, (byte)0);
}
return pos;
@@ -119,9 +163,10 @@ public class BdfArray implements IBdfType, Iterable
return this;
}
- public BdfArray remove(int index) {
+ public BdfObject remove(int index) {
+ BdfObject bdf = elements.get(index);
elements.remove(index);
- return this;
+ return bdf;
}
public BdfArray remove(BdfObject bdf) {
@@ -173,5 +218,12 @@ public class BdfArray implements IBdfType, Iterable
}
};
}
+
+ @Override
+ public void getLocationUses(int[] locations) {
+ for(BdfObject element : elements) {
+ element.getLocationUses(locations);
+ }
+ }
}
diff --git a/src/bdf/types/BdfLookupTable.java b/src/bdf/types/BdfLookupTable.java
new file mode 100644
index 0000000..d599389
--- /dev/null
+++ b/src/bdf/types/BdfLookupTable.java
@@ -0,0 +1,139 @@
+package bdf.types;
+
+import java.io.OutputStream;
+import java.util.ArrayList;
+
+import bdf.data.IBdfDatabase;
+import bdf.util.DataHelpers;
+
+class BdfLookupTable implements IBdfType
+{
+ private ArrayList keys;
+ private BdfReader reader;
+
+ BdfLookupTable(BdfReader reader)
+ {
+ this.keys = new ArrayList();
+ this.reader = reader;
+ }
+
+ BdfLookupTable(BdfReader reader, IBdfDatabase database)
+ {
+ this.keys = new ArrayList();
+ this.reader = reader;
+
+ for(int i=0;i database.size()) {
+ return;
+ }
+
+ keys.add(database.getBytes(i, key_size));
+
+ i += key_size;
+ }
+ }
+
+ int getLocation(byte[] name)
+ {
+ for(int i=0;i= 0 && location < keys.size();
+ }
+
+ byte[] getName(int location) {
+ return keys.get(location);
+ }
+
+ @Override
+ public int serialize(IBdfDatabase database, int[] locations, byte flags)
+ {
+ int upto = 0;
+
+ for(int i=0;i 0) {
+ locations[i] = next;
+ next += 1;
+ } else {
+ locations[i] = -1;
+ }
+ }
+
+ return locations;
+ }
+
+ @Override
+ public void serializeHumanReadable(OutputStream stream, BdfIndent indent, int it) {
+ }
+
+ @Override
+ public void getLocationUses(int[] locations) {
+ }
+
+ public int size() {
+ return keys.size();
+ }
+}
diff --git a/src/bdf/types/BdfNamedList.java b/src/bdf/types/BdfNamedList.java
index e0fe021..bc6d3a4 100644
--- a/src/bdf/types/BdfNamedList.java
+++ b/src/bdf/types/BdfNamedList.java
@@ -2,43 +2,140 @@ package bdf.types;
import java.io.IOException;
import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
+import bdf.data.BdfStringPointer;
import bdf.data.IBdfDatabase;
+import bdf.util.BdfError;
import bdf.util.DataHelpers;
public class BdfNamedList implements IBdfType
{
protected class Element
{
- public byte[] key;
+ public int key;
public BdfObject object;
}
protected ArrayList elements = new ArrayList();
+ protected BdfLookupTable lookupTable;
- public BdfNamedList() {
+ BdfNamedList(BdfLookupTable lookupTable, BdfStringPointer ptr)
+ {
+ this.lookupTable = lookupTable;
+ ptr.increment();
+
+ // {"key": ..., "key2": ...}
+ while(true)
+ {
+ ptr.ignoreBlanks();
+
+ char c = ptr.getChar();
+
+ if(c == '}') {
+ ptr.increment();
+ break;
+ }
+
+ if(c != '"') {
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, ptr);
+ }
+
+ String key = ptr.getQuotedString();
+
+ // There should be a colon after this
+ ptr.ignoreBlanks();
+ if(ptr.getChar() != ':') {
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, ptr);
+ }
+
+ ptr.increment();
+ ptr.ignoreBlanks();
+
+ set(key, new BdfObject(lookupTable, ptr));
+
+ // There should be a comma after this
+ ptr.ignoreBlanks();
+
+ c = ptr.getChar();
+
+ if(c == '}') {
+ ptr.increment();
+ return;
+ }
+
+ if(c != ',') {
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, ptr);
+ }
+
+ ptr.increment();
+ ptr.ignoreBlanks();
+ }
+ }
+
+ BdfNamedList(BdfLookupTable lookupTable) {
+ this.lookupTable = lookupTable;
}
- public BdfNamedList(IBdfDatabase data)
+ BdfNamedList(BdfLookupTable lookupTable, IBdfDatabase data)
{
+ this.lookupTable = lookupTable;
+
// Create an iterator value to loop over the data
int i = 0;
// Loop over the data
while(i < data.size())
{
- // Get the key
- int key_size = DataHelpers.getByteBuffer(data.getPointer(i, 4)).getInt();
- i += 4;
- byte[] key = data.getPointer(i, key_size).getBytes();
-
// Get the object
+ int key_size = 0;
+ 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;
+
+ switch(key_size_bytes)
+ {
+ case 2:
+ key_size = 1;
+ break;
+ case 1:
+ key_size = 2;
+ break;
+ case 0:
+ key_size = 4;
+ break;
+ }
+
+ // Get the key
+ ByteBuffer key_buff = DataHelpers.getByteBuffer(data.getPointer(i, key_size));
+ int key = 0;
+
+ switch(key_size_bytes)
+ {
+ case 2:
+ key = 0xff & key_buff.get();
+ break;
+ case 1:
+ key = 0xffff & key_buff.getShort();
+ break;
+ case 0:
+ key = key_buff.getInt();
+ break;
+ }
+
+ if(!lookupTable.hasLocation(key)) {
+ return;
+ }
+
i += key_size;
- int object_size = DataHelpers.getByteBuffer(data.getPointer(i, 4)).getInt();
- i += 4;
- BdfObject object = new BdfObject(data.getPointer(i, object_size));
// Create a new element and save some data to it
Element element = new Element();
@@ -47,48 +144,65 @@ public class BdfNamedList implements IBdfType
// Add the object to the elements list
elements.add(element);
-
- // Increase the iterator by the amount of bytes
- i += object_size;
}
}
@Override
- public int serialize(IBdfDatabase database)
+ public int serialize(IBdfDatabase database, int[] locations, byte flags)
{
int pos = 0;
for(Element o : elements)
{
- database.setBytes(pos, DataHelpers.serializeInt(o.key.length));
+ int location = locations[o.key];
- pos += 4;
+ byte size_bytes_tag;
+ byte size_bytes;
- database.setBytes(pos, o.key);
+ if(location > 65535) { // >= 2 ^ 16
+ size_bytes_tag = 0;
+ size_bytes = 4;
+ } else if(location > 255) { // >= 2 ^ 8
+ size_bytes_tag = 1;
+ size_bytes = 2;
+ } else { // < 2 ^ 8
+ size_bytes_tag = 2;
+ size_bytes = 1;
+ }
- pos += o.key.length;
+ int size = o.object.serialize(database.getPointer(pos), locations, size_bytes_tag);
+ int offset = pos + size;
- int size = o.object.serialize(database.getPointer(pos + 4, database.size() - (pos + 4)));
+ byte[] bytes = DataHelpers.serializeInt(location);
- database.setBytes(pos, DataHelpers.serializeInt(size));
+ for(int i=0;i 65535) { // >= 2 ^ 16
+ size += 4;
+ } else if(location > 255) { // >= 2 ^ 8
+ size += 2;
+ } else { // < 2 ^ 8
+ size += 1;
+ }
+
+ size += o.object.serializeSeeker(locations);
}
return size;
@@ -114,7 +228,7 @@ public class BdfNamedList implements IBdfType
stream.write(indent.indent.getBytes());
}
- stream.write((DataHelpers.serializeString(new String(e.key, StandardCharsets.UTF_8)) + ": ").getBytes());
+ stream.write((DataHelpers.serializeString(new String(lookupTable.getName(e.key))) + ": ").getBytes());
e.object.serializeHumanReadable(stream, indent, it + 1);
if(elements.size() > i+1) {
@@ -131,19 +245,16 @@ public class BdfNamedList implements IBdfType
stream.write('}');
}
- public BdfObject get(String key)
+ public BdfObject get(int key)
{
// Get the object to send back
BdfObject object = null;
- // Convert the key to bytes
- byte[] key_bytes = key.getBytes();
-
// Loop over the elements
for(Element e : elements)
{
// Is this the element key
- if(DataHelpers.bytesAreEqual(e.key, key_bytes))
+ if(e.key == key)
{
// Set the object
object = e.object;
@@ -154,7 +265,7 @@ public class BdfNamedList implements IBdfType
}
// Get a bdf object
- BdfObject o = new BdfObject();
+ BdfObject o = new BdfObject(lookupTable);
// Set the bdf object
this.set(key, o);
@@ -163,11 +274,8 @@ public class BdfNamedList implements IBdfType
return o;
}
- public BdfNamedList remove(String key)
+ public BdfObject remove(int key)
{
- // Convert the key to bytes
- byte[] key_bytes = key.getBytes();
-
// Loop over the elements
for(int i=0;i 1)
- {
- // Get the type and database values
- type = data.getByte(0);
- database = data.getPointer(1, data.size() - 1);
-
- // Set the object variable if there is an object specified
- if(type == BdfTypes.STRING) object = database.getString();
- if(type == BdfTypes.ARRAY) object = new BdfArray(database);
- if(type == BdfTypes.NAMED_LIST) object = new BdfNamedList(database);
-
- if(object != null) {
- database = null;
- }
+ this.lookupTable = lookupTable;
+
+ // Get the type and database values
+ int flags = 0xff & data.getByte(0);
+ type = (byte)(flags % 18);
+ flags = (byte)((flags - type) / 18);
+ int size_bytes = getSizeBytes(flags % 3);
+
+ database = data.getPointer(1);
+
+ // Skip the size bytes if size is stored
+ if(shouldStoreSize(type)) {
+ database = database.getPointer(size_bytes);
}
- else
- {
- // Create a new database
+ if(database.size() < 0) {
database = new BdfDatabase(0);
+ type = BdfTypes.UNDEFINED;
+ return;
+ }
+
+ // Set the object variable if there is an object specified
+ 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;
+ }
+ }
+
+ BdfObject(BdfLookupTable lookupTable, BdfStringPointer ptr)
+ {
+ this.lookupTable = lookupTable;
+
+ char c = ptr.getChar();
+
+ if(c == '{') {
+ setNamedList(new BdfNamedList(lookupTable, ptr));
+ return;
+ }
+
+ if(c == '[') {
+ setArray(new BdfArray(lookupTable, ptr));
+ return;
+ }
+
+ if(c == '"') {
+ setString(ptr.getQuotedString());
+ return;
+ }
+
+ boolean isDecimalArray = false;
+ boolean isPrimitiveArray = false;
+ byte type = 0;
+
+ if(ptr.isNext("int")) {
+ type = BdfTypes.ARRAY_INTEGER;
+ isPrimitiveArray = true;
+ }
+
+ else if(ptr.isNext("long")) {
+ type = BdfTypes.ARRAY_LONG;
+ isPrimitiveArray = true;
+ }
+
+ else if(ptr.isNext("byte")) {
+ type = BdfTypes.ARRAY_BYTE;
+ isPrimitiveArray = true;
+ }
+
+ else if(ptr.isNext("short")) {
+ type = BdfTypes.ARRAY_SHORT;
+ isPrimitiveArray = true;
+ }
+
+ else if(ptr.isNext("bool")) {
+ type = BdfTypes.ARRAY_BOOLEAN;
+ isPrimitiveArray = true;
+ }
+
+ 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
+ if(isPrimitiveArray)
+ {
+ ptr.ignoreBlanks();
+
+ if(ptr.getChar() != '(') {
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, ptr);
+ }
+
+ ptr.increment();
+ ptr.ignoreBlanks();
+
+ // Get the size of the array
+ int size = 0;
+
+ // Get a copy of the pointer
+ BdfStringPointer ptr2 = ptr.getPointer(0);
+
+ for(;;)
+ {
+ 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;
+ }
+
+ else
+ {
+ for(;;)
+ {
+ if(ptr2.getDataLocation() >= ptr2.getDataLength()) {
+ throw BdfError.createError(BdfError.ERROR_END_OF_FILE, ptr2.getPointer(-1));
+ }
+
+ c = ptr2.getChar();
+
+ if(c >= 'a' && c <= 'z') {
+ c -= 32;
+ }
+
+ if(c >= '0' && c <= '9' || ((c == '.' || c == 'E') && isDecimalArray) || c == '+' || c == '-') {
+ ptr2.increment();
+ continue;
+ }
+
+ if(c == 'B' || c == 'S' || c == 'I' || c == 'L' || c == 'D' || c == 'F') {
+ ptr2.increment();
+ size += 1;
+ break;
+ }
+
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, ptr2);
+ }
+ }
+
+ ptr2.ignoreBlanks();
+
+ if(ptr2.getChar() == ',') {
+ ptr2.increment();
+ ptr2.ignoreBlanks();
+ }
+
+ if(ptr2.getChar() == ')') {
+ ptr2.increment();
+ break;
+ }
+ }
+
+ Object array = null;
+
+ switch(type)
+ {
+ case BdfTypes.ARRAY_BOOLEAN:
+ array = new boolean[size];
+ break;
+ case BdfTypes.ARRAY_BYTE:
+ array = new byte[size];
+ break;
+ case BdfTypes.ARRAY_DOUBLE:
+ array = new double[size];
+ break;
+ case BdfTypes.ARRAY_FLOAT:
+ array = new float[size];
+ break;
+ case BdfTypes.ARRAY_INTEGER:
+ array = new int[size];
+ break;
+ case BdfTypes.ARRAY_LONG:
+ array = new long[size];
+ break;
+ case BdfTypes.ARRAY_SHORT:
+ array = new short[size];
+ break;
+ }
+
+ for(int i=0;;i++)
+ {
+ if(ptr.getChar() == ')') {
+ ptr.increment();
+ break;
+ }
+
+ if(ptr.isNext("true"))
+ {
+ if(type != BdfTypes.ARRAY_BOOLEAN) {
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, ptr);
+ }
+
+ boolean[] a = (boolean[]) array;
+ a[i] = true;
+ }
+
+ else if(ptr.isNext("false"))
+ {
+ if(type != BdfTypes.ARRAY_BOOLEAN) {
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, ptr);
+ }
+
+ boolean[] a = (boolean[]) array;
+ 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
+ String number = "";
+
+ for(;;)
+ {
+ 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') && isDecimalArray) || c == '+' || c == '-') {
+ ptr.increment();
+ number += c;
+ continue;
+ }
+
+ switch(c)
+ {
+ case 'D':
+ {
+ if(type != BdfTypes.ARRAY_DOUBLE)
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, ptr);
+
+ double[] a = (double[]) array;
+ a[i] = Double.parseDouble(number);
+
+ ptr.increment();
+ break;
+ }
+
+ case 'F':
+ {
+ if(type != BdfTypes.ARRAY_FLOAT)
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, ptr);
+
+ float[] a = (float[]) array;
+ a[i] = Float.parseFloat(number);
+
+ ptr.increment();
+ break;
+ }
+
+ case 'I':
+ {
+ if(type != BdfTypes.ARRAY_INTEGER)
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, ptr);
+
+ int[] a = (int[]) array;
+ a[i] = Integer.parseInt(number);
+
+ ptr.increment();
+ break;
+ }
+
+ case 'L':
+ {
+ if(type != BdfTypes.ARRAY_LONG)
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, ptr);
+
+ long[] a = (long[]) array;
+ a[i] = Long.parseLong(number);
+
+ ptr.increment();
+ break;
+ }
+
+ case 'S':
+ {
+ if(type != BdfTypes.ARRAY_SHORT)
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, ptr);
+
+ short[] a = (short[]) array;
+ a[i] = Short.parseShort(number);
+
+ ptr.increment();
+ break;
+ }
+
+ case 'B':
+ {
+ if(type != BdfTypes.ARRAY_BYTE)
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, ptr);
+
+ byte[] a = (byte[]) array;
+ a[i] = Byte.parseByte(number);
+
+ ptr.increment();
+ break;
+ }
+
+ default:
+ throw BdfError.createError(BdfError.ERROR_SYNTAX, ptr);
+ }
+
+ break;
+ }
+ }
+
+ // int (420I, 23I )
+
+ ptr.ignoreBlanks();
+
+ if(ptr.getChar() == ',') {
+ ptr.increment();
+ ptr.ignoreBlanks();
+ }
+
+ if(ptr.getChar() == ')') {
+ ptr.increment();
+ break;
+ }
+ }
+
+ switch(type)
+ {
+ case BdfTypes.ARRAY_BOOLEAN:
+ setBooleanArray((boolean[])array);
+ break;
+ case BdfTypes.ARRAY_BYTE:
+ setByteArray((byte[])array);
+ break;
+ case BdfTypes.ARRAY_DOUBLE:
+ setDoubleArray((double[])array);
+ break;
+ case BdfTypes.ARRAY_FLOAT:
+ setFloatArray((float[])array);
+ break;
+ case BdfTypes.ARRAY_INTEGER:
+ setIntegerArray((int[])array);
+ break;
+ case BdfTypes.ARRAY_LONG:
+ setLongArray((long[])array);
+ break;
+ case BdfTypes.ARRAY_SHORT:
+ setShortArray((short[])array);
+ break;
+ }
+
+ return;
+ }
+
+ if(ptr.isNext("true")) {
+ setBoolean(true);
+ return;
+ }
+
+ if(ptr.isNext("false")) {
+ setBoolean(false);
+ 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 == '.' || c == 'E') {
+ isDecimal = true;
+ number += c;
+ continue;
+ }
+
+ if(c >= '0' && c <= '9' || c == '+' || c == '-') {
+ number += c;
+ continue;
+ }
+
+ 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()));
+ }
+ }
+ }
+
+ public byte getType() {
+ return type;
+ }
+
+ private boolean shouldStoreSize(byte b) {
+ return b > 7;
+ }
+
+ static private int getSizeBytes(int size_bytes_tag)
+ {
+ switch(size_bytes_tag)
+ {
+ case 0: return 4;
+ case 1: return 2;
+ case 2: return 1;
+ default: return 4;
+ }
+ }
+
+ static byte getParentFlags(IBdfDatabase db)
+ {
+ int flags = 0xff & db.getByte(0);
+
+ byte type = (byte)(flags % 18);
+ flags = (byte)((flags - type) / 18);
+
+ byte size_bytes = (byte)(flags % 3);
+ flags = (byte)((flags - size_bytes) / 3);
+
+ byte parent_flags = (byte)(flags % 3);
+ flags = (byte)((flags - parent_flags) / 3);
+
+ return parent_flags;
+ }
+
+ static int getSize(IBdfDatabase db)
+ {
+ int flags = 0xff & db.getByte(0);
+ byte type = (byte)(flags % 18);
+ flags = (byte)((flags - type) / 18);
+
+ int size_bytes = getSizeBytes(flags % 3);
+ int size = getSize(type);
+
+ if(size != -1) {
+ return size;
+ }
+
+ ByteBuffer size_buff = DataHelpers.getByteBuffer(db.getPointer(1, size_bytes));
+
+ switch(size_bytes)
+ {
+ case 4: return size_buff.getInt();
+ case 2: return (0xffff & size_buff.getShort());
+ case 1: return (0xff & size_buff.get());
+ }
+
+ return 0;
+ }
+
+ static int getSize(byte type)
+ {
+ switch(type)
+ {
+ case BdfTypes.BOOLEAN:
+ return 2;
+ case BdfTypes.BYTE:
+ return 2;
+ case BdfTypes.DOUBLE:
+ return 9;
+ case BdfTypes.FLOAT:
+ return 5;
+ case BdfTypes.INTEGER:
+ return 5;
+ case BdfTypes.LONG:
+ return 9;
+ case BdfTypes.SHORT:
+ return 3;
+ case BdfTypes.UNDEFINED:
+ return 1;
+ default:
+ return -1;
}
}
@Override
- public int serialize(IBdfDatabase database)
+ public void getLocationUses(int[] locations)
{
- int size;
+ if(type == BdfTypes.NAMED_LIST || type == BdfTypes.ARRAY) {
+ ((IBdfType)object).getLocationUses(locations);
+ }
+ }
+
+ @Override
+ public int serialize(IBdfDatabase database, int[] locations, byte parent_flags)
+ {
+ int size = last_seek;
+ boolean storeSize = shouldStoreSize(type);
- IBdfDatabase db = database.getPointer(1);
+ byte size_bytes_tag = 0;
+ int size_bytes = 0;
+
+ if(storeSize)
+ {
+ if(size > 65535) { // >= 2 ^ 16
+ size_bytes_tag = 0;
+ size_bytes = 4;
+ } else if(size > 255) { // >= 2 ^ 8
+ size_bytes_tag = 1;
+ size_bytes = 2;
+ } else { // < 2 ^ 8
+ size_bytes_tag = 2;
+ size_bytes = 1;
+ }
+ }
+
+ int offset = size_bytes + 1;
+ byte flags = (byte)(type + (size_bytes_tag * 18) + (parent_flags * 3 * 18));
// Objects
switch(type)
{
case BdfTypes.ARRAY:
- size = ((BdfArray)object).serialize(db) + 1;
+ size = ((BdfArray)object).serialize(database.getPointer(offset), locations, (byte)0) + offset;
break;
case BdfTypes.NAMED_LIST:
- size = ((BdfNamedList)object).serialize(db) + 1;
+ size = ((BdfNamedList)object).serialize(database.getPointer(offset), locations, (byte)0) + offset;
break;
case BdfTypes.STRING:
- String str = (String)object;
- size = str.length() + 1;
- db.setBytes(0, str.getBytes());
+ byte[] str = ((String)object).getBytes();
+ size = str.length + offset;
+ database.setBytes(str, offset);
break;
default:
- size = this.database.size() + 1;
- db.setBytes(0, this.database.getBytes());
+ size = this.database.size() + offset;
+ database.setBytes(this.database, offset);
break;
}
- database.setByte(0, type);
+ database.setByte(0, flags);
+
+ if(storeSize)
+ {
+ byte[] bytes = DataHelpers.serializeInt(size);
+
+ for(int i=0;i 65531) { // >= 2 ^ 16
+ size_bytes = 4;
+ } else if(size > 253) { // >= 2 ^ 8
+ size_bytes = 2;
+ } else { // < 2 ^ 8
+ size_bytes = 1;
+ }
- return database;
+ size += size_bytes;
+ last_seek = size;
+
+ return size;
}
private String calcIndent(BdfIndent indent, int it) {
@@ -116,36 +781,6 @@ public class BdfObject implements IBdfType
return t;
}
- public String serializeHumanReadable(BdfIndent indent) {
- return serializeHumanReadable(indent, 0);
- }
-
- public String serializeHumanReadable() {
- return serializeHumanReadable(new BdfIndent("", ""), 0);
- }
-
- public String serializeHumanReadable(BdfIndent indent, int it)
- {
- ByteArrayOutputStream stream = new ByteArrayOutputStream();
-
- try {
- serializeHumanReadable(stream, indent, it);
- return stream.toString();
- }
-
- catch(IOException e) {
- return "undefined";
- }
- }
-
- public void serializeHumanReadable(OutputStream stream, BdfIndent indent) throws IOException {
- serializeHumanReadable(stream, indent, 0);
- }
-
- public void serializeHumanReadable(OutputStream stream) throws IOException {
- serializeHumanReadable(stream, new BdfIndent("", ""), 0);
- }
-
public void serializeHumanReadable(OutputStream stream, BdfIndent indent, int it) throws IOException
{
String str = null;
@@ -194,77 +829,77 @@ public class BdfObject implements IBdfType
break;
case BdfTypes.ARRAY_INTEGER: {
- stream.write(("(" + calcIndent(indent, it)).getBytes());
+ stream.write("int(".getBytes());
int[] array = this.getIntegerArray();
for(int i=0;i 2147483648L || number <= -2147483648L) {
+ setLong(number);
+ } else if(number > 32768 || number <= -32768) {
+ setInteger((int)number);
+ } else if(number > 128 || number <= -128) {
+ setShort((short)number);
+ } else {
+ setByte((byte)number);
+ }
+
+ return this;
}
- public byte getType() {
- return this.type;
+ public long getAutoInt()
+ {
+ switch(type)
+ {
+ case BdfTypes.BYTE:
+ return getByte();
+ case BdfTypes.SHORT:
+ return getShort();
+ case BdfTypes.INTEGER:
+ return getInteger();
+ case BdfTypes.LONG:
+ return getLong();
+ default:
+ return 0;
+ }
}
// Primitives
@@ -492,7 +1151,7 @@ public class BdfObject implements IBdfType
public BdfArray getArray()
{
if(this.type != BdfTypes.ARRAY)
- this.setArray();
+ setArray(newArray());
return (BdfArray)object;
}
@@ -500,7 +1159,7 @@ public class BdfObject implements IBdfType
public BdfNamedList getNamedList()
{
if(this.type != BdfTypes.NAMED_LIST)
- this.setNamedList();
+ setNamedList(newNamedList());
return (BdfNamedList)object;
}
@@ -560,7 +1219,6 @@ public class BdfObject implements IBdfType
public BdfObject setString(String value) {
this.type = BdfTypes.STRING;
- this.database = new BdfDatabase(value.getBytes());
this.object = value;
return this;
}
@@ -577,12 +1235,28 @@ public class BdfObject implements IBdfType
return this;
}
- public BdfObject setArray() {
- return this.setArray(new BdfArray());
+ public BdfObject newObject() {
+ return new BdfObject(lookupTable);
}
- public BdfObject setNamedList() {
- return this.setNamedList(new BdfNamedList());
+ public BdfNamedList newNamedList() {
+ return new BdfNamedList(lookupTable);
+ }
+
+ public BdfArray newArray() {
+ return new BdfArray(lookupTable, 0);
+ }
+
+ public BdfArray newArray(int size) {
+ return new BdfArray(lookupTable, size);
+ }
+
+ public int getKeyLocation(String key) {
+ return lookupTable.getLocation(key.getBytes());
+ }
+
+ public String getKeyName(int key) {
+ return new String(lookupTable.getName(key));
}
public BdfObject setBooleanArray(boolean[] value) {
@@ -654,84 +1328,5 @@ public class BdfObject implements IBdfType
database = DataHelpers.getDatabase(b);
return this;
}
-
- // Primitives
- public static BdfObject withInteger(int v) {
- return (new BdfObject()).setInteger(v);
- }
-
- public static BdfObject withByte(byte v) {
- return (new BdfObject()).setByte(v);
- }
-
- public static BdfObject withBoolean(boolean v) {
- return (new BdfObject()).setBoolean(v);
- }
-
- public static BdfObject withFloat(float v) {
- return (new BdfObject()).setFloat(v);
- }
-
- public static BdfObject withDouble(double v) {
- return (new BdfObject()).setDouble(v);
- }
-
- public static BdfObject withLong(long v) {
- return (new BdfObject()).setLong(v);
- }
-
- public static BdfObject withShort(short v) {
- return (new BdfObject()).setShort(v);
- }
-
- // Arrays
- public static BdfObject withIntegerArray(int[] v) {
- return (new BdfObject()).setIntegerArray(v);
- }
-
- public static BdfObject withByteArray(byte[] v) {
- return (new BdfObject()).setByteArray(v);
- }
-
- public static BdfObject withBooleanArray(boolean[] v) {
- return (new BdfObject()).setBooleanArray(v);
- }
-
- public static BdfObject withFloatArray(float[] v) {
- return (new BdfObject()).setFloatArray(v);
- }
-
- public static BdfObject withDoubleArray(double[] v) {
- return (new BdfObject()).setDoubleArray(v);
- }
-
- public static BdfObject withLongArray(long[] v) {
- return (new BdfObject()).setLongArray(v);
- }
-
- public static BdfObject withShortArray(short[] v) {
- return (new BdfObject()).setShortArray(v);
- }
-
- // Objects
- public static BdfObject withString(String v) {
- return (new BdfObject()).setString(v);
- }
-
- public static BdfObject withArray(BdfArray v) {
- return (new BdfObject()).setArray(v);
- }
-
- public static BdfObject withNamedList(BdfNamedList v) {
- return (new BdfObject()).setNamedList(v);
- }
-
- public static BdfObject withArray() {
- return (new BdfObject()).setArray(new BdfArray());
- }
-
- public static BdfObject withNamedList() {
- return (new BdfObject()).setNamedList(new BdfNamedList());
- }
}
diff --git a/src/bdf/types/BdfReader.java b/src/bdf/types/BdfReader.java
new file mode 100644
index 0000000..a61d220
--- /dev/null
+++ b/src/bdf/types/BdfReader.java
@@ -0,0 +1,182 @@
+package bdf.types;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+
+import bdf.data.BdfDatabase;
+import bdf.data.IBdfDatabase;
+import bdf.util.DataHelpers;
+
+public class BdfReader
+{
+ protected BdfLookupTable lookupTable;
+ protected BdfObject bdf;
+
+ private void initNew() {
+ lookupTable = new BdfLookupTable(this);
+ bdf = new BdfObject(lookupTable);
+ }
+
+ public BdfReader() {
+ initNew();
+ }
+
+ public BdfReader(byte[] database) {
+ this(new BdfDatabase(database));
+ }
+
+ public BdfReader(IBdfDatabase database)
+ {
+ try
+ {
+ if(database.size() == 0) {
+ 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;
+ }
+
+ if(lookupTable_size_bytes > 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();
+ }
+ }
+
+ public BdfDatabase serialize()
+ {
+ int[] locations = lookupTable.serializeGetLocations();
+
+ int bdf_size = bdf.serializeSeeker(locations);
+ int lookupTable_size = lookupTable.serializeSeeker(locations);
+
+ int lookupTable_size_bytes = 0;
+ byte lookupTable_size_tag = 0;
+
+ if(lookupTable_size > 65535) { // >= 2 ^ 16
+ lookupTable_size_tag = 0;
+ lookupTable_size_bytes = 4;
+ } else if(lookupTable_size > 255) { // >= 2 ^ 8
+ lookupTable_size_tag = 1;
+ lookupTable_size_bytes = 2;
+ } else { // < 2 ^ 8
+ lookupTable_size_tag = 2;
+ lookupTable_size_bytes = 1;
+ }
+
+ int upto = 0;
+ int database_size = bdf_size + lookupTable_size + lookupTable_size_bytes;
+ BdfDatabase database = new BdfDatabase(database_size);
+
+ bdf.serialize(database.getPointer(upto, bdf_size), locations, lookupTable_size_tag);
+ upto += bdf_size;
+
+ byte[] bytes = DataHelpers.serializeInt(lookupTable_size);
+
+ for(int i=0;i 0x7e && c < 0xa1) || c == 0xad)
+ {
+ // Will be in the format \u0000
+ size += 6;
+ }
+
+ else
+ {
+ size += 1;
+ }
+ }
+
+ char[] chars = new char[size];
+ int upto = 0;
+
+ for(int i=0;i 0x7e && c < 0xa1) || c == 0xad)
+ {
+ // Will be in the format \u0000
+ chars[upto] = '\\';
+ chars[upto+1] = 'u';
+ chars[upto+2] = HEX[(c & 0xf000) >> 12];
+ chars[upto+3] = HEX[(c & 0x0f00) >> 8];
+ chars[upto+4] = HEX[(c & 0x00f0) >> 4];
+ chars[upto+5] = HEX[(c & 0x000f)];
+ upto += 6;
+ }
+
+ else
+ {
+ chars[upto] = string_chars[i];
+ upto += 1;
+ }
+ }
+
+ string_chars = chars;
+ }
// Add quotes to the string
- serialized = "\"" + serialized + "\"";
+ string = "\"" + new String(string_chars) + "\"";
// Return the serialized string
- return serialized;
+ return string;
}
}
diff --git a/src/bdf/util/FileHelpers.java b/src/bdf/util/FileHelpers.java
deleted file mode 100644
index 7379320..0000000
--- a/src/bdf/util/FileHelpers.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package bdf.util;
-
-import java.io.ByteArrayOutputStream;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.zip.InflaterInputStream;
-
-public class FileHelpers
-{
- public static byte[] readAll(InputStream in)
- {
- try
- {
- // Get bytes to return
- ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- byte[] bytes = new byte[1024];
- int size = 0;
-
- while((size = in.read(bytes)) != -1) {
- buffer.write(bytes, 0, size);
- }
-
- // Send the bytes collected from the file stream back
- return buffer.toByteArray();
- }
-
- catch (IOException e)
- {
- // Throw the IOException as a runtime exception
- throw new RuntimeException(e);
- }
- }
-
- public static byte[] readAll(String path) throws IOException
- {
- // Create the file input stream
- FileInputStream in = new FileInputStream(path);
-
- // Load all of its data
- byte[] data = readAll(in);
-
- // Close the file input stream
- in.close();
-
- // Send back the data
- return data;
- }
-
- public static byte[] readAllCompressed(String path) throws IOException
- {
- // Create the file input stream
- InflaterInputStream in = new InflaterInputStream(new FileInputStream(path));
-
- // Load all of its data
- byte[] data = readAll(in);
-
- // Close the file input stream
- in.close();
-
- // Send back the data
- return data;
- }
-
- public static byte[] readAllIgnoreErrors(String path)
- {
- try {
- return readAll(path);
- }
-
- catch(IOException e) {
- return new byte[0];
- }
- }
-
- public static byte[] readAllCompressedIgnoreErrors(String path)
- {
- try {
- return readAllCompressed(path);
- }
-
- catch(IOException | RuntimeException e) {
- return new byte[0];
- }
- }
-}
diff --git a/src/tests/Tests.java b/src/tests/Tests.java
index ca7d29b..098ef5d 100755
--- a/src/tests/Tests.java
+++ b/src/tests/Tests.java
@@ -1,67 +1,56 @@
package tests;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
+import java.io.FileInputStream;
import java.io.IOException;
-import bdf.data.BdfDatabase;
-import bdf.file.BdfFileManager;
-import bdf.types.BdfArray;
-import bdf.types.BdfIndent;
-import bdf.types.BdfNamedList;
-import bdf.types.BdfObject;
+import bdf.data.IBdfDatabase;
+import bdf.types.BdfReader;
-public class Tests {
-
- public static void main(String[] args) throws InterruptedException, IOException
+public class Tests
+{
+ public static void displayHex(IBdfDatabase db)
{
- /*
- BdfObject bdf = new BdfObject();
- BdfNamedList nl = bdf.getNamedList();
+ char[] hex_chars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
- byte[] bytes = new byte[1024*1024*1024];
- for(int i=0;i 1000) {
+ System.out.println("" + i + ": " + done);
+ start += 1000;
+ done = 0;
+ i += 1;
+ }
+
+ done += 1;
+
+ rand.read(buffer);
+ new BdfReader(buffer);
}
-
- nl.get("next").setByteArray(bytes);
-
- BdfDatabase data = bdf.serialize();
-
- FileOutputStream file = new FileOutputStream("./database.bdf");
- data.writeToStream(file);
- */
-
-
- BdfObject bdf = new BdfObject();
- BdfArray a = bdf.getArray();
-
- byte[] bytes = new byte[1024*1024*1024/2];
- for(int i=0;i