├── README.md
├── RainCloud-Serialization
├── .classpath
├── .project
├── .settings
│ └── org.eclipse.jdt.core.prefs
└── src
│ └── com
│ └── thecherno
│ └── raincloud
│ └── serialization
│ ├── ContainerType.java
│ ├── RCArray.java
│ ├── RCBase.java
│ ├── RCDatabase.java
│ ├── RCField.java
│ ├── RCObject.java
│ ├── RCString.java
│ ├── SerializationUtils.java
│ └── Type.java
└── Sandbox
├── .classpath
├── .project
├── .settings
└── org.eclipse.jdt.core.prefs
└── src
├── Main.java
└── Sandbox.java
/README.md:
--------------------------------------------------------------------------------
1 | # JavaSerialization
2 | Source code from my YouTube Serialization series: https://www.youtube.com/playlist?list=PLlrATfBNZ98cCfmH0xPebdVVMSYRQfyKi
3 |
--------------------------------------------------------------------------------
/RainCloud-Serialization/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/RainCloud-Serialization/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | RainCloud-Serialization
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.jdt.core.javanature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/RainCloud-Serialization/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
5 | org.eclipse.jdt.core.compiler.compliance=1.8
6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate
7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate
8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate
9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
11 | org.eclipse.jdt.core.compiler.source=1.8
12 |
--------------------------------------------------------------------------------
/RainCloud-Serialization/src/com/thecherno/raincloud/serialization/ContainerType.java:
--------------------------------------------------------------------------------
1 | package com.thecherno.raincloud.serialization;
2 |
3 | public class ContainerType {
4 |
5 | public static final byte UNKNOWN = 0;
6 | public static final byte FIELD = 1;
7 | public static final byte ARRAY = 2;
8 | public static final byte STRING = 3;
9 | public static final byte OBJECT = 4;
10 | public static final byte DATABASE = 5;
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/RainCloud-Serialization/src/com/thecherno/raincloud/serialization/RCArray.java:
--------------------------------------------------------------------------------
1 | package com.thecherno.raincloud.serialization;
2 |
3 | import static com.thecherno.raincloud.serialization.SerializationUtils.*;
4 |
5 | import java.nio.ByteBuffer;
6 |
7 | public class RCArray extends RCBase {
8 |
9 | public static final byte CONTAINER_TYPE = ContainerType.ARRAY;
10 | public byte type;
11 | public int count;
12 | public byte[] data;
13 |
14 | private short[] shortData;
15 | private char[] charData;
16 | private int[] intData;
17 | private long[] longData;
18 | private float[] floatData;
19 | private double[] doubleData;
20 | private boolean[] booleanData;
21 |
22 | private RCArray() {
23 | size += 1 + 1 + 4;
24 | }
25 |
26 | private void updateSize() {
27 | size += getDataSize();
28 | }
29 |
30 | public int getBytes(byte[] dest, int pointer) {
31 | pointer = writeBytes(dest, pointer, CONTAINER_TYPE);
32 | pointer = writeBytes(dest, pointer, nameLength);
33 | pointer = writeBytes(dest, pointer, name);
34 | pointer = writeBytes(dest, pointer, size);
35 | pointer = writeBytes(dest, pointer, type);
36 | pointer = writeBytes(dest, pointer, count);
37 |
38 | switch(type) {
39 | case Type.BYTE:
40 | pointer = writeBytes(dest, pointer, data);
41 | break;
42 | case Type.SHORT:
43 | pointer = writeBytes(dest, pointer, shortData);
44 | break;
45 | case Type.CHAR:
46 | pointer = writeBytes(dest, pointer, charData);
47 | break;
48 | case Type.INTEGER:
49 | pointer = writeBytes(dest, pointer, intData);
50 | break;
51 | case Type.LONG:
52 | pointer = writeBytes(dest, pointer, longData);
53 | break;
54 | case Type.FLOAT:
55 | pointer = writeBytes(dest, pointer, floatData);
56 | break;
57 | case Type.DOUBLE:
58 | pointer = writeBytes(dest, pointer, doubleData);
59 | break;
60 | case Type.BOOLEAN:
61 | pointer = writeBytes(dest, pointer, booleanData);
62 | break;
63 | }
64 | return pointer;
65 | }
66 |
67 | public int getSize() {
68 | return size;
69 | }
70 |
71 | public int getDataSize() {
72 | switch(type) {
73 | case Type.BYTE: return data.length * Type.getSize(Type.BYTE);
74 | case Type.SHORT: return shortData.length * Type.getSize(Type.SHORT);
75 | case Type.CHAR: return charData.length * Type.getSize(Type.CHAR);
76 | case Type.INTEGER: return intData.length * Type.getSize(Type.INTEGER);
77 | case Type.LONG: return longData.length * Type.getSize(Type.LONG);
78 | case Type.FLOAT: return floatData.length * Type.getSize(Type.FLOAT);
79 | case Type.DOUBLE: return doubleData.length * Type.getSize(Type.DOUBLE);
80 | case Type.BOOLEAN: return booleanData.length * Type.getSize(Type.BOOLEAN);
81 | }
82 | return 0;
83 | }
84 |
85 | public static RCArray Byte(String name, byte[] data) {
86 | RCArray array = new RCArray();
87 | array.setName(name);
88 | array.type = Type.BYTE;
89 | array.count = data.length;
90 | array.data = data;
91 | array.updateSize();
92 | return array;
93 | }
94 |
95 | public static RCArray Short(String name, short[] data) {
96 | RCArray array = new RCArray();
97 | array.setName(name);
98 | array.type = Type.SHORT;
99 | array.count = data.length;
100 | array.shortData = data;
101 | array.updateSize();
102 | return array;
103 | }
104 |
105 | public static RCArray Char(String name, char[] data) {
106 | RCArray array = new RCArray();
107 | array.setName(name);
108 | array.type = Type.CHAR;
109 | array.count = data.length;
110 | array.charData = data;
111 | array.updateSize();
112 | return array;
113 | }
114 |
115 | public static RCArray Integer(String name, int[] data) {
116 | RCArray array = new RCArray();
117 | array.setName(name);
118 | array.type = Type.INTEGER;
119 | array.count = data.length;
120 | array.intData = data;
121 | array.updateSize();
122 | return array;
123 | }
124 |
125 | public static RCArray Long(String name, long[] data) {
126 | RCArray array = new RCArray();
127 | array.setName(name);
128 | array.type = Type.LONG;
129 | array.count = data.length;
130 | array.longData = data;
131 | array.updateSize();
132 | return array;
133 | }
134 |
135 | public static RCArray Float(String name, float[] data) {
136 | RCArray array = new RCArray();
137 | array.setName(name);
138 | array.type = Type.FLOAT;
139 | array.count = data.length;
140 | array.floatData = data;
141 | array.updateSize();
142 | return array;
143 | }
144 |
145 | public static RCArray Double(String name, double[] data) {
146 | RCArray array = new RCArray();
147 | array.setName(name);
148 | array.type = Type.DOUBLE;
149 | array.count = data.length;
150 | array.doubleData = data;
151 | array.updateSize();
152 | return array;
153 | }
154 |
155 | public static RCArray Boolean(String name, boolean[] data) {
156 | RCArray array = new RCArray();
157 | array.setName(name);
158 | array.type = Type.BOOLEAN;
159 | array.count = data.length;
160 | array.booleanData = data;
161 | array.updateSize();
162 | return array;
163 | }
164 |
165 | public static RCArray Deserialize(byte[] data, int pointer) {
166 | byte containerType = data[pointer++];
167 | assert(containerType == CONTAINER_TYPE);
168 |
169 | RCArray result = new RCArray();
170 | result.nameLength = readShort(data, pointer);
171 | pointer += 2;
172 | result.name = readString(data, pointer, result.nameLength).getBytes();
173 | pointer += result.nameLength;
174 |
175 | result.size = readInt(data, pointer);
176 | pointer += 4;
177 |
178 | result.type = data[pointer++];
179 |
180 | result.count = readInt(data, pointer);
181 | pointer += 4;
182 |
183 | switch(result.type) {
184 | case Type.BYTE:
185 | result.data = new byte[result.count];
186 | readBytes(data, pointer, result.data);
187 | break;
188 | case Type.SHORT:
189 | result.shortData = new short[result.count];
190 | readShorts(data, pointer, result.shortData);
191 | break;
192 | case Type.CHAR:
193 | result.charData = new char[result.count];
194 | readChars(data, pointer, result.charData);
195 | break;
196 | case Type.INTEGER:
197 | result.intData = new int[result.count];
198 | readInts(data, pointer, result.intData);
199 | break;
200 | case Type.LONG:
201 | result.longData = new long[result.count];
202 | readLongs(data, pointer, result.longData);
203 | break;
204 | case Type.FLOAT:
205 | result.floatData = new float[result.count];
206 | readFloats(data, pointer, result.floatData);
207 | break;
208 | case Type.DOUBLE:
209 | result.doubleData = new double[result.count];
210 | readDoubles(data, pointer, result.doubleData);
211 | break;
212 | case Type.BOOLEAN:
213 | result.booleanData = new boolean[result.count];
214 | readBooleans(data, pointer, result.booleanData);
215 | break;
216 | }
217 |
218 | pointer += result.count * Type.getSize(result.type);
219 |
220 | return result;
221 | }
222 |
223 | }
224 |
--------------------------------------------------------------------------------
/RainCloud-Serialization/src/com/thecherno/raincloud/serialization/RCBase.java:
--------------------------------------------------------------------------------
1 | package com.thecherno.raincloud.serialization;
2 |
3 | public abstract class RCBase {
4 |
5 | protected short nameLength;
6 | protected byte[] name;
7 |
8 | protected int size = 2 + 4;
9 |
10 | public String getName() {
11 | return new String(name, 0, nameLength);
12 | }
13 |
14 | public void setName(String name) {
15 | assert(name.length() < Short.MAX_VALUE);
16 |
17 | if (this.name != null)
18 | size -= this.name.length;
19 |
20 | nameLength = (short)name.length();
21 | this.name = name.getBytes();
22 | size += nameLength;
23 | }
24 |
25 | public abstract int getSize();
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/RainCloud-Serialization/src/com/thecherno/raincloud/serialization/RCDatabase.java:
--------------------------------------------------------------------------------
1 | package com.thecherno.raincloud.serialization;
2 |
3 | import static com.thecherno.raincloud.serialization.SerializationUtils.*;
4 |
5 | import java.io.BufferedInputStream;
6 | import java.io.BufferedOutputStream;
7 | import java.io.FileInputStream;
8 | import java.io.FileOutputStream;
9 | import java.io.IOException;
10 | import java.util.ArrayList;
11 | import java.util.List;
12 |
13 | public class RCDatabase extends RCBase {
14 |
15 | public static final byte[] HEADER = "RCDB".getBytes();
16 | public static final short VERSION = 0x0100;
17 | public static final byte CONTAINER_TYPE = ContainerType.DATABASE;
18 | private short objectCount;
19 | public List objects = new ArrayList();
20 |
21 | private RCDatabase() {
22 | }
23 |
24 | public RCDatabase(String name) {
25 | setName(name);
26 |
27 | size += HEADER.length + 2 + 1 + 2;
28 | }
29 |
30 | public void addObject(RCObject object) {
31 | objects.add(object);
32 | size += object.getSize();
33 |
34 | objectCount = (short)objects.size();
35 | }
36 |
37 | public int getSize() {
38 | return size;
39 | }
40 |
41 | public int getBytes(byte[] dest, int pointer) {
42 | pointer = writeBytes(dest, pointer, HEADER);
43 | pointer = writeBytes(dest, pointer, VERSION);
44 | pointer = writeBytes(dest, pointer, CONTAINER_TYPE);
45 | pointer = writeBytes(dest, pointer, nameLength);
46 | pointer = writeBytes(dest, pointer, name);
47 | pointer = writeBytes(dest, pointer, size);
48 |
49 | pointer = writeBytes(dest, pointer, objectCount);
50 | for (RCObject object : objects)
51 | pointer = object.getBytes(dest, pointer);
52 |
53 | return pointer;
54 | }
55 |
56 | public static RCDatabase Deserialize(byte[] data) {
57 | int pointer = 0;
58 | assert(readString(data, pointer, HEADER.length).equals(HEADER));
59 | pointer += HEADER.length;
60 |
61 | if (readShort(data, pointer) != VERSION) {
62 | System.err.println("Invalid RCDB version!");
63 | return null;
64 | }
65 | pointer += 2;
66 |
67 | byte containerType = readByte(data, pointer++);
68 | assert(containerType == CONTAINER_TYPE);
69 |
70 | RCDatabase result = new RCDatabase();
71 | result.nameLength = readShort(data, pointer);
72 | pointer += 2;
73 | result.name = readString(data, pointer, result.nameLength).getBytes();
74 | pointer += result.nameLength;
75 |
76 | result.size = readInt(data, pointer);
77 | pointer += 4;
78 |
79 | result.objectCount = readShort(data, pointer);
80 | pointer += 2;
81 |
82 | for (int i = 0; i < result.objectCount; i++) {
83 | RCObject object = RCObject.Deserialize(data, pointer);
84 | result.objects.add(object);
85 | pointer += object.getSize();
86 | }
87 |
88 | return result;
89 | }
90 |
91 | public RCObject findObject(String name) {
92 | for (RCObject object : objects) {
93 | if (object.getName().equals(name))
94 | return object;
95 | }
96 | return null;
97 | }
98 |
99 | public static RCDatabase DeserializeFromFile(String path) {
100 | byte[] buffer = null;
101 | try {
102 | BufferedInputStream stream = new BufferedInputStream(new FileInputStream(path));
103 | buffer = new byte[stream.available()];
104 | stream.read(buffer);
105 | stream.close();
106 | } catch (IOException e) {
107 | e.printStackTrace();
108 | }
109 |
110 | return Deserialize(buffer);
111 | }
112 |
113 | public void serializeToFile(String path) {
114 | byte[] data = new byte[getSize()];
115 | getBytes(data, 0);
116 | try {
117 | BufferedOutputStream stream = new BufferedOutputStream(new FileOutputStream(path));
118 | stream.write(data);
119 | stream.close();
120 | } catch (IOException e) {
121 | e.printStackTrace();
122 | }
123 | }
124 |
125 | }
126 |
--------------------------------------------------------------------------------
/RainCloud-Serialization/src/com/thecherno/raincloud/serialization/RCField.java:
--------------------------------------------------------------------------------
1 | package com.thecherno.raincloud.serialization;
2 |
3 | import static com.thecherno.raincloud.serialization.SerializationUtils.*;
4 |
5 | public class RCField extends RCBase {
6 |
7 | public static final byte CONTAINER_TYPE = ContainerType.FIELD;
8 | public byte type;
9 | public byte[] data;
10 |
11 | private RCField() {
12 | }
13 |
14 | public byte getByte() {
15 | return data[0];
16 | }
17 |
18 | public short getShort() {
19 | return readShort(data, 0);
20 | }
21 |
22 | public char getChar() {
23 | return readChar(data, 0);
24 | }
25 |
26 | public int getInt() {
27 | return readInt(data, 0);
28 | }
29 |
30 | public long getLong() {
31 | return readLong(data, 0);
32 | }
33 |
34 | public double getDouble() {
35 | return readDouble(data, 0);
36 | }
37 |
38 | public float getFloat() {
39 | return readFloat(data, 0);
40 | }
41 |
42 | public boolean getBoolean() {
43 | return readBoolean(data, 0);
44 | }
45 |
46 | public int getBytes(byte[] dest, int pointer) {
47 | pointer = writeBytes(dest, pointer, CONTAINER_TYPE);
48 | pointer = writeBytes(dest, pointer, nameLength);
49 | pointer = writeBytes(dest, pointer, name);
50 | pointer = writeBytes(dest, pointer, type);
51 | pointer = writeBytes(dest, pointer, data);
52 | return pointer;
53 | }
54 |
55 | public int getSize() {
56 | assert(data.length == Type.getSize(type));
57 | return 1 + 2 + name.length + 1 + data.length;
58 | }
59 |
60 | public static RCField Byte(String name, byte value) {
61 | RCField field = new RCField();
62 | field.setName(name);
63 | field.type = Type.BYTE;
64 | field.data = new byte[Type.getSize(Type.BYTE)];
65 | writeBytes(field.data, 0, value);
66 | return field;
67 | }
68 |
69 | public static RCField Short(String name, short value) {
70 | RCField field = new RCField();
71 | field.setName(name);
72 | field.type = Type.SHORT;
73 | field.data = new byte[Type.getSize(Type.SHORT)];
74 | writeBytes(field.data, 0, value);
75 | return field;
76 | }
77 |
78 | public static RCField Char(String name, char value) {
79 | RCField field = new RCField();
80 | field.setName(name);
81 | field.type = Type.CHAR;
82 | field.data = new byte[Type.getSize(Type.CHAR)];
83 | writeBytes(field.data, 0, value);
84 | return field;
85 | }
86 |
87 | public static RCField Integer(String name, int value) {
88 | RCField field = new RCField();
89 | field.setName(name);
90 | field.type = Type.INTEGER;
91 | field.data = new byte[Type.getSize(Type.INTEGER)];
92 | writeBytes(field.data, 0, value);
93 | return field;
94 | }
95 |
96 | public static RCField Long(String name, long value) {
97 | RCField field = new RCField();
98 | field.setName(name);
99 | field.type = Type.LONG;
100 | field.data = new byte[Type.getSize(Type.LONG)];
101 | writeBytes(field.data, 0, value);
102 | return field;
103 | }
104 |
105 | public static RCField Float(String name, float value) {
106 | RCField field = new RCField();
107 | field.setName(name);
108 | field.type = Type.FLOAT;
109 | field.data = new byte[Type.getSize(Type.FLOAT)];
110 | writeBytes(field.data, 0, value);
111 | return field;
112 | }
113 |
114 | public static RCField Double(String name, double value) {
115 | RCField field = new RCField();
116 | field.setName(name);
117 | field.type = Type.DOUBLE;
118 | field.data = new byte[Type.getSize(Type.DOUBLE)];
119 | writeBytes(field.data, 0, value);
120 | return field;
121 | }
122 |
123 | public static RCField Boolean(String name, boolean value) {
124 | RCField field = new RCField();
125 | field.setName(name);
126 | field.type = Type.BOOLEAN;
127 | field.data = new byte[Type.getSize(Type.BOOLEAN)];
128 | writeBytes(field.data, 0, value);
129 | return field;
130 | }
131 |
132 | public static RCField Deserialize(byte[] data, int pointer) {
133 | byte containerType = data[pointer++];
134 | assert(containerType == CONTAINER_TYPE);
135 |
136 | RCField result = new RCField();
137 | result.nameLength = readShort(data, pointer);
138 | pointer += 2;
139 | result.name = readString(data, pointer, result.nameLength).getBytes();
140 | pointer += result.nameLength;
141 |
142 | result.type = data[pointer++];
143 |
144 | result.data = new byte[Type.getSize(result.type)];
145 | readBytes(data, pointer, result.data);
146 | pointer += Type.getSize(result.type);
147 | return result;
148 | }
149 |
150 | }
151 |
--------------------------------------------------------------------------------
/RainCloud-Serialization/src/com/thecherno/raincloud/serialization/RCObject.java:
--------------------------------------------------------------------------------
1 | package com.thecherno.raincloud.serialization;
2 |
3 | import static com.thecherno.raincloud.serialization.SerializationUtils.*;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | public class RCObject extends RCBase {
9 |
10 | public static final byte CONTAINER_TYPE = ContainerType.OBJECT;
11 | private short fieldCount;
12 | public List fields = new ArrayList();
13 | private short stringCount;
14 | public List strings = new ArrayList();
15 | private short arrayCount;
16 | public List arrays = new ArrayList();
17 |
18 | private RCObject() {
19 | }
20 |
21 | public RCObject(String name) {
22 | size += 1 + 2 + 2 + 2;
23 | setName(name);
24 | }
25 |
26 | public void addField(RCField field) {
27 | fields.add(field);
28 | size += field.getSize();
29 |
30 | fieldCount = (short)fields.size();
31 | }
32 |
33 | public void addString(RCString string) {
34 | strings.add(string);
35 | size += string.getSize();
36 |
37 | stringCount = (short)strings.size();
38 | }
39 |
40 | public void addArray(RCArray array) {
41 | arrays.add(array);
42 | size += array.getSize();
43 |
44 | arrayCount = (short)arrays.size();
45 | }
46 |
47 | public int getSize() {
48 | return size;
49 | }
50 |
51 | public RCField findField(String name) {
52 | for (RCField field : fields) {
53 | if (field.getName().equals(name))
54 | return field;
55 | }
56 | return null;
57 | }
58 |
59 | public RCString findString(String name) {
60 | for (RCString string : strings) {
61 | if (string.getName().equals(name))
62 | return string;
63 | }
64 | return null;
65 | }
66 |
67 | public RCArray findArray(String name) {
68 | for (RCArray array : arrays) {
69 | if (array.getName().equals(name))
70 | return array;
71 | }
72 | return null;
73 | }
74 |
75 | public int getBytes(byte[] dest, int pointer) {
76 | pointer = writeBytes(dest, pointer, CONTAINER_TYPE);
77 | pointer = writeBytes(dest, pointer, nameLength);
78 | pointer = writeBytes(dest, pointer, name);
79 | pointer = writeBytes(dest, pointer, size);
80 |
81 | pointer = writeBytes(dest, pointer, fieldCount);
82 | for (RCField field : fields)
83 | pointer = field.getBytes(dest, pointer);
84 |
85 | pointer = writeBytes(dest, pointer, stringCount);
86 | for (RCString string : strings)
87 | pointer = string.getBytes(dest, pointer);
88 |
89 | pointer = writeBytes(dest, pointer, arrayCount);
90 | for (RCArray array : arrays)
91 | pointer = array.getBytes(dest, pointer);
92 |
93 | return pointer;
94 | }
95 |
96 | public static RCObject Deserialize(byte[] data, int pointer) {
97 | byte containerType = data[pointer++];
98 | assert(containerType == CONTAINER_TYPE);
99 |
100 | RCObject result = new RCObject();
101 | result.nameLength = readShort(data, pointer);
102 | pointer += 2;
103 | result.name = readString(data, pointer, result.nameLength).getBytes();
104 | pointer += result.nameLength;
105 |
106 | result.size = readInt(data, pointer);
107 | pointer += 4;
108 |
109 | // Early-out: pointer += result.size - sizeOffset - result.nameLength;
110 |
111 | result.fieldCount = readShort(data, pointer);
112 | pointer += 2;
113 |
114 | for (int i = 0; i < result.fieldCount; i++) {
115 | RCField field = RCField.Deserialize(data, pointer);
116 | result.fields.add(field);
117 | pointer += field.getSize();
118 | }
119 |
120 | result.stringCount = readShort(data, pointer);
121 | pointer += 2;
122 |
123 | for (int i = 0; i < result.stringCount; i++) {
124 | RCString string = RCString.Deserialize(data, pointer);
125 | result.strings.add(string);
126 | pointer += string.getSize();
127 | }
128 |
129 | result.arrayCount = readShort(data, pointer);
130 | pointer += 2;
131 |
132 | for (int i = 0; i < result.arrayCount; i++) {
133 | RCArray array = RCArray.Deserialize(data, pointer);
134 | result.arrays.add(array);
135 | pointer += array.getSize();
136 | }
137 |
138 | return result;
139 | }
140 |
141 | }
142 |
--------------------------------------------------------------------------------
/RainCloud-Serialization/src/com/thecherno/raincloud/serialization/RCString.java:
--------------------------------------------------------------------------------
1 | package com.thecherno.raincloud.serialization;
2 |
3 | import static com.thecherno.raincloud.serialization.SerializationUtils.*;
4 |
5 | public class RCString extends RCBase {
6 |
7 | public static final byte CONTAINER_TYPE = ContainerType.STRING;
8 | public int count;
9 | private char[] characters;
10 |
11 | private RCString() {
12 | size += 1 + 4;
13 | }
14 |
15 | public String getString() {
16 | return new String(characters);
17 | }
18 |
19 | private void updateSize() {
20 | size += getDataSize();
21 | }
22 |
23 | public int getBytes(byte[] dest, int pointer) {
24 | pointer = writeBytes(dest, pointer, CONTAINER_TYPE);
25 | pointer = writeBytes(dest, pointer, nameLength);
26 | pointer = writeBytes(dest, pointer, name);
27 | pointer = writeBytes(dest, pointer, size);
28 | pointer = writeBytes(dest, pointer, count);
29 | pointer = writeBytes(dest, pointer, characters);
30 | return pointer;
31 | }
32 |
33 | public int getSize() {
34 | return size;
35 | }
36 |
37 | public int getDataSize() {
38 | return characters.length * Type.getSize(Type.CHAR);
39 | }
40 |
41 | public static RCString Create(String name, String data) {
42 | RCString string = new RCString();
43 | string.setName(name);
44 | string.count = data.length();
45 | string.characters = data.toCharArray();
46 | string.updateSize();
47 | return string;
48 | }
49 |
50 | public static RCString Deserialize(byte[] data, int pointer) {
51 | byte containerType = data[pointer++];
52 | assert(containerType == CONTAINER_TYPE);
53 |
54 | RCString result = new RCString();
55 | result.nameLength = readShort(data, pointer);
56 | pointer += 2;
57 | result.name = readString(data, pointer, result.nameLength).getBytes();
58 | pointer += result.nameLength;
59 |
60 | result.size = readInt(data, pointer);
61 | pointer += 4;
62 |
63 | result.count = readInt(data, pointer);
64 | pointer += 4;
65 |
66 | result.characters = new char[result.count];
67 | readChars(data, pointer, result.characters);
68 |
69 | pointer += result.count * Type.getSize(Type.CHAR);
70 | return result;
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/RainCloud-Serialization/src/com/thecherno/raincloud/serialization/SerializationUtils.java:
--------------------------------------------------------------------------------
1 | package com.thecherno.raincloud.serialization;
2 |
3 | import java.nio.ByteBuffer;
4 |
5 | public class SerializationUtils {
6 |
7 | public static int writeBytes(byte[] dest, int pointer, byte[] src) {
8 | assert(dest.length > pointer + src.length);
9 | for (int i = 0; i < src.length; i++)
10 | dest[pointer++] = src[i];
11 | return pointer;
12 | }
13 |
14 | public static int writeBytes(byte[] dest, int pointer, char[] src) {
15 | assert(dest.length > pointer + src.length);
16 | for (int i = 0; i < src.length; i++)
17 | pointer = writeBytes(dest, pointer, src[i]);
18 | return pointer;
19 | }
20 |
21 | public static int writeBytes(byte[] dest, int pointer, short[] src) {
22 | assert(dest.length > pointer + src.length);
23 | for (int i = 0; i < src.length; i++)
24 | pointer = writeBytes(dest, pointer, src[i]);
25 | return pointer;
26 | }
27 |
28 | public static int writeBytes(byte[] dest, int pointer, int[] src) {
29 | assert(dest.length > pointer + src.length);
30 | for (int i = 0; i < src.length; i++)
31 | pointer = writeBytes(dest, pointer, src[i]);
32 | return pointer;
33 | }
34 |
35 | public static int writeBytes(byte[] dest, int pointer, long[] src) {
36 | assert(dest.length > pointer + src.length);
37 | for (int i = 0; i < src.length; i++)
38 | pointer = writeBytes(dest, pointer, src[i]);
39 | return pointer;
40 | }
41 |
42 | public static int writeBytes(byte[] dest, int pointer, float[] src) {
43 | assert(dest.length > pointer + src.length);
44 | for (int i = 0; i < src.length; i++)
45 | pointer = writeBytes(dest, pointer, src[i]);
46 | return pointer;
47 | }
48 |
49 | public static int writeBytes(byte[] dest, int pointer, double[] src) {
50 | assert(dest.length > pointer + src.length);
51 | for (int i = 0; i < src.length; i++)
52 | pointer = writeBytes(dest, pointer, src[i]);
53 | return pointer;
54 | }
55 |
56 | public static int writeBytes(byte[] dest, int pointer, boolean[] src) {
57 | assert(dest.length > pointer + src.length);
58 | for (int i = 0; i < src.length; i++)
59 | pointer = writeBytes(dest, pointer, src[i]);
60 | return pointer;
61 | }
62 |
63 | public static int writeBytes(byte[] dest, int pointer, byte value) {
64 | assert(dest.length > pointer + Type.getSize(Type.BYTE));
65 | dest[pointer++] = value;
66 | return pointer;
67 | }
68 |
69 | public static int writeBytes(byte[] dest, int pointer, short value) {
70 | assert(dest.length > pointer + Type.getSize(Type.SHORT));
71 | dest[pointer++] = (byte)((value >> 8) & 0xff);
72 | dest[pointer++] = (byte)((value >> 0) & 0xff);
73 | return pointer;
74 | }
75 |
76 | public static int writeBytes(byte[] dest, int pointer, char value) {
77 | assert(dest.length > pointer + Type.getSize(Type.CHAR));
78 | dest[pointer++] = (byte)((value >> 8) & 0xff);
79 | dest[pointer++] = (byte)((value >> 0) & 0xff);
80 | return pointer;
81 | }
82 |
83 | public static int writeBytes(byte[] dest, int pointer, int value) {
84 | assert(dest.length > pointer + Type.getSize(Type.INTEGER));
85 | dest[pointer++] = (byte)((value >> 24) & 0xff);
86 | dest[pointer++] = (byte)((value >> 16) & 0xff);
87 | dest[pointer++] = (byte)((value >> 8) & 0xff);
88 | dest[pointer++] = (byte)((value >> 0) & 0xff);
89 | return pointer;
90 | }
91 |
92 | public static int writeBytes(byte[] dest, int pointer, long value) {
93 | assert(dest.length > pointer + Type.getSize(Type.LONG));
94 | dest[pointer++] = (byte)((value >> 56) & 0xff);
95 | dest[pointer++] = (byte)((value >> 48) & 0xff);
96 | dest[pointer++] = (byte)((value >> 40) & 0xff);
97 | dest[pointer++] = (byte)((value >> 32) & 0xff);
98 | dest[pointer++] = (byte)((value >> 24) & 0xff);
99 | dest[pointer++] = (byte)((value >> 16) & 0xff);
100 | dest[pointer++] = (byte)((value >> 8) & 0xff);
101 | dest[pointer++] = (byte)((value >> 0) & 0xff);
102 | return pointer;
103 | }
104 |
105 | public static int writeBytes(byte[] dest, int pointer, float value) {
106 | assert(dest.length > pointer + Type.getSize(Type.FLOAT));
107 | int data = Float.floatToIntBits(value);
108 | return writeBytes(dest, pointer, data);
109 | }
110 |
111 | public static int writeBytes(byte[] dest, int pointer, double value) {
112 | assert(dest.length > pointer + Type.getSize(Type.DOUBLE));
113 | long data = Double.doubleToLongBits(value);
114 | return writeBytes(dest, pointer, data);
115 | }
116 |
117 | public static int writeBytes(byte[] dest, int pointer, boolean value) {
118 | assert(dest.length > pointer + Type.getSize(Type.BOOLEAN));
119 | dest[pointer++] = (byte)(value ? 1 : 0);
120 | return pointer;
121 | }
122 |
123 | public static int writeBytes(byte[] dest, int pointer, String string) {
124 | pointer = writeBytes(dest, pointer, (short) string.length());
125 | return writeBytes(dest, pointer, string.getBytes());
126 | }
127 |
128 | public static byte readByte(byte[] src, int pointer) {
129 | return src[pointer];
130 | }
131 |
132 | public static void readBytes(byte[] src, int pointer, byte[] dest) {
133 | for (int i = 0; i < dest.length; i++)
134 | dest[i] = src[pointer + i];
135 | }
136 |
137 | public static void readShorts(byte[] src, int pointer, short[] dest) {
138 | for (int i = 0; i < dest.length; i++) {
139 | dest[i] = readShort(src, pointer);
140 | pointer += Type.getSize(Type.SHORT);
141 | }
142 | }
143 |
144 | public static void readChars(byte[] src, int pointer, char[] dest) {
145 | for (int i = 0; i < dest.length; i++) {
146 | dest[i] = readChar(src, pointer);
147 | pointer += Type.getSize(Type.CHAR);
148 | }
149 | }
150 |
151 | public static void readInts(byte[] src, int pointer, int[] dest) {
152 | for (int i = 0; i < dest.length; i++) {
153 | dest[i] = readInt(src, pointer);
154 | pointer += Type.getSize(Type.INTEGER);
155 | }
156 | }
157 |
158 | public static void readLongs(byte[] src, int pointer, long[] dest) {
159 | for (int i = 0; i < dest.length; i++) {
160 | dest[i] = readLong(src, pointer);
161 | pointer += Type.getSize(Type.LONG);
162 | }
163 | }
164 |
165 | public static void readFloats(byte[] src, int pointer, float[] dest) {
166 | for (int i = 0; i < dest.length; i++) {
167 | dest[i] = readFloat(src, pointer);
168 | pointer += Type.getSize(Type.FLOAT);
169 | }
170 | }
171 |
172 | public static void readDoubles(byte[] src, int pointer, double[] dest) {
173 | for (int i = 0; i < dest.length; i++) {
174 | dest[i] = readDouble(src, pointer);
175 | pointer += Type.getSize(Type.DOUBLE);
176 | }
177 | }
178 |
179 | public static void readBooleans(byte[] src, int pointer, boolean[] dest) {
180 | for (int i = 0; i < dest.length; i++) {
181 | dest[i] = readBoolean(src, pointer);
182 | pointer += Type.getSize(Type.BOOLEAN);
183 | }
184 | }
185 | public static short readShort(byte[] src, int pointer) {
186 | return ByteBuffer.wrap(src, pointer, 2).getShort();
187 | }
188 |
189 | public static char readChar(byte[] src, int pointer) {
190 | return ByteBuffer.wrap(src, pointer, 2).getChar();
191 | }
192 |
193 | public static int readInt(byte[] src, int pointer) {
194 | return ByteBuffer.wrap(src, pointer, 4).getInt();
195 | }
196 |
197 | public static long readLong(byte[] src, int pointer) {
198 | return ByteBuffer.wrap(src, pointer, 8).getLong();
199 | }
200 |
201 | public static float readFloat(byte[] src, int pointer) {
202 | return Float.intBitsToFloat(readInt(src, pointer));
203 | }
204 |
205 | public static double readDouble(byte[] src, int pointer) {
206 | return Double.longBitsToDouble(readLong(src, pointer));
207 | }
208 |
209 | public static boolean readBoolean(byte[] src, int pointer) {
210 | assert(src[pointer] == 0 || src[pointer] == 1);
211 | return src[pointer] != 0;
212 | }
213 |
214 | public static String readString(byte[] src, int pointer, int length) {
215 | return new String(src, pointer, length);
216 | }
217 | }
218 |
--------------------------------------------------------------------------------
/RainCloud-Serialization/src/com/thecherno/raincloud/serialization/Type.java:
--------------------------------------------------------------------------------
1 | package com.thecherno.raincloud.serialization;
2 |
3 | public class Type {
4 |
5 | public static final byte UNKNOWN = 0;
6 | public static final byte BYTE = 1;
7 | public static final byte SHORT = 2;
8 | public static final byte CHAR = 3;
9 | public static final byte INTEGER = 4;
10 | public static final byte LONG = 5;
11 | public static final byte FLOAT = 6;
12 | public static final byte DOUBLE = 7;
13 | public static final byte BOOLEAN = 8;
14 |
15 | public static int getSize(byte type) {
16 | switch (type) {
17 | case BYTE: return 1;
18 | case SHORT: return 2;
19 | case CHAR: return 2;
20 | case INTEGER: return 4;
21 | case LONG: return 8;
22 | case FLOAT: return 4;
23 | case DOUBLE: return 8;
24 | case BOOLEAN: return 1;
25 | }
26 | assert(false);
27 | return 0;
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/Sandbox/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Sandbox/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | Sandbox
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.jdt.core.javanature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Sandbox/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
5 | org.eclipse.jdt.core.compiler.compliance=1.8
6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate
7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate
8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate
9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
11 | org.eclipse.jdt.core.compiler.source=1.8
12 |
--------------------------------------------------------------------------------
/Sandbox/src/Main.java:
--------------------------------------------------------------------------------
1 | import java.io.BufferedOutputStream;
2 | import java.io.FileOutputStream;
3 | import java.io.IOException;
4 | import java.util.Random;
5 |
6 | import com.thecherno.raincloud.serialization.RCArray;
7 | import com.thecherno.raincloud.serialization.RCBase;
8 | import com.thecherno.raincloud.serialization.RCDatabase;
9 | import com.thecherno.raincloud.serialization.RCField;
10 | import com.thecherno.raincloud.serialization.RCObject;
11 | import com.thecherno.raincloud.serialization.RCString;
12 |
13 | public class Main {
14 |
15 | static Random random = new Random();
16 |
17 | static void printBytes(byte[] data) {
18 | for (int i = 0; i < data.length; i++) {
19 | System.out.printf("0x%x ", data[i]);
20 | }
21 | }
22 |
23 | public static void serializationTest() {
24 | int[] data = new int[50000];
25 | for (int i = 0; i < data.length; i++) {
26 | data[i] = random.nextInt();
27 | }
28 |
29 | RCDatabase database = new RCDatabase("Database");
30 | RCArray array = RCArray.Integer("RandomNumbers", data);
31 | RCField field = RCField.Integer("Integer", 8);
32 | RCField positionx = RCField.Short("xpos", (short)2);
33 | RCField positiony = RCField.Short("ypos", (short)43);
34 |
35 | RCObject object = new RCObject("Entity");
36 | object.addArray(array);
37 | object.addArray(RCArray.Char("String", "Hello World!".toCharArray()));
38 | object.addField(field);
39 | object.addField(positionx);
40 | object.addField(positiony);
41 | object.addString(RCString.Create("Example String", "Testing our RCString class!"));
42 |
43 | database.addObject(object);
44 | database.addObject(new RCObject("Cherno"));
45 | database.addObject(new RCObject("Cherno1"));
46 | RCObject c = new RCObject("Cherno2");
47 | c.addField(RCField.Boolean("a", false));
48 | database.addObject(c);
49 | database.addObject(new RCObject("Cherno3"));
50 |
51 | database.serializeToFile("test.rcd");
52 | }
53 |
54 | public static void deserializationTest() {
55 | RCDatabase database = RCDatabase.DeserializeFromFile("test.rcd");
56 | System.out.println("Database: " + database.getName());
57 | for (RCObject object : database.objects) {
58 | System.out.println("\t" + object.getName());
59 | for (RCField field : object.fields)
60 | System.out.println("\t\t" + field.getName());
61 | System.out.println();
62 | for (RCString string : object.strings)
63 | System.out.println("\t\t" + string.getName() + " = " + string.getString());
64 | System.out.println();
65 | for (RCArray array : object.arrays)
66 | System.out.println("\t\t" + array.getName());
67 | System.out.println();
68 | }
69 | System.out.println();
70 | }
71 |
72 | public static void main(String[] args) {
73 | // serializationTest();
74 | // deserializationTest();
75 |
76 | Sandbox sandbox = new Sandbox();
77 | sandbox.play();
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/Sandbox/src/Sandbox.java:
--------------------------------------------------------------------------------
1 | import java.util.ArrayList;
2 | import java.util.List;
3 |
4 | import com.thecherno.raincloud.serialization.RCDatabase;
5 | import com.thecherno.raincloud.serialization.RCField;
6 | import com.thecherno.raincloud.serialization.RCObject;
7 | import com.thecherno.raincloud.serialization.RCString;
8 |
9 | public class Sandbox {
10 |
11 | static class Level {
12 |
13 | private String name;
14 | private String path;
15 | private int width, height;
16 | private List entities = new ArrayList();
17 |
18 | private Level() {
19 | }
20 |
21 | public Level(String path) {
22 | this.name = "Level One";
23 | this.path = path;
24 | width = 64;
25 | height = 128;
26 | }
27 |
28 | public void add(Entity e) {
29 | e.init(this);
30 | entities.add(e);
31 | }
32 |
33 | public void update() {
34 | }
35 |
36 | public void render() {
37 | }
38 |
39 | public void save(String path) {
40 | RCDatabase database = new RCDatabase(name);
41 | RCObject object = new RCObject("LevelData");
42 | object.addString(RCString.Create("name", name));
43 | object.addString(RCString.Create("path", this.path));
44 | object.addField(RCField.Integer("width", width));
45 | object.addField(RCField.Integer("height", height));
46 | object.addField(RCField.Integer("entityCount", entities.size()));
47 | database.addObject(object);
48 | for (int i = 0; i < entities.size(); i++) {
49 | Entity e = entities.get(i);
50 |
51 | RCObject entity = new RCObject("E" + i);
52 | byte type = 0;
53 | if (e instanceof Player)
54 | type = 1;
55 | entity.addField(RCField.Byte("type", type));
56 | entity.addField(RCField.Integer("arrayIndex", i));
57 | e.serialize(entity);
58 | database.addObject(entity);
59 | }
60 |
61 | database.serializeToFile(path);
62 | }
63 |
64 | public static Level load(String path) {
65 | RCDatabase database = RCDatabase.DeserializeFromFile(path);
66 | RCObject levelData = database.findObject("LevelData");
67 |
68 | Level result = new Level();
69 | result.name = levelData.findString("name").getString();
70 | result.path = levelData.findString("path").getString();
71 | result.width = levelData.findField("width").getInt();
72 | result.height = levelData.findField("height").getInt();
73 | int entityCount = levelData.findField("entityCount").getInt();
74 |
75 | for (int i = 0; i < entityCount; i++) {
76 | RCObject entity = database.findObject("E" + i);
77 | Entity e;
78 | if (entity.findField("type").getByte() == 1)
79 | e = Player.deserialize(entity);
80 | else
81 | e = Entity.deserialize(entity);
82 | result.add(e);
83 | }
84 | return result;
85 | }
86 |
87 | }
88 |
89 | static class Entity {
90 |
91 | protected int x, y;
92 | protected boolean removed = false;
93 | protected Level level;
94 |
95 | public Entity() {
96 | x = 0;
97 | y = 0;
98 | }
99 |
100 | public void init(Level level) {
101 | this.level = level;
102 | }
103 |
104 | public void serialize(RCObject object) {
105 | object.addField(RCField.Integer("x", x));
106 | object.addField(RCField.Integer("y", y));
107 | object.addField(RCField.Boolean("removed", removed));
108 | }
109 |
110 | public static Entity deserialize(RCObject object) {
111 | Entity result = new Entity();
112 | result.x = object.findField("x").getInt();
113 | result.y = object.findField("y").getInt();
114 | result.removed = object.findField("removed").getBoolean();
115 | return result;
116 | }
117 |
118 | }
119 |
120 | static class Player extends Entity {
121 |
122 | private String name;
123 | private String avatarPath;
124 |
125 | private Player() {
126 | }
127 |
128 | public Player(String name, int x, int y) {
129 | this.x = x;
130 | this.y = y;
131 |
132 | this.name = name;
133 | avatarPath = "res/avatar.png";
134 | }
135 |
136 | public void serialize(RCObject object) {
137 | super.serialize(object);
138 | object.addString(RCString.Create("name", name));
139 | object.addString(RCString.Create("avatarPath", avatarPath));
140 | }
141 |
142 | public static Player deserialize(RCObject object) {
143 | Entity e = Entity.deserialize(object);
144 |
145 | Player result = new Player();
146 | result.x = e.x;
147 | result.y = e.y;
148 | result.removed = e.removed;
149 |
150 | result.name = object.findString("name").getString();
151 | result.avatarPath = object.findString("avatarPath").getString();
152 |
153 | return result;
154 | }
155 |
156 | }
157 |
158 | public void play() {
159 | {
160 | Entity mob = new Entity();
161 | Player player = new Player("Cherno", 40, 28);
162 |
163 | Level level = new Level("res/level.lvl");
164 | level.add(mob);
165 | level.add(player);
166 |
167 | level.save("level.rcd");
168 | }
169 | {
170 | Level level = Level.load("level.rcd");
171 | System.out.println();
172 | }
173 | }
174 |
175 | }
176 |
--------------------------------------------------------------------------------