Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

332 lines
9.7 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================
  7. #include "UtlMsgBuffer.h"
  8. #include <string.h>
  9. //-----------------------------------------------------------------------------
  10. // Purpose: bitfields for use in variable descriptors
  11. //-----------------------------------------------------------------------------
  12. enum
  13. {
  14. PACKBIT_CONTROLBIT = 0x01, // this must always be set
  15. PACKBIT_INTNAME = 0x02, // if this is set then it's an int named variable, instead of a string
  16. PACKBIT_BINARYDATA = 0x04, // signifies the data in this variable is binary, it's not a string
  17. };
  18. //-----------------------------------------------------------------------------
  19. // Purpose: Constructor
  20. //-----------------------------------------------------------------------------
  21. CUtlMsgBuffer::CUtlMsgBuffer(unsigned short msgID, int initialSize) : m_Memory(0, initialSize)
  22. {
  23. m_iMsgID = msgID;
  24. m_iWritePos = 0;
  25. m_iReadPos = 0;
  26. m_iNextVarPos = 0;
  27. }
  28. //-----------------------------------------------------------------------------
  29. // Purpose: Constructor, takes initial data
  30. //-----------------------------------------------------------------------------
  31. CUtlMsgBuffer::CUtlMsgBuffer(unsigned short msgID, void const *data, int dataSize) : m_Memory(0, dataSize)
  32. {
  33. m_iMsgID = msgID;
  34. m_iWritePos = (short)dataSize;
  35. m_iReadPos = 0;
  36. m_iNextVarPos = 0;
  37. memcpy(Base(), data, dataSize);
  38. }
  39. //-----------------------------------------------------------------------------
  40. // Purpose: Destructor
  41. //-----------------------------------------------------------------------------
  42. CUtlMsgBuffer::~CUtlMsgBuffer()
  43. {
  44. }
  45. //-----------------------------------------------------------------------------
  46. // Purpose: Copy
  47. //-----------------------------------------------------------------------------
  48. CUtlMsgBuffer &CUtlMsgBuffer::Copy(const CUtlMsgBuffer &rhs)
  49. {
  50. m_iWritePos = rhs.m_iWritePos;
  51. m_iReadPos = rhs.m_iReadPos;
  52. m_iNextVarPos = rhs.m_iNextVarPos;
  53. m_Memory.EnsureCapacity(rhs.m_Memory.NumAllocated());
  54. if ( rhs.m_Memory.NumAllocated() > 0 )
  55. {
  56. memcpy(Base(), rhs.Base(), rhs.m_Memory.NumAllocated());
  57. }
  58. return *this;
  59. }
  60. //-----------------------------------------------------------------------------
  61. // Purpose: Writes string data to the message
  62. // Input : *name - name of the variable
  63. // *data - pointer to the string data to write
  64. //-----------------------------------------------------------------------------
  65. void CUtlMsgBuffer::WriteString(const char *name, const char *data)
  66. {
  67. // write out the variable type
  68. unsigned char vtype = PACKBIT_CONTROLBIT; // stringname var, string data
  69. Write(&vtype, 1);
  70. // write out the variable name
  71. Write(name, strlen(name) + 1);
  72. // write out the size of the data
  73. unsigned short size = (unsigned short)(strlen(data) + 1);
  74. Write(&size, 2);
  75. // write out the data itself
  76. Write(data, size);
  77. }
  78. //-----------------------------------------------------------------------------
  79. // Purpose: Writes out a named block of data
  80. //-----------------------------------------------------------------------------
  81. void CUtlMsgBuffer::WriteBlob(const char *name, const void *data, int dataSize)
  82. {
  83. // write out the variable type
  84. unsigned char vtype = PACKBIT_CONTROLBIT | PACKBIT_BINARYDATA; // stringname var, binary data
  85. Write(&vtype, 1);
  86. // write out the variable name
  87. Write(name, strlen(name) + 1);
  88. // write out the size of the data
  89. unsigned short size = (unsigned short)dataSize;
  90. Write(&size, 2);
  91. // write out the data itself
  92. Write(data, dataSize);
  93. }
  94. //-----------------------------------------------------------------------------
  95. // Purpose: Writes out another UtlMsgBuffer as an element of this one
  96. //-----------------------------------------------------------------------------
  97. void CUtlMsgBuffer::WriteBuffer(const char *name, const CUtlMsgBuffer *buffer)
  98. {
  99. // write out the variable type
  100. unsigned char vtype = PACKBIT_CONTROLBIT | PACKBIT_BINARYDATA; // stringname var, binary data
  101. Write(&vtype, 1);
  102. // write out the variable name
  103. Write(name, strlen(name) + 1);
  104. // write out the size of the data
  105. unsigned short size = (unsigned short) buffer->DataSize();
  106. Write(&size, 2);
  107. // write out the data itself
  108. Write(buffer->Base(), size);
  109. }
  110. //-----------------------------------------------------------------------------
  111. // Purpose: Reads from the buffer, increments read position
  112. // returns false if past end of buffer
  113. //-----------------------------------------------------------------------------
  114. bool CUtlMsgBuffer::Read(void *buffer, int readAmount)
  115. {
  116. if (m_iReadPos + readAmount >= m_iWritePos)
  117. return false;
  118. memcpy(buffer, &m_Memory[m_iReadPos], readAmount);
  119. m_iReadPos += readAmount;
  120. return true;
  121. }
  122. //-----------------------------------------------------------------------------
  123. // Purpose: Reads characterse from the buffer until a null is hit
  124. //-----------------------------------------------------------------------------
  125. bool CUtlMsgBuffer::ReadUntilNull(void *buffer, int bufferSize)
  126. {
  127. int nullPos = m_iReadPos;
  128. // look through the buffer for the null terminator
  129. while (nullPos < m_Memory.NumAllocated() && m_Memory[nullPos] != 0)
  130. {
  131. nullPos++;
  132. }
  133. if (nullPos >= m_Memory.NumAllocated())
  134. {
  135. // never found a null terminator
  136. ((char *)buffer)[0] = 0;
  137. return false;
  138. }
  139. // copy from the null terminator
  140. int copySize = nullPos - m_iReadPos;
  141. if (copySize > bufferSize)
  142. {
  143. copySize = bufferSize - 1;
  144. }
  145. // copy out the data and return
  146. memcpy(buffer, &m_Memory[m_iReadPos], copySize);
  147. ((char *)buffer)[copySize] = 0;
  148. m_iReadPos += (copySize+1);
  149. return true;
  150. }
  151. //-----------------------------------------------------------------------------
  152. // Purpose: Writes to the buffer, incrementing the write position
  153. // assumes enough space has already been allocated for the write
  154. //-----------------------------------------------------------------------------
  155. void CUtlMsgBuffer::Write(void const *data, int size)
  156. {
  157. // make sure it will fit
  158. m_Memory.EnsureCapacity(m_iWritePos + size);
  159. // normal write
  160. memcpy(&m_Memory[m_iWritePos], data, size);
  161. // increment write position
  162. m_iWritePos += size;
  163. }
  164. //-----------------------------------------------------------------------------
  165. // Purpose: Reads in a named variable length data blob
  166. // returns number of bytes read, 0 on failure
  167. //-----------------------------------------------------------------------------
  168. int CUtlMsgBuffer::ReadBlob(const char *name, void *data, int dataBufferSize)
  169. {
  170. int dataSize = 0;
  171. char *readData = (char *)FindVar(name, dataSize);
  172. if (!readData)
  173. {
  174. memset(data, 0, dataBufferSize);
  175. return 0;
  176. }
  177. // ensure against buffer overflow
  178. if (dataSize > dataBufferSize)
  179. dataSize = dataBufferSize;
  180. // copy out data
  181. memcpy(data, readData, dataSize);
  182. return dataSize;
  183. }
  184. //-----------------------------------------------------------------------------
  185. // Purpose: Reads a blob of binary data into it's own buffer
  186. //-----------------------------------------------------------------------------
  187. bool CUtlMsgBuffer::ReadBuffer(const char *name, CUtlMsgBuffer &buffer)
  188. {
  189. int dataSize = 0;
  190. char *readData = (char *)FindVar(name, dataSize);
  191. if (!readData)
  192. {
  193. return false;
  194. }
  195. buffer.m_Memory.EnsureCapacity(dataSize);
  196. memcpy(&buffer.m_Memory[0], readData, dataSize);
  197. buffer.m_iReadPos = 0;
  198. buffer.m_iWritePos = (short)dataSize;
  199. return true;
  200. }
  201. //-----------------------------------------------------------------------------
  202. // Purpose: reads out the next variable available in the buffer
  203. // fills out parameters with var details and data
  204. // returns false if no more vars available
  205. //-----------------------------------------------------------------------------
  206. bool CUtlMsgBuffer::ReadNextVar(char varname[32], bool &stringData, void *data, int &dataSize)
  207. {
  208. // read the type
  209. unsigned char vtype = 1;
  210. if (!Read(&vtype, 1))
  211. return false;
  212. // check for null-termination type
  213. if (vtype == 0)
  214. return false;
  215. stringData = !(vtype & PACKBIT_BINARYDATA);
  216. // read the variable name
  217. if (!ReadUntilNull(varname, 31))
  218. return false;
  219. // read the data size
  220. unsigned short size = 0;
  221. if (!Read(&size, 2))
  222. return false;
  223. // ensure against buffer overflows
  224. if (dataSize > size)
  225. dataSize = size;
  226. // copy data
  227. memcpy(data, &m_Memory[m_iReadPos], dataSize);
  228. // store of the next position, since that is probably where the next read needs to occur
  229. m_iReadPos += size;
  230. m_iNextVarPos = m_iReadPos;
  231. return true;
  232. }
  233. //-----------------------------------------------------------------------------
  234. // Purpose: sets the read/write position to be at the specified variable
  235. // returns pointer to buffer position on success, NULL if not found
  236. //-----------------------------------------------------------------------------
  237. void *CUtlMsgBuffer::FindVar(const char *name, int &dataSize)
  238. {
  239. // reset to where we Think the next var will be read from
  240. m_iReadPos = m_iNextVarPos;
  241. int loopCount = 2;
  242. // loop through looking for the specified variable
  243. while (loopCount--)
  244. {
  245. unsigned char vtype = 1;
  246. while (Read(&vtype, 1))
  247. {
  248. // check for null-termination type
  249. if (vtype == 0)
  250. break;
  251. // read the variable name
  252. char varname[32];
  253. if (!ReadUntilNull(varname, 31))
  254. break;
  255. // read the data size
  256. unsigned short size = 0;
  257. if (!Read(&size, 2))
  258. break;
  259. // is this our variable?
  260. if (!stricmp(varname, name))
  261. {
  262. dataSize = size;
  263. void *data = &m_Memory[m_iReadPos];
  264. // store of the next position, since that is probably where the next read needs to occur
  265. m_iReadPos += size;
  266. m_iNextVarPos = m_iReadPos;
  267. return data;
  268. }
  269. // skip over the data block to the next variable
  270. m_iReadPos += size;
  271. if (m_iReadPos >= m_iWritePos)
  272. break;
  273. }
  274. // we haven't found the data yet, Start again
  275. m_iReadPos = 0;
  276. }
  277. return NULL;
  278. }