How to convert uint8 arrays to Fstrings?

I am developing a very simple application which should behave accordingly to a stream of data coming from a TCP Socket.

I have managed to make the network part work, but now I have encountered a very strange behaviour. When I receive data from the network I convert it into a string using the integrated functions, like this:

TArray<FRotator> UNetworkBlueprintLibrary::GetRotationPacket(){

	bool				bDataPresent;
	uint32				netData;
	int32				bytesRead;
	TArray<FRotator>	tempData;
	uint8				receivedData[100];

	bDataPresent = UNetworkBlueprintLibrary::ServerSocket->HasPendingData(netData);

	if (netData >= 16) {
		UNetworkBlueprintLibrary::ServerSocket->Recv(receivedData, (int32) 100, bytesRead);
		
		FString debugData = BytesToString(receivedData, bytesRead);
		// Writing received data to log
		UE_LOG(NetworkInfo, Warning, TEXT("Got message %s"), *debugData);
		
	} 

	return tempData;
}

I will have to fix some things as the code is not very good, but I was just testing. The application behaves accordingly, receives the message and then outputs what’s in the buffer on the LOG screen in the Editor.

What’s strange is that, even if the message is:

Server: Welcome 127.0.0.1

What gets written in the LOG dialog is:

Got message Tfswfs;!Xfmdpnf!238/1/1/2

Which… Looks like the message with each of the characters increased by one. After checking my code I decided to check the definition of BytesToString, and it looks like this:

/** 
 * Convert an array of bytes to a TCHAR
 * @param In byte array values to convert
 * @param Count number of bytes to convert
 * @return Valid string representing bytes.
 */
inline FString BytesToString(const uint8* In, int32 Count)
{
	FString Result;
	Result.Empty(Count);

	while (Count)
	{
		// Put the byte into an int16 and add 1 to it, this keeps anything from being put into the string as a null terminator
		int16 Value = *In;
		Value += 1;

		Result += TCHAR(Value);

		++In;
		Count--;
	}
	return Result;
}

Oh, ok! Now I get it, the function adds one to each character in the string because… Reasons, I suppose, as I don’t understand why they should not allow null terminators inside FStrings. If I remember correctly they should be null-terminated strings, but there might be a reason behind this behaviour.

Is there a function to use a FString that has been encoded this way?

Or, better yet, should I change that code and sent a pull request to the GIT repository?

I can confirm that removing the Value += 1; comand from the conversion function did not break anything in my project and resulted in the right output. However I would like to understand if this is a good approach or if I should call another function to re-convert the string to use as intended.

The BytesToString function was not thought to be used with normal text data, but with binary data. It allows you to store the binary data in a string, but to use the data you will have to use the StringToBytes function to get the original data back.

In C++ a string is always terminated by a 0x00 character. So when you receive and arbitrary stream of bytes as binary data and convert it to a string, there might be a chance that one of the bytes is a 0x00. In this case the string would be considered finished at the first 0x00 character and everything after that would be ignored by any function trying to use that string.

To prevent this problem, every byte gets added +1 so that in case of a 0x00 it would become a 0x01. The string itself would then be terminated with a 0x00 at the end, but the string content itself would never have a 0x00 inside it. When you use the StringToBytes function, the process is reversed and every character gets subtracted -1 so that the 0x01 created by the BytesToString function becomes a 0x00 again.

Oh, great, thank you!
Ok, now I get how this is used. I am using the function for a very simple socket communication layer as I wanted to use as much as possible the internal functions for String management.
I have done the conversion by hand in my code, but your answer clarified me on some of the inner workings.

Null terminator (value 0) is used to signify the end of a string in C. So the string containing: “Jazzinghen” is actually 11 characters long. The last character being null ‘\0’.

You could try something like this

char ansiiData[1024]; //A temp buffer for the data

memcpy(ansiiData, receivedData, bytesRead); //Assumes bytesRead is always smaller than 1024 bytes

ansiiData[bytesRead] = 0; //Add null terminator

FString debugData = ANSI_TO_TCHAR(ansiiData); //Convert to FString

I assume on the Sending side you are not sending the null terminator. Also this is only good for decoding simple strings. Any float, ints, structures etc would be garbage to the Log output without more formatting.

Is there any chance you might post your UNetworkBlueprintLibrary class? I am also trying to get networking working, and I’d love to see how you are doing it.

Thanks, this works for me