Serialize protocol buffer objects to a string in ObjectiveC - objective-c

I'm trying to serialize objects generated from protocol buffer for objective C.
I used the method:
[protocObj data]
to serialize data but it returns an NSData object which contains many zero bytes so when I try to convert it to string to send, it's not converted with it's full size.
Example:
NSData: <09000000 00000040 40110000 00000080 40401900 00000000 00414021 00000000 00804140 28013500 00a04038 2b407b>
string: "\t"
I understand that 00 is translated to \0 (string null termination) in UTF8.
So how to convert it properly ?

Related

Why the bitfield's least significant bit is promoted to MSb during typecasting in the below program?

Why do we get this value as output:- ffffffff
struct bitfield {
signed char bitflag:1;
};
int main()
{
unsigned char i = 1;
struct bitfield *var = (struct bitfield*)&i;
printf("\n %x \n", var->bitflag);
return 0;
}
I know that in a memory block of size equal to the data-type, the first bit is used to represent if it is positive(0) or negative(1); when interpreted as a signed data-type. But, still can't figure out why -1 (ffffffff) is printed. When the struct with only one bit set, I was expecting that when it gets promoted to a 1 byte char. Because, my machine is a little-endian and I was expecting that one bit in the field to be interpreted as the LSb in my 1 byte character.
Can somehow please explain. I'm really confused.

Unpack hex-encoded NSData

