G'day All,

I am trying to use the Expat XML parser from within my ASM Win32
application.

I have built a library "lib" file as per Iczelion's "How toCreate your
own MASM Import Libraries" instructions. I can load the library and call
some expat functions without error:



invoke XML_ParserCreate, 0
...
invoke XML_SetElementHandler, hXMLParser, funStart, funEnd
...


However when I call "XML_Parse", the program crashes:


invoke XML_Parse, hXMLParser, buff, 21, 0 ; BANG


So I tried to load the "libexpat.dll" dynamically, with much the
same result:


.data
...
; Dynamically load the DLL
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MyDLLName db "libexpat.dll",0
XMLParse db "XML_Parse",0
XMLParserCreate db "XML_ParserCreate",0
XMLSetElementHandler db "XML_SetElementHandler",0
...
hMyDLL dd ?
addrParse dd ?
addrParserCreate dd ?
addrSetElementHandler dd ?
...

; Expat XML processing callback functions
fStart db 'funStart',0
fEnd db 'funEnd',0

buff db '<action> id </action>',0

.code

start:
...

; Dynamically load the DLL
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
invoke LoadLibrary, OFFSET MyDLLName
mov [hMyDLL], eax

; XML_ParserCreate
invoke GetProcAddress, [hMyDLL], offset XMLParserCreate
.if(eax == NULL)
invoke Beep, 1000, 100
.endif
mov [addrParserCreate], eax
; p = XML_ParserCreate(NULL);
push NULL ; dword1
call [addrParserCreate]
mov hXMLParser, eax

; XML_SetElementHandler
invoke GetProcAddress, [hMyDLL], offset XMLSetElementHandler
.if(eax == NULL)
invoke Beep, 1000, 100
.endif
mov [addrSetElementHandler], eax
; XML_SetElementHandler(p, start, end);
push offset fEnd ; dword3
push offset fStart ; dword2
push [hXMLParser] ; dword1
call [addrSetElementHandler]

; XML_Parse [CRASH]
invoke GetProcAddress, [hMyDLL], offset XMLParse
.if(eax == NULL)
invoke Beep, 1000, 100
.endif
mov [addrParse], eax
; XML_Parse(XML_Parser p, const char *s, int len, int isFinal)
push 0 ; dword4
push 21 ; dword3
push offset buff ; dword2
push [hXMLParser] ; dword1
call [addrParse] ; BANG



Does anyone know what I have done wrong, and why the XMLParse function
crashes my application. I have also tried the LibXML XML C parser with
no luck :(


Links:
Expat XML Parser http://www.libexpat.org
LibXML XML C parser http://www.xmlsoft.org/

Also:
I am fairly new to ASM amd Win32 programming


Thanks

Dorf
Posted on 2004-08-30 00:36:52 by dorf
Try:

invoke XML_Parse, hXMLParser, addr buff, sizeof buff, 0


- if you don't use addr/sizeof, masm will pass the first element (byte) of buff, expat will treat that as a pointer, and *boom*. Also, it's bad to use hardcoded magic values (ie: 21), especially when masm has 'sizeof' :-)
Posted on 2004-08-30 01:10:45 by f0dder
G'day f0dder,

Thanks for the quick response

That helped. The app still crashes however.


The parser now calls my start function and pops a message box
with the opening tag "<action>". :)

