sources/network/bytestream.cpp

changeset 157
42bb29924218
parent 137
485cb6d6b98c
child 158
de7574d292ad
--- 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

mercurial