| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509 |
- /*
- * Copyright (c) 2014, Oculus VR, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- */
- /// \file
- ///
- #include "StringCompressor.h"
- #include "DS_HuffmanEncodingTree.h"
- #include "BitStream.h"
- #include "RakString.h"
- #include "RakAssert.h"
- #include <string.h>
- #include <memory.h>
- using namespace RakNet;
- StringCompressor* StringCompressor::instance=0;
- int StringCompressor::referenceCount=0;
- void StringCompressor::AddReference(void)
- {
- if (++referenceCount==1)
- {
- instance = RakNet::OP_NEW<StringCompressor>( _FILE_AND_LINE_ );
- }
- }
- void StringCompressor::RemoveReference(void)
- {
- RakAssert(referenceCount > 0);
- if (referenceCount > 0)
- {
- if (--referenceCount==0)
- {
- RakNet::OP_DELETE(instance, _FILE_AND_LINE_);
- instance=0;
- }
- }
- }
- StringCompressor* StringCompressor::Instance(void)
- {
- return instance;
- }
- unsigned int englishCharacterFrequencies[ 256 ] =
- {
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 722,
- 0,
- 0,
- 2,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 11084,
- 58,
- 63,
- 1,
- 0,
- 31,
- 0,
- 317,
- 64,
- 64,
- 44,
- 0,
- 695,
- 62,
- 980,
- 266,
- 69,
- 67,
- 56,
- 7,
- 73,
- 3,
- 14,
- 2,
- 69,
- 1,
- 167,
- 9,
- 1,
- 2,
- 25,
- 94,
- 0,
- 195,
- 139,
- 34,
- 96,
- 48,
- 103,
- 56,
- 125,
- 653,
- 21,
- 5,
- 23,
- 64,
- 85,
- 44,
- 34,
- 7,
- 92,
- 76,
- 147,
- 12,
- 14,
- 57,
- 15,
- 39,
- 15,
- 1,
- 1,
- 1,
- 2,
- 3,
- 0,
- 3611,
- 845,
- 1077,
- 1884,
- 5870,
- 841,
- 1057,
- 2501,
- 3212,
- 164,
- 531,
- 2019,
- 1330,
- 3056,
- 4037,
- 848,
- 47,
- 2586,
- 2919,
- 4771,
- 1707,
- 535,
- 1106,
- 152,
- 1243,
- 100,
- 0,
- 2,
- 0,
- 10,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
- };
- StringCompressor::StringCompressor()
- {
- DataStructures::Map<int, HuffmanEncodingTree *>::IMPLEMENT_DEFAULT_COMPARISON();
- // Make a default tree immediately, since this is used for RPC possibly from multiple threads at the same time
- HuffmanEncodingTree *huffmanEncodingTree = RakNet::OP_NEW<HuffmanEncodingTree>( _FILE_AND_LINE_ );
- huffmanEncodingTree->GenerateFromFrequencyTable( englishCharacterFrequencies );
- huffmanEncodingTrees.Set(0, huffmanEncodingTree);
- }
- void StringCompressor::GenerateTreeFromStrings( unsigned char *input, unsigned inputLength, uint8_t languageId )
- {
- HuffmanEncodingTree *huffmanEncodingTree;
- if (huffmanEncodingTrees.Has(languageId))
- {
- huffmanEncodingTree = huffmanEncodingTrees.Get(languageId);
- RakNet::OP_DELETE(huffmanEncodingTree, _FILE_AND_LINE_);
- }
- unsigned index;
- unsigned int frequencyTable[ 256 ];
- if ( inputLength == 0 )
- return ;
- // Zero out the frequency table
- memset( frequencyTable, 0, sizeof( frequencyTable ) );
- // Generate the frequency table from the strings
- for ( index = 0; index < inputLength; index++ )
- frequencyTable[ input[ index ] ] ++;
- // Build the tree
- huffmanEncodingTree = RakNet::OP_NEW<HuffmanEncodingTree>( _FILE_AND_LINE_ );
- huffmanEncodingTree->GenerateFromFrequencyTable( frequencyTable );
- huffmanEncodingTrees.Set(languageId, huffmanEncodingTree);
- }
- StringCompressor::~StringCompressor()
- {
- for (unsigned i=0; i < huffmanEncodingTrees.Size(); i++)
- RakNet::OP_DELETE(huffmanEncodingTrees[i], _FILE_AND_LINE_);
- }
- void StringCompressor::EncodeString( const char *input, int maxCharsToWrite, RakNet::BitStream *output, uint8_t languageId )
- {
- HuffmanEncodingTree *huffmanEncodingTree;
- if (huffmanEncodingTrees.Has(languageId)==false)
- return;
- huffmanEncodingTree=huffmanEncodingTrees.Get(languageId);
- if ( input == 0 )
- {
- output->WriteCompressed( (uint32_t) 0 );
- return ;
- }
- RakNet::BitStream encodedBitStream;
- uint32_t stringBitLength;
- int charsToWrite;
- if ( maxCharsToWrite<=0 || ( int ) strlen( input ) < maxCharsToWrite )
- charsToWrite = ( int ) strlen( input );
- else
- charsToWrite = maxCharsToWrite - 1;
- huffmanEncodingTree->EncodeArray( ( unsigned char* ) input, charsToWrite, &encodedBitStream );
- stringBitLength = (uint32_t) encodedBitStream.GetNumberOfBitsUsed();
- output->WriteCompressed( stringBitLength );
- output->WriteBits( encodedBitStream.GetData(), stringBitLength );
- }
- bool StringCompressor::DecodeString( char *output, int maxCharsToWrite, RakNet::BitStream *input, uint8_t languageId )
- {
- HuffmanEncodingTree *huffmanEncodingTree;
- if (huffmanEncodingTrees.Has(languageId)==false)
- return false;
- if (maxCharsToWrite<=0)
- return false;
- huffmanEncodingTree=huffmanEncodingTrees.Get(languageId);
- uint32_t stringBitLength;
- int bytesInStream;
- output[ 0 ] = 0;
- if ( input->ReadCompressed( stringBitLength ) == false )
- return false;
- if ( (unsigned) input->GetNumberOfUnreadBits() < stringBitLength )
- return false;
- bytesInStream = huffmanEncodingTree->DecodeArray( input, stringBitLength, maxCharsToWrite, ( unsigned char* ) output );
- if ( bytesInStream < maxCharsToWrite )
- output[ bytesInStream ] = 0;
- else
- output[ maxCharsToWrite - 1 ] = 0;
- return true;
- }
- #ifdef _CSTRING_COMPRESSOR
- void StringCompressor::EncodeString( const CString &input, int maxCharsToWrite, RakNet::BitStream *output )
- {
- LPTSTR p = input;
- EncodeString(p, maxCharsToWrite*sizeof(TCHAR), output, languageID);
- }
- bool StringCompressor::DecodeString( CString &output, int maxCharsToWrite, RakNet::BitStream *input, uint8_t languageId )
- {
- LPSTR p = output.GetBuffer(maxCharsToWrite*sizeof(TCHAR));
- DecodeString(p,maxCharsToWrite*sizeof(TCHAR), input, languageID);
- output.ReleaseBuffer(0)
- }
- #endif
- #ifdef _STD_STRING_COMPRESSOR
- void StringCompressor::EncodeString( const std::string &input, int maxCharsToWrite, RakNet::BitStream *output, uint8_t languageId )
- {
- EncodeString(input.c_str(), maxCharsToWrite, output, languageId);
- }
- bool StringCompressor::DecodeString( std::string *output, int maxCharsToWrite, RakNet::BitStream *input, uint8_t languageId )
- {
- if (maxCharsToWrite <= 0)
- {
- output->clear();
- return true;
- }
- char *destinationBlock;
- bool out;
- #if USE_ALLOCA==1
- if (maxCharsToWrite < MAX_ALLOCA_STACK_ALLOCATION)
- {
- destinationBlock = (char*) alloca(maxCharsToWrite);
- out=DecodeString(destinationBlock, maxCharsToWrite, input, languageId);
- *output=destinationBlock;
- }
- else
- #endif
- {
- destinationBlock = (char*) rakMalloc_Ex( maxCharsToWrite, _FILE_AND_LINE_ );
- out=DecodeString(destinationBlock, maxCharsToWrite, input, languageId);
- *output=destinationBlock;
- rakFree_Ex(destinationBlock, _FILE_AND_LINE_ );
- }
- return out;
- }
- #endif
- void StringCompressor::EncodeString( const RakString *input, int maxCharsToWrite, RakNet::BitStream *output, uint8_t languageId )
- {
- EncodeString(input->C_String(), maxCharsToWrite, output, languageId);
- }
- bool StringCompressor::DecodeString( RakString *output, int maxCharsToWrite, RakNet::BitStream *input, uint8_t languageId )
- {
- if (maxCharsToWrite <= 0)
- {
- output->Clear();
- return true;
- }
- char *destinationBlock;
- bool out;
- #if USE_ALLOCA==1
- if (maxCharsToWrite < MAX_ALLOCA_STACK_ALLOCATION)
- {
- destinationBlock = (char*) alloca(maxCharsToWrite);
- out=DecodeString(destinationBlock, maxCharsToWrite, input, languageId);
- *output=destinationBlock;
- }
- else
- #endif
- {
- destinationBlock = (char*) rakMalloc_Ex( maxCharsToWrite, _FILE_AND_LINE_ );
- out=DecodeString(destinationBlock, maxCharsToWrite, input, languageId);
- *output=destinationBlock;
- rakFree_Ex(destinationBlock, _FILE_AND_LINE_ );
- }
- return out;
- }
|