a swift questions about String and c strcpy - ios

I want to call a c++ function in swift
bool getId3Info(const char * filename , char *artist , char * title )
{
// get the file's id3v2 tag, write info back
strcpy(artist,(const char*) id3v2tag->artist().toCString(true));
strcpy(title,id3v2tag->title().toCString(true));
}
So I write a object-c wrapper for this function:
-(bool) getId3Info:(const char * )filename :( const char *)artist :( const char *) title
{
return getId3Info(filename, (char*)artist, (char*)title);
}
So the questions is I can only get the representation of a C string using cStringUsingEncoding ,
can not get the true buffer of a swift String,
is there another way to do this?

In Swift, you can pass a const char* to a C function like this:
func foo(s: String) { s.withCString({ p in cfunction(p) }) }
or, to be more explicit about the type:
func foo(s: String) { s.withCString({ (p:UnsafePointer<CChar>) in cfunction(p) }) }
(i.e., p is a UnsafePointer<CChar>, equivalent to const char*)
If you want to initialize a string from a C function, you need a more complex incantation, something like this:
var buf = Array<CChar>(count: 1000, repeatedValue: 0);
let result = buf.withUnsafeMutableBufferPointer({
(inout ptr: UnsafeMutableBufferPointer<CChar>) -> String? in
cfunction(ptr.baseAddress, ptr.count - 1)
String.fromCString(ptr.baseAddress)
})
Note that the C function must leave the buffer null-terminated. Either it needs to never modify the last byte (thus the ptr.count - 1, like you would call strncpy) or it needs to add the null terminator itself (like snprintf), in which case you can pass in the full buffer size.

Related

Swift 3 - How to convert memory of Int32 as four characters

