Deserialize BinaryData and mapping to an object - ios

I have a small project where I have a list with questions (96 questions).
I try to serialize that list of questions into a BinaryData and to save that result in CoreData.
After I want to deserialize that BinaryData from CoreData and to map the values to an object.
The problem is that my serialization I think is working, but the deserialization is not working for some reason.
This line of code is not called when I run the code and I don't know why:
https://github.com/tygruletz/AddTagsForRows/blob/master/PreloadQuestions/Controller/Communication/TTable.swift#L457
To generate a report in CoreData just click Next-> Next-> Finish.
Here is the code for deserialization:
func deStreamBin(stream: InputStream, format: EStreamFormat){
var protocolByte: UInt8 = 0
var columns: UInt16 = 0
var rows: UInt32 = 0
var tableFlag: ETableFlags
//We should scroll through 0's until we find '1' indicating the start of a table
while protocolByte != 0x01 {
protocolByte = deserializeByte(stream: stream)
}
// Header
_ = deserializeUInt32(stream: stream)
columns = deserializeUInt16(stream: stream)
rows = deserializeUInt32(stream: stream)
print("Number of rows in TTable: \(rows)")
tableFlag = ETableFlags(rawValue: UInt(deserializeUInt16(stream: stream))) ?? ETableFlags.none // 0x0001 = Exception, 0x002 = Interrupt
_ = deserializeByte(stream: stream) // Flags (0x01 = Meta, 0x02 = Last Row, 0x00 = The rest)
// Read the Meta Details
var tMeta: [TMeta] = []
for _ in 0..<columns {
guard let type = EMeta(rawValue: deserializeString(stream: stream, length: 1)) else {return}
var name = ""
if format == EStreamFormat.bin1 {
let nameLength = Int(deserializeByte(stream: stream))
name = deserializeString(stream: stream, length: nameLength)
}
else{
// No names for the bin2
}
tMeta.append(TMeta(type: type, name: name))
}
self.tMeta = tMeta
self.flags = tableFlag
for _ in 0..<rows {
let row: TRow = TRow(tMeta: tMeta)
_ = deserializeUInt32(stream: stream) // Row Number
_ = deserializeByte(stream: stream) // Flags (0x01 = Meta, 0x02 = Last Row, 0x00 = The rest)
for i in 0..<tMeta.count {
let m: TMeta = tMeta[i]
switch m.type {
// Integer (Int32)
case EMeta.i:
row.cell[i] = TCell(i: Int(deserializeInt32(stream: stream)))
// Boolean
case EMeta.b:
row.cell[i] = TCell(b: deserializeBoolean(stream: stream))
// String (length as UInt32, followed by array of chars)
case EMeta.s:
let nLenString = Int(deserializeUInt32(stream: stream))
row.cell[i] = TCell(s: deserializeString(stream: stream, length: nLenString))
// DateTime (BCD Array: YY YY MM DD hh mm ss)
case EMeta.t:
row.cell[i] = TCell(date: deserializeDateTime(stream: stream) ?? Date())
// Database Bytes (Length as Int32, followed by array of bytes)
case EMeta.z:
let nLenBytes = Int(deserializeUInt32(stream: stream))
row.cell[i] = TCell(data: deserializeByteArray(stream: stream, lenght: Int32(nLenBytes)))
// Double (IEEE 8-byte double)
case EMeta.d:
row.cell[i] = TCell(d: deserializeDouble(stream: stream))
// Single Byte
case EMeta.u:
row.cell[i] = TCell(b: deserializeByte(stream: stream))
}
}
do {
try add(row: row)
} catch{
print("deStreamBin: Can't add the row in tMeta: \(error)")
}
}
}
Please help me to deserialize my BinaryData to be able to map the values to an object.
Thanks in advance !

Related

Transform ASN. 1 signature to IEEE P1363 signature

I did generate a signature using the below code but, I want a signature in IEEE P1336 (length 80) format
guard let signData = SecKeyCreateSignature(
key,
SecKeyAlgorithm.ecdsaSignatureMessageX962SHA256,
signatureString.data(using: .utf8)! as CFData, &error) else {
let e = error!.takeRetainedValue() as Error
print("Signing Error \( e.localizedDescription)")
return nil
}
let signedData = signData as Data
let signedString = signedData.base64EncodedString(options: [])
I am not an expert in iOS. But I fixed this issue for a signature generated by iOS. You can create this format by your own. e.g. for SHA-256 hashed signature. JavaScript sample
function parseASN1ToIEEEP1363(signature) {
const buffer = new ArrayBuffer(signature.length);
const int8View = new Int8Array(buffer);
for (let i = 0, strLen = signature.length; i < strLen; i++) {
int8View[i] = signature.charCodeAt(i);
}
//Currently these bytes getting for SHA256. for other hashings need to make it dynamic
const r = new Int8Array(buffer.slice(4, 36));
const s = new Int8Array(buffer.slice(39));
return appendBuffer(r, s);
}
function appendBuffer(buffer1, buffer2) {
var tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength);
tmp.set(new Uint8Array(buffer1), 0);
tmp.set(new Uint8Array(buffer2), buffer1.byteLength);
return tmp;
};

