| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336 |
- /* Copyright The kNet Project.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License. */
- /** @file DataDeserializer.cpp
- @brief */
- #include <cassert>
- #include <cstring>
- #include <cmath>
- #include "kNet/DebugMemoryLeakCheck.h"
- #include "kNet/VLEPacker.h"
- #include "kNet/DataDeserializer.h"
- #include "kNet/NetException.h"
- using namespace std;
- namespace kNet
- {
- DataDeserializer::DataDeserializer(const char *data_, size_t size_)
- :data(data_), size(size_)
- {
- if (!data && size > 0)
- throw NetException("Specified a null input buffer to DataDeserializer, but a nonzero input size!");
- ResetTraversal();
- }
- DataDeserializer::DataDeserializer(const char *data_, size_t size_, const SerializedMessageDesc *msgTemplate)
- :data(data_), size(size_)
- {
- if (!data && size > 0)
- throw NetException("Specified a null input buffer to DataDeserializer, but a nonzero input size!");
- assert(msgTemplate);
- iter = new SerializedDataIterator(*msgTemplate);
- ResetTraversal();
- }
- void DataDeserializer::ResetTraversal()
- {
- elemOfs = 0;
- bitOfs = 0;
- if (iter)
- iter->ResetTraversal();
- }
- u32 DataDeserializer::ReadBitsToU32(int count)
- {
- if (BitsLeft() < (u32)count)
- throw NetException("Not enough bits left in DataDeserializer::ReadBits!");
- u32 var = 0;
- int bitsFilled = 0;
- while(count > 0)
- {
- int bitsToRead = std::min(std::min(8, count), 8 - bitOfs);
- u32 readMask = ((1 << bitsToRead) - 1) << bitOfs;
- assert(elemOfs < size); // We already counted above we should have enough bits to read.
- var |= (((u32)data[elemOfs] & readMask) >> bitOfs) << bitsFilled;
- bitsFilled += bitsToRead;
- bitOfs += bitsToRead;
- assert(bitOfs <= 8);
- // If bitOfs has accumulated a full byte, move elemOfs ahead by one.
- elemOfs += (bitOfs >> 3);
- bitOfs &= 7;
- count -= bitsToRead;
- }
- return var;
- }
- /// Need to have a message template to use this function.
- u32 DataDeserializer::GetDynamicElemCount()
- {
- const SerializedElementDesc *desc = iter->NextElementDesc();
- assert(desc);
- assert(desc->varyingCount == true);
- if (BitsLeft() < (u32)desc->count)
- throw NetException("Not enough bits left in DataDeserializer::GetDynamicElemCount!");
- u32 count = ReadBitsToU32(desc->count);
- iter->SetVaryingElemSize(count);
- return count;
- }
- template<>
- std::string DataDeserializer::Read<std::string>()
- {
- return ReadString();
- }
- template<>
- bool DataDeserializer::Read<bit>()
- {
- assert(!iter || iter->NextElementType() == SerialBit);
- bool value = (ReadBitsToU32(1) != 0);
- if (iter)
- iter->ProceedToNextVariable();
- return value;
- }
- u32 DataDeserializer::ReadBits(int numBits)
- {
- assert(!iter || iter->NextElementType() == SerialBit);
- u32 val = ReadBitsToU32(numBits);
- if (iter)
- iter->ProceedNVariables(numBits);
- return val;
- }
- float DataDeserializer::ReadUnsignedFixedPoint(int numIntegerBits, int numDecimalBits)
- {
- u32 fp = ReadBits(numIntegerBits + numDecimalBits);
- return fp / (float)(1 << numDecimalBits);
- }
- float DataDeserializer::ReadSignedFixedPoint(int numIntegerBits, int numDecimalBits)
- {
- // Reading a [0, 2k-1] range -> remap back to [-k, k-1] range.
- return ReadUnsignedFixedPoint(numIntegerBits, numDecimalBits) - (float)(1 << (numIntegerBits-1));
- }
- float DataDeserializer::ReadQuantizedFloat(float minRange, float maxRange, int numBits)
- {
- u32 val = ReadBits(numBits);
- return minRange + val * (maxRange-minRange) / (float)((1 << numBits) - 1);
- }
- float DataDeserializer::ReadMiniFloat(bool signBit, int exponentBits, int mantissaBits, int exponentBias)
- {
- assert(sizeof(float) == 4);
- assert(exponentBits > 0);
- assert(exponentBits <= 8);
- assert(mantissaBits > 0);
- assert(mantissaBits <= 23);
- bool sign = signBit ? Read<bit>() : false;
- u32 exponent = ReadBits(exponentBits);
- u32 mantissa = ReadBits(mantissaBits);
- // Shift back the decoded mantissa to proper position.
- mantissa <<= 23 - mantissaBits;
- // Reconstruct the float exponent.
- if (exponent == (u32)((1 << exponentBits) - 1)) // If the read exponent was all ones, reconstruct 11111111.
- exponent = 0xFF;
- else if (exponent != 0) // If the read exponent was not zero, it was a normal number.
- exponent = exponent - exponentBias + 127;
- // else exponent == 0, meaning a zero or a denormal.
- u32 value = (sign ? 0x80000000 : 0) | (exponent << 23) | mantissa;
- return *(float*)&value;
- }
- #define PI ((float)3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679)
- void DataDeserializer::ReadNormalizedVector2D(int numBits, float &x, float &y)
- {
- float angle = ReadQuantizedFloat(-PI, PI, numBits);
- x = cos(angle);
- y = sin(angle);
- }
- void DataDeserializer::ReadVector2D(int magnitudeIntegerBits, int magnitudeDecimalBits, int directionBits, float &x, float &y)
- {
- // Read the length in unsigned fixed point format.
- // The following line is effectively the same as calling ReadUnsignedFixedPoint, but manually perform it
- // to be precisely able to examine whether the length is zero.
- u32 fp = ReadBits(magnitudeIntegerBits + magnitudeDecimalBits);
- if (fp != 0) // If length is non-zero, the stream also contains the direction.
- {
- float length = fp / (float)(1 << magnitudeDecimalBits);
- // Read the direction in the stream.
- float angle = ReadQuantizedFloat(-PI, PI, directionBits);
- x = cos(angle) * length;
- y = sin(angle) * length;
- }
- else // Zero length, no direction present in the buffer.
- {
- x = y = 0.f;
- }
- }
- void DataDeserializer::ReadNormalizedVector3D(int numBitsYaw, int numBitsPitch, float &x, float &y, float &z)
- {
- float azimuth = ReadQuantizedFloat(-PI, PI, numBitsYaw);
- float inclination = ReadQuantizedFloat(-PI/2, PI/2, numBitsPitch);
- float cx = cos(inclination);
- x = cx * sin(azimuth);
- y = -sin(inclination);
- z = cx * cos(azimuth);
- }
- void DataDeserializer::ReadVector3D(int numBitsYaw, int numBitsPitch, int magnitudeIntegerBits, int magnitudeDecimalBits, float &x, float &y, float &z)
- {
- // Read the length in unsigned fixed point format.
- // The following line is effectively the same as calling ReadUnsignedFixedPoint, but manually perform it
- // to be precisely able to examine whether the length is zero.
- u32 fp = ReadBits(magnitudeIntegerBits + magnitudeDecimalBits);
- if (fp != 0) // If length is non-zero, the stream also contains the direction.
- {
- float length = fp / (float)(1 << magnitudeDecimalBits);
- float azimuth = ReadQuantizedFloat(-PI, PI, numBitsYaw);
- float inclination = ReadQuantizedFloat(-PI/2, PI/2, numBitsPitch);
- float cx = cos(inclination);
- x = cx * sin(azimuth) * length;
- y = -sin(inclination) * length;
- z = cx * cos(azimuth) * length;
- }
- else // length is zero, stream does not contain the direction.
- {
- x = y = z = 0.f;
- }
- }
- void DataDeserializer::ReadArithmeticEncoded(int numBits, int &val1, int max1, int &val2, int max2)
- {
- assert(max1 * max2 < (1 << numBits));
- u32 val = ReadBits(numBits);
- val2 = val % max2;
- val1 = val / max2;
- }
- void DataDeserializer::ReadArithmeticEncoded(int numBits, int &val1, int max1, int &val2, int max2, int &val3, int max3)
- {
- assert(max1 * max2 * max3 < (1 << numBits));
- u32 val = ReadBits(numBits);
- val3 = val % max3;
- val /= max3;
- val2 = val % max2;
- val1 = val / max2;
- }
- void DataDeserializer::ReadArithmeticEncoded(int numBits, int &val1, int max1, int &val2, int max2, int &val3, int max3, int &val4, int max4)
- {
- assert(max1 * max2 * max3 * max4 < (1 << numBits));
- u32 val = ReadBits(numBits);
- val4 = val % max4;
- val /= max4;
- val3 = val % max3;
- val /= max3;
- val2 = val % max2;
- val1 = val / max2;
- }
- void DataDeserializer::ReadArithmeticEncoded(int numBits, int &val1, int max1, int &val2, int max2, int &val3, int max3, int &val4, int max4, int &val5, int max5)
- {
- assert(max1 * max2 * max3 * max4 * max5 < (1 << numBits));
- u32 val = ReadBits(numBits);
- val5 = val % max5;
- val /= max5;
- val4 = val % max4;
- val /= max4;
- val3 = val % max3;
- val /= max3;
- val2 = val % max2;
- val1 = val / max2;
- }
- void DataDeserializer::SkipBits(int numBits)
- {
- assert(!iter);
- bitOfs += numBits;
- // Move all accumulated full bytes from bitOfs to elemOfs.
- elemOfs += (bitOfs >> 3);
- bitOfs &= 7;
- if (elemOfs > size)
- throw NetException("Not enough bits left in DataDeserializer::SkipBits!");
- if (elemOfs == size && bitOfs != 0)
- throw NetException("Not enough bits left in DataDeserializer::SkipBits(2)!");
- }
- std::string DataDeserializer::ReadString()
- {
- u32 length = (iter ? GetDynamicElemCount() : ReadVLE<VLE8_16_32>());
- if (BitsLeft() < length*8)
- throw NetException("Not enough bytes left in DataDeserializer::ReadString!");
- std::string str;
- if (bitOfs == 0)
- {
- str.append(data + elemOfs, length);
- elemOfs += length;
- }
- else
- {
- std::vector<u8> bytes(length+1);
- ReadArray<u8>(&bytes[0], length);
- str.append((char*)&bytes[0], length);
- }
- if (iter)
- for(u32 i = 0; i < length; ++i)
- iter->ProceedToNextVariable();
- // Perform string validation: Replace any offending values with the space bar character.
- // Valid values: 0x00 (null), 0x09 (tab), 0x0D, 0x0A (newlines), [32, 253] (characters)
- for(size_t i = 0; i < str.length(); ++i)
- if ((unsigned char)str[i] >= 254 || ((unsigned char)str[i] < 32 && str[i] != 0x0D && str[i] != 0x0A && str[i] != 0x09)) // Retain newlines and tab.
- str[i] = 0x20; // Space bar character
- return str;
- }
- } // ~kNet
|