SRL Archive - General Botting Help

WriteINI/ReadINI TStringArray?


Flight

2014-04-15 23:47:02

I've a quick question: Is it currently possible to read & write a TStringArray? If nothing else I can just write & read multiple lines in a text document then merge them into an array but that's kinda sloppy, so if anyone has any better suggestions do tell. Please and thank you.

Brandon

2014-04-16 00:38:34

Either NULL terminate each string or double NULL terminate each string.. This technique is used in basic C serialization if binary isn't allowed.. You could use the NULL terminator as a delimiter. It isn't visible to the naked eye but can be viewed using a hex editor. This also makes it easy to read and allows the string to contain any characters.. Further optimisation can be done by storing the size of the array in the first chunk. This way, you only resize/setlength the read array once..


Demo:

Procedure WriteINIArray(const Section, KeyName, FileName: String; const StrArr: TStringArray);
var
I: Integer;
Str: String;
begin
For I := 0 To High(StrArr) Do
Str := Str + StrArr[I] + #0;

WriteINI(Section, KeyName, ToStr(Length(StrArr)) + #0 + Str, FileName);
end;

Function ReadINIArray(const Section, KeyName, FileName: String): TStringArray;
var
Str: String;
I, J, K, Size: Integer;
Begin
J := 0;
I := 1;
Str := ReadINI(Section, KeyName, FileName);
While (Str[Inc(I)] <> #0) Do;

Size := StrToIntDef(Copy(Str, 0, I), -1);
If (Size > 0) Then
Begin
SetLength(Result, Size); //Optimisation..

For Inc(I) To Length(Str)
If (Str[I] <> #0) Then
Result[J] := Result[J] + Str[I]
Else
Inc(J);
End;
End;

var
Arr: TStringArray;
begin
Arr := ['one', 'two', 'three', 'four', 'five'];
WriteINIArray('Sector', 'Key', 'C:/Users/Brandon/Desktop/Test.INI', Arr);

writeln(ReadINIArray('Sector', 'Key', 'C:/Users/Brandon/Desktop/Test.INI'));
end.


Results:


[one, two, three, four, five]
Successfully executed.

CynicRus

2014-04-16 02:43:08

From: Flight
I've a quick question: Is it currently possible to read & write a TStringArray? If nothing else I can just write & read multiple lines in a text document then merge them into an array but that's kinda sloppy, so if anyone has any better suggestions do tell. Please and thank you.


Also you can use this method:

Save:

procedure WriteToFile3;
var
FileStream1: TFileStream;
arrayString: Array of String;
Len1, c: Cardinal;
begin
SetLength(arrayString, 4);
arrayString[0] := 'First string in this Array';
arrayString[1] := 'the Second Array string';
arrayString[2] := 'String number three of this Array';
arrayString[3] := 'this is the fourth String';

FileStream1.init('D:\arraystr.msf',
$FF00 or $0001 or $0020);

try
c := Length(arrayString);
FileStream1.WriteBuffer(c, SizeOf(c));
FOR c := 0 to High(arrayString) do
begin
Len1 := Length(arrayString[c]);
FileStream1.WriteBuffer(Len1, SizeOf(Len1));
if Len1 > 0 then
FileStream1.WriteBuffer(arrayString[c][1], Len1);
end;
finally
FileStream1.Free;
end;
end;

Load:

procedure ReadFromFile3;
var
FileStream1: TFileStream;
arrayString: Array of String;
Len1, c: Cardinal;

begin
FileStream1.Init('D:\arraystr.msf',
$0000 or $0020);
try
FileStream1.ReadBuffer(Len1, SizeOf(Len1));
if (Len1 = 0) or (Len1 > 1000) then Exit;
SetLength(arrayString, Len1);
FOR c := 0 to Len1-1 do
begin
FileStream1.ReadBuffer(Len1, SizeOf(Len1));
if Len1 > 2048 then Exit;
SetLength(arrayString[c], Len1);
FileStream1.ReadBuffer(arrayString[c][1], Len1);
end;
finally
FileStream1.Free;;
end;
WriteLn(arrayString[0]);
WriteLn(arrayString[High(arrayString)]);
end;

And you can read more about the file reading/writing here:)

Flight

2014-04-16 03:22:17

Thanks a million Brandon. I'll give that a shot, even though most of what you said makes no sense to me, haha.

Thank you for that as well CynicRus, I'll definitely take a look at it.

Brandon

2014-04-16 06:58:11

@CynicRus; +1 for binary serialisation. Had no clue you could do that in Simba without doing it manually. @Op, you should use that.

Flight

2014-04-16 07:13:19

From: Brandon
@CynicRus; +1 for binary serialisation. Had no clue you could do that in Simba without doing it manually. @Op, you should use that.


I would be happy to but what I like about the default Read/WriteINI is the Section & KeyName. I'd like the same simplicity but instead of a single string assigned to KeyName I'd like to write & read an array; exactly what you posted before.

CynicRus, would would be the advantages of using your method over Brandon's example posted above?

CynicRus

2014-04-16 07:30:57

Well, you just take your array and save it in binary stream. Instead TFileStream, you can use TSringStream or TMemoryStream. Or you can create your own file format. Using binary delimiters.

CynicRus

2014-04-16 15:35:27

Example of idea:

http://villavu.com/forum/showthread.php?t=108702

Brandon

2014-04-16 16:14:16

@Flight; I'm not sure there is a "advantage" in Simba itself but if you are interfacing with another language or plan on communicating with another API, then binary serialization IS beneficial.


For example, in that link Cynic linked above, you could easily just write the Bitmap string to the file and when reading it back, you do BitmapFromString.. However, instead of doing that, he chose to write every pixel to the file in binary format. Advantage there is that someone else can just read the pixels from any language/api and be able to use the image too without having to write Simba's internal algorithm for interpreting bitmap strings.. If you can guarantee that this information isn't used by anything other than your script and no other programs, then there is little advantage to binary serialisation.

That is the advantage. Simba-wise, there isn't "much" but there is a little bit. One such advantage is that reading is simply the opposite of writing.

If you noticed in my example, writing is way easier than reading. Writing is a couple lines long but reading requires a bit extra work. With binary serialisation, the way you write is the exact same way you read. It's also good for POD structures (Plain Old Datatypes)..


Write one byte, read one byte. Write one int, read one int, etc.. - Binary Serialisation.

Write a one byte, delimit, write another, delimit. Write one int, delimit, write another.
Read until each delimiter is reached, reinterpret that data as the correct type, rinse and repeat. - Plain Serialisation.

Binary can be smaller in terms of bytes and is native. Example: 0xFF is 255 in binary. It takes up 1 byte. 255 in plain-text is 3 bytes aka 3 digits. Binary require more knowledge of language and bytes and structure.

That is the differences. Whether it is an advantage in Simba is highly debatable because there isn't any interfacing or outside communication going on.

Just choose whichever suits your needs.. There isn't really a right or wrong.

http://stackoverflow.com/questions/2364581/binary-vs-text-protocols

Flight

2014-04-16 21:26:40

Thanks very much for your input and explanation Brandon. Actually the task I'm doing is quite simple, just reading & writing strings (and string arrays) to & from a text file . So I imagine the examples you first posted would work just fine.

rj

2014-04-16 23:00:56

I guess im a little late to the party but what I did with my SS fighter was save a tstringarray of uptext like so

['ave^rawl^raw']

I replace that '' with ^

And convert it back to a string array like

function string.toStringArray():TStringArray;
var
strArr:TStringArray;
strArrPtr: ^String;
i, len:integer;
begin
self := Replace(self, ']', '', [rfReplaceAll]);
self := Replace(self, '[', '', [rfReplaceAll]);
strArr := explode('^', self);
len := length(strArr);
setLength(result, len);
strArrPtr := @strArr[0];
for i := 0 to (len - 1) do
result[i] := strArrPtr[i]^;
end;


Above is probably better what w/e thought id throw my 2 cents in

Flight

2014-04-16 23:25:00

From: Robert
I guess im a little late to the party but what I did with my SS fighter was save a tstringarray of uptext like so

['ave^rawl^raw']

I replace that '' with ^


Yep I thought about doing something similar, saving a single string to a file, separating strings by certain character and parsing it Simba-side; nothing wrong with that. Thanks for the suggestion, Robert.