Integers Larger than Int64

I'm attempting to get a user input number and find the sum of all the digits. I'm having issues with larger numbers, however, as they won't register under an Int64. Any idea as to what structures I could use to store the value? (I tried UInt64 and that didn't work very well with negatives, however, I'd prefer something larger than UInt64, anyways. I'm having a hard time implementing a UInt128 from Is there a number type with bigger capacity than u_long/UInt64 in Swift?)
import Foundation
func getInteger() -> Int64 {
var value:Int64 = 0
while true {
//we aren't doing anything with input, so we make it a constant
let input = readLine()
//ensure its not nil
if let unwrappedInput = input {
if let unwrappedInt = Int64(unwrappedInput) {
value = unwrappedInt
break
}
}
else { print("You entered a nil. Try again:") }
}
return value
}
print("Please enter an integer")
// Gets user input
var input = getInteger()
var arr = [Int] ()
var sum = 0
var negative = false
// If input is less than 0, makes it positive
if input < 0 {
input = (input * -1)
negative = true
}
if (input < 10) && (input >= 1) && (negative == true) {
var remain = (-1)*(input%10)
arr.append(Int(remain))
input = (input/10)
}
else {
var remain = (input%10)
arr.append(Int(remain))
input = (input/10)
}
}
// Adds numbers in array to find sum of digits
var i:Int = 0
var size:Int = (arr.count - 1)
while i<=size {
sum = sum + arr[i]
i = (i+1)
}
// Prints sum
print("\(sum)")
You can use a string to perform the operation you describe. Loop through each character and convert it to an integer and add to the sum. Be careful to handle errors.

Extract data from kCBAdvDataManufacturerData on Swift

