You are not logged in.
Pages: 1
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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:
1 | 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | :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 str 1 7@ str 2 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.
1 2 | 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
The case formatting option is set to "As is", isn't it?
Offline
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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 8B4C 2404 // mov ecx, [esp+0x04] 51 // push ecx 8B4C 2408 // mov ecx, [esp+0x08] ? 51 // push ecx 8B4C240C // mov ecx, [esp+0x0C] ? 51 // push ecx 9AAD 208200 // call 0x8220AD - 9A is the right one for a direct address? // get return? C 3 // 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
1 | 9AAD 208200 // call 0x8220AD - 9A is the right one for a direct address? |
The immediate value in this instruction is relative, not absolute. Use this code:
1 2 | mov eax, 0x8220AD call eax |
Offline
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
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:
1 | 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
Yes, I know how the sub works, but what is the logic behind this...
1 2 3 4 5 | A1D 5865300 // mov eax, [0x005386D5] // Offset 0x008220ED 05D 9865300 // add eax, 0x005386D9 // FFD 0 // call eax 81C4A 8000000 // add esp, 0x000000A8h C 3 // 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
The logic is the different address of sscanf in 1.0us and 1.0eu, I think.
1 2 3 4 5 | mov eax, [0x005386D5] ; 1.0us: 'eax = 0x2E99D4' , 1.0eu: 'eax = 0x2E9A14' add eax, 0x005386D 9 ; 'eax += 0x5386D9' call eax ; 1.0us: 'call 0x8220AD' , 1.0eu: 'call 0x8220ED' add esp, 0x000000A8h ret |
Offline
Pages: 1