Fri, 22 Jul 2016 17:50:00 +0300
Bytestream now behaves more like a cursor. It does not store the data anymore, rather it leaves the user to specify a vector to use for storage.
--- a/sources/basics.h Wed Jul 20 22:56:16 2016 +0300 +++ b/sources/basics.h Fri Jul 22 17:50:00 2016 +0300 @@ -90,6 +90,11 @@ return (a < b) ? b : (a > c) ? c : a; } +inline const char *plural(int value) +{ + return value != 1 ? "s" : ""; +} + template <typename T, size_t N> char (&_ArraySizeHelper(T (&array)[N]))[N]; #define countof(array) (sizeof(_ArraySizeHelper( array )))
--- a/sources/list.h Wed Jul 20 22:56:16 2016 +0300 +++ b/sources/list.h Fri Jul 22 17:50:00 2016 +0300 @@ -58,12 +58,24 @@ Container (const C& other) : m_container (other) {} + Container(std::initializer_list<T> initializerList) : + m_container(initializerList) {} + T& append (const T& value) { m_container.push_back (value); return m_container[m_container.size() - 1]; } + void append(const T* values, size_t numValues) + { + size_t i0 = size(); + resize(size() + numValues); + + for (size_t i : range(numValues)) + (*this)[i0 + i] = values[i]; + } + Iterator begin() { return m_container.begin(); @@ -256,22 +268,29 @@ std::sort (begin(), end()); } - Self splice (int a, int b) const + Self splice(int start, int end, int step = 1) const { - if (a < 0 or b >= size() or b < a) - return Self(); + start = clamp(start, 0, size() - 1); + end = clamp(end, 0, size() - 1); - Self result; + if (end <= start) + { + return Self(); + } + else + { + Self result; - for (int i = a; i < b; ++i) - result << operator[] (i); + for (int i : range(start, end, step)) + result << operator[] (i); - return result; + return result; + } } - Self splice (const Range<int>& a) const + Self splice(Range<int>& range) const { - return splice (a.min(), a.max()); + return splice(range.min(), range.max(), range.step()); } Self& operator<< (const T& value) @@ -358,6 +377,12 @@ Vector (T* data, size_t length) : Super (std::vector<T> (data, data + length)) {} + Vector(std::initializer_list<T> initializerList) : + Super(initializerList) {} + + Vector(const Super& other) : + Super(other) {} + T* data() { return Super::m_container.data();
--- a/sources/mystring.cpp Wed Jul 20 22:56:16 2016 +0300 +++ b/sources/mystring.cpp Fri Jul 22 17:50:00 2016 +0300 @@ -561,6 +561,16 @@ } /*! + * \brief Constructs a string from a vector of bytes. The bytes do not have to be null-terminated. + * \param bytes Bytes to use for construction + * \returns the resulting string. + */ +String String::fromBytes(const Vector<unsigned char>& bytes) +{ + return String(reinterpret_cast<const Vector<char>&>(bytes)); +} + +/*! * \returns the MD5-checksum of this string. */ String String::md5() const
--- a/sources/mystring.h Wed Jul 20 22:56:16 2016 +0300 +++ b/sources/mystring.h Fri Jul 22 17:50:00 2016 +0300 @@ -93,6 +93,7 @@ const std::string& stdString() const; void strip(char unwanted); void strip(const List<char> &unwanted); + const unsigned char* toBytes() const; double toDouble(bool* ok = nullptr) const; float toFloat(bool* ok = nullptr) const; long toInt(bool* ok = nullptr, int base = 10) const; @@ -107,6 +108,7 @@ static String fromNumber(unsigned int a); static String fromNumber(unsigned long int a); static String fromNumber(double a); + static String fromBytes(const Vector<unsigned char>& bytes); String operator+(const String& data) const; String operator+(const char* data) const; @@ -553,6 +555,14 @@ } /*! + * \returns the underlying char-array representation of this string, casted to unsigned chars. + */ +inline const unsigned char* String::toBytes() const +{ + return reinterpret_cast<const unsigned char*>(chars()); +} + +/*! * \brief Constructs an empty string list. */ inline StringList::StringList() {}
--- a/sources/network/bytestream.cpp Wed Jul 20 22:56:16 2016 +0300 +++ b/sources/network/bytestream.cpp Fri Jul 22 17:50:00 2016 +0300 @@ -32,270 +32,224 @@ #include <string.h> BEGIN_ZFC_NAMESPACE -// ------------------------------------------------------------------------------------------------- -// -Bytestream::Bytestream (unsigned long length) : - m_data (nullptr) -{ - resize (length); - clear(); -} - -// ------------------------------------------------------------------------------------------------- -// -Bytestream::Bytestream (const unsigned char* data, unsigned long length) : - m_data (nullptr) -{ - init (data, length); -} - -// ------------------------------------------------------------------------------------------------- -// -Bytestream::Bytestream (const Vector<unsigned char>& bytes) : - m_data (nullptr) -{ - init (bytes.data(), bytes.size()); -} - -// ------------------------------------------------------------------------------------------------- -// -Bytestream::Bytestream (const Bytestream& other) : - m_data (nullptr) -{ - init (other.data(), other.written_length()); -} - -// ------------------------------------------------------------------------------------------------- -// -Bytestream::~Bytestream() -{ - delete[] m_data; -} - -// ------------------------------------------------------------------------------------------------- -Bytestream& Bytestream::operator= (const Bytestream& other) -{ - init (other.data(), other.written_length()); - return *this; -} +/*! + * \brief Constructs a byte cursor. The cursor is placed to the beginning of the stream. + * \param data + */ +Bytestream::Bytestream(Vector<unsigned char>& data) : + m_data(data), + m_position(0) {} -// ------------------------------------------------------------------------------------------------- -// -void Bytestream::resize (unsigned long newsize) -{ - Vector<unsigned char> olddata; - unsigned long oldsize = 0L; - - if (m_data != nullptr) - { - oldsize = allocated_size(); - olddata.resize (oldsize); - memcpy (olddata.data(), m_data, oldsize); - } - - delete[] m_data; - m_allocatedSize = newsize; - m_data = new unsigned char[newsize]; - - if (oldsize > 0L) - memcpy (m_data, olddata, min (oldsize, newsize)); -} - -// ------------------------------------------------------------------------------------------------- -// -void Bytestream::init (const unsigned char* data, unsigned long length) +/*! + * \brief Ensures that the specified amount of bytes can be read. Raises IOError if this is not the case. + * \param bytes Amount of bytes to check. + */ +void Bytestream::ensureReadSpace(int bytes) { - resize (length); - memcpy (m_data, data, length); - m_cursor = &m_data[0]; - m_writtenLength = length; -} - -// ------------------------------------------------------------------------------------------------- -// -void Bytestream::clear() -{ - m_cursor = &m_data[0]; - m_writtenLength = 0; -} - -// ------------------------------------------------------------------------------------------------- -// -void Bytestream::ensure_read_space (unsigned int bytes) -{ - if (bytes_left() < bytes) + if (bytesLeft() < bytes) { - int bytesPast = bytes - bytes_left(); - + int bytesPast = bytes - bytesLeft(); String message; - message.sprintf ("attempted to read %d byte%s past the end of bytestream", - bytesPast, bytesPast != -1 ? "s" : ""); + message.sprintf("attempted to read %d byte%s past the end of bytestream", bytesPast, plural(bytesPast)); throw IOError (message); } } -// ------------------------------------------------------------------------------------------------- -// -int8_t Bytestream::read_byte() +/*! + * \returns the amount of bytes remaining for reading. + */ +int Bytestream::bytesLeft() const { - ensure_read_space (1); - return *m_cursor++; + return m_data.size() - m_position; +} + +/*! + * \returns an iterator to the current data position. + */ +Vector<unsigned char>::Iterator Bytestream::getCurrentIterator() +{ + return m_data.begin() + m_position; } -// ------------------------------------------------------------------------------------------------- -// -int16_t Bytestream::read_short() +/*! + * \brief Reads in a byte. + * \returns the read byte. + */ +int8_t Bytestream::readByte() { - ensure_read_space (2); - short int result = 0; + ensureReadSpace(1); + return read(); +} + +/*! + * \brief Reads in two bytes to form an integer value. + * \returns the read value. + */ +int16_t Bytestream::readShort() +{ + ensureReadSpace (2); + int16_t result = 0; for (int i : range(2)) - result |= m_cursor[i] << (i * 8); + result |= read() << (i * 8); - m_cursor += 2; return result; } -// ------------------------------------------------------------------------------------------------- -// -int32_t Bytestream::read_long() +/*! + * \brief Reads in four bytes to form an integer value. + * \returns the read value. + */ +int32_t Bytestream::readLong() { - ensure_read_space (4); - long int result = 0; + ensureReadSpace (4); + int32_t result = 0; for (int i : range(4)) - result |= m_cursor[i] << (i * 8); + result |= read() << (i * 8); - m_cursor += 4; return result; } -// ------------------------------------------------------------------------------------------------- -// -float Bytestream::read_float() +/*! + * \brief Reads in four bytes to form a floating point number. + * \returns the read value. + */ +float Bytestream::readFloat() { float value; - int intvalue = read_long(); - memcpy (&value, &intvalue, sizeof intvalue); + int intvalue = readLong(); + memcpy(&value, &intvalue, sizeof intvalue); return value; } -// ------------------------------------------------------------------------------------------------- -// -String Bytestream::read_string() +/*! + * \brief Reads in characters until a null terminator is encountered. + * \returns the read string. + */ +String Bytestream::readString() { - // Zandronum sends strings of maximum 2048 characters, though it only - // reads 2047-character long ones so I guess we can follow up and do - // the same :-) - static char buffer[MAX_NETWORK_STRING]; - unsigned char* stringEnd; - unsigned char* stringBegin = m_cursor; - unsigned char* end = m_data + allocated_size(); + Vector<unsigned char>::Iterator stringEndIterator; // Where's the end of the string? - for (stringEnd = m_cursor; *stringEnd != '\0'; ++stringEnd) + for (stringEndIterator = getCurrentIterator(); *stringEndIterator != '\0'; ++stringEndIterator) { - if (stringEnd == end) + if (stringEndIterator == m_data.end()) { // Past the end of the buffer - throw IOError ("unterminated or too long string in packet"); + throw IOError("unterminated or too long string in packet"); } } - unsigned int length = stringEnd - m_cursor; - m_cursor = stringEnd + 1; - memcpy (buffer, stringBegin, length); - buffer[length] = '\0'; - return String (buffer); -} + // Skip past the null terminator. + if (*stringEndIterator == '\0') + stringEndIterator += 1; -// ------------------------------------------------------------------------------------------------- -// -void Bytestream::read (unsigned char* buffer, unsigned long length) -{ - ensure_read_space (length); - memcpy (buffer, m_cursor, length); - m_cursor += length; + // Build and return the string, and advance the position. + int stringStart = m_position; + unsigned int length = stringEndIterator - getCurrentIterator(); + length = min<int>(length, MAX_NETWORK_STRING); + m_position += length; + return String::fromBytes(m_data.splice(stringStart, stringStart + length)); } -// ------------------------------------------------------------------------------------------------- -// -void Bytestream::write (unsigned char val) +/*! + * \brief Reads in a buffer of the specified length. + * \param length Amount of bytes to read. + * \returns the read buffer. + */ +Vector<unsigned char> Bytestream::readBuffer(int length) { - *m_cursor++ = val; - m_writtenLength++; -} - -// ------------------------------------------------------------------------------------------------- -// -void Bytestream::write (const unsigned char* val, unsigned int length) -{ - grow_to_fit (length); - memcpy (m_cursor, val, length); - m_cursor += length; - m_writtenLength += length; + ensureReadSpace(length); + Vector<unsigned char> result(length); + memcpy(result.data(), m_data.data() + m_position, length); + m_position += length; + return result; } -// ------------------------------------------------------------------------------------------------- -// -void Bytestream::grow_to_fit (unsigned long bytes) +/*! + * \brief Writes an integer to the end of the data as one byte. + * \param value Value to write + */ +void Bytestream::writeByte(int8_t value) { - if (space_left() < bytes) - resize (allocated_size() + bytes + 128); -} - -// ------------------------------------------------------------------------------------------------- -// -void Bytestream::write_byte (int8_t val) -{ - grow_to_fit (1); - write (val); + m_data.append(value); } -// ------------------------------------------------------------------------------------------------- -// -void Bytestream::write_short (int16_t val) +/*! + * \brief Writes an integer to the end of the data as 2 bytes. + * \param value Value to write + */ +void Bytestream::writeShort(int16_t value) { - grow_to_fit (2); - for (int i : range(2)) - write ((val >> (i * 8)) & 0xFF); + m_data.append((value >> (i * 8)) & 0xFF); } -// ------------------------------------------------------------------------------------------------- -// -void Bytestream::write_long (int32_t val) +/*! + * \brief Writes an integer to the end of the data as 4 bytes. + * \param value Value to write + */ +void Bytestream::writeLong(int32_t value) { - grow_to_fit (4); - for (int i : range(4)) - write ((val >> (i * 8)) & 0xFF); + m_data.append((value >> (i * 8)) & 0xFF); } -// ------------------------------------------------------------------------------------------------- -// -void Bytestream::write_float (float val) +/*! + * \brief Writes a floating-point number to the end of the data. + * \param value Value to write. + */ +void Bytestream::writeFloat(float value) { // I know this is probably dangerous but this is what Zandronum does so yeah int intvalue; - memcpy (&intvalue, &val, sizeof val); - write_long (intvalue); + memcpy (&intvalue, &value, sizeof value); + writeLong (intvalue); +} + +/*! + * \brief Writes the given string to the end of the data. + * \param text String to write. + */ +void Bytestream::writeString(const String& string) +{ + m_data.append(string.toBytes(), string.length()); + m_data.append(0); +} + +/*! + * \returns the current position the stream cursor in the data. + */ +int Bytestream::position() const +{ + return m_position; } -// ------------------------------------------------------------------------------------------------- -// -void Bytestream::write_string (const String& val) +/*! + * \brief Seeks the stream cursor to the beginning of the data. + */ +void Bytestream::rewind() { - grow_to_fit (val.length() + 1); - write (reinterpret_cast<const unsigned char*> (val.chars()), val.length()); - write (0); + m_position = 0; } -// ------------------------------------------------------------------------------------------------- -// -void Bytestream::write_buffer (const Bytestream& other) +/*! + * \brief Seeks the stream cursor to a custom location. + * \param position Position to seek too. + */ +void Bytestream::seek(int position) { - write (other.data(), other.written_length()); + m_position = position; +} + +/*! + * \brief Reads a byte and advances the cursor. No safety checks are done. + * \returns the read byte. + */ +int8_t Bytestream::read() +{ + return m_data[m_position++]; } END_ZFC_NAMESPACE \ No newline at end of file
--- a/sources/network/bytestream.h Wed Jul 20 22:56:16 2016 +0300 +++ b/sources/network/bytestream.h Fri Jul 22 17:50:00 2016 +0300 @@ -40,119 +40,51 @@ MAX_NETWORK_STRING = 0x800 }; -// TODO: Make able to handle big-endian too +class IOError : public std::exception +{ + String m_message; + +public: + IOError(String message) : + m_message(message) {} + + const char* what() const throw() + { + return m_message; + } +}; + class Bytestream { public: - class IOError : public std::exception - { - String m_message; - - public: - IOError (String message) : - m_message (message) {} - - const char* what() const throw() - { - return m_message; - } - }; - - Bytestream (unsigned long length = 0x800); - Bytestream (const unsigned char* data, unsigned long length); - Bytestream (const Vector<unsigned char>& bytes); - Bytestream (const Bytestream& other); - ~Bytestream(); - - void clear(); - void grow_to_fit (unsigned long bytes); - void read (unsigned char* buffer, unsigned long length); - int8_t read_byte(); - int32_t read_long(); - int16_t read_short(); - String read_string(); - float read_float(); - void resize (unsigned long length); - void write (const unsigned char* val, unsigned int length); - void write_buffer (const Bytestream& other); - void write_buffer (const Vector<unsigned char>& other); - void write_byte (int8_t val); - void write_double (double val); - void write_float (float val); - void write_long (int32_t val); - void write_short (int16_t val); - void write_string (const String& val); - - Bytestream& operator= (const Bytestream& other); - - unsigned long allocated_size() const - { - return m_allocatedSize; - } + Bytestream(Vector<unsigned char>& data); - unsigned long bytes_left() const - { - return m_writtenLength - (m_cursor - &m_data[0]); - } - - inline unsigned char* data() - { - return m_data; - } - inline const unsigned char* data() const - { - return m_data; - } - - unsigned long position() const - { - return m_cursor - m_data; - } - - void rewind() - { - m_cursor = m_data; - } - - void seek (unsigned long pos) - { - m_cursor = m_data + pos; - } - - Vector<unsigned char> to_vector() const - { - return Vector<unsigned char> (m_data, m_writtenLength); - } - - unsigned long written_length() const - { - return m_writtenLength; - } - - unsigned char& operator[] (unsigned long idx) - { - return m_data[idx]; - } - - unsigned char operator[] (unsigned long idx) const - { - return m_data[idx]; - } + int bytesLeft() const; + Vector<unsigned char>::Iterator getCurrentIterator(); + int position() const; + Vector<unsigned char> readBuffer(int length); + int8_t readByte(); + int32_t readLong(); + int16_t readShort(); + String readString(); + float readFloat(); + void rewind(); + void seek(int position); + void write(const unsigned char* val, unsigned int length); + void writeBuffer(const Vector<unsigned char>& other); + void writeByte(int8_t value); + void writeDouble(double val); + void writeFloat(float value); + void writeLong(int32_t value); + void writeShort(int16_t value); + void writeString(const String& string); private: - unsigned char* m_data; - unsigned char* m_cursor; - unsigned long m_allocatedSize; - unsigned long m_writtenLength; + Vector<unsigned char>& m_data; + int m_position; - void init (const unsigned char* data, unsigned long length); - void write (unsigned char val); - void ensure_read_space (unsigned int bytes); - - unsigned long space_left() const - { - return m_allocatedSize - m_writtenLength; - } + int8_t read(); + void ensureReadSpace(int bytes); }; END_ZFC_NAMESPACE
--- a/sources/network/rconsession.cpp Wed Jul 20 22:56:16 2016 +0300 +++ b/sources/network/rconsession.cpp Fri Jul 22 17:50:00 2016 +0300 @@ -70,9 +70,7 @@ if (m_state > RCON_CONNECTING) { // Say goodbye to remote - Bytestream packet; - packet.write_byte(CLRC_DISCONNECT); - this->send(packet); + send({CLRC_DISCONNECT}); m_interface->disconnected(); } @@ -81,7 +79,7 @@ // ------------------------------------------------------------------------------------------------- // -void RCONSession::send(const Bytestream& packet) +void RCONSession::send(const Vector<unsigned char>& packet) { m_socket.send(m_address, packet); } @@ -108,9 +106,7 @@ } else if (m_state == RCON_CONNECTED and m_lastPing + 5 < now) { - Bytestream packet; - packet.write_byte(CLRC_PONG); - send(packet); + send({CLRC_PONG}); bumpLastPing(); } } @@ -126,11 +122,13 @@ if (datagram.address != m_address) return; + Bytestream stream(datagram.message); + try { - while (datagram.message.bytes_left() > 0) + while (stream.bytesLeft() > 0) { - int header = datagram.message.read_byte(); + int header = stream.readByte(); switch (ServerResponse(header)) { @@ -145,7 +143,7 @@ break; case SVRC_SALT: - m_salt = datagram.message.read_string(); + m_salt = stream.readString(); m_state = RCON_AUTHENTICATING; sendPassword(); break; @@ -157,7 +155,7 @@ case SVRC_MESSAGE: { - String message = datagram.message.read_string(); + String message = stream.readString(); message.normalize(); m_interface->printText("%s\n", message.chars()); } @@ -165,19 +163,19 @@ case SVRC_LOGGEDIN: m_interface->print("Login successful!\n"); - m_serverProtocol = datagram.message.read_byte(); - m_hostname = datagram.message.read_string(); + m_serverProtocol = stream.readByte(); + m_hostname = stream.readString(); m_interface->setTitle(m_hostname); m_state = RCON_CONNECTED; - for (int i = datagram.message.read_byte(); i > 0; --i) - processServerUpdates(datagram.message); + for (int i = stream.readByte(); i > 0; --i) + processServerUpdates(stream); m_interface->print("Previous messages:\n"); - for (int i = datagram.message.read_byte(); i > 0; --i) + for (int i = stream.readByte(); i > 0; --i) { - String message = datagram.message.read_string(); + String message = stream.readString(); message.normalize(); m_interface->printText("--- %s\n", message.chars()); } @@ -186,12 +184,12 @@ break; case SVRC_UPDATE: - processServerUpdates(datagram.message); + processServerUpdates(stream); break; case SVRC_TOOMANYTABCOMPLETES: { - unsigned int numCompletions = datagram.message.read_short(); + unsigned int numCompletions = stream.readShort(); m_interface->print("%d completions for '%s'.\n", int(numCompletions), m_lastTabComplete.chars()); } @@ -200,10 +198,10 @@ case SVRC_TABCOMPLETE: { StringList completes; - completes.resize(datagram.message.read_byte()); + completes.resize(stream.readByte()); for (String& completion : completes) - completion = datagram.message.read_string(); + completion = stream.readString(); if (completes.size() == 1) { @@ -233,7 +231,7 @@ void RCONSession::processServerUpdates(Bytestream& packet) { - int header = packet.read_byte(); + int header = packet.readByte(); switch (RCONUpdateType(header)) { @@ -241,20 +239,20 @@ { StringList players; - for (int i = packet.read_byte(); i > 0; --i) - players.append(packet.read_string()); + for (int i = packet.readByte(); i > 0; --i) + players.append(packet.readString()); m_interface->setPlayerNames(players); } break; case SVRCU_ADMINCOUNT: - m_adminCount = packet.read_byte(); + m_adminCount = packet.readByte(); m_interface->updateStatusBar(); break; case SVRCU_MAP: - m_level = packet.read_string(); + m_level = packet.readString(); m_interface->updateStatusBar(); break; @@ -276,10 +274,7 @@ void RCONSession::sendHello() { m_interface->print("Connecting to %s...\n", m_address.to_string(IPAddress::WITH_PORT).chars()); - Bytestream packet; - packet.write_byte(CLRC_BEGINCONNECTION); - packet.write_byte(RCON_PROTOCOL_VERSION); - send(packet); + send({CLRC_BEGINCONNECTION, RCON_PROTOCOL_VERSION}); bumpLastPing(); } @@ -288,10 +283,11 @@ void RCONSession::sendPassword() { m_interface->print("Authenticating...\n"); - Bytestream packet; - packet.write_byte(CLRC_PASSWORD); - packet.write_string((m_salt + m_password).md5()); - send(packet); + Vector<unsigned char> message; + Bytestream stream(message); + stream.writeByte(CLRC_PASSWORD); + stream.writeString((m_salt + m_password).md5()); + send(message); bumpLastPing(); } @@ -321,15 +317,16 @@ // ------------------------------------------------------------------------------------------------- // Returns true if the message was successfully sent. // -bool RCONSession::sendCommand(const String& message) +bool RCONSession::sendCommand(const String& commandString) { - if (m_state != RCON_CONNECTED or message.isEmpty()) + if (m_state != RCON_CONNECTED or commandString.isEmpty()) return false; - Bytestream packet; - packet.write_byte(CLRC_COMMAND); - packet.write_string(message); - send(packet); + Vector<unsigned char> message; + Bytestream stream(message); + stream.writeByte(CLRC_COMMAND); + stream.writeString(commandString); + send(message); bumpLastPing(); return true; } @@ -368,10 +365,11 @@ { if (m_serverProtocol >= 4) { - Bytestream packet; - packet.write_byte(CLRC_TABCOMPLETE); - packet.write_string(part); - send(packet); + Vector<unsigned char> message; + Bytestream stream(message); + stream.writeByte(CLRC_TABCOMPLETE); + stream.writeString(part); + send(message); bumpLastPing(); m_lastTabComplete = part; }
--- a/sources/network/rconsession.h Wed Jul 20 22:56:16 2016 +0300 +++ b/sources/network/rconsession.h Fri Jul 22 17:50:00 2016 +0300 @@ -107,8 +107,8 @@ bool isActive() const; void processServerUpdates(Bytestream& packet); void requestTabCompletion(const String& part); - void send(const Bytestream& packet); - bool sendCommand(const String& message); + void send(const Vector<unsigned char>& packet); + bool sendCommand(const String& commandString); void sendHello(); void sendPassword(); void setInterface(class Interface* interface);
--- a/sources/network/udpsocket.cpp Wed Jul 20 22:56:16 2016 +0300 +++ b/sources/network/udpsocket.cpp Fri Jul 22 17:50:00 2016 +0300 @@ -135,17 +135,16 @@ decodedPacket, length, &decodedLength); datagram.address.host = ntohl (claddr.sin_addr.s_addr); datagram.address.port = ntohs (claddr.sin_port); - datagram.message = Bytestream (decodedPacket, decodedLength); + datagram.message = Vector<unsigned char>(decodedPacket, decodedLength); return true; } // ------------------------------------------------------------------------------------------------- // -bool UDPSocket::send (const IPAddress& address, const Bytestream& data) +bool UDPSocket::send (const IPAddress& address, const Vector<unsigned char>& data) { int encodedlength = sizeof HuffmanBuffer; - HUFFMAN_Encode (data.data(), reinterpret_cast<unsigned char*> (HuffmanBuffer), - data.written_length(), &encodedlength); + HUFFMAN_Encode (data.data(), reinterpret_cast<unsigned char*> (HuffmanBuffer), data.size(), &encodedlength); sockaddr_in claddr = address.to_sockaddr_in(); int res = ::sendto (m_socket, HuffmanBuffer, encodedlength, 0, reinterpret_cast<sockaddr*> (&claddr), sizeof claddr);
--- a/sources/network/udpsocket.h Wed Jul 20 22:56:16 2016 +0300 +++ b/sources/network/udpsocket.h Fri Jul 22 17:50:00 2016 +0300 @@ -38,7 +38,7 @@ struct Datagram { - Bytestream message; + Vector<unsigned char> message; IPAddress address; }; @@ -52,7 +52,7 @@ bool bind (unsigned short port); bool read (Datagram& datagram); - bool send (const IPAddress& address, const Bytestream& data); + bool send (const IPAddress& address, const Vector<unsigned char>& data); bool set_blocking (bool a); const String& error_string() const { return m_error; } int file_descriptor() const { return m_socket; }