MessageListParser.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /* Copyright The kNet Project.
  2. Licensed under the Apache License, Version 2.0 (the "License");
  3. you may not use this file except in compliance with the License.
  4. You may obtain a copy of the License at
  5. http://www.apache.org/licenses/LICENSE-2.0
  6. Unless required by applicable law or agreed to in writing, software
  7. distributed under the License is distributed on an "AS IS" BASIS,
  8. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. See the License for the specific language governing permissions and
  10. limitations under the License. */
  11. /** @file MessageListParser.cpp
  12. @brief */
  13. #ifdef KNET_USE_TINYXML
  14. #include <tinyxml.h>
  15. #endif
  16. #include <cassert>
  17. #include <cstring>
  18. #include "kNet/DebugMemoryLeakCheck.h"
  19. #include "kNet/NetworkLogging.h"
  20. #include "kNet/MessageListParser.h"
  21. #include "kNet/NetException.h"
  22. #include "kNet/Socket.h"
  23. #define NUMELEMS(x) (sizeof(x)/sizeof(x[0]))
  24. namespace
  25. {
  26. ///\note See BasicSerializedDataTypes.h:31: The order of these elements matches that of the BasicSerializedDataType enum.
  27. const char *data[] = { "", "bit", "u8", "s8", "u16", "s16", "u32", "s32", "u64", "s64", "float", "double", "string", "struct" };
  28. const size_t typeSizes[] = { 0xFFFFFFFF, 0xFFFFFFFF, 1, 1, 2, 2, 4, 4, 8, 8, 4, 8, 0xFFFFFFFF, 0xFFFFFFFF }; // 0xFFFFFFFF here denotes 'does not apply'.
  29. }
  30. namespace kNet
  31. {
  32. BasicSerializedDataType StringToSerialType(const char *type)
  33. {
  34. if (!strcmp(type, "string") || !strcmp(type, "std::string"))
  35. return SerialString;
  36. assert(NumSerialTypes-2 == NUMELEMS(data));
  37. for(size_t i = 0; i < NUMELEMS(data); ++i)
  38. if (!strcmp(type, data[i]))
  39. return (BasicSerializedDataType)i;
  40. return SerialInvalid;
  41. }
  42. const char *SerialTypeToReadableString(BasicSerializedDataType type)
  43. {
  44. assert(NumSerialTypes-2 == NUMELEMS(data));
  45. assert(type >= SerialInvalid);
  46. assert(type < NumSerialTypes);
  47. return data[type];
  48. }
  49. const char *SerialTypeToCTypeString(BasicSerializedDataType type)
  50. {
  51. if (type == SerialString)
  52. return "std::string";
  53. assert(NumSerialTypes-2 == NUMELEMS(data));
  54. assert(type >= SerialInvalid);
  55. assert(type < NumSerialTypes);
  56. return data[type];
  57. }
  58. size_t SerialTypeSize(BasicSerializedDataType type)
  59. {
  60. assert(NumSerialTypes-2 == NUMELEMS(data));
  61. assert(type >= SerialInvalid);
  62. assert(type < NumSerialTypes);
  63. return typeSizes[type];
  64. }
  65. SerializedElementDesc *SerializedMessageList::ParseNode(TiXmlElement *node, SerializedElementDesc *parentNode)
  66. {
  67. #ifdef KNET_USE_TINYXML
  68. elements.push_back(SerializedElementDesc());
  69. SerializedElementDesc *elem = &elements.back();
  70. elem->parent = parentNode;
  71. elem->name = node->Attribute("name") ? node->Attribute("name") : "";
  72. if (!strcmp(node->Value(), "message"))
  73. {
  74. elem->count = 1;
  75. elem->varyingCount = false;
  76. elem->type = SerialStruct;
  77. }
  78. else
  79. {
  80. // Cannot have both static count and dynamic count!
  81. if (node->Attribute("count") && node->Attribute("varyingCount"))
  82. KNET_LOG(LogError, "Warning: An XML node contains both 'count' and 'varyingCount' attributes! 'varyingCount' takes precedence.");
  83. if (node->Attribute("dynamicCount"))
  84. {
  85. node->QueryIntAttribute("dynamicCount", &elem->count);
  86. elem->varyingCount = true;
  87. }
  88. else if (node->Attribute("count"))
  89. {
  90. node->QueryIntAttribute("count", &elem->count);
  91. elem->varyingCount = false;
  92. }
  93. else
  94. {
  95. elem->count = 1;
  96. elem->varyingCount = false;
  97. }
  98. elem->typeString = node->Value();
  99. if (elem->typeString == "string")
  100. elem->typeString = "std::string";
  101. elem->type = StringToSerialType(node->Value());
  102. if (elem->type == SerialInvalid && !elem->typeString.empty())
  103. elem->type = SerialOther;
  104. if (elem->type == SerialStruct)
  105. elem->typeString = "S_" + elem->name; ///\todo Add a ClassName parameter for better control over naming here?
  106. }
  107. // If this node is a structure, parse all its members.
  108. if (elem->type == SerialStruct)
  109. {
  110. TiXmlElement *child = node->FirstChildElement();
  111. while(child)
  112. {
  113. SerializedElementDesc *childElem = ParseNode(child, elem);
  114. elem->elements.push_back(childElem);
  115. child = child->NextSiblingElement();
  116. }
  117. }
  118. return elem;
  119. #else
  120. throw NetException("kNet was built without TinyXml support! SerializedMessageList is not available!");
  121. #endif
  122. }
  123. bool ParseBool(const char *str)
  124. {
  125. if (!str)
  126. return false;
  127. if (!_stricmp(str, "true") || !_stricmp(str, "1"))
  128. return true;
  129. else
  130. return false;
  131. }
  132. void SerializedMessageList::ParseMessages(TiXmlElement *root)
  133. {
  134. #ifdef KNET_USE_TINYXML
  135. TiXmlElement *node = root->FirstChildElement("message");
  136. while(node)
  137. {
  138. SerializedMessageDesc desc;
  139. int success = node->QueryIntAttribute("id", (int*)&desc.id);
  140. if (success == TIXML_NO_ATTRIBUTE)
  141. {
  142. KNET_LOG(LogError, "Error parsing message attribute 'id' as int!");
  143. node = node->NextSiblingElement("message");
  144. continue;
  145. }
  146. success = node->QueryIntAttribute("priority", (int*)&desc.priority);
  147. if (success == TIXML_NO_ATTRIBUTE)
  148. desc.priority = 0; // If priority not specified, use the default priority of zero - the lowest priority possible.
  149. if (node->Attribute("name"))
  150. desc.name = node->Attribute("name");
  151. desc.reliable = ParseBool(node->Attribute("reliable"));
  152. desc.inOrder = ParseBool(node->Attribute("inOrder"));
  153. desc.data = ParseNode(node, 0);
  154. // Work a slight convenience - if there is a single struct inside a single struct inside a single struct - jump straight through to the data.
  155. messages.push_back(desc);
  156. node = node->NextSiblingElement("message");
  157. }
  158. #else
  159. throw NetException("kNet was built without TinyXml support! SerializedMessageList is not available!");
  160. #endif
  161. }
  162. void SerializedMessageList::ParseStructs(TiXmlElement *root)
  163. {
  164. #ifdef KNET_USE_TINYXML
  165. TiXmlElement *node = root->FirstChildElement("struct");
  166. while(node)
  167. {
  168. ParseNode(node, 0);
  169. node = node->NextSiblingElement("struct");
  170. }
  171. #else
  172. throw NetException("kNet was built without TinyXml support! SerializedMessageList is not available!");
  173. #endif
  174. }
  175. void SerializedMessageList::LoadMessagesFromFile(const char *filename)
  176. {
  177. #ifdef KNET_USE_TINYXML
  178. TiXmlDocument doc(filename);
  179. bool success = doc.LoadFile();
  180. if (!success)
  181. {
  182. KNET_LOG(LogError, "TiXmlDocument open failed on filename %s!", filename);
  183. return;
  184. }
  185. TiXmlElement *xmlRoot = doc.FirstChildElement();
  186. ParseStructs(xmlRoot);
  187. ParseMessages(xmlRoot);
  188. #else
  189. throw NetException("kNet was built without TinyXml support! SerializedMessageList is not available!");
  190. #endif
  191. }
  192. const SerializedMessageDesc *SerializedMessageList::FindMessageByID(u32 id)
  193. {
  194. for(std::list<SerializedMessageDesc>::iterator iter = messages.begin();
  195. iter != messages.end(); ++iter)
  196. if (iter->id == id)
  197. return &*iter;
  198. return 0;
  199. }
  200. const SerializedMessageDesc *SerializedMessageList::FindMessageByName(const char *name)
  201. {
  202. for(std::list<SerializedMessageDesc>::iterator iter = messages.begin();
  203. iter != messages.end(); ++iter)
  204. if (iter->name == name)
  205. return &*iter;
  206. return 0;
  207. }
  208. } // ~kNet