on peripheral:didReceiveWriteRequest a CBATTRequest returns hex-encoded NSData via request.value.
This is what I have tried
// Define struct
typedef struct __attribute__((packed)) {
UInt8 pktNo;
UInt8 ctrlCmd;
UInt8 txPowerRequest;
UInt16 uuid;
UInt16 userPayload; // how to store 15 octets?
} Packet;
// Unpack
Packet *packet = (Packet *)request.value.bytes;
if (packet) {
UInt8 pktNo = packet->pktNo;
UInt8 cmd = packet->ctrlCmd;
UInt8 tx = packet->txPowerRequest;
UInt16 uuid = packet->uuid;
UInt16 payload = packet->userPayload;
NSLog(#"pktNo: %hhu, cmd: %hhu, tx: %hhu, uuid: %hu, payload: %hu", pktNo, cmd, tx, uuid, payload);
}
Console
pktNo: 121, cmd: 202, tx: 130, uuid: 48321, payload: 21421
First, these numbers look inaccurate, and I'm uncertain about what format this is even in, since the following analogous values I got from debugging tool don't seem to match.
Default: raw strings?
packet Packet * 0x281af0cc0 0x0000000281af0cc0
pktNo UInt8 'y'
ctrlCmd UInt8 '\xca'
txPowerRequest UInt8 '\x82'
uuid UInt16 48321
userPayload UInt16 21421
The hex string representation of your NSData is apparently:
<79ca82c1 bcad530e 016a1435 127993ee 01ef7579>
That translates to:
The 0x79 is the PKT, 121 in decimal
The 0xca is the CMD, 202 in decimal
The 0x82 is the TXP, 130 in decimal
The 0xbcc1 is the UUID, 48321 in decimal
The PAYLOAD is ad 53 0e 01 6a 14 35 12 79 93 ee 01 ef 75 79
So, you can use:
typedef struct __attribute__((packed)) {
UInt8 pktNo;
UInt8 ctrlCmd;
UInt8 txPowerRequest;
UInt16 uuid;
UInt8 userPayload[15];
} Packet;
Which you can populate with:
Packet packet = {};
assert(data.length == sizeof(Packet));
memcpy(&packet, data.bytes, sizeof(Packet));
Note, I didn’t just set the packet to a pointer to the bytes of the NSData, because if the NSData is deallocated, you don’t want to use a pointer to that deallocated memory. Instead, copy the bytes to your packet struct (perhaps checking to make sure the two match in size).
In the interest of full disclosure, the above makes a somewhat cavalier assumption that endianness of the payload matches that of device running your app. You theoretically might want to make the UUID a UInt8 uuid[2], instead, and then if you need the UUID value, recalculate it from those two octets.

Convert Hex value to Base64 using Kotlin

I have this value:
263e5df7a93ec5f5ea6ac215ed957c30
When I fill this in on: https://8gwifi.org/base64Hex.jsp (Hex to Base64)
It gives me back:
Jj5d96k+xfXqasIV7ZV8MA==
This is the expected value. However, when I try this in Kotlin,
val encodedHexB64 = Base64.encodeToString("263e5df7a93ec5f5ea6ac215ed957c30".toByteArray(UTF_8), Base64.NO_WRAP)
It gives me back:
MjYzZTVkZjdhOTNlYzVmNWVhNmFjMjE1ZWQ5NTdjMzA=
How to get the correct value in Kotlin?
To complete the previous:
val input = "263e5df7a93ec5f5ea6ac215ed957c30"
val bytes = input.chunked(2).map { it.toInt(16).toByte() }.toByteArray()
val encodeBase64 = Base64.encodeToString(bytes, Base64.DEFAULT)
Now you have: Jj5d96k+xfXqasIV7ZV8MA==
It looks like the input string represents 16 bytes, where each byte is coded with two hex digit chars of that string.
On the contrary toByteArray(UTF_8) encodes the string in UTF-8 encoding turning each char into one or more bytes. When you convert these bytes to base64, first you get the longer result and second — these are completely different bytes.
I suppose the correct way to convert the input hex string into byte array would be:
val input = "263e5df7a93ec5f5ea6ac215ed957c30"
val bytes = input.chunked(2).map { it.toInt(16).toByte() }.toByteArray()
Then you encode these bytes to base64 as usual.

NSData with different content have the same hash

I was using hash function on NSData when I have noticed that the hash was the same for two different data contents.
This was my code:
NSDictionary * d1 = #{#"sums":#[#{#"label":#"Work", #"value":#30}, #{#"label":#"Transport", #"value":#50}, #{#"label":#"Material", #"value":#300}]};
NSData * dd1 = [NSKeyedArchiver archivedDataWithRootObject:d1];
NSDictionary * d2 = #{#"sums":#[#{#"label":#"Work", #"value":#30}, #{#"label":#"Transport", #"value":#50}, #{#"label":#"Material", #"value":#9}]};
NSData * dd2 = [NSKeyedArchiver archivedDataWithRootObject:d2];
NSInteger hashd1 = [dd1 hash];
NSInteger hashd2 = [dd2 hash];
Last value is different, but hash values are the same.
I was wondering how is hash for NSData calculated in Objective-C as there is no clear guidance from the docs.?
Printing description of hashd1:
(NSInteger) hashd1 = 211676908
Printing description of hashd2:
(NSInteger) hashd2 = 211676908
Printing description of dd2:
<62706c69 73743030 d4010203 04050641 42582476 65727369 6f6e5824 6f626a65 63747359 24617263 68697665 72542474 6f701200 0186a0af 10110708 11121820 21222324 2a323334 3c3d3e55 246e756c 6cd3090a 0b0c0e10 574e532e 6b657973 5a4e532e 6f626a65 63747356 24636c61 7373a10d 8002a10f 80038009 5473756d 73d20a0b 1317a314 15168004 800a800d 8010d309 0a0b191c 10a21a1b 80058006 a21d1e80 07800880 09556c61 62656c55 76616c75 6554576f 726b101e d2252627 285a2463 6c617373 6e616d65 5824636c 61737365 735c4e53 44696374 696f6e61 7279a227 29584e53 4f626a65 6374d309 0a0b2b2e 10a21a1b 80058006 a22f3080 0b800c80 09595472 616e7370 6f727410 32d3090a 0b353810 a21a1b80 058006a2 393a800e 800f8009 584d6174 65726961 6c1205f5 e100d225 263f4057 4e534172 726179a2 3f295f10 0f4e534b 65796564 41726368 69766572 d1434454 726f6f74 80010008 0011001a 0023002d 00320037 004b0051 00580060 006b0072 00740076 0078007a 007c0081 0086008a 008c008e 00900092 0099009c 009e00a0 00a300a5 00a700a9 00af00b5 00ba00bc 00c100cc 00d500e2 00e500ee 00f500f8 00fa00fc 00ff0101 01030105 010f0111 0118011b 011d011f 01220124 01260128 01310136 013b0143 01460158 015b0160 00000000 00000201 00000000 00000045 00000000 00000000 00000000 00000162>
Printing description of dd1:
<62706c69 73743030 d4010203 04050641 42582476 65727369 6f6e5824 6f626a65 63747359 24617263 68697665 72542474 6f701200 0186a0af 10110708 11121820 21222324 2a323334 3c3d3e55 246e756c 6cd3090a 0b0c0e10 574e532e 6b657973 5a4e532e 6f626a65 63747356 24636c61 7373a10d 8002a10f 80038009 5473756d 73d20a0b 1317a314 15168004 800a800d 8010d309 0a0b191c 10a21a1b 80058006 a21d1e80 07800880 09556c61 62656c55 76616c75 6554576f 726b101e d2252627 285a2463 6c617373 6e616d65 5824636c 61737365 735c4e53 44696374 696f6e61 7279a227 29584e53 4f626a65 6374d309 0a0b2b2e 10a21a1b 80058006 a22f3080 0b800c80 09595472 616e7370 6f727410 32d3090a 0b353810 a21a1b80 058006a2 393a800e 800f8009 584d6174 65726961 6c11012c d225263f 40574e53 41727261 79a23f29 5f100f4e 534b6579 65644172 63686976 6572d143 4454726f 6f748001 00080011 001a0023 002d0032 0037004b 00510058 0060006b 00720074 00760078 007a007c 00810086 008a008c 008e0090 00920099 009c009e 00a000a3 00a500a7 00a900af 00b500ba 00bc00c1 00cc00d5 00e200e5 00ee00f5 00f800fa 00fc00ff 01010103 0105010f 01110118 011b011d 011f0122 01240126 01280131 01340139 01410144 01560159 015e0000 00000000 02010000 00000000 00450000 00000000 00000000 00000000 0160>
even the byte length is different
(lldb) po [dd1 length]
522
(lldb) po [dd2 length]
524
It's an implementation detail of NSData, but it only uses the first 80 bytes of data to compute the hash, viz: https://opensource.apple.com/source/CF/CF-635.21/CFData.c:
static CFHashCode __CFDataHash(CFTypeRef cf) {
CFDataRef data = (CFDataRef)cf;
return CFHashBytes((uint8_t *)CFDataGetBytePtr(data), __CFMin(__CFDataLength(data), 80));
}
The keyed archiver adds enough preamble that the two results are the same up to that length.
You might like the additional detail available at How does NSData's implementation of the hash method work?

Declaring Byte in Kotlin does compile-time error 'The integer literal does not conform to the expected type Byte'

As seen another question in 0xFF0000FF An integer literal does not conform to the expected type kotlin.Int
I declaring value 0xFF as Byte
val b:Byte = 0xFF
receiving The integer literal does not conform to the expected type Byte compile error
Since I have clue about kotlin.Byte is signed byte
How to declaring Byte in Kotlin with 0x00 - 0xFF unsigned byte just like .net Byte b = 0xFF ?
.
.
If you want instant compiler for testing and answer:
rextester , try.kotlinlang.org
Kotlin doesn't automatically convert between number types.
If you do val b:Byte = 0xFF.toByte() then it compiles and results in a byte with value -1.
If you want to hold the unsigned byte value then you need to store it as a Char, but you will need to convert it to another type to print it as a number:
val b = 0xFF.toChar()
println(b.toInt())
Kotlin now supports unsigned integer types:
val b: UByte = 255u
val c: UByte = 0xFFu