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