You can create and write a file using Unreal

Discussions about Coding and Scripting
User avatar
PrinceOfFunky
Godlike
Posts: 1204
Joined: Mon Aug 31, 2015 10:31 pm

Re: You can create and write a file using Unreal

Post by PrinceOfFunky »

nogardilaref wrote:Hence when I created hashing functions for instance (namely MD5 and SHA family), I had to specifically create byte arrays so I could handle the NULL bytes
Idk what kind but there are two functions returning checksums:
Within StatLog.uc:

Code: Select all

native static function GetPlayerChecksum( PlayerPawn P, out string Checksum );
Within StatLogFile.uc:

Code: Select all

native final function GetChecksum( out string Checksum );
nogardilaref
Masterful
Posts: 577
Joined: Tue Jun 20, 2017 1:00 pm
Personal rank: βš‹βšŠβšŒβ˜°βšžβŒ–βšŸβ˜°βšŒβšŠβš‹

Re: You can create and write a file using Unreal

Post by nogardilaref »

My previous function had some mistakes, namely on the endianess of the data, and the fact that I coded it PHP-style and forgot that UT doesn't have things like "===" and doesn't allow me to access the string characters as an array. :lol2:
(it was untested after all when I posted it)

So, I fixed it and ended up creating this class for experimentation:

Code: Select all

class IntFile extends StatLogFile;

var string data;

function open(string filename)
{
	StatLogFile = filename $ ".tmp";
	StatLogFinal = filename $ ".int";
	OpenLog();
}

function write(string data, optional bool newline)
{
	self.data = self.data $ data;
	if (newline) {
		self.data = self.data $ chr(13) $ chr(10);
	}
}

function writeLine(string data)
{
	write(data, true);
}

function close()
{
local string data;

	//data
	data = self.data;
	if (asc(chr(1000)) == 1000) {
		data = convert(self.data);
	}
	FileLog(data);

	//flush and close
	FileFlush();
	CloseLog();
}

function string convert(string data)
{
local string final_data;
local int data_len, i;

	//convert
	data_len = len(data);
	for (i = 1; i < data_len; i += 2) {
		final_data = final_data $ chr((asc(mid(data, i, 1)) << 8) | asc(mid(data, i - 1, 1)));
	}
   
	//convert remaining byte
	if (data_len % 2 == 1) {
		final_data = final_data $ mid(data, data_len - 1, 1);
	}
   
 	//return
	return final_data;
}
and then ran it like this:

Code: Select all

function PostBeginPlay()
{
local IntFile file;

	//file
	file = Spawn(class'IntFile');
	file.open("test");
	file.writeLine("[MySection]");
	file.writeLine("a={\"key\":\"value\"}");
	file.writeLine("b=This is some ANSI text.");
	file.close();

	//test log
	log("TEST.MySection.a = " $ Localize("MySection", "a", "TEST"), 'YOLO_TEST');
	log("TEST.MySection.b = " $ Localize("MySection", "b", "TEST"), 'YOLO_TEST');
}
and it worked, and the .int file was correctly written in ANSI rather than UTF-16.
However, it has a catch: FileLog always adds a carriage return and a new line at the end, which are them forcefully converted to UTF-16, which means that in editors such as Notepad++, you will see the last lines as "NULL", this is because the editor understood the file as ANSI, and since in UTF-16 the ASCII character set only has an extra NULL byte in practice, this is what the editor is showing.

I am not sure if there's a way around that tbh, so perhaps we're better off just writing the BOM at the start if we're in a UTF-16 environment when creating an .int file rather than converting it to ANSI.
Also, this shows that binary files are possible to some extent, although there's still the overall NULL bytes problem to deal with.

But given that we're able to call batch/bash files from outside at least, this means that one possible way to write full binary files is to write them in Base64 encoding, and then write a file with the necessary scripting into itself so from outside this Base64 encoded file gets decoded and then used in some way.
There's probably a more direct way of doing it, but this alone shows it to be possible to write full binary files in one way or another, and this sounds awfully close to how to build something like a NPLoader.
PrinceOfFunky wrote:
nogardilaref wrote:Hence when I created hashing functions for instance (namely MD5 and SHA family), I had to specifically create byte arrays so I could handle the NULL bytes
Idk what kind but there are two functions returning checksums:
Within StatLog.uc:

Code: Select all

native static function GetPlayerChecksum( PlayerPawn P, out string Checksum );
Within StatLogFile.uc:

