SLikeNet 0.1.3

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
StringCompressor.cpp
Go to the documentation of this file.
1 /*
2 * Original work: Copyright (c) 2014, Oculus VR, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * RakNet License.txt file in the licenses directory of this source tree. An additional grant
7 * of patent rights can be found in the RakNet Patents.txt file in the same directory.
8 *
9 *
10 * Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
11 *
12 * This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
13 * license found in the license.txt file in the root directory of this source tree.
14 */
15
18
19
20
21 #include "slikenet/StringCompressor.h"
22 #include "slikenet/DS_HuffmanEncodingTree.h"
23 #include "slikenet/BitStream.h"
24 #include "slikenet/string.h"
25 #include "slikenet/assert.h"
26 #include <string.h>
27
28 #include <memory.h>
29
30
31
32
33
34
35
36 using namespace SLNet;
37
38 StringCompressor* StringCompressor::instance=0;
39 int StringCompressor::referenceCount=0;
40
41 void StringCompressor::AddReference(void)
42 {
43 if (++referenceCount==1)
44 {
45 instance = SLNet::OP_NEW<StringCompressor>( _FILE_AND_LINE_ );
46 }
47 }
48 void StringCompressor::RemoveReference(void)
49 {
50 RakAssert(referenceCount > 0);
51
52 if (referenceCount > 0)
53 {
54 if (--referenceCount==0)
55 {
56 SLNet::OP_DELETE(instance, _FILE_AND_LINE_);
57 instance=0;
58 }
59 }
60 }
61
62 StringCompressor* StringCompressor::Instance(void)
63 {
64 return instance;
65 }
66
67 unsigned int englishCharacterFrequencies[ 256 ] =
68 {
69 0,
70 0,
71 0,
72 0,
73 0,
74 0,
75 0,
76 0,
77 0,
78 0,
79 722,
80 0,
81 0,
82 2,
83 0,
84 0,
85 0,
86 0,
87 0,
88 0,
89 0,
90 0,
91 0,
92 0,
93 0,
94 0,
95 0,
96 0,
97 0,
98 0,
99 0,
100 0,
101 11084,
102 58,
103 63,
104 1,
105 0,
106 31,
107 0,
108 317,
109 64,
110 64,
111 44,
112 0,
113 695,
114 62,
115 980,
116 266,
117 69,
118 67,
119 56,
120 7,
121 73,
122 3,
123 14,
124 2,
125 69,
126 1,
127 167,
128 9,
129 1,
130 2,
131 25,
132 94,
133 0,
134 195,
135 139,
136 34,
137 96,
138 48,
139 103,
140 56,
141 125,
142 653,
143 21,
144 5,
145 23,
146 64,
147 85,
148 44,
149 34,
150 7,
151 92,
152 76,
153 147,
154 12,
155 14,
156 57,
157 15,
158 39,
159 15,
160 1,
161 1,
162 1,
163 2,
164 3,
165 0,
166 3611,
167 845,
168 1077,
169 1884,
170 5870,
171 841,
172 1057,
173 2501,
174 3212,
175 164,
176 531,
177 2019,
178 1330,
179 3056,
180 4037,
181 848,
182 47,
183 2586,
184 2919,
185 4771,
186 1707,
187 535,
188 1106,
189 152,
190 1243,
191 100,
192 0,
193 2,
194 0,
195 10,
196 0,
197 0,
198 0,
199 0,
200 0,
201 0,
202 0,
203 0,
204 0,
205 0,
206 0,
207 0,
208 0,
209 0,
210 0,
211 0,
212 0,
213 0,
214 0,
215 0,
216 0,
217 0,
218 0,
219 0,
220 0,
221 0,
222 0,
223 0,
224 0,
225 0,
226 0,
227 0,
228 0,
229 0,
230 0,
231 0,
232 0,
233 0,
234 0,
235 0,
236 0,
237 0,
238 0,
239 0,
240 0,
241 0,
242 0,
243 0,
244 0,
245 0,
246 0,
247 0,
248 0,
249 0,
250 0,
251 0,
252 0,
253 0,
254 0,
255 0,
256 0,
257 0,
258 0,
259 0,
260 0,
261 0,
262 0,
263 0,
264 0,
265 0,
266 0,
267 0,
268 0,
269 0,
270 0,
271 0,
272 0,
273 0,
274 0,
275 0,
276 0,
277 0,
278 0,
279 0,
280 0,
281 0,
282 0,
283 0,
284 0,
285 0,
286 0,
287 0,
288 0,
289 0,
290 0,
291 0,
292 0,
293 0,
294 0,
295 0,
296 0,
297 0,
298 0,
299 0,
300 0,
301 0,
302 0,
303 0,
304 0,
305 0,
306 0,
307 0,
308 0,
309 0,
310 0,
311 0,
312 0,
313 0,
314 0,
315 0,
316 0,
317 0,
318 0,
319 0,
320 0,
321 0,
322 0,
323 0,
324 0
325 };
326
327 StringCompressor::StringCompressor()
328 {
329 DataStructures::Map<int, HuffmanEncodingTree *>::IMPLEMENT_DEFAULT_COMPARISON();
330
331 // Make a default tree immediately, since this is used for RPC possibly from multiple threads at the same time
332 HuffmanEncodingTree *huffmanEncodingTree = SLNet::OP_NEW<HuffmanEncodingTree>( _FILE_AND_LINE_ );
333 huffmanEncodingTree->GenerateFromFrequencyTable( englishCharacterFrequencies );
334
335 huffmanEncodingTrees.Set(0, huffmanEncodingTree);
336 }
337 void StringCompressor::GenerateTreeFromStrings( unsigned char *input, unsigned inputLength, uint8_t languageId )
338 {
339 HuffmanEncodingTree *huffmanEncodingTree;
340 if (huffmanEncodingTrees.Has(languageId))
341 {
342 huffmanEncodingTree = huffmanEncodingTrees.Get(languageId);
343 SLNet::OP_DELETE(huffmanEncodingTree, _FILE_AND_LINE_);
344 }
345
346 unsigned index;
347 unsigned int frequencyTable[ 256 ];
348
349 if ( inputLength == 0 )
350 return ;
351
352 // Zero out the frequency table
353 memset( frequencyTable, 0, sizeof( frequencyTable ) );
354
355 // Generate the frequency table from the strings
356 for ( index = 0; index < inputLength; index++ )
357 frequencyTable[ input[ index ] ] ++;
358
359 // Build the tree
360 huffmanEncodingTree = SLNet::OP_NEW<HuffmanEncodingTree>( _FILE_AND_LINE_ );
361 huffmanEncodingTree->GenerateFromFrequencyTable( frequencyTable );
362 huffmanEncodingTrees.Set(languageId, huffmanEncodingTree);
363 }
364
365 StringCompressor::~StringCompressor()
366 {
367 for (unsigned i=0; i < huffmanEncodingTrees.Size(); i++)
368 SLNet::OP_DELETE(huffmanEncodingTrees[i], _FILE_AND_LINE_);
369 }
370
371 void StringCompressor::EncodeString( const char *input, int maxCharsToWrite, SLNet::BitStream *output, uint8_t languageId )
372 {
373 HuffmanEncodingTree *huffmanEncodingTree;
374 if (huffmanEncodingTrees.Has(languageId)==false)
375 return;
376 huffmanEncodingTree=huffmanEncodingTrees.Get(languageId);
377
378 if ( input == 0 )
379 {
380 output->WriteCompressed( (uint32_t) 0 );
381 return ;
382 }
383
384 SLNet::BitStream encodedBitStream;
385
386 uint32_t stringBitLength;
387
388 int charsToWrite;
389
390 if ( maxCharsToWrite<=0 || ( int ) strlen( input ) < maxCharsToWrite )
391 charsToWrite = ( int ) strlen( input );
392 else
393 charsToWrite = maxCharsToWrite - 1;
394
395 huffmanEncodingTree->EncodeArray( ( unsigned char* ) input, charsToWrite, &encodedBitStream );
396
397 stringBitLength = (uint32_t) encodedBitStream.GetNumberOfBitsUsed();
398
399 output->WriteCompressed( stringBitLength );
400
401 output->WriteBits( encodedBitStream.GetData(), stringBitLength );
402 }
403
404 bool StringCompressor::DecodeString( char *output, int maxCharsToWrite, SLNet::BitStream *input, uint8_t languageId )
405 {
406 HuffmanEncodingTree *huffmanEncodingTree;
407 if (huffmanEncodingTrees.Has(languageId)==false)
408 return false;
409 if (maxCharsToWrite<=0)
410 return false;
411 huffmanEncodingTree=huffmanEncodingTrees.Get(languageId);
412
413 uint32_t stringBitLength;
414 int bytesInStream;
415
416 output[ 0 ] = 0;
417
418 if ( input->ReadCompressed( stringBitLength ) == false )
419 return false;
420
421 if ( (unsigned) input->GetNumberOfUnreadBits() < stringBitLength )
422 return false;
423
424 bytesInStream = huffmanEncodingTree->DecodeArray( input, stringBitLength, maxCharsToWrite, ( unsigned char* ) output );
425
426 if ( bytesInStream < maxCharsToWrite )
427 output[ bytesInStream ] = 0;
428 else
429 output[ maxCharsToWrite - 1 ] = 0;
430
431 return true;
432 }
433 #ifdef _CSTRING_COMPRESSOR
434 void StringCompressor::EncodeString( const CString &input, int maxCharsToWrite, SLNet::BitStream *output )
435 {
436 LPTSTR p = input;
437 EncodeString(p, maxCharsToWrite*sizeof(TCHAR), output, languageID);
438 }
439 bool StringCompressor::DecodeString( CString &output, int maxCharsToWrite, SLNet::BitStream *input, uint8_t languageId )
440 {
441 LPSTR p = output.GetBuffer(maxCharsToWrite*sizeof(TCHAR));
442 DecodeString(p,maxCharsToWrite*sizeof(TCHAR), input, languageID);
443 output.ReleaseBuffer(0)
444
445 }
446 #endif
447 #ifdef _STD_STRING_COMPRESSOR
448 void StringCompressor::EncodeString( const std::string &input, int maxCharsToWrite, SLNet::BitStream *output, uint8_t languageId )
449 {
450 EncodeString(input.c_str(), maxCharsToWrite, output, languageId);
451 }
452 bool StringCompressor::DecodeString( std::string *output, int maxCharsToWrite, SLNet::BitStream *input, uint8_t languageId )
453 {
454 if (maxCharsToWrite <= 0)
455 {
456 output->clear();
457 return true;
458 }
459
460 char *destinationBlock;
461 bool out;
462
463 #if USE_ALLOCA==1
464 if (maxCharsToWrite < MAX_ALLOCA_STACK_ALLOCATION)
465 {
466 destinationBlock = (char*) alloca(maxCharsToWrite);
467 out=DecodeString(destinationBlock, maxCharsToWrite, input, languageId);
468 *output=destinationBlock;
469 }
470 else
471 #endif
472 {
473 destinationBlock = (char*) rakMalloc_Ex( maxCharsToWrite, _FILE_AND_LINE_ );
474 out=DecodeString(destinationBlock, maxCharsToWrite, input, languageId);
475 *output=destinationBlock;
476 rakFree_Ex(destinationBlock, _FILE_AND_LINE_ );
477 }
478
479 return out;
480 }
481 #endif
482 void StringCompressor::EncodeString( const RakString *input, int maxCharsToWrite, SLNet::BitStream *output, uint8_t languageId )
483 {
484 EncodeString(input->C_String(), maxCharsToWrite, output, languageId);
485 }
486 bool StringCompressor::DecodeString( RakString *output, int maxCharsToWrite, SLNet::BitStream *input, uint8_t languageId )
487 {
488 if (maxCharsToWrite <= 0)
489 {
490 output->Clear();
491 return true;
492 }
493
494 char *destinationBlock;
495 bool out;
496
497 #if USE_ALLOCA==1
498 if (maxCharsToWrite < MAX_ALLOCA_STACK_ALLOCATION)
499 {
500 destinationBlock = (char*) alloca(maxCharsToWrite);
501 out=DecodeString(destinationBlock, maxCharsToWrite, input, languageId);
502 *output=destinationBlock;
503 }
504 else
505 #endif
506 {
507 destinationBlock = (char*) rakMalloc_Ex( maxCharsToWrite, _FILE_AND_LINE_ );
508 out=DecodeString(destinationBlock, maxCharsToWrite, input, languageId);
509 *output=destinationBlock;
510 rakFree_Ex(destinationBlock, _FILE_AND_LINE_ );
511 }
512
513 return out;
514 }