1 /**
2  * Binary format (represents as bytecode)
3  *
4  * Copyright: © 2017 Andrey Kabylin
5  * License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file.
6  */
7 
8 module rpdl.file_formats.bin;
9 
10 import std.conv;
11 
12 import rpdl.node;
13 import rpdl.value;
14 import rpdl.writer;
15 import rpdl.reader;
16 
17 /// Available bytecode commands
18 enum OpCode {
19     none = 0x00,
20     end = 0x01,  /// End of node or file
21     object = 0x02,  /// Represent `rpdl.node.ObjectNode`
22     klass = 0x03,  /// Deprecated op code
23     parameter = 0x04,  /// Represent `rpdl.node.Parameter`
24     numberValue = 0x05,  /// Represent `rpdl.value.NumberValue`
25     booleanValue = 0x06,  /// Represent `rpdl.value.BooleanValue`
26     stringValue = 0x07,  /// Represent `rpdl.value.StringValue`
27     identifierValue = 0x08,  /// Represent `rpdl.value.IdentifierValue`
28     arrayValue = 0x09  /// Represent `rpdl.value.ArrayValue`
29 }
30 
31 /// Tree writer to byte code
32 class BinWriter : Writer {
33     this(Node root) { super(root); }
34 
35     override void save(in string fileName) {
36         super.save(fileName);
37         writeOpCode(OpCode.end);
38     }
39 
40 protected:
41     /// Write name of `node` - pair of name length and name data.
42     void writeName(Node node) {
43         rawWrite(cast(ubyte) node.name.length);
44         rawWrite(node.name);
45     }
46 
47     /// Pair of string length and string data.
48     void writeString(string str) {
49         rawWrite(cast(ubyte) str.length);
50         rawWrite(str);
51     }
52 
53     void writeOpCode(OpCode code) {
54         rawWrite(cast(ubyte) code);
55     }
56 
57     override void writeObject(ObjectNode object) {
58         writeOpCode(OpCode.object);
59         writeName(object);
60         super.writeObject(object);
61         writeOpCode(OpCode.end);
62     }
63 
64     override void writeParameter(Parameter parameter) {
65         writeOpCode(OpCode.parameter);
66         writeName(parameter);
67         super.writeParameter(parameter);
68         writeOpCode(OpCode.end);
69     }
70 
71     override void writeNumberValue(NumberValue node) {
72         writeOpCode(OpCode.numberValue);
73         writeName(node);
74         rawWrite(node.value);
75     }
76 
77     override void writeBooleanValue(BooleanValue node) {
78         writeOpCode(OpCode.booleanValue);
79         writeName(node);
80         rawWrite(node.value);
81     }
82 
83     override void writeStringValue(StringValue node) {
84         writeOpCode(OpCode.stringValue);
85         writeName(node);
86         writeString(node.value);
87     }
88 
89     override void writeIdentifierValue(IdentifierValue node) {
90         writeOpCode(OpCode.identifierValue);
91         writeName(node);
92         writeString(node.value);
93     }
94 
95     override void writeArrayValue(ArrayValue array) {
96         writeOpCode(OpCode.arrayValue);
97         writeName(array);
98         super.writeArrayValue(array);
99         writeOpCode(OpCode.end);
100     }
101 }
102 
103 /// Tree reader from byte code.
104 class BinReader : Reader {
105     this(Node root) { super(root); }
106 
107 protected:
108     ubyte currentOpCode = OpCode.none;
109 
110     T rawRead(T)() {
111         T[1] buf;
112         file.rawRead(buf);
113         return buf[0];
114     }
115 
116     alias readByte = rawRead!ubyte;
117     alias readBoolean = rawRead!bool;
118     alias readNumber = rawRead!float;
119 
120     string readString(in ubyte length) {
121         char[] buf = new char[length];
122         file.rawRead(buf);
123         return cast(string) buf;
124     }
125 
126     override void readObjects() {
127         ubyte opCode;
128 
129         while (opCode != OpCode.end) {
130             opCode = readByte();
131 
132             if (opCode == OpCode.end)
133                 break;
134 
135             if (opCode != OpCode.object)
136                 assert(false);  // TODO: throw an exception
137 
138             readObject(root);
139         }
140     }
141 
142     override void readObject(Node parent) {
143         const ubyte nameLength = readByte();
144         const string name = readString(nameLength);
145 
146         ObjectNode object = new ObjectNode(name);
147         parent.insert(object);
148         ubyte opCode = readByte();
149 
150         while (opCode != OpCode.end) {
151             switch (opCode) {
152                 case OpCode.object:
153                     readObject(object);
154                     break;
155 
156                 case OpCode.parameter:
157                     readParameter(object);
158                     break;
159 
160                 default:
161                     assert(false);  // TODO: throw an exception
162             }
163 
164             opCode = readByte();
165         }
166     }
167 
168     override void readParameter(Node parent) {
169         const ubyte nameLength = readByte();
170         const string name = readString(nameLength);
171 
172         Parameter parameter = new Parameter(name);
173         parent.insert(parameter);
174 
175         ubyte opCode = readByte();
176 
177         while (opCode != OpCode.end) {
178             currentOpCode = opCode;
179             readValue(parameter);
180             opCode = readByte();
181         }
182     }
183 
184     override void readArrayValue(Node parent) {
185         const ubyte nameLength = readByte();
186         const string name = readString(nameLength);
187 
188         ArrayValue arrayNode = new ArrayValue(name);
189         parent.insert(arrayNode);
190 
191         ubyte opCode = readByte();
192 
193         while (opCode != OpCode.end) {
194             currentOpCode = opCode;
195             readValue(arrayNode);
196             opCode = readByte();
197         }
198     }
199 
200     override void readValue(Node parent) {
201         switch (currentOpCode) {
202             case OpCode.numberValue:
203                 readNumberValue(parent);
204                 break;
205 
206             case OpCode.booleanValue:
207                 readBooleanValue(parent);
208                 break;
209 
210             case OpCode.stringValue:
211                 readStringValue(parent);
212                 break;
213 
214             case OpCode.identifierValue:
215                 readIdentifierValue(parent);
216                 break;
217 
218             case OpCode.arrayValue:
219                 readArrayValue(parent);
220                 break;
221 
222             default:
223                 assert(false);  // TODO: throw an exception
224         }
225     }
226 
227     override void readNumberValue(Node parent) {
228         const ubyte nameLength = readByte();
229         const string name = readString(nameLength);
230         const float value = readNumber();
231 
232         NumberValue valueNode = new NumberValue(name, value);
233         parent.insert(valueNode);
234     }
235 
236     override void readBooleanValue(Node parent) {
237         const ubyte nameLength = readByte();
238         const string name = readString(nameLength);
239         const bool value = readBoolean();
240 
241         BooleanValue valueNode = new BooleanValue(name, value);
242         parent.insert(valueNode);
243     }
244 
245     override void readStringValue(Node parent) {
246         const ubyte nameLength = readByte();
247         const string name = readString(nameLength);
248 
249         const ubyte stringLength = readByte();
250         const string value = readString(stringLength);
251         const dstring utfValue = to!dstring(value);
252 
253         StringValue valueNode = new StringValue(name, value, utfValue);
254         parent.insert(valueNode);
255     }
256 
257     override void readIdentifierValue(Node parent) {
258         const ubyte nameLength = readByte();
259         const string name = readString(nameLength);
260 
261         const ubyte stringLength = readByte();
262         const string value = readString(stringLength);
263 
264         IdentifierValue valueNode = new IdentifierValue(name, value);
265         parent.insert(valueNode);
266     }
267 }