aboutsummaryrefslogtreecommitdiff
path: root/src/network
diff options
context:
space:
mode:
Diffstat (limited to 'src/network')
-rw-r--r--src/network/networkpacket.cpp49
-rw-r--r--src/network/networkpacket.h2
-rw-r--r--src/network/serverpackethandler.cpp15
3 files changed, 42 insertions, 24 deletions
diff --git a/src/network/networkpacket.cpp b/src/network/networkpacket.cpp
index 6d0abb12c..a71e26572 100644
--- a/src/network/networkpacket.cpp
+++ b/src/network/networkpacket.cpp
@@ -50,7 +50,7 @@ void NetworkPacket::checkReadOffset(u32 from_offset, u32 field_size)
}
}
-void NetworkPacket::putRawPacket(u8 *data, u32 datasize, session_t peer_id)
+void NetworkPacket::putRawPacket(const u8 *data, u32 datasize, session_t peer_id)
{
// If a m_command is already set, we are rewriting on same packet
// This is not permitted
@@ -145,6 +145,8 @@ void NetworkPacket::putLongString(const std::string &src)
putRawString(src.c_str(), msgsize);
}
+static constexpr bool NEED_SURROGATE_CODING = sizeof(wchar_t) > 2;
+
NetworkPacket& NetworkPacket::operator>>(std::wstring& dst)
{
checkReadOffset(m_read_offset, 2);
@@ -160,9 +162,16 @@ NetworkPacket& NetworkPacket::operator>>(std::wstring& dst)
checkReadOffset(m_read_offset, strLen * 2);
dst.reserve(strLen);
- for(u16 i=0; i<strLen; i++) {
- wchar_t c16 = readU16(&m_data[m_read_offset]);
- dst.append(&c16, 1);
+ for (u16 i = 0; i < strLen; i++) {
+ wchar_t c = readU16(&m_data[m_read_offset]);
+ if (NEED_SURROGATE_CODING && c >= 0xD800 && c < 0xDC00 && i+1 < strLen) {
+ i++;
+ m_read_offset += sizeof(u16);
+
+ wchar_t c2 = readU16(&m_data[m_read_offset]);
+ c = 0x10000 + ( ((c & 0x3ff) << 10) | (c2 & 0x3ff) );
+ }
+ dst.push_back(c);
m_read_offset += sizeof(u16);
}
@@ -175,15 +184,37 @@ NetworkPacket& NetworkPacket::operator<<(const std::wstring &src)
throw PacketError("String too long");
}
- u16 msgsize = src.size();
+ if (!NEED_SURROGATE_CODING || src.size() == 0) {
+ *this << static_cast<u16>(src.size());
+ for (u16 i = 0; i < src.size(); i++)
+ *this << static_cast<u16>(src[i]);
- *this << msgsize;
+ return *this;
+ }
- // Write string
- for (u16 i=0; i<msgsize; i++) {
- *this << (u16) src[i];
+ // write dummy value, to be overwritten later
+ const u32 len_offset = m_read_offset;
+ u32 written = 0;
+ *this << static_cast<u16>(0xfff0);
+
+ for (u16 i = 0; i < src.size(); i++) {
+ wchar_t c = src[i];
+ if (c > 0xffff) {
+ // Encode high code-points as surrogate pairs
+ u32 n = c - 0x10000;
+ *this << static_cast<u16>(0xD800 | (n >> 10))
+ << static_cast<u16>(0xDC00 | (n & 0x3ff));
+ written += 2;
+ } else {
+ *this << static_cast<u16>(c);
+ written++;
+ }
}
+ if (written > WIDE_STRING_MAX_LEN)
+ throw PacketError("String too long");
+ writeU16(&m_data[len_offset], written);
+
return *this;
}
diff --git a/src/network/networkpacket.h b/src/network/networkpacket.h
index e77bfb744..c7ff03b8e 100644
--- a/src/network/networkpacket.h
+++ b/src/network/networkpacket.h
@@ -34,7 +34,7 @@ public:
~NetworkPacket();
- void putRawPacket(u8 *data, u32 datasize, session_t peer_id);
+ void putRawPacket(const u8 *data, u32 datasize, session_t peer_id);
void clear();
// Getters
diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp
index 02af06abc..270b8e01f 100644
--- a/src/network/serverpackethandler.cpp
+++ b/src/network/serverpackethandler.cpp
@@ -752,21 +752,8 @@ void Server::handleCommand_InventoryAction(NetworkPacket* pkt)
void Server::handleCommand_ChatMessage(NetworkPacket* pkt)
{
- /*
- u16 command
- u16 length
- wstring message
- */
- u16 len;
- *pkt >> len;
-
std::wstring message;
- for (u16 i = 0; i < len; i++) {
- u16 tmp_wchar;
- *pkt >> tmp_wchar;
-
- message += (wchar_t)tmp_wchar;
- }
+ *pkt >> message;
session_t peer_id = pkt->getPeerId();
RemotePlayer *player = m_env->getPlayer(peer_id);