1 #include "StringTable.h"
2 #include <string.h>
3 #include "RakAssert.h"
4 #include <stdio.h>
5 #include "BitStream.h"
6 #include "StringCompressor.h"
7 using namespace RakNet;
8
9 StringTable* StringTable::instance=0;
10 int StringTable::referenceCount=0;
11
12
StrAndBoolComp(char * const & key,const StrAndBool & data)13 int StrAndBoolComp( char *const &key, const StrAndBool &data )
14 {
15 return strcmp(key,(const char*)data.str);
16 }
17
StringTable()18 StringTable::StringTable()
19 {
20
21 }
22
~StringTable()23 StringTable::~StringTable()
24 {
25 unsigned i;
26 for (i=0; i < orderedStringList.Size(); i++)
27 {
28 if (orderedStringList[i].b)
29 rakFree_Ex(orderedStringList[i].str, __FILE__, __LINE__ );
30 }
31 }
32
AddReference(void)33 void StringTable::AddReference(void)
34 {
35 if (++referenceCount==1)
36 {
37 instance = RakNet::OP_NEW<StringTable>( __FILE__, __LINE__ );
38 }
39 }
RemoveReference(void)40 void StringTable::RemoveReference(void)
41 {
42 RakAssert(referenceCount > 0);
43
44 if (referenceCount > 0)
45 {
46 if (--referenceCount==0)
47 {
48 RakNet::OP_DELETE(instance, __FILE__, __LINE__);
49 instance=0;
50 }
51 }
52 }
53
Instance(void)54 StringTable* StringTable::Instance(void)
55 {
56 return instance;
57 }
58
AddString(const char * str,bool copyString)59 void StringTable::AddString(const char *str, bool copyString)
60 {
61 StrAndBool sab;
62 sab.b=copyString;
63 if (copyString)
64 {
65 sab.str = (char*) rakMalloc_Ex( strlen(str)+1, __FILE__, __LINE__ );
66 strcpy(sab.str, str);
67 }
68 else
69 {
70 sab.str=(char*)str;
71 }
72
73 // If it asserts inside here you are adding duplicate strings.
74 if (orderedStringList.Insert(sab.str,sab, true, __FILE__,__LINE__)!=(unsigned)-1)
75 {
76 if (copyString)
77 RakNet::OP_DELETE(sab.str, __FILE__, __LINE__);
78 }
79
80 // If this assert hits you need to increase the range of StringTableType
81 RakAssert(orderedStringList.Size() < (StringTableType)-1);
82
83 }
EncodeString(const char * input,int maxCharsToWrite,RakNet::BitStream * output)84 void StringTable::EncodeString( const char *input, int maxCharsToWrite, RakNet::BitStream *output )
85 {
86 unsigned index;
87 bool objectExists;
88 // This is fast because the list is kept ordered.
89 index=orderedStringList.GetIndexFromKey((char*)input, &objectExists);
90 if (objectExists)
91 {
92 output->Write(true);
93 output->Write((StringTableType)index);
94 }
95 else
96 {
97 LogStringNotFound(input);
98 output->Write(false);
99 stringCompressor->EncodeString(input, maxCharsToWrite, output);
100 }
101 }
102
DecodeString(char * output,int maxCharsToWrite,RakNet::BitStream * input)103 bool StringTable::DecodeString( char *output, int maxCharsToWrite, RakNet::BitStream *input )
104 {
105 bool hasIndex;
106 RakAssert(maxCharsToWrite>0);
107
108 if (maxCharsToWrite==0)
109 return false;
110 if (!input->Read(hasIndex))
111 return false;
112 if (hasIndex==false)
113 {
114 stringCompressor->DecodeString(output, maxCharsToWrite, input);
115 }
116 else
117 {
118 StringTableType index;
119 if (!input->Read(index))
120 return false;
121 if (index >= orderedStringList.Size())
122 {
123 #ifdef _DEBUG
124 // Critical error - got a string index out of range, which means AddString was called more times on the remote system than on this system.
125 // All systems must call AddString the same number of types, with the same strings in the same order.
126 RakAssert(0);
127 #endif
128 return false;
129 }
130
131 strncpy(output, orderedStringList[index].str, maxCharsToWrite);
132 output[maxCharsToWrite-1]=0;
133 }
134
135 return true;
136 }
LogStringNotFound(const char * strName)137 void StringTable::LogStringNotFound(const char *strName)
138 {
139 (void) strName;
140
141 #ifdef _DEBUG
142 RAKNET_DEBUG_PRINTF("Efficiency Warning! Unregistered String %s sent to StringTable.\n", strName);
143 #endif
144 }
145