I have a TI sensor Tag as a peripheral that broadcasts BLE data in the form of kCBAdvDataManufacturerData. I would like to extract different values from this data in iOS.
I am executing the following in Swift:
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber){
for (index, foundPeripheral) in peripherals.enumerated(){
if foundPeripheral.peripheral?.identifier == peripheral.identifier{
peripherals[index].lastRSSI = RSSI
print("AdvertisementData:\(advertisementData)")
return
}
}
let isConnectable = advertisementData["kCBAdvDataIsConnectable"] as! Bool
let displayPeripheral = DisplayPeripheral(peripheral: peripheral, lastRSSI: RSSI, isConnectable: isConnectable)
peripherals.append(displayPeripheral)
tableView.reloadData()
}
}
And this is what I see in the console:
AdvertisementData:["kCBAdvDataIsConnectable": 0, "kCBAdvDataManufacturerData": <0d00fe05 0c6f32>, "kCBAdvDataLocalName": CLIMBC]
The data that I am interested in decoding is kCBAdvDataManufacturerData : <0d00fe05 0c6f32> and displaying each field on the screen.
Specifically, this is what the numbers represent in my case:
0d00 - TI manufacturer ID
fe - the node ID that I have given
05 - state of the node (something that remains constant
c6f - is the sensor tag battery voltage
32- is the BLE packet counter.
In Android I am able to decode as following:
private static String getNodeIdFromRawPacket(byte[] manufSpecField) {
if(manufSpecField != null && manufSpecField.length > 1) {
return String.format("%02X", manufSpecField[0]);
}else{
return null;
}
}
private static int getNodeBatteryVoltageFromRawPacket(byte[] manufSpecField){
if(manufSpecField != null && manufSpecField.length > 4) {
return (((((int) manufSpecField[manufSpecField.length - 3]) << 24) >>> 24) << 8) + ((((int) manufSpecField[manufSpecField.length - 2]) << 24) >>> 24);
}else{
return 0;
}
}
private byte[] extractManufacturerSpecificData(byte[] scanRecord, int manufacturer_id){
if(scanRecord != null) {
int ptr = 0;
while (ptr < scanRecord.length && scanRecord[ptr] != 0) {
int field_length = scanRecord[ptr];
if (scanRecord[ptr + 1] == (byte) (0xFF)) { //this is true when the manufacturer specific data field has been found
if (((scanRecord[ptr + 3] << 8) + scanRecord[ptr + 2]) == manufacturer_id) {
byte[] manufacturerSpecificData = new byte[field_length - 3];
System.arraycopy(scanRecord, ptr + 4, manufacturerSpecificData, 0, field_length - 3);
return manufacturerSpecificData;
}
}
ptr += (field_length + 1);
}
return null;
}else{
return null;
}
}
};
How exactly can I achieve this? I am new to Swift that is why I am finding some difficulties. Any code snippet will be most welcome.
Seeing the output of your console, advertisementData["kCBAdvDataManufacturerData"] seems to be an NSData containing 7 bytes. You can easily access it as a Swift Data, and each byte in a Data can be accessed with subscript:
if let manufacturerData = advertisementData["kCBAdvDataManufacturerData"] as? Data {
assert(manufacturerData.count >= 7)
//0d00 - TI manufacturer ID
//Constructing 2-byte data as little endian (as TI's manufacturer ID is 000D)
let manufactureID = UInt16(manufacturerData[0]) + UInt16(manufacturerData[1]) << 8
print(String(format: "%04X", manufactureID)) //->000D
//fe - the node ID that I have given
let nodeID = manufacturerData[2]
print(String(format: "%02X", nodeID)) //->FE
//05 - state of the node (something that remains constant
let state = manufacturerData[3]
print(String(format: "%02X", state)) //->05
//c6f - is the sensor tag battery voltage
//Constructing 2-byte data as big endian (as shown in the Java code)
let batteryVoltage = UInt16(manufacturerData[4]) << 8 + UInt16(manufacturerData[5])
print(String(format: "%04X", batteryVoltage)) //->0C6F
//32- is the BLE packet counter.
let packetCounter = manufacturerData[6]
print(String(format: "%02X", packetCounter)) //->32
}
Here is an implementation of swift 3 Data method subdata with an example of a string converted to data and then split out to bytes that you can convert back to strings:
let input = "505450578"
let data = input.data(using: .utf8)
let manufacturerId:Range<Int> = 0..<2
let nodeId:Range<Int> = 2..<4
let nodeState:Range<Int> = 4..<5
let voltage:Range<Int> = 5..<6
let packetCounter:Range<Int> = 6..<9
let subdata1 = data?.subdata(in: manufacturerId)
let subdata2 = data?.subdata(in: nodeId)
let subdata3 = data?.subdata(in: nodeState)
let subdata4 = data?.subdata(in: voltage)
let subdata5 = data?.subdata(in: packetCounter)
//Results from original given string
let str1 = String(data: subdata1!, encoding:.utf8) //50
let str2 = String(data: subdata2!, encoding:.utf8) //54
let str3 = String(data: subdata3!, encoding:.utf8) //5
let str4 = String(data: subdata4!, encoding:.utf8) //0
let str5 = String(data: subdata5!, encoding:.utf8) //578
Updated for Swift:
let yourServiceUUIDString = "FFF0"
if let mAdvData = advertisementData["kCBAdvDataServiceUUIDs"] as? [AnyObject], (mAdvData.contains { ($0 as? CBUUID)?.uuidString == yourServiceUUIDString}) {
print("BLE device found..!")
}

ExtAudioFile into a float buffer produces zeros