Code: Select all

native final function GetChecksum( out string Checksum );
Didn't test them, but those are probably CRC32 checksums.
User avatar
PrinceOfFunky
Godlike
Posts: 1204
Joined: Mon Aug 31, 2015 10:31 pm

Re: You can create and write a file using Unreal

Post by PrinceOfFunky »

nogardilaref wrote:But given that we're able to call batch/bash files from outside at least, this means that one possible way to write full binary files is to write them in Base64 encoding, and then write a file with the necessary scripting into itself so from outside this Base64 encoded file gets decoded and then used in some way.
There's probably a more direct way of doing it, but this alone shows it to be possible to write full binary files in one way or another, and this sounds awfully close to how to build something like a NPLoader.
In WebRequest.uc there's a function to decode Base64:

Code: Select all

native final function string DecodeBase64(string Encoded);
I think a file reader could be made running an external script that would read a file and copy it in the clipboard, using then PlayerPawn.PasteFromClipboard() to get the content.
nogardilaref
Masterful
Posts: 577
Joined: Tue Jun 20, 2017 1:00 pm
Personal rank: βš‹βšŠβšŒβ˜°βšžβŒ–βšŸβ˜°βšŒβšŠβš‹

Re: You can create and write a file using Unreal

Post by nogardilaref »

Using the clipboard is a very "hacky" and intrusive way of doing it:
1 - It's not expected for the clipboard to be automatically manipulated without explicit knowledge from the user;
2 - You cannot be sure if some other parallel process is doing anything with it, so what you paste may not be what you expect;
3 - We may be talking about a relatively gigantic amount of data, which may be problematic for the user should he/she try to paste somewhere else.

The function you just posted is rather useless however for anything that translates into binary data, because as I mentioned previously, you cannot represent a NULL byte within a string (0x00), because strings in UE1 are NULL-terminated, and for anything not binary, you don't even need to encode and decode stuff from Base64, clear text generally suffices.
Also I think Windows and Linux already both come with a command to decode them, and even if they don't, doing a Base64 decoder is not hard, so that's not much of a problem.
User avatar
PrinceOfFunky
Godlike
Posts: 1204
Joined: Mon Aug 31, 2015 10:31 pm

Re: You can create and write a file using Unreal

Post by PrinceOfFunky »

I first thought about populating an INT with optionN=fileLineN, but I don't know if it could ever work.
nogardilaref
Masterful
Posts: 577
Joined: Tue Jun 20, 2017 1:00 pm
Personal rank: βš‹βšŠβšŒβ˜°βšžβŒ–βšŸβ˜°βšŒβšŠβš‹

Re: You can create and write a file using Unreal

Post by nogardilaref »

What do you mean exactly?
User avatar
PrinceOfFunky
Godlike
Posts: 1204
Joined: Mon Aug 31, 2015 10:31 pm

Re: You can create and write a file using Unreal

Post by PrinceOfFunky »

nogardilaref wrote:What do you mean exactly?
To read a file, I'm trying right now, the INT is populated with the file_to_read lines(one for key) by an external script and then Unreal checks the localization etc to retrieve the lines.
EDIT: Well it works but it needs to loop until the file has been fully read. (I guess I should use TCP to know when the file_lines.int is ready)
nogardilaref
Masterful
Posts: 577
Joined: Tue Jun 20, 2017 1:00 pm
Personal rank: βš‹βšŠβšŒβ˜°βšžβŒ–βšŸβ˜°βšŒβšŠβš‹

Re: You can create and write a file using Unreal

Post by nogardilaref »

Unless I am misunderstanding, you mean to have each line in the int file corresponding to each "line" of the file itself?

Then I think you're overcomplicating things a bit there, although I do understand where you're coming from, given that the new line has a special meaning in an int file as well, but instead you could have a single key in the entire int file with the full contents of the file, but base64 encoded, or having the new lines and carriage returns escaped at most (I don't remember if the .int format allows for new lines to be escaped in some way).
Here, yes, that decode function you have shown would make sense to use there, as long as you don't intend to work with binary data.
User avatar
PrinceOfFunky
Godlike
Posts: 1204
Joined: Mon Aug 31, 2015 10:31 pm

Re: You can create and write a file using Unreal

Post by PrinceOfFunky »

BeginPlay set the timer to 30 and the Timer logs players info, so if you don't want your file to include the players info every 30 seconds, you should disable Timer() or overwrite BeginPlay().