#1 25-10-2010 16:53

Deji
From: UK
Registered: 09-11-2008
Posts: 189
Website

Extracting data from a file

This seems to be an impossible task... I've tried just about everything to try and fix this, but nothing is working.

This is the code I have now, after long battles with previous code.

if
    0A9A: TEMP_1 = openfile "file.dat" mode "r"
then
    while 0AB1: call_scm_func @GetConfigLine 1 0@ TEMP_2
        0AC6: TEMP_3 = label @TempMemory offset
        0AD3: TEMP_3 = format "BF"
        if
            0AB1:   call_scm_func @strpos 2 TEMP_3 TEMP_2 TEMP_4
        then
            0ACE: show_formatted_text_box "True! %s %d" TEMP_2 TEMP_4
        else
            0ACE: show_formatted_text_box "False! %s %d" TEMP_2 TEMP_4
        end
        wait 1000
    end
end

I'm trying to get data from a file similar to the GTA .dat files. :GetConfigLine returns the first valid .dat line it finds (non-commented and not blank). The line is stored in a part of SA's memory which was made for storing .dat lines.


Now I have to get each value of a line like this:

10,BFOST,Street

CLEO 4's opcode doesn't fit here because the scan_file/scan_string opcodes can't return to pointers. I've tried using aDMA, but that didn't work either, I get a "cleo.asi" error report. Also, with it a format like "%s,%s" doesn't work. It returns all the way to the newline.

SA's function seesm to allow "%s%s" to get two strings, which could be split by a comma and any amount of whitespaces.


I tried to use the sscanf function in SA but no matter how I use it there is a crash (in function "strcpy" or "strlen" apparently). I've even got a d3d9.dll error with this.


Finally I decided to make a sscanf function from scratch, which requires the use of other functions. I added "strpos" as from PHP. It finds the first occurance of a char sequence within a string and returns how far into the string it is.


Simple task.. except that the "strcmp" (string compare) function in SA is failing me now... I've tried all of them, I think.

:strpos
0AA7: call_function FUNC_strlen num_params 1 pop 1 0@ 3@
0AA7: call_function FUNC_strlen num_params 1 pop 1 1@ 4@
if and
    8039:   not 3@ == 0
    8039:   not 4@ == 0
then
    000A: 3@ += 1
    000A: 4@ += 1
    0AC8: 7@ = allocate_memory_size 3@
    for 5@ = 0 to 4@
        0A8E: 6@ = 3@ + 5@
        if 001D:   6@ > 4@
        then break
        end
        0A8E: 8@ = 4@ + 1@
        0AD3: 7@ = format "%s" 8@
        0AA7: FUNC_strcmp 2 2 str1 7@ str2 0@ store_to 9@
        wait 5000
        if
            0039:   9@ == 0
            //0AD4: 9@ = scan_string "%*s" format 7@ 0@  // CLEO 4 probably doesn't support %* anyway.
            //0AD4: 9@ = scan_string 7@ format 0@          // hmm.. doesn't work without specifiers?
        then
            0ACE: show_formatted_text_box "True! %d" 5@
            0062: 5@ -= 2@
            0AC9: free_allocated_memory 7@
            0485: return_true
            0AB2: ret 1 5@
        end
    end
    0AC9: free_allocated_memory 7@
end
059A: return_false
0AB2: ret 1 0

Calling the stcmp function gives me a crash. I've also tested with strings and it still doesn't work.

File: ntdll.dll
Offset: 10E6

Maybe I need to pass an offset instead of an address? Offset from what?

So for some reason, any string related operation I try with SA's functions fail, except for the gtaStrlen one.


It'd be nice to be able to do it without creating my own C++ level function in SCM, but if that's not possible I guess it's the only option I have.

Offline

#2 25-10-2010 23:54

Seemann
Registered: 07-08-2006
Posts: 2,155

Re: Extracting data from a file

The case formatting option is set to "As is", isn't it?

Offline

#3 26-10-2010 01:40

Deji
From: UK
Registered: 09-11-2008
Posts: 189
Website

Re: Extracting data from a file

Yes. I think the problem with calling these string functions directly might be down to how the data is passed.

