| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- /* 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. */
- #pragma once
- /** @file DataDeserializer.h
- @brief The class \ref kNet::DataDeserializer DataDeserializer. */
- #include "kNetBuildConfig.h"
- #include "kNet/Types.h"
- #include "BasicSerializedDataTypes.h"
- #include "SerializedDataIterator.h"
- namespace kNet
- {
- /// DataDeserializer is an utility class that walks through and deserializes data in a stream of raw bytes. The stream
- /// itself does not contain information about what types of data is contained within, but the user of DataDeserializer must
- /// know the contents of the data.
- /// DataDeserializer never copies the data it is given to read into an internal memory buffer, but instead it reads
- /// the given existing memory buffers. DataDeserializer maintains an internal bit offset position to keep track the position
- /// that is currently being read.
- class DataDeserializer
- {
- public:
- /// Constructs a DataDeserializer that reads its data from the given buffer.
- /// DataDeserializer will not copy the contents of the buffer to its own memory area, so
- /// be sure to keep the data alive and unmoved for the duration DataDeserializer exists.
- /// @param data A pointer to the data to deserialize. This may be null, but only if size == 0. If data == 0 and size > 0,
- /// an exception is thrown.
- /// @param size The number of bytes in the input buffer.
- DataDeserializer(const char *data, size_t size);
- /// Constructs a DataDeserializer that reads its data from the given buffer.
- /// DataDeserializer will not copy the contents of the buffer to its own memory area, so
- /// be sure to keep the data alive and unmoved for the duration DataDeserializer exists.
- /// @param data A pointer to the data to deserialize. This may be null, but only if size == 0. If data == 0 and size > 0,
- /// an exception is thrown.
- /// @param size The number of bytes in the input buffer.
- /// @param msgTemplate A pointer to an existing message template structure, which is used
- /// to validate that deserialization of the data proceeds in the defined order.
- /// DataDeserializer does not make a copy of this description, but dereferences
- /// it directly. Be sure to keep it alive for the duration that DataDeserializer exists.
- /// Do not pass in a zero pointer here.
- DataDeserializer(const char *data, size_t size, const SerializedMessageDesc *msgTemplate);
- /// Moves the bit offset position counter to the beginning of the data buffer.
- void ResetTraversal();
- /// Deserializes a single value of type T off the stream and advances the internal read offset.
- template<typename T>
- T Read();
- static const u32 VLEReadError = 0xFFFFFFFF;
- /// Reads a variable-length encoded integer off the stream and advances the internal read offset.
- template<typename VLEType>
- u32 ReadVLE();
- /// Deserializes an array of values of type T off the stream and advances the internal read offset.
- /// @param dst [out] Pointer to an array to receive the read data.
- /// @param numElems The number of elements to read. The array dst must be able to hold that many elements.
- template<typename T>
- void ReadArray(T *dst, size_t numElems);
- /// Reads an ASCII string from the stream. If we are using a template, the template tells how the string is stored.
- /// Otherwise, we are assuming the string was stored length-prepended, using a single byte to denote the length (no null padding).
- /// Use the 's8' data type with dynamicCount set in the message template description for a string variable.
- /// The returned string will only contain ascii values in the range [32, 253], 0x0D, 0x0A, 0x09. Other values will
- /// be replaced with a space bar character (0x20). Because of this string validation method, do not use this function
- /// to extract binary data of any kind (base64-encoded is fine).
- std::string ReadString();
- /// Reads the given amount of bits and packs them into a u32, which is returned.
- /// @param numBits the number of bits to read, [1, 32].
- u32 ReadBits(int numBits);
- float ReadUnsignedFixedPoint(int numIntegerBits, int numDecimalBits);
- float ReadSignedFixedPoint(int numIntegerBits, int numDecimalBits);
- float ReadQuantizedFloat(float minRange, float maxRange, int numBits);
- float ReadMiniFloat(bool signBit, int exponentBits, int mantissaBits, int exponentBias);
- void ReadNormalizedVector2D(int numBits, float &x, float &y);
- void ReadVector2D(int magnitudeIntegerBits, int magnitudeDecimalBits, int directionBits, float &x, float &y);
- void ReadNormalizedVector3D(int numBitsYaw, int numBitsPitch, float &x, float &y, float &z);
- void ReadVector3D(int numBitsYaw, int numBitsPitch, int magnitudeIntegerBits, int magnitudeDecimalBits, float &x, float &y, float &z);
- void ReadArithmeticEncoded(int numBits, int &val1, int max1, int &val2, int max2);
- void ReadArithmeticEncoded(int numBits, int &val1, int max1, int &val2, int max2, int &val3, int max3);
- void ReadArithmeticEncoded(int numBits, int &val1, int max1, int &val2, int max2, int &val3, int max3, int &val4, int max4);
- void ReadArithmeticEncoded(int numBits, int &val1, int max1, int &val2, int max2, int &val3, int max3, int &val4, int max4, int &val5, int max5);
- u32 GetDynamicElemCount();
- /// @return The number of bytes left in the stream to read.
- u32 BytesLeft() const { return (u32)((elemOfs >= size) ? 0 : (size - elemOfs)); }
- /// @return The number of bits left in the stream to read.
- u32 BitsLeft() const { return (u32)((elemOfs >= size) ? 0 : ((size - elemOfs)*8 - bitOfs)); }
- /// @return The current byte of the stream that will be read next.
- u32 BytePos() const { return (u32)elemOfs; }
- /// @return The bit index, [0, 7] of the byte that will be read next. The reading will proceed from LSBit to MSBit, i.e. 0 -> 7.
- u32 BitPos() const { return bitOfs; }
- /// @return The number of bits read so far in total.
- size_t BitsReadTotal() const { return elemOfs * 8 + bitOfs; }
- /// @return A pointer in the byte stream at the current read position.
- const char *CurrentData() const { return data + BytePos(); }
- /// Advances the read pointer with the given amount of bits. Can only be used in nontemplate read mode.
- void SkipBits(int numBits);
- /// Advances the read pointer with the given amount of bytes. Can only be used in nontemplate read mode.
- void SkipBytes(int numBytes) { SkipBits(numBytes * 8); }
- private:
- /// The data pointer to read from.
- const char *data;
- /// The length of the read buffer in bytes.
- size_t size;
- /// The element we're reading next from in the data buffer.
- size_t elemOfs;
- /// The current bit index of the byte we're reading, [0, 7].
- int bitOfs;
- Ptr(SerializedDataIterator) iter;
- u32 ReadBitsToU32(int count);
- DataDeserializer(const DataDeserializer &);
- void operator =(const DataDeserializer &);
- };
- template<typename T>
- T DataDeserializer::Read()
- {
- assert(!iter || iter->NextElementType() == SerializedDataTypeTraits<T>::type);
- T value;
- u8 *data = reinterpret_cast<u8*>(&value);
- for(size_t i = 0; i < sizeof(value); ++i)
- data[i] = (u8)ReadBitsToU32(8);
- if (iter)
- iter->ProceedToNextVariable();
- return value;
- }
- template<> std::string DataDeserializer::Read<std::string>();
- template<> bool DataDeserializer::Read<bit>();
- template<typename VLEType>
- u32 DataDeserializer::ReadVLE()
- {
- const u32 cStreamEndError = 0xFFFFFFFF;
- if (BitsLeft() < VLEType::numBits1 + 1)
- return cStreamEndError;
- u32 sml = ReadBits(VLEType::numBits1 + 1);
- if ((sml & (1 << VLEType::numBits1)) == 0)
- return sml;
- sml &= (1 << VLEType::numBits1) - 1;
- const u32 numBitsMed = VLEType::numBits2 + (VLEType::numBits3 == 0 ? 0 : 1);
- if (BitsLeft() < numBitsMed)
- return cStreamEndError;
- u32 med = ReadBits(numBitsMed);
- if ((med & (1 << VLEType::numBits2)) == 0)
- return sml | (med << VLEType::numBits1);
- if (BitsLeft() < (u32)VLEType::numBits3)
- return cStreamEndError;
- med &= (1 << VLEType::numBits2) - 1;
- u32 large = ReadBits(VLEType::numBits3);
- return sml | (med << VLEType::numBits1) | (large << (VLEType::numBits1 + VLEType::numBits2));
- }
- template<typename T>
- void DataDeserializer::ReadArray(T *dst, size_t numElems)
- {
- for(size_t i = 0; i < numElems; ++i)
- dst[i] = Read<T>();
- // The above will move on to the next variable in the template accordingly, but if the number
- // of elements to read is zero, it needs to be assumed that this was a dynamic block and
- // the size was 0.
- if (numElems == 0 && iter)
- iter->ProceedToNextVariable();
- }
- template<>
- void DataDeserializer::ReadArray(bit *dst, size_t numElems);
- } // ~kNet
|