I have this code in Swift 3 and my output is 0.0 zeros most of the time and rarely I see very small numbers to the e^-50
The fileURL is a recording.caf with sound in it.
Does anyone know what's up?
func readBuff(_ fileURL:CFURL) {
var fileRef:ExtAudioFileRef? = nil
let openStatus = ExtAudioFileOpenURL(fileURL , &fileRef)
guard openStatus == noErr else {
print("Failed to open audio file '\(fileURL)' with error \(openStatus)")
return
}
var audioFormat2 = AudioStreamBasicDescription()
audioFormat2.mSampleRate = 44100; // GIVE YOUR SAMPLING RATE
audioFormat2.mFormatID = kAudioFormatLinearPCM;
audioFormat2.mFormatFlags = kLinearPCMFormatFlagIsFloat;
audioFormat2.mBitsPerChannel = UInt32(MemoryLayout<Float32>.size) * 8
audioFormat2.mChannelsPerFrame = 1; // Mono
audioFormat2.mBytesPerFrame = audioFormat2.mChannelsPerFrame * UInt32(MemoryLayout<Float32>.size); // == sizeof(Float32)
audioFormat2.mFramesPerPacket = 1;
audioFormat2.mBytesPerPacket = audioFormat2.mFramesPerPacket * audioFormat2.mBytesPerFrame; // = sizeof(Float32)
//apply audioFormat2 to the extended audio file
ExtAudioFileSetProperty(fileRef!, kExtAudioFileProperty_ClientDataFormat,UInt32(MemoryLayout<AudioStreamBasicDescription>.size),&audioFormat2)
let numSamples = 1024 //How many samples to read in at a startTime
let sizePerPacket:UInt32 = audioFormat2.mBytesPerPacket // sizeof(Float32) = 32 byts
let packetsPerBuffer:UInt32 = UInt32(numSamples)
let outputBufferSize:UInt32 = packetsPerBuffer * sizePerPacket //4096
//so the 1 value of outputbuffer is a the memory location where we have reserved space
let outputbuffer = UnsafeMutablePointer<UInt8>.allocate(capacity: MemoryLayout<UInt8>.size * Int(outputBufferSize))
var convertedData = AudioBufferList()
convertedData.mNumberBuffers = 1 //set this for Mono
convertedData.mBuffers.mNumberChannels = audioFormat2.mChannelsPerFrame // also = 1
convertedData.mBuffers.mDataByteSize = outputBufferSize
convertedData.mBuffers.mData = UnsafeMutableRawPointer(outputbuffer)
var frameCount:UInt32 = UInt32(numSamples)
while (frameCount > 0) {
Utility.check(ExtAudioFileRead(fileRef!,
&frameCount,
&convertedData),
operation: "Couldn't read from input file")
if frameCount == 0 {
Swift.print("done reading from file")
return
}
var arrayFloats:[Float] = []
let ptr = convertedData.mBuffers.mData?.assumingMemoryBound(to: Float.self)
var j = 0
var floatDataArray:[Double] = [882000]// SPECIFY YOUR DATA LIMIT MINE WAS 882000 , SHOULD BE EQUAL TO OR MORE THAN DATA LIMIT
if(frameCount > 0){
var audioBuffer:AudioBuffer = convertedData.mBuffers
let floatArr = UnsafeBufferPointer(start: audioBuffer.mData?.assumingMemoryBound(to: Float.self), count: 882000)
for i in 0...1024{
//floatDataArray[j] = Double(floatArr[i]) //put your data into float array
// print("\(floatDataArray[j])")
floatDataArray.append(Double(floatArr[i]))
print(Float((ptr?[i])!))
j += 1
}
// print(floatDataArray)
}
}
}
I'm reading from
guard let fileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, "./output.caf" as CFString!, .cfurlposixPathStyle, false) else {
// unable to create file
exit(-1)
}
steps after recording:
Swift.print("Recording, press <return> to stop:\n")
// wait for a key to be pressed
getchar()
// end recording
Swift.print("* recording done *\n")
recorder.running = false
// stop the Queue
Utility.check(AudioQueueStop(queue!, true),
operation: "AudioQueueStop failed")
// a codec may update its magic cookie at the end of an encoding session
// so reapply it to the file now
Utility.applyEncoderCookie(fromQueue: queue!, toFile: recorder.recordFile!)
// cleanup
AudioQueueDispose(queue!, true)
AudioFileClose(recorder.recordFile!)
readBuff(fileURL)
You're setting up your ExtAudioFile and its client format, but you're not actually reading from it (with ExtAudioFileRead), so your "output" is actually uninitialised, and in your case, very small.

Parse CSV file in swift

