Swift: Turning a String into UnsafeMutablePointer<Int8> - c

I have a C function mapped to Swift defined as
predictX010(inputString: UnsafePointer<emxArray_char_T>!, ypred: UnsafeMutablePointer<emxArray_real_T>!)
I want to input a string in the inputString, but in order to do that I have to play around with emxArray_char_T which is
emxArray_char_T.init(data: UnsafeMutablePointer<Int8>!, size: UnsafeMutablePointer<Int32>!, allocatedSize: Int32, numDimensions: Int32, canFreeData: boolean_T)
My string will consist of let x = ":1580222503,GCP001,007,Male,30,Left,1,IL8 and IL10,0000; 0,281411,-78,521074,-3,344657,132,347776,-93,25,44" and I just cannot figure out how to input it in data of the emxArray_char_T

First you should write a wrapper function in your bridging header that accepts char pointers then cast/create the emxArray_char_T in c IE:
// casting the func as void because you didn't specify
void predictWrapper(const char *aChar, char *bChar) {
// do your casting and call original func predictX010(...)
}
Then in swift (This isn't going to be pretty)
var arg: String = "some arg"
var arg2: String = "another arg"
// use closure to prevent dangling pointer
arg.withCString{ body in // body is UnsafePointer<Int8>
arg2.withCString{ body2 in // we'll cast this to UnsafeMutablePointer
var arg2Mutable = UnsafeMutablePointer<Int8>(mutating: body2)
//call your wrapper
predictWrapper(body, arg2Mutable)
}
}
You may be able to use the original types and function, but i've always found it easier (less banging my head on the desk) to use the most standard c types you can in swift and casting to custom/complex types in c

Related

How do I pass a multiline string from Python to C using ctypes?

I have the following simple C function:
void pyentry(const char *config)
{
printf("%s\n",config);
fflush(stdout);
}
My ctypes definition is as follows:
libc = ct.CDLL("./amr.so")
entry = wrap_function(libc, 'pyentry', ct.POINTER(Checkpoint), [ct.c_wchar_p])
json = "this is a test"
start = entry(json)
Where wrap_function is simply a wrapper for more easily defining ctypes access to C functions:
def wrap_function(lib, funcname, restype, argtypes):
func = lib.__getattr__(funcname)
func.restype = restype
func.argtypes = argtypes
return func
I have compiled as a shared library and I am trying to call it, but in C it is only printing the first character of the string I send in. I am assuming this is because I have the wrong argument tpyes in my ctypes definition, but I am not having any luck figuring out out the right one.
Can someone tell me why my C function is only seeing the first character in the passed string?
Try:
entry = wrap_function(libc, 'pyentry', None, [ct.POINTER(ct.c_char)])
json = "this is a test".encode('utf-8')
pyentry takes const char* and returns void. So argtypes and restype could be [ct.POINTER(ct.c_char)] and None.
And char* points a sequence of bytes, not Python string. So json should be converted to bytes.

Why does the first character of my string get cut off when I pass from swift to C?

Here is the function in swift to convert from a swift string to a C string
func swiftStringToCString(swiftString: String) -> UnsafeMutablePointer<CString>?{
let convertedCString: [CChar]? = swiftString.cString(using: .utf8)
if let safeConvertedCString = convertedCString {
var cString = UnsafeMutablePointer<CString>.allocate(capacity: 1)
//defer {
// cString.deallocate()
//}
cString.pointee.count = UInt32(safeConvertedCString.count) - 1
cString.pointee.data = UnsafePointer<Int8>(safeConvertedCString)
return cString
}
else
{
return nil
}
}
The CString struct is defined in a C header file:
typedef struct {
const char *data;
uint32_t count;
} CString;
I also have an addition test function which simply prints out the string passed in:
extern void __cdecl testCString(CString *pCString);
When I call
testCString(swiftStringToCString(swiftString: "swiftString"))
This gets printed out:
wiftString
I also noticed that I get the warning
Initialization of 'UnsafePointer<Int8>' results in a dangling pointer
when I do
cString.pointee.data = UnsafePointer<Int8>(safeConvertedCString)
This approach is incorrect. You can't just hold onto pointers into a String's internal storage and expect it to stick around past the current line of code. That's what the warning is telling you.
In order to ensure that a pointer is valid, you need to use .withUnsafeBufferPointer. I would expect something along these lines:
"swiftString".utf8CString.withUnsafeBufferPointer { buffer in
var cString = CString(data: buffer.baseAddress!, count: UInt32(buffer.count))
testCString(&cString);
}
This ensures that the utf8 buffer exists until the end of the block. If you want to hold onto it beyond that, you're going to need to add code to copy those bytes into memory you allocate and release yourself.

Golang pointer receiver technicalities confusion

I recently started to learn Golang for a work project. I come from a 'c' background and have some confusion about the technicalities of Pointer Receivers in functions. Am I to assume receiver are generalized and don't care if the object is actually a pointer or a literal, it will translate it to whatever the receiver type is.
I know my question wording may be confusing so here is some code for example:
func (v *clients) makePtr() {
(*v).slice = make([]client, 0)
return
}
func (v clients) makeLit() []client {
return make([]client, 0)
}
func main() {
clsPtr := &clients{} // pointer
clsLit := clients{} // literal
clsLit.makePtr() // literal with pointer reciever
clsLit.makeLit() // literal with pointer reciever
clsPtr.makePtr() // pointer with literal reciever
clsPtr.makeLit() // pointer with pointer reciever
}
I expected the the functions with pointer receivers to only work on pointers and vice versa. from this am I just suppose to assume receivers are a blanket statement and don't care if its a pointer, literal?
EDIT:
Apologizes guys, I may not have been to clear with my question, I understand that a pointer receiver is used to modify a object but I'm more confused as to the syntax, why does a pointer receiver work for both a literal and a pointer, since it receives a pointer shouldn't it only work on a pointer?
The pointer receiver means if you mutate the object on the method it will change the underlying struct.
When you call it, it doesnt make a difference.
package main
import (
"fmt"
)
type data struct {
val int
}
func (d data) changeNonPersistent(newval int) {
d.val = newval
}
func (d *data) changePersistent(newval int) {
d.val = newval
}
func main() {
// initialize both ptr and val version to 5
dptr := &data{val: 5}
dval := data{val: 5}
fmt.Println(*dptr)
fmt.Println(dval)
// non persistent val change to 10
dptr.changeNonPersistent(10)
dval.changeNonPersistent(10)
fmt.Println("Non Persistent-")
fmt.Println(*dptr)
fmt.Println(dval)
// persistent val change to 15
dptr.changePersistent(15)
dval.changePersistent(15)
fmt.Println("Persistent-")
fmt.Println(*dptr)
fmt.Println(dval)
}
or see the code here https://play.golang.org/p/jwOUwsso3PZ
tl;dr; the object or reference does not make a difference, as long as the receiver is right.
And you usually only want to have pointer receiver if your goal is to mutate. Other wise just send a copy.
In golang these are called methods which are function with receiver.
The receiver argument can be passed by value or by pointer.
You can write functions like below which are plain functions.
type Client struct{}
//A pointer to Client
func makePtr(c *Client){
//do something with c
}
//A copy of client is made.
func makeLit(cs Client){
//do something with c
}
Instead if you write methods then it gives association with struct.
type Client struct{}
func (c *Client) makePtr(){
//do something with c
}
//A copy of client is made.
func (c Client)makeLit(){
//do something with c
}
The main purpose of methods I see in golang is for interface implementation
It is by virtue of methods structs implement (or satisfy) interfaces.

Modifying value char** from C callback in Swift and Avoiding EXC_BAD_ACCESS

I am working on a project that implements a C library using Swift. So far I have been able to manage how to get String from C strings and some others.
Now I am facing an issue when dealing with a C callback that returns OUT variables type char**. The swift code needs to reallocate memory and change the value. These variables are used for String type.
The Header for the C function is:
DllExport void STDCALL DvProviderGetProtocolInfo(THandle aProvider, CallbackGetProtocolInfo aCallback, void* aPtr);
And the header for the C Callback is:
typedef int32_t (STDCALL *CallbackGetProtocolInfo)(void* aPtr, IDvInvocationC* aInvocation, void* aInvocationPtr, char** aSource, char** aSink);
In swift I call the function like that:
DvProviderGetProtocolInfo(prvHandleId, { (pointer, aInvocation, aInvocationPtr, aSource, aSink) -> Int32 in
let senderClass:SenderClass = bridgeToTypeUnretained(ptr: pointer!)
senderClass.writeCStringValue(from: aSource, withValue: senderClass.sourceProtocolInfoArray)
senderClass.writeCStringValue(from: aSink, withValue: senderClass.sinkProtocolInfoArray)
return 0
}, bridgeToPointerRetained(obj: self))
The functions used are:
public func writeCStringValue(from pointer:UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>?, withValue value:String){
pointer!.pointee = UnsafeMutablePointer<Int8>.allocate(capacity:value.utf8.count)
strcpy(pointer!.pointee, value)
}
And declared in another Swift File:
/*** Convert const void* To Any T ***/
func bridgeToTypeRetained<T : AnyObject>(ptr : UnsafeMutableRawPointer) -> T {
return Unmanaged<T>.fromOpaque(ptr).takeRetainedValue()
}
func bridgeToTypeUnretained<T : AnyObject>(ptr : UnsafeRawPointer) -> T {
return Unmanaged<T>.fromOpaque(ptr).takeUnretainedValue()
}
/*** Convert const void* To Any T ***/
func bridgeToPointerRetained<T : AnyObject>(obj : T) -> UnsafeMutableRawPointer {
return UnsafeMutableRawPointer(Unmanaged.passRetained(obj).toOpaque())
}
func bridgeToPointerUnretained<T : AnyObject>(obj : T) -> UnsafeMutableRawPointer {
return UnsafeMutableRawPointer(Unmanaged.passUnretained(obj).toOpaque())
}
So far, for small values, writeCStringValue function works fine but when I try to send a long String like:
let aTest = "http-get:*:audio/m4a:*,http-get:*:audio/x-m4a:*,http-get:*:audio/aiff:*,http-get:*:audio/x-aiff:*,http-get:*:audio/mpeg:DLNA.ORG_PN=MP3,http-get:*:audio/mp4:*,http-get:*:audio/wav:*,http-get:*:audio/wave:*,http-get:*:audio/x-wav:*,http-get:*:video/mpeg:*,http-get:*:video/mp4:*,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_MED,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_LRG,http-get:*:image/png:DLNA.ORG_PN=PNG_TN,http-get:*:image/png:DLNA.ORG_PN=PNG_LRG"
I get a EXC_BAD_ACCESS at the end of writeCStringValue function.
If I include the code in writeCStringValue function inside the callback, then there is no crash.
Ideally i would like to use writeCStringValue function.
Am i changing the values of char** correctly?
Thank you
strcpy(pointer!.pointee, value)
creates a temporary C string representation of the Swift string value,
and copies that to the address given by pointer!.pointee.
C strings are delimited by a trailing null character and that is not
taken into account in the allocation
pointer!.pointee = UnsafeMutablePointer<Int8>.allocate(capacity:value.utf8.count)
Therefore strcpy() copies one char more than is allocated. That may or may
not cause a crash, but is undefined behavior in any case.
strdup() does both the allocation and the copy, so a simpler solution is
pointer?.pointee = strdup(value)
That may be better anyway, if the C function (eventually) releases the string with free().

Converting from Swift string to const char*

I'm trying to pass a const char * to an old C library converted from a Swift string in Swift.
This is the C function I'm calling:
artnet_node artnet_new(const char *ip, int verbose) { ...
how can I convert a Swift string to this const char type? It works when I pass ipAddress like this:
internal var ipAddress = "192.168.1.43"
but dit does not work when I pass it like this
internal var ipAddress:String = "192.168.1.43"
I need this in a function where I need to specify the type:
internal func setupArtnode(ip:String) -> Int{
I tried using AnyObject instead of String but that doesn't work either.
Thanks.
You should be able to pass a String directly to a C function expecting const char * and it will be automatically converted to a null-terminated UTF-8 string:
let string = "string"
let node = artnet_new(string, 1)
See Interacting with C APIs for more information. Here is the relevant excerpt:
When a function is declared as taking an UnsafePointer argument,
it can accept any of the following:
A String value, if Type is Int8 or UInt8. The string will automatically be converted to UTF8 in a buffer, and a pointer to that
buffer is passed to the function.
Not sure why but this code is working. This passes a string to a C function expecting a const char* which seems to be the same as a unsafePointer.
internal func setupArtnode(ipAddress:String) -> NSInteger{
let cString = self.ipAddress.cString(using: String.defaultCStringEncoding)!
let newString:String = NSString(bytes: cString, length: Int(ipAddress.characters.count), encoding:String.Encoding.ascii.rawValue)! as String
let key2Pointer = UnsafePointer<Int8>(newString)
node = artnet_new(key2Pointer, Int32(verbose)) // VERBOSE : true(1) , false(0)
...
Simple way for Swift 3
var ipAddress: String = "192.168.1.43"
var verbose: Int = 1
artnet_node artnet_new((ipAddress as NSString).utf8String, verbose)
You didn't specify what your Swift array contains. In any case, you need to convert your Swift array to an array of Int8:
let str = "Hello world"
let cArray = str.cString(using: .utf8)
artnet_new(cArray, 1)

Resources