But it crashes before calling the end function :(




; start(void *data, const char *el, const char **attr)
funStart proc data:DWORD, el:DWORD, attr:DWORD
;invoke Beep, 1000, 100 ; Bell
invoke MessageBox, NULL, el, NULL, MB_OK
ret
funStart endp

; end(void *data, const char *el) {
funEnd proc data:DWORD, el:DWORD
invoke Beep, 100, 100 ; Bell
ret
funEnd endp


Thanks for your help
Dorf
Posted on 2004-08-30 02:01:02 by dorf
If you're doing a typical masm file, you have ".model flat,stdcall" somewhere - this sets the default calling convention for all further PROCs to stdcall. I assume EXPAT is written in C, and that it doesn't have "__stdcall" or similar qualifiers for it's callbacks.

So, try adding a 'C' to your callback procs - like


funStart proc C data:DWORD, el:DWORD, attr:DWORD
;invoke Beep, 1000, 100 ; Bell
invoke MessageBox, NULL, el, NULL, MB_OK
ret
funStart endp

; end(void *data, const char *el) {
funEnd proc C data:DWORD, el:DWORD
invoke Beep, 100, 100 ; Bell
ret
funEnd endp
Posted on 2004-08-30 02:04:49 by f0dder
G'day f0dder,

Yep ... that seems to have done the trick :)

Just for the record, I had to now define the start/end function
prototypes as:



funStart proto C :DWORD, :DWORD, :DWORD
funEnd proto C :DWORD, :DWORD


Now I can start testing the expat parser :-D

Thank you very much

I think Win32Asm is very cool

Thanks again
Dorf
Posted on 2004-08-30 02:36:01 by dorf
G'day All,

Next problem ...
Does anyone know how to access a pointer-to-a-pointer (const char **attr") in MASM.

The Expat XML parser - in C


/* Read an XML document from standard input and print an element */
/* outline on standard output. */
void start(void *data, const char *el, const char **attr) {
int i;
...
printf("%s", el);

for (i = 0; attr[i]; i += 2) {
printf(" %s='%s'", attr[i], attr[i + 1]);
}
...
}


To the Expat XML parser - in RadASM/MASM


funStart proc C data:DWORD, el:DWORD, attr:DWORD

invoke SaveIndent
invoke lstrcat, addr strBuff, el
invoke lstrcat, addr strBuff, addr szNewLine

inc level
invoke SaveIndent

; Handle the element attributes
; *** HOW TO DEREFERENCE A POINTER TO A POINTER ("const char **attr")***
invoke lstrcat, addr strBuff, attr
invoke lstrcat, addr strBuff, addr szNewLine
;inc level

ret
funStart endp


Thanks

Dorf
Posted on 2004-08-30 21:22:04 by dorf
Looking at the C code attr seems to be a pointer to an array of pointers to strings so you could try for example this code which should mimic the "for" loop given. I haven't tested this though :)
;Loop through attrs

mov ecx,attr ; ecx point to attr array
cmp [ecx],0 ; test ecx for NULL
jz endLoop
startLoop:
mov eax,[ecx] ; eax points to string

; ... do something here ...

; move ecx onto next string and recheck for NULL
add ecx,4
cmp [ecx],0
jnz startLoop
endLooop:

Basically if a memory variable is a pointer to a point then the following will get you to the "thing"
mov eax,attr	; eax is pointer to pointer

mov eax,[eax] ; eax is pointer
mov eax,[eax] ; eax is the "thing"

For strings though you wont need the last mov cause you'll be dealing with their pointers anyway.
Posted on 2004-08-31 08:59:22 by Eóin
G'day E?in,

That helped a lot :)

I'm having some trouble with the loop ... detecting null
attributes, but it basically works.

I'll post my little demo of parsing an XML file into
a Treeview control in a day or so.

Thanks

Dorf
Posted on 2004-09-01 03:03:24 by dorf
Just thinking it might be important to also check ecx for NULL ie
;Loop through attrs

mov ecx,attr ; ecx point to attr array
cmp ecx,0 ; <-- check if attr is null
jz endLoop
cmp [ecx],0 ; test ecx for NULL
jz endLoop
startLoop:
Posted on 2004-09-01 03:28:28 by Eóin
You can make use of jecxz if the displacement is less than 127 bytes.
Posted on 2004-09-01 07:08:57 by roticv
G'day All,

Here is my little demo of using the Expat XML parser in an
RadASM/MASM project.

This application parses an XML file into a Treeview control.
See the included "Readme.txt" for a more detailed description.

I've also included a project to create the import library
for the Expat XML parser C library.

Issues:
After reading the XML file into a string buffer, I cannot get
the actual length of the XML contents (with sizeof buff).
If I pass this buffer to Expat, it complains about malformed
document, or something.

As a workaround I get the size of the XML file:
invoke GetFileSizeFile, fileName
and pass this return value (eax) to Expat.
invoke XML_Parse, hXMLParser, addr buff, eax, 0
and Expat seems happy with this.

Someone that knows what they're doing may be able to figure this
out ... perhaps!


Use this at your own risk - I am fairly new to ASM/Win32 :)

Thanks for the help

ASM/Win32 rocks.

dorf
Posted on 2004-09-04 00:39:30 by dorf

After reading the XML file into a string buffer, I cannot get
the actual length of the XML contents (with sizeof buff).


Sizeof works at assemble-time - it returns the size the assembler has reserved for the data object. The assembler has no notion of "the size of the contents", you'll need some runtime code for that. In case of an ASCII text file, you could use a strlen routine, or - as you're doing right now - simply the filesize.
Posted on 2004-09-04 00:55:03 by f0dder
dorf:

  Hello, I could not find the demo you mentioned. Will you please check the link?

  Thank you.
Posted on 2006-01-17 02:57:13 by seasea
The link got zapped when the board got hacked some time back, I think.

The Expat XML parser demo is here, also a couple of other Masm32 examples:

http://www.phpmvc.net/asm/

Download -  83,888 Bytes
http://www.phpmvc.net/asm/expat-xml-parser-test.zip

Regards
dorf
Posted on 2006-01-17 15:19:11 by dorf