I am parsing data from csv file to dictionary with the help of github.
After parsing I am getting this type of dictionary :-
{
"" = "";
"\"barred_date\"" = "\"\"";
"\"company_id\"" = "\"1\"";
"\"company_name\"" = "\"\"";
"\"contact_no\"" = "\"1234567890\"";
"\"created_date\"" = "\"2015-06-01 12:43:11\"";
"\"current_project\"" = "\"111\"";
"\"designation\"" = "\"Developer\"";
"\"doj\"" = "\"2015-06-01 00:00:00\"";
"\"fin_no\"" = "\"ABC001\"";
"\"first_name\"" = "\"sssd\"";
"\"last_name\"" = "\"dd\"";
"\"project_name\"" = "\"Project 1\"";
"\"qr_code\"" = "\"12345678\"";
"\"resignation_date\"" = "\"\"";
"\"status\"" = "\"1\"";
"\"work_permit_no\"" = "\"ssdda11\"";
"\"worker_id\"" = "\"1\"";
"\"worker_image\"" = "\"assets/uploads/workers/eb49364ca5c5d22f11db2e3c84ebfce6.jpeg\"";
"\"worker_image_thumb\"" = "\"assets/uploads/workers/thumbs/eb49364ca5c5d22f11db2e3c84ebfce6.jpeg\"";}
How can I convert this to simple dictionary. I need data like this "company_id" = "1"
Thanks
I recommend using CSVImporter – it takes care of things like quoted text (following RFC 4180) for you and even handles very large files without problems.
Compared to other solutions it works both asynchronously (prevents delays) and reads your CSV file line by line instead of loading the entire String into memory (prevents memory issues). On top of that it is easy to use and provides beautiful callbacks for indicating failure, progress, completion and even data mapping if you desire to.
You can use it like this to get an array of Strings per line:
let path = "path/to/your/CSV/file"
let importer = CSVImporter<[String]>(path: path)
importer.startImportingRecords { $0 }.onFinish { importedRecords in
for record in importedRecords {
// record is of type [String] and contains all data in a line
}
}
Take advantage of more sophisticated features like header structure support like this:
// given this CSV file content
firstName,lastName
Harry,Potter
Hermione,Granger
Ron,Weasley
// you can import data in Dictionary format
let path = "path/to/Hogwarts/students"
let importer = CSVImporter<[String: String]>(path: path)
importer.startImportingRecords(structure: { (headerValues) -> Void in
// use the header values CSVImporter has found if needed
print(headerValues) // => ["firstName", "lastName"]
}) { $0 }.onFinish { importedRecords in
for record in importedRecords {
// a record is now a Dictionary with the header values as keys
print(record) // => e.g. ["firstName": "Harry", "lastName": "Potter"]
print(record["firstName"]) // prints "Harry" on first, "Hermione" on second run
print(record["lastName"]) // prints "Potter" on first, "Granger" on second run
}
}
Use the CSwiftV parser instead: https://github.com/Daniel1of1/CSwiftV
It actually handles quoted text, and therefore it handles both line breaks and commas in text. SwiftCSV cost me some time in that it doesn't handle that. But I did learn about the CSV format and parsing it ;)
Parse CSV to two-dimension array of Strings (rows and columns)
func parseCsv(_ data: String) -> [[String]] {
// data: String = contents of a CSV file.
// Returns: [[String]] = two-dimension array [rows][columns].
// Data minimum two characters or fail.
if data.count < 2 {
return []
}
var a: [String] = [] // Array of columns.
var index: String.Index = data.startIndex
let maxIndex: String.Index = data.index(before: data.endIndex)
var q: Bool = false // "Are we in quotes?"
var result: [[String]] = []
var v: String = "" // Column value.
while index < data.endIndex {
if q { // In quotes.
if (data[index] == "\"") {
// Found quote; look ahead for another.
if index < maxIndex && data[data.index(after: index)] == "\"" {
// Found another quote means escaped.
// Increment and add to column value.
data.formIndex(after: &index)
v += String(data[index])
} else {
// Next character not a quote; last quote not escaped.
q = !q // Toggle "Are we in quotes?"
}
} else {
// Add character to column value.
v += String(data[index])
}
} else { // Not in quotes.
if data[index] == "\"" {
// Found quote.
q = !q // Toggle "Are we in quotes?"
} else if data[index] == "\r" || data[index] == "\r\n" {
// Reached end of line.
// Column and row complete.
a.append(v)
v = ""
result.append(a)
a = []
} else if data[index] == "," {
// Found comma; column complete.
a.append(v)
v = ""
} else {
// Add character to column value.
v += String(data[index])
}
}
if index == maxIndex {
// Reached end of data; flush.
if v.count > 0 || data[data.index(before: index)] == "," {
a.append(v)
}
if a.count > 0 {
result.append(a)
}
break
}
data.formIndex(after: &index) // Increment.
}
return result
}
Call above with the CSV data
let dataArray: [[String]] = parseCsv(yourStringOfCsvData)
Then extract the header row
let dataHeader = dataArray.removeFirst()
I assume you want an array of dictionaries (most spreadsheet data includes mulitple rows, not just one). The next loop is for that. But if you only need a single row (and header for keys) into a single dictionary, you can study below and get the idea of how to get there.
var da: [Dictionary<String, String>] = [] // Array of dictionaries.
for row in dataArray {
for (index, column) in row.enumerated() {
var d: Dictionary<String, String> = Dictionary()
d.updateValue(column, forKey: dataHeader[index])
da.append(d)
}
}

Resources