StringCompressor.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. /*
  2. * 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. * LICENSE file in the root directory of this source tree. An additional grant
  7. * of patent rights can be found in the PATENTS file in the same directory.
  8. *
  9. */
  10. /// \file
  11. ///
  12. #include "StringCompressor.h"
  13. #include "DS_HuffmanEncodingTree.h"
  14. #include "BitStream.h"
  15. #include "RakString.h"
  16. #include "RakAssert.h"
  17. #include <string.h>
  18. #include <memory.h>
  19. using namespace RakNet;
  20. StringCompressor* StringCompressor::instance=0;
  21. int StringCompressor::referenceCount=0;
  22. void StringCompressor::AddReference(void)
  23. {
  24. if (++referenceCount==1)
  25. {
  26. instance = RakNet::OP_NEW<StringCompressor>( _FILE_AND_LINE_ );
  27. }
  28. }
  29. void StringCompressor::RemoveReference(void)
  30. {
  31. RakAssert(referenceCount > 0);
  32. if (referenceCount > 0)
  33. {
  34. if (--referenceCount==0)
  35. {
  36. RakNet::OP_DELETE(instance, _FILE_AND_LINE_);
  37. instance=0;
  38. }
  39. }
  40. }
  41. StringCompressor* StringCompressor::Instance(void)
  42. {
  43. return instance;
  44. }
  45. unsigned int englishCharacterFrequencies[ 256 ] =
  46. {
  47. 0,
  48. 0,
  49. 0,
  50. 0,
  51. 0,
  52. 0,
  53. 0,
  54. 0,
  55. 0,
  56. 0,
  57. 722,
  58. 0,
  59. 0,
  60. 2,
  61. 0,
  62. 0,
  63. 0,
  64. 0,
  65. 0,
  66. 0,
  67. 0,
  68. 0,
  69. 0,
  70. 0,
  71. 0,
  72. 0,
  73. 0,
  74. 0,
  75. 0,
  76. 0,
  77. 0,
  78. 0,
  79. 11084,
  80. 58,
  81. 63,
  82. 1,
  83. 0,
  84. 31,
  85. 0,
  86. 317,
  87. 64,
  88. 64,
  89. 44,
  90. 0,
  91. 695,
  92. 62,
  93. 980,
  94. 266,
  95. 69,
  96. 67,
  97. 56,
  98. 7,
  99. 73,
  100. 3,
  101. 14,
  102. 2,
  103. 69,
  104. 1,
  105. 167,
  106. 9,
  107. 1,
  108. 2,
  109. 25,
  110. 94,
  111. 0,
  112. 195,
  113. 139,
  114. 34,
  115. 96,
  116. 48,
  117. 103,
  118. 56,
  119. 125,
  120. 653,
  121. 21,
  122. 5,
  123. 23,
  124. 64,
  125. 85,
  126. 44,
  127. 34,
  128. 7,
  129. 92,
  130. 76,
  131. 147,
  132. 12,
  133. 14,
  134. 57,
  135. 15,
  136. 39,
  137. 15,
  138. 1,
  139. 1,
  140. 1,
  141. 2,
  142. 3,
  143. 0,
  144. 3611,
  145. 845,
  146. 1077,
  147. 1884,
  148. 5870,
  149. 841,
  150. 1057,
  151. 2501,
  152. 3212,
  153. 164,
  154. 531,
  155. 2019,
  156. 1330,
  157. 3056,
  158. 4037,
  159. 848,
  160. 47,
  161. 2586,
  162. 2919,
  163. 4771,
  164. 1707,
  165. 535,
  166. 1106,
  167. 152,
  168. 1243,
  169. 100,
  170. 0,
  171. 2,
  172. 0,
  173. 10,
  174. 0,
  175. 0,
  176. 0,
  177. 0,
  178. 0,
  179. 0,
  180. 0,
  181. 0,
  182. 0,
  183. 0,
  184. 0,
  185. 0,
  186. 0,
  187. 0,
  188. 0,
  189. 0,
  190. 0,
  191. 0,
  192. 0,
  193. 0,
  194. 0,
  195. 0,
  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. };
  304. StringCompressor::StringCompressor()
  305. {
  306. DataStructures::Map<int, HuffmanEncodingTree *>::IMPLEMENT_DEFAULT_COMPARISON();
  307. // Make a default tree immediately, since this is used for RPC possibly from multiple threads at the same time
  308. HuffmanEncodingTree *huffmanEncodingTree = RakNet::OP_NEW<HuffmanEncodingTree>( _FILE_AND_LINE_ );
  309. huffmanEncodingTree->GenerateFromFrequencyTable( englishCharacterFrequencies );
  310. huffmanEncodingTrees.Set(0, huffmanEncodingTree);
  311. }
  312. void StringCompressor::GenerateTreeFromStrings( unsigned char *input, unsigned inputLength, uint8_t languageId )
  313. {
  314. HuffmanEncodingTree *huffmanEncodingTree;
  315. if (huffmanEncodingTrees.Has(languageId))
  316. {
  317. huffmanEncodingTree = huffmanEncodingTrees.Get(languageId);
  318. RakNet::OP_DELETE(huffmanEncodingTree, _FILE_AND_LINE_);
  319. }
  320. unsigned index;
  321. unsigned int frequencyTable[ 256 ];
  322. if ( inputLength == 0 )
  323. return ;
  324. // Zero out the frequency table
  325. memset( frequencyTable, 0, sizeof( frequencyTable ) );
  326. // Generate the frequency table from the strings
  327. for ( index = 0; index < inputLength; index++ )
  328. frequencyTable[ input[ index ] ] ++;
  329. // Build the tree
  330. huffmanEncodingTree = RakNet::OP_NEW<HuffmanEncodingTree>( _FILE_AND_LINE_ );
  331. huffmanEncodingTree->GenerateFromFrequencyTable( frequencyTable );
  332. huffmanEncodingTrees.Set(languageId, huffmanEncodingTree);
  333. }
  334. StringCompressor::~StringCompressor()
  335. {
  336. for (unsigned i=0; i < huffmanEncodingTrees.Size(); i++)
  337. RakNet::OP_DELETE(huffmanEncodingTrees[i], _FILE_AND_LINE_);
  338. }
  339. void StringCompressor::EncodeString( const char *input, int maxCharsToWrite, RakNet::BitStream *output, uint8_t languageId )
  340. {
  341. HuffmanEncodingTree *huffmanEncodingTree;
  342. if (huffmanEncodingTrees.Has(languageId)==false)
  343. return;
  344. huffmanEncodingTree=huffmanEncodingTrees.Get(languageId);
  345. if ( input == 0 )
  346. {
  347. output->WriteCompressed( (uint32_t) 0 );
  348. return ;
  349. }
  350. RakNet::BitStream encodedBitStream;
  351. uint32_t stringBitLength;
  352. int charsToWrite;
  353. if ( maxCharsToWrite<=0 || ( int ) strlen( input ) < maxCharsToWrite )
  354. charsToWrite = ( int ) strlen( input );
  355. else
  356. charsToWrite = maxCharsToWrite - 1;
  357. huffmanEncodingTree->EncodeArray( ( unsigned char* ) input, charsToWrite, &encodedBitStream );
  358. stringBitLength = (uint32_t) encodedBitStream.GetNumberOfBitsUsed();
  359. output->WriteCompressed( stringBitLength );
  360. output->WriteBits( encodedBitStream.GetData(), stringBitLength );
  361. }
  362. bool StringCompressor::DecodeString( char *output, int maxCharsToWrite, RakNet::BitStream *input, uint8_t languageId )
  363. {
  364. HuffmanEncodingTree *huffmanEncodingTree;
  365. if (huffmanEncodingTrees.Has(languageId)==false)
  366. return false;
  367. if (maxCharsToWrite<=0)
  368. return false;
  369. huffmanEncodingTree=huffmanEncodingTrees.Get(languageId);
  370. uint32_t stringBitLength;
  371. int bytesInStream;
  372. output[ 0 ] = 0;
  373. if ( input->ReadCompressed( stringBitLength ) == false )
  374. return false;
  375. if ( (unsigned) input->GetNumberOfUnreadBits() < stringBitLength )
  376. return false;
  377. bytesInStream = huffmanEncodingTree->DecodeArray( input, stringBitLength, maxCharsToWrite, ( unsigned char* ) output );
  378. if ( bytesInStream < maxCharsToWrite )
  379. output[ bytesInStream ] = 0;
  380. else
  381. output[ maxCharsToWrite - 1 ] = 0;
  382. return true;
  383. }
  384. #ifdef _CSTRING_COMPRESSOR
  385. void StringCompressor::EncodeString( const CString &input, int maxCharsToWrite, RakNet::BitStream *output )
  386. {
  387. LPTSTR p = input;
  388. EncodeString(p, maxCharsToWrite*sizeof(TCHAR), output, languageID);
  389. }
  390. bool StringCompressor::DecodeString( CString &output, int maxCharsToWrite, RakNet::BitStream *input, uint8_t languageId )
  391. {
  392. LPSTR p = output.GetBuffer(maxCharsToWrite*sizeof(TCHAR));
  393. DecodeString(p,maxCharsToWrite*sizeof(TCHAR), input, languageID);
  394. output.ReleaseBuffer(0)
  395. }
  396. #endif
  397. #ifdef _STD_STRING_COMPRESSOR
  398. void StringCompressor::EncodeString( const std::string &input, int maxCharsToWrite, RakNet::BitStream *output, uint8_t languageId )
  399. {
  400. EncodeString(input.c_str(), maxCharsToWrite, output, languageId);
  401. }
  402. bool StringCompressor::DecodeString( std::string *output, int maxCharsToWrite, RakNet::BitStream *input, uint8_t languageId )
  403. {
  404. if (maxCharsToWrite <= 0)
  405. {
  406. output->clear();
  407. return true;
  408. }
  409. char *destinationBlock;
  410. bool out;
  411. #if USE_ALLOCA==1
  412. if (maxCharsToWrite < MAX_ALLOCA_STACK_ALLOCATION)
  413. {
  414. destinationBlock = (char*) alloca(maxCharsToWrite);
  415. out=DecodeString(destinationBlock, maxCharsToWrite, input, languageId);
  416. *output=destinationBlock;
  417. }
  418. else
  419. #endif
  420. {
  421. destinationBlock = (char*) rakMalloc_Ex( maxCharsToWrite, _FILE_AND_LINE_ );
  422. out=DecodeString(destinationBlock, maxCharsToWrite, input, languageId);
  423. *output=destinationBlock;
  424. rakFree_Ex(destinationBlock, _FILE_AND_LINE_ );
  425. }
  426. return out;
  427. }
  428. #endif
  429. void StringCompressor::EncodeString( const RakString *input, int maxCharsToWrite, RakNet::BitStream *output, uint8_t languageId )
  430. {
  431. EncodeString(input->C_String(), maxCharsToWrite, output, languageId);
  432. }
  433. bool StringCompressor::DecodeString( RakString *output, int maxCharsToWrite, RakNet::BitStream *input, uint8_t languageId )
  434. {
  435. if (maxCharsToWrite <= 0)
  436. {
  437. output->Clear();
  438. return true;
  439. }
  440. char *destinationBlock;
  441. bool out;
  442. #if USE_ALLOCA==1
  443. if (maxCharsToWrite < MAX_ALLOCA_STACK_ALLOCATION)
  444. {
  445. destinationBlock = (char*) alloca(maxCharsToWrite);
  446. out=DecodeString(destinationBlock, maxCharsToWrite, input, languageId);
  447. *output=destinationBlock;
  448. }
  449. else
  450. #endif
  451. {
  452. destinationBlock = (char*) rakMalloc_Ex( maxCharsToWrite, _FILE_AND_LINE_ );
  453. out=DecodeString(destinationBlock, maxCharsToWrite, input, languageId);
  454. *output=destinationBlock;
  455. rakFree_Ex(destinationBlock, _FILE_AND_LINE_ );
  456. }
  457. return out;
  458. }
粤ICP备19079148号