Perhaps ASM would work if the bytes were passed one-by-one... But I still have troubles when it comes to handling registers.

while 0AB1: call_scm_func @GetConfigLine 1 0@ 1@
    0AC6: 2@ = label @TempMemory offset
    0AD3: 2@ = format "%d %s %s"
    0AC6: 3@ = label @FUNC_sscanf offset
    0AA7: call_function 3@ num_params 2 pop 2 1@ 2@ 4@ 5@ 6@
    0ACE: show_formatted_text_box "%d %s %s" 4@ 5@ 6@
end

:FUNC_sscanf
8B4C2404        // mov ecx, [esp+0x04]
51              // push ecx
8B4C2408        // mov ecx, [esp+0x08] ?
51              // push ecx 
8B4C240C        // mov ecx, [esp+0x0C] ?
51              // push ecx
9AAD208200      // call 0x8220AD - 9A is the right one for a direct address?
// get return?
C3              // ret

I doubt this will even call right, since this is probably similar to what 0AA5 does... I think the bytes at the first address need to be read, and maybe the second.

Still, I don't understand the functions not working or why the opcode doesn't support aDMA.

Last edited by Deji (26-10-2010 01:49)

Offline

#4 27-10-2010 13:47

Alien
Registered: 12-10-2008
Posts: 564

Re: Extracting data from a file

9AAD208200      // call 0x8220AD - 9A is the right one for a direct address?

The immediate value in this instruction is relative, not absolute. Use this code:

mov eax, 0x8220AD
call eax

Offline

#5 27-10-2010 14:50

Deji
From: UK
Registered: 09-11-2008
Posts: 189
Website

Re: Extracting data from a file

Thanks. I actually found a caller for "sscanf" in Ryosukes Missile mod.

He uses mov, then add to some up to halves of the address... I assumed because mov used a signed integer, making 0x8220AD go in the wrong direction?

Offline

#6 27-10-2010 16:34

Alien
Registered: 12-10-2008
Posts: 564

Re: Extracting data from a file

I mean that the instruction 'call' doesn't send to the register eip immediate value, but increases its contents by this immediate value. Such approach allows to organize short (two-byte) passages (in case increment value lies between-0x8000 and 0x7FFF). Absolute transfer in eip is possible with instruction:

 call r/m32

The quote from intel's manual:

CALL /rel32: Call near, relative, displacement relative to next instruction.
CALL r/m32: Call near, absolute indirect, address given in r/m32.

PS: What you mean "mov used a signed integer"? Instruction 'mov' just moves some value to a receiver. Difference between 'signed and unsigned' appears only in arithmetic operations. This operations switches some flags. CF (carry flag) is responsible for unsigned jumps (ja, jb, jna, jnb, jae, jbe) and SF (sign flag) is responsible for signed jumps (jg, jl, jng, jnl,  jge, jle).

Last edited by Alien (27-10-2010 16:36)

Offline

#7 27-10-2010 16:40

Deji
From: UK
Registered: 09-11-2008
Posts: 189
Website

Re: Extracting data from a file

Yes, I know how the sub works, but what is the logic behind this...

A1D5865300      // mov eax, [0x005386D5]        // Offset 0x008220ED
05D9865300      // add eax, 0x005386D9          //
FFD0            // call eax
81C4A8000000    // add esp, 0x000000A8h
C3              // ret

From Ryosukes source. 0x5386D5 contains an offset from one function to the sscanf function, then the add operation increases that value to get the exact address.

Which is why I assumed the exact value could not be copied.

Offline

#8 27-10-2010 17:13

Alien
Registered: 12-10-2008
Posts: 564

Re: Extracting data from a file

The logic is the different address of sscanf in 1.0us and 1.0eu, I think.

mov eax, [0x005386D5] ; 1.0us: 'eax = 0x2E99D4',  1.0eu: 'eax = 0x2E9A14'
add eax, 0x005386D9 ; 'eax += 0x5386D9'
call eax ;  1.0us: 'call 0x8220AD',  1.0eu: 'call 0x8220ED'
add esp, 0x000000A8h
ret

Offline

Board footer

Powered by FluxBB