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 }