0
votes

I am trying to write pointers to c method as such:

//c signature:
typedef void (*startDocumentSAXFunc) (void *ctx);

//Swift2 working code 
let startDocument: @convention(c) (UnsafeMutablePointer<Void>) -> Void  = { (ctx) -> Void in
    NSLog("Start Document")

}
  • I can't find what type to use for xmlChar**
    //c signature
    typedef void (*startElementSAXFunc) (void *ctx,
                const xmlChar *name,
                const xmlChar **atts);

    //Swift2 code
    let startElement: @convention(c) (UnsafeMutablePointer, UnsafePointer, ???) -> Void  = { (ctx, name, attributes) -> Void in
        NSLog("Start Element \(name), \(attributes)")
    }
  • I can't find what type to use for const char*
    //c signature
    typedef void (XMLCDECL *errorSAXFunc) (void *ctx,
                const char *msg, ...);

    //Swift2
     let error: @convention(c) (UnsafeMutablePointer, ???) -> Void =
    { (ctx, msg) -> Void in
        NSLog("Error \(msg)")
    }

I tried the type UnsafePointer<CChar> but it is not working.

The aim here is to be able to use the libXML which is quicker than NSXML lib.

Thanks for your help !

2
C does not support methods, only functions - too honest for this site
My advice is to wrap libXML in an Objective-C wrapper. Use the Objective-C wrapper in Swift. - Jeffery Thomas

2 Answers

1
votes

The C function type

void (*startElementSAXFunc) (void *ctx,
            const xmlChar *name,
            const xmlChar **atts);

maps to Swift as

(UnsafeMutablePointer<Void>, UnsafePointer<xmlChar>, UnsafeMutablePointer<UnsafePointer<xmlChar>>) -> Void

so a valid startElementSAXFunc is

func onStartElement(ctx: UnsafeMutablePointer<Void>,
    name: UnsafePointer<xmlChar>,
    atts: UnsafeMutablePointer<UnsafePointer<xmlChar>>) {

    // ... 
}

and that can be assigned to the handler without any cast:

var handler = xmlSAXHandler()
handler.initialized = XML_SAX2_MAGIC
// ...
handler.startElement = onStartElement

Now xmlChar is a type alias for unsigned char which is UInt8 in Swift, and different from CChar aka Int8, therefore an additional cast is necessary if you convert the passed characters to a Swift string in onStartElement:

    let sName = String.fromCString(UnsafePointer(name))!
    print("start element, name = ", sName)

atts is a pointer to an array of character pointers, and you can traverse that array quite similar as you would in C:

    if atts != nil {
        var ptr = atts
        while ptr[0] != nil && ptr[1] != nil {
            let key = String.fromCString(UnsafePointer(ptr[0]))!
            let value = String.fromCString(UnsafePointer(ptr[1]))!
            print("attr:", key, "=", value)
            ptr += 2
        }
    }

In a similar fashion, you can implement the endElementSAXFunc and charactersSAXFunc.


With the errorSAXFunc however, there is a big problem: that function uses a variable argument list and therefore cannot be implemented in Swift, so you are out of luck here.

The following compiles and seems to run:

let onError : @convention(c) (UnsafeMutablePointer<Void>, UnsafePointer<xmlChar>)->Void = {
        (ctx, msg) in

        let sMsg = String.fromCString(UnsafePointer(msg))!
        print("error:", sMsg)
}

handler.error = unsafeBitCast(onError, errorSAXFunc.self)

but that is – to the best of my knowledge – undefined behaviour. It is also not helpful because you will get the error format string only (which was just %s in my test case).

0
votes

check this 'self explanatory' example

let str = "A"
var c = str.utf8.map { (c) -> CChar in
    return CChar(c)
}[0]
print(c, c.dynamicType)  // 65 Int8

var p = UnsafeMutablePointer<CChar>.alloc(1)
print(p.memory, p.memory.dynamicType) // 0 Int8
p.memory = 65

func modify(pp: UnsafeMutablePointer<UnsafeMutablePointer<CChar>>)->Void {
    print(pp.memory.memory, pp.memory.memory.dynamicType)
}

let pp = withUnsafeMutablePointer(&p){ $0 }
print(pp, pp.dynamicType) // 0x0000000119bbf750 UnsafeMutablePointer<UnsafeMutablePointer<Int8>>

modify(pp) // 65 Int8

...

p.dealloc(1)
modify(pp) // -107 Int8
// -107 is some 'random' value, becase the memory there was dealocated!!

UnsafePoiner<CChar> is const char * while UndafeMutablePointer<CChar> is char * etc ...