I want to convert an Int32 to a string consisting of four C-style, 1-byte wide characters (probably closely related to this but in Swift 3).
The use for this is that many API functions of Core Audio return an OSStatus (really an Int32), which can often be interpreted as string consisting of four C-style characters.
fun interpretAsString(possibleMsg: Int32) -> String {
// Blackbox
}
Actually a "four character code" is usually an unsigned 32-bit
value:
public typealias FourCharCode = UInt32
public typealias OSType = FourCharCode
The four bytes (from the MSB to the LSB) each define one character.
Here is a simple Swift 3 function to convert the integer to a string,
inspired by the various C/Objective-C/Swift 1+2 solutions in
iOS/C: Convert "integer" into four character string:
func fourCCToString(_ value: FourCharCode) -> String {
let utf16 = [
UInt16((value >> 24) & 0xFF),
UInt16((value >> 16) & 0xFF),
UInt16((value >> 8) & 0xFF),
UInt16((value & 0xFF)) ]
return String(utf16CodeUnits: utf16, count: 4)
}
Example:
print(fourCCToString(0x48454C4F)) // HELO
I have chosen an array with the UTF-16 code points as intermediate storage because that can directly be used to create a string.
If you really need it for a signed 32-bit integer then you can
call
fourCCToString(FourCharCode(bitPattern: i32value)
or define a similar function taking an Int32 parameter.
As Tim Vermeulen suggested below, the UTF-16 array can also be
created with map:
let utf16 = stride(from: 24, through: 0, by: -8).map {
UInt16((value >> $0) & 0xFF)
}
or
let utf16 = [24, 16, 8, 0].map { UInt16((value >> $0) & 0xFF) }
Unless the function is performance critical for your application,
pick what you feel most familiar with (otherwise measure and compare).
I don't test this code but try this:
func interpretAsString(possibleMsg: Int32) -> String {
var result = String()
result.append(Character(UnicodeScalar(UInt32(possibleMsg>>24))!))
result.append(Character(UnicodeScalar(UInt32((possibleMsg>>16) & UInt32(0xFF)))!))
result.append(Character(UnicodeScalar(UInt32((possibleMsg>>8) & UInt32(0xFF)))!))
result.append(Character(UnicodeScalar(UInt32((possibleMsg) & UInt32(0xFF)))!))
return result
}
This may be an old question, but since it was asking in the context of Core Audio, I just wanted to share a variant I was playing with.
For Core Audio, where some (but not all?) OSStatus/Int32 values are defined using four characters, some code from Apple's old Core Audio Utility Classes can provide inspiration (very similar to the linked question)
From CAXException.h:
class CAX4CCStringNoQuote {
public:
CAX4CCStringNoQuote(OSStatus error) {
// see if it appears to be a 4-char-code
UInt32 beErr = CFSwapInt32HostToBig(error);
char *str = mStr;
memcpy(str, &beErr, 4);
if (isprint(str[0]) && isprint(str[1]) && isprint(str[2]) && isprint(str[3])) {
str[4] = '\0';
} else if (error > -200000 && error < 200000)
// no, format it as an integer
snprintf(str, sizeof(mStr), "%d", (int)error);
else
snprintf(str, sizeof(mStr), "0x%x", (int)error);
}
const char *get() const { return mStr; }
operator const char *() const { return mStr; }
private:
char mStr[16];
};
In Swift 5, one rough translation (without the hex representation for large values) might be:
private func osStatusToString(_ value: OSStatus) -> String {
let data = withUnsafeBytes(of: value.bigEndian, { Data($0) })
// If all bytes are printable characters, we treat it like characters of a string
if data.allSatisfy({ 0x20 <= $0 && $0 <= 0x7e }) {
return String(data: data, encoding: .ascii)!
} else {
return String(value)
}
}
Note that the Data initializer is making a copy of the bytes, though it may be possible to avoid that if desired.
Of course, with Core Audio we encounter four character codes with both Int32 and UInt32 types. I haven't done generics with Swift before, but one way to handle them in a single function could be:
private func stringifyErrorCode<T: FixedWidthInteger>(_ value: T) -> String {
let data = withUnsafeBytes(of: value.bigEndian, { Data($0) })
// If all bytes are printable characters, we treat it like characters of a string
if data.allSatisfy({ 0x20 <= $0 && $0 <= 0x7e }) {
return String(data: data, encoding: .ascii)!
} else {
return String(value, radix: 10)
}
}
This may not be suitable for general purpose handling of four character codes (I've seen other answers that support characters in the MacOS Roman encoding versus ASCII in the example above. There's likely some history there I'm not aware of), but may be reasonable for Core Audio status/selector codes.

use fscanf() function in swift code

In objective c, I use fscanf to read stream from file and assign the value to variables:
int count;
char type[5];
fscanf(myFile, “count is %d, type is %4s ”, &count, type)
I want to do the same thing in swift code, I tried:
//ERROR: Type annotation missing in pattern
//What type should I use for `count`?
var count
//ERROR: consecutive statement on a line must be separated by ‘;’
var type[5] : char
fscanf(myFile, “count is %d, type is %4s ”, &count, type)
But I got compiler errors showing above. What is the correct way to use fscanf in swift ?
If you know any swift way to achieve the same thing (without using fscanf), it would be great too!
I recommend you use Foundation framework solution for reading/writing file data. A sample code to read contents of files which I used in my app to stream file into NSData:
if let fileHandle = NSFileHandle(forReadingAtPath: "path/to/file") {
fileHandle.seekToFileOffset(0)
var data = fileHandle.readDataOfLength(5)
var chars = [UInt8](count: 5, repeatedValue: 0)
data.getBytes(&chars, length: 5)
fileHandle.closeFile()
}
In case you need read Int64 data from file at a specific location:
if let fileHandle = NSFileHandle(forReadingAtPath: "path/to/file") {
fileHandle.seekToFileOffset(0)
var data = fileHandle.readDataOfLength(500)
var intFetched: Int64 = 0
let location = 100 // start at 101st character of file
data.getBytes(&intFetched, range: NSMakeRange(location, 8))
println(intFetched.littleEndian)
fileHandle.closeFile()
}

Swift/iOS: How to use address (reference, pointer) in swift?

Like what you can do with inout parameters, or like what you can do with * and & in C++. For example:
#include <iostream>
using namespace std;
int main ()
{
int firstvalue, secondvalue;
int * mypointer;
mypointer = &firstvalue;
*mypointer = 10;
mypointer = &secondvalue;
*mypointer = 20;
cout << "firstvalue is " << firstvalue << '\n';
cout << "secondvalue is " << secondvalue << '\n';
return 0;
}
and the result is:
firstvalue is 10
secondvalue is 20
Can I do something similar to this in Swift?
As a general rule, no. Swift, like most modern programming languages, does not give you direct access to pointers most of the time.
There are special pointer types you can use if you need them. https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithCAPIs.html. However, if you find yourself wanting to use these, except in special cases, I suspect that you are still thinking in C/Objective-C/C++ terms.
The inout parameter allows you to pass by reference not value.
Example:
func test1(inout a : Int) { a = 5 }
func test2(a : Int) { a = 5 }
Here the 1st function (because of the inout parameter) will modify whatever is passed in to it.
The second function will receive a copy of the variable so when you are done
var a = 4;
var b = 4;
test1(&a);
test2(b);
print(a);
print(b):
will print out
5
4
Because swift gives you full access to C stuff you can use the type unsafePointer and unsafeMutablePointer for doing funky stuff.
Check out this post for more details: http://chris.eidhof.nl/posts/swift-c-interop.html
When I want to manipulate individual bytes in a NSData type i do the following:
var rawData: NSMutableData
/* Using unsafeMutablePointers allows for raw data manipulation */
var ptr: UnsafeMutablePointer<UInt8>; // = UnsafePointer<UInt8>(rawData.bytes)
var bytes: UnsafeMutableBufferPointer<UInt8>; // = UnsafeBufferPointer<UInt8>
self.rawData = NSMutableData(data: initData)
ptr = UnsafeMutablePointer<UInt8>(rawData.mutableBytes)
bytes = UnsafeMutableBufferPointer<UInt8>(start: ptr, count: rawData.length)
Then i can access individual bytes with:
bytes[i]
this uses pointers.

strtoul() Function- Swift

I'm trying to create a swift iOS program that converts a number into dec, bin, and hex numbers. I've come across the strtoul function, but don't quite understand how to use it, would someone be able to explain it? Thanks!
The method strtoul is pretty simple to use. You will need also to use String(radix:()) to convert it to the other direction. You can create an extension to convert from hexaToDecimal or from binaryToDecimal as follow:
Usage String(radix:())
extension Int {
var toBinary: String {
return String(self, radix: 2)
}
var toHexa: String {
return String(self, radix: 16)
}
}
Usage strtoul()
extension String {
var hexaToDecimal: Int {
return Int(strtoul(self, nil, 16))
}
var hexaToBinary: String {
return hexaToDecimal.toBinary
}
var binaryToDecimal: Int {
return Int(strtoul(self, nil, 2))
}
var binaryToHexa: String {
return binaryToDecimal.toHexa
}
}
Testing
let myBinFromInt = 255.toBinary // "11111111"
let myhexaFromInt = 255.toHexa // "ff"
let myIntFromHexa = "ff".hexaToDecimal // 255
let myBinFromHexa = "ff".hexaToBinary // "11111111"
let myIntFromBin = "11111111".binaryToDecimal // 255
let myHexaFromBin = "11111111".binaryToHexa // "ff"
The strtoul() function converts the string in str to an unsigned long
value. The conversion is done according to the given base, which must be between 2 and 36 inclusive, or be the special value 0.
Really it sounds like you want to use NSString
From what it sounds like, you want to convert an unsigned integer to decimal, hex and binary.
For example, if you had an integer n:
var st = NSString(format:"%2X", n)
would convert the integer to hexadecimal and store it in the variable st.
//NSString(format:"%2X", 10) would give you 'A' as 10 is A in hex
//NSString(format:"%2X", 17) would give you 11 as 17 is 11 in hex
Binary:
var st = NSString(format:"%u", n)
Decimal (2 decimal places)
var st = NSString(format:"%.02f", n)

Using AudioBufferList with Swift

I have a bridging function in Swift, one of whose arguments in C is AudioBufferList *. In Swift this generates an UnsafePointer<AudioBufferList>. I've manage to deference the pointer by calling audioData[0] (is there a better way?). But I'm struggling with the next 2 tiers down: the .mBuffers array of AudioBuffer's and their void * / UnsafePointer<()> .mData members.
In C it would simply be
Float32 *audioData = (Float 32*)abl->mBuffers[0]->mData;
output = audioData[sampleNum]...
In Swift the first odd thing is that it won't let me access the elements of mBuffers but is perfectly happy when I access it as a property. In other words, this works and even has correct data (for the first member of mBuffers I presume)...
println(abl[0].mBuffers.mNumberChannels) // But .mBuffers should be an []!
Second, it let's me print out .mData subscripts but the value is always ()
println(abl[0].mBuffers.mData[10]) // Prints '()'
I've tried various casting ops and accessing with multiple indices but to no avail...any ideas?
Here are the C and Swift definitions for AudioBufferList and AudioBuffer for convenience...
// C
struct AudioBufferList
{
UInt32 mNumberBuffers;
AudioBuffer mBuffers[1]; // this is a variable length array of mNumberBuffers elements
// ...and a bit more for c++
}
struct AudioBuffer
{
UInt32 mNumberChannels;
UInt32 mDataByteSize;
void* mData;
};
...
// SWIFT
struct AudioBufferList {
var mNumberBuffers: UInt32
var mBuffers: (AudioBuffer)
}
struct AudioBuffer {
var mNumberChannels: UInt32
var mDataByteSize: UInt32
var mData: UnsafePointer<()>
}
I found this by accident. Oddly the type ahead was actually working with Swift when it suggested UnsafeMutableAudioBufferListPointer. Which you can initialize with an UnsafeMutablePointer argument. This type is a MutableCollectionType and provides subscript and generator access to the contained Audio Buffers.
For example you can set an ABL to silence with the following code
func renderCallback(ioData: UnsafeMutablePointer<AudioBufferList>) -> OSStatus {
let abl = UnsafeMutableAudioBufferListPointer(ioData)
for buffer in abl {
memset(buffer.mData, 0, Int(buffer.mDataByteSize))
}
return noErr
}
Edit: Adam Ritenauer's answer is probably the best one now. To expand on it, you can look at the new utility functions/types in the iOS 8.3 Core Audio changes.
UnsafeMutableAudioBufferListPointer can be used to read/access some given data:
struct UnsafeMutableAudioBufferListPointer {
init(_ p: UnsafeMutablePointer<AudioBufferList>)
var count: Int
subscript (index: Int) -> AudioBuffer { get nonmutating set }
}
And you can use the extensions on AudioBuffer & AudioBufferList to allocate your own:
extension AudioBufferList {
static func sizeInBytes(maximumBuffers maximumBuffers: Int) -> Int
static func allocate(maximumBuffers maximumBuffers: Int) -> UnsafeMutableAudioBufferListPointer
}
extension AudioBuffer {
init<Element>(_ typedBuffer: UnsafeMutableBufferPointer<Element>, numberOfChannels: Int)
}
Old answer:
This is a bit tricky because AudioBufferList is actually a variable-size struct. This means it's declared as having a single AudioBuffer, but really it has as many as specified by the mNumberBuffers member. This notion doesn't translate very well to Swift, which is why you see var mBuffers: (AudioBuffer).
So the canonical way to access these buffers, and their data, would be using UnsafeArray. The code below provides some ideas, but UnsafePointer and UnsafeArray aren't well documented, so this could be wrong.
// ***WARNING: UNTESTED CODE AHEAD***
let foo: UnsafePointer<AudioBufferList> // from elsewhere...
// This looks intuitive, but accessing `foo.memory` may be doing a copy.
let bufs = UnsafeArray<AudioBuffer>(start: &foo.memory.mBuffers, length: Int(foo.memory.mNumberBuffers))
// This is another alternative that should work...
let bufsStart = UnsafePointer<AudioBuffer>(UnsafePointer<UInt32>(foo) + 1) // Offset to mBuffers member
let bufs = UnsafeArray<AudioBuffer>(start: bufsStart, length: Int(foo.memory.mNumberBuffers))
// Hopefully this isn't doing a copy, but it shouldn't be too much of a problem anyway.
let buf: AudioBuffer = bufs[0] // or you could use a for loop over bufs, etc.
typealias MySample = Float32
let numSamples = Int(buf.mDataByteSize / UInt32(sizeof(MySample)))
let samples = UnsafeArray<MySample>(start: UnsafePointer<MySample>(buf.mData), length: numSamples)
// Now use the samples array...
This seems to work in the playground but it's hard for me to test on real audio data. In particular, I'm not 100% sure that using start: &foo.memory.mBuffers will work as expected. (It returns a different pointer from the original, although the data seem to be there.) Give it a shot and report back!
Edit: to debug this, by the way, you can for example:
(lldb) p foo
(UnsafePointer<AudioBufferList>) $R1 = (value = Builtin.RawPointer = 0x0000000100700740)
(lldb) expr -lc -- ((int*)0x0000000100700740)[0]
(int) $2 = 42
(lldb) expr -lc -- ((int*)0x0000000100700740)[1]
(int) $3 = 43
...
I've found this works OK. abl is an AudioBufferList created from loading a 16bit AIFF audio file.
let mBuffers=abl.memory.mBuffers
let data=UnsafePointer<Int16>(mBuffers.mData)
let dataArray=UnsafeBufferPointer<Int16>(start:data, count: Int(mBuffers.mDataByteSize)/sizeof(Int16))
//checking resulting array
let count=dataArray.count //this matches the expected number of samples in my case
for i in 0..<count
{
print(dataArray[i]) //values look OK in my case
print(" ")
}
This works for me with Swift 1.2
var ddata: NSData
buf = AudioBuffer(mNumberChannels: 1, mDataByteSize: numberOfFrames * UInt32(sizeof(Float32)), mData: &ddata)
var audioBuffers = AudioBufferList(mNumberBuffers: 1, mBuffers: buf!)

Resources