1 /* 2 Copyright (c) 2016-2018 Timur Gafarov 3 4 Boost Software License - Version 1.0 - August 17th, 2003 5 6 Permission is hereby granted, free of charge, to any person or organization 7 obtaining a copy of the software and accompanying documentation covered by 8 this license (the "Software") to use, reproduce, display, distribute, 9 execute, and transmit the Software, and to prepare derivative works of the 10 Software, and to permit third-parties to whom the Software is furnished to 11 do so, all subject to the following: 12 13 The copyright notices in the Software and this entire statement, including 14 the above license grant, this restriction and the following disclaimer, 15 must be included in all copies of the Software, in whole or in part, and 16 all derivative works of the Software, unless such copies or derivative 17 works are solely in the form of machine-executable object code generated by 18 a source language processor. 19 20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 23 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 24 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 DEALINGS IN THE SOFTWARE. 27 */ 28 29 module dagon.resource.props; 30 31 import std.stdio; 32 import std.ascii; 33 import std.conv; 34 import dlib.core.memory; 35 import dlib.container.array; 36 import dlib.container.dict; 37 import dlib.text.utils; 38 import dlib.math.vector; 39 import dlib.image.color; 40 import dlib.text.lexer; 41 import dagon.core.ownership; 42 43 enum DPropType 44 { 45 Undefined, 46 Number, 47 Vector, 48 String 49 } 50 51 struct DProperty 52 { 53 DPropType type; 54 string name; 55 string data; 56 57 string toString() 58 { 59 return data; 60 } 61 62 double toDouble() 63 { 64 return to!double(data); 65 } 66 67 float toFloat() 68 { 69 return to!float(data); 70 } 71 72 int toInt() 73 { 74 return to!int(data); 75 } 76 77 int toUInt() 78 { 79 return to!uint(data); 80 } 81 82 bool toBool() 83 { 84 return cast(bool)cast(int)(to!float(data)); 85 } 86 87 Vector3f toVector3f() 88 { 89 return Vector3f(data); 90 } 91 92 Vector4f toVector4f() 93 { 94 return Vector4f(data); 95 } 96 97 Color4f toColor4f() 98 { 99 return Color4f(Vector4f(data)); 100 } 101 } 102 103 class Properties: Owner 104 { 105 protected Dict!(DProperty, string) props; 106 107 this(Owner o) 108 { 109 super(o); 110 props = dict!(DProperty, string); 111 } 112 113 bool parse(string input) 114 { 115 return parseProperties(input, this); 116 } 117 118 DProperty opIndex(string name) 119 { 120 if (name in props) 121 return props[name]; 122 else 123 return DProperty(DPropType.Undefined, ""); 124 } 125 /* 126 DProperty opIndexAssign(DProperty v, string name) 127 { 128 if (name in props) 129 { 130 Delete(props[name].name); 131 Delete(props[name].data); 132 props[name] = v; 133 } 134 else 135 { 136 props[name] = v; 137 } 138 return v; 139 } 140 */ 141 142 void set(DPropType type, string name, string value) 143 { 144 auto p = name in props; 145 if (p) 146 { 147 Delete(p.name); 148 Delete(p.data); 149 auto nameCopy = copyStr(name); 150 auto valueCopy = copyStr(value); 151 props[nameCopy] = DProperty(type, nameCopy, valueCopy); 152 //props[name] = v; 153 } 154 else 155 { 156 //props[name] = v; 157 auto nameCopy = copyStr(name); 158 auto valueCopy = copyStr(value); 159 props[nameCopy] = DProperty(type, nameCopy, valueCopy); 160 } 161 } 162 163 DProperty opDispatch(string s)() 164 { 165 if (s in props) 166 return props[s]; 167 else 168 return DProperty(DPropType.Undefined, ""); 169 } 170 171 DProperty* opIn_r(string k) 172 { 173 return (k in props); 174 } 175 176 void remove(string name) 177 { 178 if (name in props) 179 { 180 auto n = props[name].name; 181 Delete(props[name].data); 182 props.remove(name); 183 Delete(n); 184 } 185 } 186 187 int opApply(int delegate(string, ref DProperty) dg) 188 { 189 foreach(k, v; props) 190 { 191 dg(k, v); 192 } 193 194 return 0; 195 } 196 197 ~this() 198 { 199 foreach(k, v; props) 200 { 201 Delete(v.data); 202 Delete(v.name); 203 } 204 Delete(props); 205 } 206 } 207 208 bool isWhiteStr(string s) 209 { 210 bool res; 211 foreach(c; s) 212 { 213 res = false; 214 foreach(w; std.ascii.whitespace) 215 { 216 if (c == w) 217 res = true; 218 } 219 220 if (c == '\n' || c == '\r') 221 res = true; 222 } 223 return res; 224 } 225 226 bool isValidIdentifier(string s) 227 { 228 return (isAlpha(s[0]) || s[0] == '_'); 229 } 230 231 string copyStr(T)(T[] s) 232 { 233 auto res = New!(char[])(s.length); 234 foreach(i, c; s) 235 res[i] = c; 236 return cast(string)res; 237 } 238 239 bool parseProperties(string input, Properties props) 240 { 241 enum Expect 242 { 243 PropName, 244 Colon, 245 Semicolon, 246 Value, 247 String, 248 Vector, 249 Number 250 } 251 252 bool res = true; 253 auto lexer = New!Lexer(input, [":", ";", "\"", "[", "]", ","]); 254 255 lexer.ignoreNewlines = true; 256 257 Expect expect = Expect.PropName; 258 string propName; 259 DynamicArray!char propValue; 260 DPropType propType; 261 262 while(true) 263 { 264 auto lexeme = lexer.getLexeme(); 265 if (lexeme.length == 0) 266 { 267 if (expect != Expect.PropName) 268 { 269 writefln("Error: unexpected end of string"); 270 res = false; 271 } 272 break; 273 } 274 275 if (isWhiteStr(lexeme) && expect != Expect.String) 276 continue; 277 278 if (expect == Expect.PropName) 279 { 280 if (!isValidIdentifier(lexeme)) 281 { 282 writefln("Error: illegal identifier name \"%s\"", lexeme); 283 res = false; 284 break; 285 } 286 287 propName = lexeme; 288 expect = Expect.Colon; 289 } 290 else if (expect == Expect.Colon) 291 { 292 if (lexeme != ":") 293 { 294 writefln("Error: expected \":\", got \"%s\"", lexeme); 295 res = false; 296 break; 297 } 298 299 expect = Expect.Value; 300 } 301 else if (expect == Expect.Semicolon) 302 { 303 if (lexeme != ";") 304 { 305 writefln("Error: expected \";\", got \"%s\"", lexeme); 306 res = false; 307 break; 308 } 309 310 //auto nameCopy = copyStr(propName); 311 //auto valueCopy = copyStr(propValue.data); 312 313 //props[nameCopy] = DProperty(propType, nameCopy, valueCopy); 314 props.set(propType, propName, cast(string)propValue.data); 315 316 expect = Expect.PropName; 317 propName = ""; 318 propValue.free(); 319 } 320 else if (expect == Expect.Value) 321 { 322 if (lexeme == "\"") 323 { 324 propType = DPropType.String; 325 expect = Expect.String; 326 } 327 else if (lexeme == "[") 328 { 329 propType = DPropType.Vector; 330 expect = Expect.Vector; 331 propValue.append(lexeme); 332 } 333 else 334 { 335 propType = DPropType.Number; 336 propValue.append(lexeme); 337 expect = Expect.Semicolon; 338 } 339 } 340 else if (expect == Expect.String) 341 { 342 if (lexeme == "\"") 343 expect = Expect.Semicolon; 344 else 345 propValue.append(lexeme); 346 } 347 else if (expect == Expect.Vector) 348 { 349 if (lexeme == "]") 350 expect = Expect.Semicolon; 351 352 propValue.append(lexeme); 353 } 354 } 355 356 propValue.free(); 357 Delete(lexer); 358 359 return res; 360 }