I have a 60 byte Data stream as follows
let myDataStream = Data(bytes: [24, 163, 209, 194, 255, 1, 184, 230, 37, 208, 140, 201, 6, 0, 64, 0, 7, 98, 108, 117, ...])
Byte #1 (index 0) represents represent the length of the first object, so in this case the first object is comprised of the first 24 objects including byte #1
I have tried numerous methods but I have been unable to figure out
How to extract the first 24 bytes into a new Data object
How to remove the first 24 bytes from myDataStream once #1 has been accomplished. As byte #25 will again have size of next object
The closest I have come to solving #1 is
let streamLength = Int(myDataStream[0])
let newStream = Data(bytes: myDataStream[0...streamLength])
but I get an error stating cannot invoke initializer for Data with Data.subsequence
You can utilize a combination of the subdata and removeSubRange methods to achieve your desired results.
subData(in:) is an instance method on a Data struct.
removeSubRange() is also an instance method on a Data struct.
You can read more about these methods here: https://developer.apple.com/reference/foundation/data
Example Method:
func extract(from data: inout Data) -> Data? {
guard data.count > 0 else {
return nil
}
// Define the length of data to return
let length = Int.init(data[0])
// Create a range based on the length of data to return
let range = Range(0..<length)
// Get a new copy of data
let subData = data.subdata(in: range)
// Mutate data
data.removeSubrange(range)
// Return the new copy of data
return subData
}
Usage:
// Data (27 bytes)
var data = Data(bytes: [24, 163, 209, 194, 255, 1, 184, 230, 37, 208, 140, 201, 6, 0, 64, 0, 7, 98, 108, 117, 42, 63, 78, 200, 3, 34, 36])
// First extraction
let first = extract(from: &data)
print(first!) // Prints 24 bytes
print(data) // Prints 3 bytes
// Second extraction
let second = extract(from: &data)
print(second!) // Prints 3 bytes
print(data) // Prints 0 bytes
// Third extraction
let third = extract(from: &data)
print(third ?? "No Data") // Prints "No Data"
Making an Extension
You could also wrap the extract method above in an extension of Data as follows:
extension Data {
mutating func extract() -> Data? {
guard self.count > 0 else {
return nil
}
// Define the length of data to return
let length = Int.init(self[0])
// Create a range based on the length of data to return
let range = Range(0..<length)
// Get a new copy of data
let subData = self.subdata(in: range)
// Mutate data
self.removeSubrange(range)
// Return the new copy of data
return subData
}
}
Then you could you use the method like this:
// Data (27 bytes)
var data = Data(bytes: [24, 163, 209, 194, 255, 1, 184, 230, 37, 208, 140, 201, 6, 0, 64, 0, 7, 98, 108, 117, 42, 63, 78, 200, 3, 34, 36])
// First extraction
let first = data.extract()
print(first!) // Prints 24 bytes
print(data) // Prints 3 bytes
// Second extraction
let second = data.extract()
print(second!) // Prints 3 bytes
print(data) // Prints 0 bytes
// Third extraction
let third = data.extract()
print(third ?? "No Data") // Prints "No Data"
Data has dedicated functions to handle subdata:
let streamLength = Int(myDataStream[0])
let newStream = myDataStream.subdata(in: 1..<streamLength + 1)
let nextStream = myDataStream.subdata(in: streamLength + 1..<myDataStream.count)
You're probably looking for InputStream.
import Foundation
let data = Data(bytes: [24, 163, 209, 194, 255, 1, 184, 230, 37, 208, 140, 201, 6, 0, 64, 0, 7, 98, 108, 117])
let dataStream = InputStream(data: data)
dataStream.open()
let numBytesPerObject = 2
var buffer = [UInt8](repeating: 0, count: numBytesPerObject)
while dataStream.read(&buffer, maxLength: numBytesPerObject) != 0 {
print(buffer)
}
Related
Based on this question, I have a list of bytes in Dart:
final data = [123, 34, 106, 115, 111, 110, 114, 112, 99, 34, 58, 34, 50, 46, 48, 34, 44, 34, 109, 101, 116, 104, 111, 100, 34, 58, 34, 115];
It represents a Float32 value from TensorFlow Lite. How do convert that to a readable double value?
Your data contains 28 bytes, and since it represents 32-bit float values (each of which are 4 bytes), that's equivalent to seven 32-bit values.
final data = [
123, 34, 106, 115, // 1
111, 110, 114, 112, // 2
99, 34, 58, 34, // 3
50, 46, 48, 34, // 4
44, 34, 109, 101, // 5
116, 104, 111, 100, // 6
34, 58, 34, 115, // 7
];
The ByteData class from the dart:typed_data library gives you different views on byte data. What you want is the Float32 view, which will give you a double in Dart.
final bytes = Uint8List.fromList(data);
final byteData = ByteData.sublistView(bytes);
double value = byteData.getFloat32(0);
print(value); // 8.433111377393183e+35
The 0 in getFloat32(0) means that you want to get the 32-bit float value starting at index 0 in the byte array. That only gives you the first value of the seven, though, so if you want the rest you need to loop though the entire byte list:
for (var i = 0; i < data.length; i += 4) {
print(byteData.getFloat32(i));
}
On every loop you increase the index by 4 to get the beginning of the next 32-bit float value. Run that loop and you'll see the results for all seven values:
8.433111377393183e+35
7.3795778785962275e+28
2.9925614505443553e+21
1.0139077133430874e-8
2.308231080230816e-12
7.366162972792583e+31
2.522593777484324e-18
See also
Working with bytes in Dart
connecting TCP Socket server and sending Request. and also Server sends the response in Byte array. How to read byte array data in dart.
Socket.connect('localhost', 8081)
.then((socket) {
//Establish the onData, and onDone callbacks
socket.listen((data) {
print(new String.fromCharCodes(data).trim()); //Here data is byte[]
//How to read byte array data
},
onDone: () {
print("Done");
// socket.destroy();
},
onError: (e) {
print('Server error: $e');
});
socket.add([255, 12, 0, 11, 0, 9, 34, 82, 69, 70, 84, 65, 72, 73, 76]);
});
}
It depends on with data type was encoded to bytes. Let's suppose it's String
Then you can do it with dart:convert library.
import 'dart:convert' show utf8;
final decoded = utf8.decode(data);
It's pretty clear that there's a message structure in those bytes. You give two examples of messages:
[255, 12, 0, 11, 0, 9, 34, 82, 69, 70, 84, 65, 72, 73, 76]
and
[255, 20, 0, 11, 0, 0, 0, 15, 80, 82, 69, 77, 84, 65, 72, 73, 76, 45, 53, 53, 57, 55, 48]
Both start with 255, followed by what looks like two or three little endian 16 bit words (12 and 11) and (20, 11 and 0) followed by a string, who's length is encoded in a leading byte. If you are expected to inter-operate with another system, you really need the protocol spec.
Assuming I've guessed the structure correctly, this code
main() {
Uint8List input = Uint8List.fromList([
255,
20,
0,
11,
0,
0,
0,
15,
80,
82,
69,
77,
84,
65,
72,
73,
76,
45,
53,
53,
57,
55,
48
]);
ByteData bd = input.buffer.asByteData();
print(bd.getUint16(1, Endian.little)); // print the first short
print(bd.getUint16(3, Endian.little)); // and the second
print(bd.getUint16(5, Endian.little)); // and the third
int stringLength = input[7]; // get the length of the string
print(utf8.decode(input.sublist(8, 8 + stringLength))); // decode the string
}
produces
20
11
0
PREMTAHIL-55970
as expected
I am trying to use
UnsafeMutablePointer<UnsafeMutablePointer<Float>?>!
as it is required for a parameter for a method i need to use. Yet I have no idea what this is or how to use it.
I created this value by doing this :
var bytes2: [Float] = [39, 77, 111, 111, 102, 33, 39, 0]
let uint8Pointer2 = UnsafeMutablePointer<Float>.allocate(capacity: 8)
uint8Pointer2.initialize(from: &bytes2, count: 8)
var bytes: [Float] = [391, 771, 1111, 1111, 1012, 331, 319, 10]
var uint8Pointer = UnsafeMutablePointer<Float>?.init(uint8Pointer2)
uint8Pointer?.initialize(from: &bytes, count: 8)
let uint8Pointer1 = UnsafeMutablePointer<UnsafeMutablePointer<Float>?>!.init(&uint8Pointer)
uint8Pointer1?.initialize(from: &uint8Pointer, count: 8)
But I get the error :
Thread 1: Fatal error: UnsafeMutablePointer.initialize overlapping range
What am I doing wrong?
You are creating bad behaviour..
var bytes2: [Float] = [39, 77, 111, 111, 102, 33, 39, 0]
let uint8Pointer2 = UnsafeMutablePointer<Float>.allocate(capacity: 8)
uint8Pointer2.initialize(from: &bytes2, count: 8)
Creates a pointer to some memory and initializes that memory to the values stored in bytes2..
So: uint8Pointer2 = [39, 77, 111, 111, 102, 33, 39, 0]
Then you decided to create a pointer that references that pointer's memory:
var uint8Pointer = UnsafeMutablePointer<Float>?.init(uint8Pointer2)
So if you printed uint8Pointer, it would have the EXACT same values as uint8Pointer2.. If you decided to change any of its values as well, it'd also change the values of uint8Pointer2..
So when you do:
var bytes: [Float] = [391, 771, 1111, 1111, 1012, 331, 319, 10]
uint8Pointer?.initialize(from: &bytes, count: 8)
It overwrote the values of uint8Pointer2 with [391, 771, 1111, 1111, 1012, 331, 319, 10]..
So far, uint8Pointer is just a shallow copy of uint8Pointer2.. Changing one affects the other..
Now you decided to do:
let uint8Pointer1 = UnsafeMutablePointer<UnsafeMutablePointer<Float>?>!.init(&uint8Pointer)
uint8Pointer1?.initialize(from: &uint8Pointer, count: 8)
Here you created a pointer (uint8Pointer1) to uint8Pointer and you said uint8Pointer1 initialize with uint8Pointer.. but you're initializing a pointer with a pointer to itself and a count of 8..
First of all, don't bother calling initialize on a pointer to pointer with a value of itself.. It's already pointing to the correct values..
What's nice is that:
uint8Pointer1?.initialize(from: &uint8Pointer, count: 1)
//Same as: memcpy(uint8Pointer1, &uint8Pointer, sizeof(uint8Pointer)`
//However, they both point to the same memory address..
will crash, but:
uint8Pointer1?.initialize(from: &uint8Pointer)
//Same as: `uint8Pointer1 = uint8Pointer`.. Note: Just a re-assignment.
won't.. because it doesn't do a memcpy for the latter.. whereas the former does.
Hopefully I explained it correctly..
P.S. Name your variables properly!
Translation for the C++ people:
//Initial pointer to array..
float bytes2[] = {39, 77, 111, 111, 102, 33, 39, 0};
float* uint8Pointer2 = &bytes[2];
memcpy(uint8Pointer2, &bytes2[0], bytes2.size() * sizeof(float));
//Shallow/Shadowing Pointer...
float* uint8Pointer = uint8Pointer2;
float bytes[] = {391, 771, 1111, 1111, 1012, 331, 319, 10};
memcpy(uint8Pointer, &bytes[0], bytes.size() * sizeof(float));
//Pointer to pointer..
float** uint8Pointer1 = &uint8Pointer;
//Bad.. uint8Pointer1 and &uint8Pointer is the same damn thing (same memory address)..
//See the line above (float** uint8Pointer1 = &uint8Pointer)..
memcpy(uint8Pointer1, &uint8Pointer, 8 * sizeof(uint8Pointer));
//The memcpy is unnecessary because it already pointers to the same location.. plus it's also wrong lol.
How to convert signed array of [Int8] to unsigned array of [UInt8].
let arryData: [Int8] = [-108, 11, -107, -14, 35, -57, -116, 118, 54, 91, 12, 67, 21, 29, -44, 111]
I just want to convert this above into array of Unsigned [UInt8]. How to achieve this in swift.? Thanks in advance.
If your intention is to convert signed 8-bit integers to
unsigned ones with the same bit representation (e.g. -1 -> 255):
let intArray: [Int8] = [0, 1, 2, 127, -1, -2, -128]
let uintArray = intArray.map { UInt8(bitPattern: $0) }
print(uintArray)
// [0, 1, 2, 127, 255, 254, 128]
[Int8] -> [UInt8]
You haven't specified how you want to treat negative values; by flipping them to their positive counterpart or by removing them. Below follows both cases.
Transforming negative values to positive ones by flipping sign:
let arrayData: [Int8] = [-108, 11, -107, -14, 35, -57, -116, 118, 54, 91, 12, 67, 21, 29, -44, 111]
let arrayDataUnsigned = arrayData.map { UInt8(abs($0)) }
/* [108, 11, 107, 14, 35, 57, 116, 118, 54, 91,
12, 67, 21, 29, 44, 111] */
Or, by removing the negative values:
let arrayDataUnsigned = arrayData.flatMap { $0 < 0 ? nil : UInt8($0) }
/* [11, 35, 118, 54, 91, 12, 67, 21, 29, 111] */
I'm trying to work out an example which is provided on developer.apple.com website 'Swift Playground'. I had to adapt it a little since swift 2 is, what looks like, different in handling 'inout' variables. In the example showed on the presentation 'inout' was not used in the function declaration. Anyway the result of 'data' is not showing in the Playground although the code doesn't show any compile errors.
import UIKit
var data = [16, 97, 13, 55, 95, 53, 18, 10, 79, 53, 79, 34, 50, 34, 0, 91, 94, 55, 6, 38, 7]
func exchange<T>(inout data:[T], i: Int, j: Int) {
let temp = data[i]
data[i] = data[j]
data[j] = temp
}
func swapLeft<T: Comparable>(inout data: [T], index: Int) {
for i in reverse(1...index) {
if data[i] < data[i-1] {
exchange(&data, i, i-1)
}else {
break
}
}
}
func isort<T: Comparable>(inout data: [T]) {
for i in 1...data.count {
swapLeft(&data,i)
}
}
data //result [16, 97, 13, 55, 95, 53, 18, 10, 79, 53, 79, 34, 50, 34, 0, 91, 94, 55, 6, 38, 7]
isort(&data)
data //no result shown
Screenshot
It isn't showing a result because it is crashing with Array index out of range. Try this for isort:
func isort<T: Comparable>(inout data: [T]) {
for i in 1..<data.count {
swapLeft(&data,i)
}
}
You can always use println(data)
Make sure your Debug Area is shown. See this post for more info.