Properties.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820
  1. #include "Base.h"
  2. #include "Properties.h"
  3. #include "FileSystem.h"
  4. #include "Quaternion.h"
  5. namespace gameplay
  6. {
  7. Properties::Properties()
  8. {
  9. }
  10. Properties::Properties(const Properties& copy)
  11. {
  12. _namespace = copy._namespace;
  13. _id = copy._id;
  14. _parentID = copy._parentID;
  15. _properties = copy._properties;
  16. _namespaces = std::vector<Properties*>();
  17. std::vector<Properties*>::const_iterator it;
  18. for (it = copy._namespaces.begin(); it < copy._namespaces.end(); it++)
  19. {
  20. _namespaces.push_back(new Properties(**it));
  21. }
  22. rewind();
  23. }
  24. Properties::Properties(FILE* file)
  25. {
  26. readProperties(file);
  27. rewind();
  28. }
  29. Properties::Properties(FILE* file, const char* name, const char* id, const char* parentID) : _namespace(name)
  30. {
  31. if (id)
  32. {
  33. _id = id;
  34. }
  35. if (parentID)
  36. {
  37. _parentID = parentID;
  38. }
  39. readProperties(file);
  40. rewind();
  41. }
  42. Properties* Properties::create(const char* filePath)
  43. {
  44. assert(filePath);
  45. FILE* file = FileSystem::openFile(filePath, "rb");
  46. if (!file)
  47. {
  48. return NULL;
  49. }
  50. Properties* properties = new Properties(file);
  51. properties->resolveInheritance();
  52. fclose(file);
  53. return properties;
  54. }
  55. void Properties::readProperties(FILE* file)
  56. {
  57. char line[2048];
  58. int c;
  59. char* name;
  60. char* value;
  61. char* parentID;
  62. char* rc;
  63. char* rcc;
  64. while (true)
  65. {
  66. skipWhiteSpace(file);
  67. // Stop when we have reached the end of the file.
  68. if (feof(file))
  69. break;
  70. // Read the next line.
  71. rc = fgets(line, 2048, file);
  72. if (rc == NULL)
  73. {
  74. return;
  75. }
  76. // Ignore comment, skip line.
  77. if (strncmp(line, "//", 2) != 0)
  78. {
  79. // If an '=' appears on this line, parse it as a name/value pair.
  80. // Note: strchr() has to be called before strtok(), or a backup of line has to be kept.
  81. rc = strchr(line, '=');
  82. if (rc != NULL)
  83. {
  84. // There could be a '}' at the end of the line, ending a namespace.
  85. rc = strchr(line, '}');
  86. // First token should be the property name.
  87. name = strtok(line, " =\t");
  88. if (name == NULL)
  89. {
  90. LOG_ERROR("Error parsing properties file: value without name.");
  91. return;
  92. }
  93. // Scan for next token, the property's value.
  94. value = strtok(NULL, "=");
  95. if (value == NULL)
  96. {
  97. LOG_ERROR("Error parsing properties file: name without value.");
  98. }
  99. // Remove white-space from value.
  100. value = trimWhiteSpace(value);
  101. // Store name/value pair.
  102. _properties[name] = value;
  103. if (rc != NULL)
  104. {
  105. // End of namespace.
  106. return;
  107. }
  108. }
  109. else
  110. {
  111. parentID = NULL;
  112. // This line might begin or end a namespace,
  113. // or it might be a key/value pair without '='.
  114. // Check for '{' on same line.
  115. rc = strchr(line, '{');
  116. // Check for inheritance: ':'
  117. rcc = strchr(line, ':');
  118. // Get the name of the namespace.
  119. name = strtok(line, " \t\n{");
  120. name = trimWhiteSpace(name);
  121. if (name == NULL)
  122. {
  123. LOG_ERROR("Error parsing properties file: unknown error.");
  124. }
  125. else if (name[0] == '}')
  126. {
  127. // End of namespace.
  128. return;
  129. }
  130. // Get its ID if it has one.
  131. value = strtok(NULL, ":{");
  132. value = trimWhiteSpace(value);
  133. if (rcc != NULL)
  134. {
  135. parentID = strtok(NULL, "{");
  136. parentID = trimWhiteSpace(parentID);
  137. }
  138. if (value != NULL && value[0] == '{')
  139. {
  140. // New namespace without an ID.
  141. Properties* space = new Properties(file, name, NULL, parentID);
  142. _namespaces.push_back(space);
  143. }
  144. else
  145. {
  146. // If '{' appears on the same line.
  147. if (rc != NULL)
  148. {
  149. // Create new namespace.
  150. Properties* space = new Properties(file, name, value, parentID);
  151. _namespaces.push_back(space);
  152. }
  153. else
  154. {
  155. // Find out if the next line starts with "{"
  156. skipWhiteSpace(file);
  157. c = fgetc(file);
  158. if (c == '{')
  159. {
  160. // Create new namespace.
  161. Properties* space = new Properties(file, name, value, parentID);
  162. _namespaces.push_back(space);
  163. }
  164. else
  165. {
  166. // Back up from fgetc()
  167. fseek(file, -1, SEEK_CUR);
  168. // Store "name value" as a name/value pair, or even just "name".
  169. if (value != NULL)
  170. {
  171. _properties[name] = value;
  172. }
  173. else
  174. {
  175. _properties[name] = std::string();
  176. }
  177. }
  178. }
  179. }
  180. }
  181. }
  182. }
  183. }
  184. Properties::~Properties()
  185. {
  186. unsigned int count = _namespaces.size();
  187. for (unsigned int i = 0; i < count; i++)
  188. {
  189. SAFE_DELETE(_namespaces[i]);
  190. }
  191. }
  192. void Properties::skipWhiteSpace(FILE* file)
  193. {
  194. int c;
  195. do
  196. {
  197. c = fgetc(file);
  198. } while (isspace(c));
  199. // If we are not at the end of the file, then since we found a
  200. // non-whitespace character, we put the cursor back in front of it.
  201. if (c != EOF)
  202. fseek(file, -1, SEEK_CUR);
  203. }
  204. char* Properties::trimWhiteSpace(char *str)
  205. {
  206. if (str == NULL)
  207. {
  208. return str;
  209. }
  210. char *end;
  211. // Trim leading space.
  212. while (isspace(*str))
  213. str++;
  214. // All spaces?
  215. if (*str == 0)
  216. {
  217. return str;
  218. }
  219. // Trim trailing space.
  220. end = str + strlen(str) - 1;
  221. while (end > str && isspace(*end))
  222. end--;
  223. // Write new null terminator.
  224. *(end+1) = 0;
  225. return str;
  226. }
  227. void Properties::resolveInheritance(const char* id)
  228. {
  229. // Namespaces can be defined like so:
  230. // "name id : parentID { }"
  231. // This method merges data from the parent namespace into the child.
  232. // Get a top-level namespace.
  233. Properties* derived;
  234. if (id)
  235. {
  236. derived = getNamespace(id);
  237. }
  238. else
  239. {
  240. derived = getNextNamespace();
  241. }
  242. while (derived)
  243. {
  244. // If the namespace has a parent ID, find the parent.
  245. if (!derived->_parentID.empty())
  246. {
  247. Properties* parent = getNamespace(derived->_parentID.c_str());
  248. if (parent)
  249. {
  250. resolveInheritance(parent->getId());
  251. // Copy the child.
  252. Properties* overrides = new Properties(*derived);
  253. // Delete the child's data.
  254. unsigned int count = derived->_namespaces.size();
  255. for (unsigned int i = 0; i < count; i++)
  256. {
  257. SAFE_DELETE(derived->_namespaces[i]);
  258. }
  259. // Copy data from the parent into the child.
  260. derived->_properties = parent->_properties;
  261. derived->_namespaces = std::vector<Properties*>();
  262. std::vector<Properties*>::const_iterator itt;
  263. for (itt = parent->_namespaces.begin(); itt < parent->_namespaces.end(); itt++)
  264. {
  265. derived->_namespaces.push_back(new Properties(**itt));
  266. }
  267. derived->rewind();
  268. // Take the original copy of the child and override the data copied from the parent.
  269. derived->mergeWith(overrides);
  270. // Delete the child copy.
  271. SAFE_DELETE(overrides);
  272. }
  273. }
  274. // Resolve inheritance within this namespace.
  275. derived->resolveInheritance();
  276. // Get the next top-level namespace and check again.
  277. if (!id)
  278. {
  279. derived = getNextNamespace();
  280. }
  281. else
  282. {
  283. derived = NULL;
  284. }
  285. }
  286. }
  287. void Properties::mergeWith(Properties* overrides)
  288. {
  289. // Overwrite or add each property found in child.
  290. char* value = new char[255];
  291. overrides->rewind();
  292. const char* name = overrides->getNextProperty(&value);
  293. while (name)
  294. {
  295. this->_properties[name] = value;
  296. name = overrides->getNextProperty(&value);
  297. }
  298. SAFE_DELETE(value);
  299. this->_propertiesItr = this->_properties.end();
  300. // Merge all common nested namespaces, add new ones.
  301. Properties* overridesNamespace = overrides->getNextNamespace();
  302. while (overridesNamespace)
  303. {
  304. bool merged = false;
  305. rewind();
  306. Properties* derivedNamespace = getNextNamespace();
  307. while (derivedNamespace)
  308. {
  309. if (strcmp(derivedNamespace->getNamespace(), overridesNamespace->getNamespace()) == 0 &&
  310. strcmp(derivedNamespace->getId(), overridesNamespace->getId()) == 0)
  311. {
  312. derivedNamespace->mergeWith(overridesNamespace);
  313. merged = true;
  314. }
  315. derivedNamespace = getNextNamespace();
  316. }
  317. if (!merged)
  318. {
  319. // Add this new namespace.
  320. Properties* newNamespace = new Properties(*overridesNamespace);
  321. this->_namespaces.push_back(newNamespace);
  322. this->_namespacesItr = this->_namespaces.end();
  323. }
  324. overridesNamespace = overrides->getNextNamespace();
  325. }
  326. }
  327. const char* Properties::getNextProperty(char** value)
  328. {
  329. if (_propertiesItr == _properties.end())
  330. {
  331. // Restart from the beginning
  332. _propertiesItr = _properties.begin();
  333. }
  334. else
  335. {
  336. // Move to the next property
  337. _propertiesItr++;
  338. }
  339. if (_propertiesItr != _properties.end())
  340. {
  341. const std::string& name = _propertiesItr->first;
  342. if (!name.empty())
  343. {
  344. if (value)
  345. {
  346. strcpy(*value, _propertiesItr->second.c_str());
  347. }
  348. return name.c_str();
  349. }
  350. }
  351. return NULL;
  352. }
  353. Properties* Properties::getNextNamespace()
  354. {
  355. if (_namespacesItr == _namespaces.end())
  356. {
  357. // Restart from the beginning
  358. _namespacesItr = _namespaces.begin();
  359. }
  360. else
  361. {
  362. _namespacesItr++;
  363. }
  364. if (_namespacesItr != _namespaces.end())
  365. {
  366. Properties* ns = *_namespacesItr;
  367. return ns;
  368. }
  369. return NULL;
  370. }
  371. void Properties::rewind()
  372. {
  373. _propertiesItr = _properties.end();
  374. _namespacesItr = _namespaces.end();
  375. }
  376. Properties* Properties::getNamespace(const char* id) const
  377. {
  378. Properties* ret = NULL;
  379. std::vector<Properties*>::const_iterator it;
  380. for (it = _namespaces.begin(); it < _namespaces.end(); it++)
  381. {
  382. ret = *it;
  383. if (strcmp(ret->_id.c_str(), id) == 0)
  384. {
  385. return ret;
  386. }
  387. // Search recursively.
  388. ret = ret->getNamespace(id);
  389. if (ret != NULL)
  390. {
  391. return ret;
  392. }
  393. }
  394. return ret;
  395. }
  396. const char* Properties::getNamespace() const
  397. {
  398. return _namespace.c_str();
  399. }
  400. const char* Properties::getId() const
  401. {
  402. return _id.c_str();
  403. }
  404. bool Properties::exists(const char* name) const
  405. {
  406. assert(name);
  407. return _properties.find(name) != _properties.end();
  408. }
  409. const bool isStringNumeric(const char* str)
  410. {
  411. // The first character may be '-'
  412. if (*str == '-')
  413. str++;
  414. // The first character after the sign must be a digit
  415. if (!isdigit(*str))
  416. return false;
  417. str++;
  418. // All remaining characters must be digits, with a single decimal (.) permitted
  419. unsigned int decimalCount = 0;
  420. while (*str)
  421. {
  422. if (!isdigit(*str))
  423. {
  424. if (*str == '.' && decimalCount == 0)
  425. {
  426. // Max of 1 decimal allowed
  427. decimalCount++;
  428. }
  429. else
  430. {
  431. return false;
  432. }
  433. }
  434. str++;
  435. }
  436. return true;
  437. }
  438. Properties::Type Properties::getType(const char* name) const
  439. {
  440. const char* value = getString(name);
  441. if (!value)
  442. {
  443. return Properties::NONE;
  444. }
  445. // Parse the value to determine the format
  446. unsigned int commaCount = 0;
  447. //unsigned int length = strlen(value);
  448. char* valuePtr = const_cast<char*>(value);
  449. while (valuePtr = strchr(valuePtr, ','))
  450. {
  451. valuePtr++;
  452. commaCount++;
  453. }
  454. switch (commaCount)
  455. {
  456. case 0:
  457. return isStringNumeric(value) ? Properties::NUMBER : Properties::STRING;
  458. case 1:
  459. return Properties::VECTOR2;
  460. case 2:
  461. return Properties::VECTOR3;
  462. case 3:
  463. return Properties::VECTOR4;
  464. case 15:
  465. return Properties::MATRIX;
  466. default:
  467. return Properties::STRING;
  468. }
  469. }
  470. const char* Properties::getString(const char* name) const
  471. {
  472. if (name)
  473. {
  474. std::map<std::string, std::string>::const_iterator itr = _properties.find(name);
  475. if (itr != _properties.end())
  476. {
  477. return itr->second.c_str();
  478. }
  479. }
  480. else
  481. {
  482. if (_propertiesItr != _properties.end())
  483. {
  484. return _propertiesItr->second.c_str();
  485. }
  486. }
  487. return NULL;
  488. }
  489. bool Properties::getBool(const char* name) const
  490. {
  491. const char* valueString = getString(name);
  492. if (valueString)
  493. {
  494. return (strcmp(valueString, "true") == 0);
  495. }
  496. return false;
  497. }
  498. int Properties::getInt(const char* name) const
  499. {
  500. const char* valueString = getString(name);
  501. if (valueString)
  502. {
  503. int value;
  504. int scanned;
  505. scanned = sscanf(valueString, "%d", &value);
  506. if (scanned != 1)
  507. {
  508. LOG_ERROR_VARG("Error parsing property: %s", name);
  509. return 0;
  510. }
  511. return value;
  512. }
  513. return 0;
  514. }
  515. float Properties::getFloat(const char* name) const
  516. {
  517. const char* valueString = getString(name);
  518. if (valueString)
  519. {
  520. float value;
  521. int scanned;
  522. scanned = sscanf(valueString, "%f", &value);
  523. if (scanned != 1)
  524. {
  525. LOG_ERROR_VARG("Error parsing property: %s", name);
  526. return 0.0f;
  527. }
  528. return value;
  529. }
  530. return 0.0f;
  531. }
  532. long Properties::getLong(const char* name) const
  533. {
  534. const char* valueString = getString(name);
  535. if (valueString)
  536. {
  537. long value;
  538. int scanned;
  539. scanned = sscanf(valueString, "%ld", &value);
  540. if (scanned != 1)
  541. {
  542. LOG_ERROR_VARG("Error parsing property: %s", name);
  543. return 0L;
  544. }
  545. return value;
  546. }
  547. return 0L;
  548. }
  549. bool Properties::getMatrix(const char* name, Matrix* out) const
  550. {
  551. assert(out);
  552. const char* valueString = getString(name);
  553. if (valueString)
  554. {
  555. float m[16];
  556. int scanned;
  557. scanned = sscanf(valueString, "%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f",
  558. &m[0], &m[1], &m[2], &m[3], &m[4], &m[5], &m[6], &m[7],
  559. &m[8], &m[9], &m[10], &m[11], &m[12], &m[13], &m[14], &m[15]);
  560. if (scanned != 16)
  561. {
  562. LOG_ERROR_VARG("Error parsing property: %s", name);
  563. out->setIdentity();
  564. return false;
  565. }
  566. out->set(m);
  567. return true;
  568. }
  569. out->setIdentity();
  570. return false;
  571. }
  572. bool Properties::getVector2(const char* name, Vector2* out) const
  573. {
  574. assert(out);
  575. const char* valueString = getString(name);
  576. if (valueString)
  577. {
  578. float x, y;
  579. int scanned;
  580. scanned = sscanf(valueString, "%f,%f", &x, &y);
  581. if (scanned != 2)
  582. {
  583. LOG_ERROR_VARG("Error parsing property: %s", name);
  584. out->set(0.0f, 0.0f);
  585. return false;
  586. }
  587. out->set(x, y);
  588. return true;
  589. }
  590. out->set(0.0f, 0.0f);
  591. return false;
  592. }
  593. bool Properties::getVector3(const char* name, Vector3* out) const
  594. {
  595. assert(out);
  596. const char* valueString = getString(name);
  597. if (valueString)
  598. {
  599. float x, y, z;
  600. int scanned;
  601. scanned = sscanf(valueString, "%f,%f,%f", &x, &y, &z);
  602. if (scanned != 3)
  603. {
  604. LOG_ERROR_VARG("Error parsing property: %s", name);
  605. out->set(0.0f, 0.0f, 0.0f);
  606. return false;
  607. }
  608. out->set(x, y, z);
  609. return true;
  610. }
  611. out->set(0.0f, 0.0f, 0.0f);
  612. return false;
  613. }
  614. bool Properties::getVector4(const char* name, Vector4* out) const
  615. {
  616. assert(out);
  617. const char* valueString = getString(name);
  618. if (valueString)
  619. {
  620. float x, y, z, w;
  621. int scanned;
  622. scanned = sscanf(valueString, "%f,%f,%f,%f", &x, &y, &z, &w);
  623. if (scanned != 4)
  624. {
  625. LOG_ERROR_VARG("Error parsing property: %s", name);
  626. out->set(0.0f, 0.0f, 0.0f, 0.0f);
  627. return false;
  628. }
  629. out->set(x, y, z, w);
  630. return true;
  631. }
  632. out->set(0.0f, 0.0f, 0.0f, 0.0f);
  633. return false;
  634. }
  635. bool Properties::getQuaternionFromAxisAngle(const char* name, Quaternion* out) const
  636. {
  637. assert(out);
  638. const char* valueString = getString(name);
  639. if (valueString)
  640. {
  641. float x, y, z, theta;
  642. int scanned;
  643. scanned = sscanf(valueString, "%f,%f,%f,%f", &x, &y, &z, &theta);
  644. if (scanned != 4)
  645. {
  646. LOG_ERROR_VARG("Error parsing property: %s", name);
  647. out->set(0.0f, 0.0f, 0.0f, 1.0f);
  648. return false;
  649. }
  650. out->set(Vector3(x, y, z), MATH_DEG_TO_RAD(theta));
  651. return true;
  652. }
  653. out->set(0.0f, 0.0f, 0.0f, 1.0f);
  654. return false;
  655. }
  656. bool Properties::getColor(const char* name, Vector3* out) const
  657. {
  658. assert(out);
  659. const char* valueString = getString(name);
  660. if (valueString)
  661. {
  662. if (strlen(valueString) != 7 ||
  663. valueString[0] != '#')
  664. {
  665. // Not a color string.
  666. LOG_ERROR_VARG("Error parsing property: %s", name);
  667. out->set(0.0f, 0.0f, 0.0f);
  668. return false;
  669. }
  670. // Read the string into an int as hex.
  671. unsigned int color;
  672. sscanf(valueString+1, "%x", &color);
  673. out->set(Vector3::fromColor(color));
  674. return true;
  675. }
  676. out->set(0.0f, 0.0f, 0.0f);
  677. return false;
  678. }
  679. bool Properties::getColor(const char* name, Vector4* out) const
  680. {
  681. assert(out);
  682. const char* valueString = getString(name);
  683. if (valueString)
  684. {
  685. if (strlen(valueString) != 9 ||
  686. valueString[0] != '#')
  687. {
  688. // Not a color string.
  689. LOG_ERROR_VARG("Error parsing property: %s", name);
  690. out->set(0.0f, 0.0f, 0.0f, 0.0f);
  691. return false;
  692. }
  693. // Read the string into an int as hex.
  694. unsigned int color;
  695. sscanf(valueString+1, "%x", &color);
  696. out->set(Vector4::fromColor(color));
  697. return true;
  698. }
  699. out->set(0.0f, 0.0f, 0.0f, 0.0f);
  700. return false;
  701. }
  702. }