I have variable in String format in kotlin:
var a ="[B#53c1c428"
I want to change it's datatype from String to ByteArray i.e typecast it to ByteArray, somewhat like:
var b: ByteArray = a
I also tried:
var b = a as ByteArray, but this throws an Exception
If I do:
var b = a.toByteArray(), I get output like:
[B#3aea9e4
But I want [B#53c1c428 as ByteArray.
Any suggestions?
Just to clarify:
[B#53c1c428 is the hexadecimal hash code of that object with a B[# prefix. The string "[B#53c1c428" itself does not contain the data needed to reconstruct the ByteArray.
Consider this:
val str = "Test"
val byteArray = str.toByteArray()
println(Integer.toHexString(byteArray.hashCode())) // 1f32e575
println(byteArray) // [B# + hash code as hexadecimal representation
val str2 = "This is a really long text and no 8 digit hex number in this world could encode it."
val byteArray2 = str2.toByteArray()
println(Integer.toHexString(byteArray2.hashCode())) // 279f2327
println(byteArray2) // [B# + hash code as hexadecimal representation
toByteArray() already gives you a ByteArray. If you want to print the single digits as integers do it like this:
val str = "Test"
println(str.toByteArray().joinToString(" "){ "$it" })
Output:
84 101 115 116
This output would be enough to fully restore the ByteArray, because it contains all necessary information.
Related
I have a json as below. I need to convert the image to a byte array and post it as a String.
I can convert the image to byte array but how can I convert it to String?
I am getting an error while converting byte array to String.
Error:
"not a valid UTF-8 sequence"
JSON:
"photo1": "[255,216,255,224,0,16,74,70,73, ..... ,]"
Image Data to Byte Array:
func getArrayOfBytesFromImage(imageData:NSData) -> Array<UInt8> {
// the number of elements:
let count = imageData.length / MemoryLayout<Int8>.size
// create array of appropriate length:
var bytes = [UInt8](repeating: 0, count: count)
// copy bytes into array
imageData.getBytes(&bytes, length:count * MemoryLayout<Int8>.size)
var byteArray:Array = Array<UInt8>()
for i in 0 ..< count {
byteArray.append(bytes[i])
}
return byteArray
}
Using getArrayOfBytesFromImage Function:
if let string = String(bytes: getArrayOfBytesFromImage(imageData: imageData), encoding: .utf8) {
print(string)
} else {
print("not a valid UTF-8 sequence")
}
Those are not UTF-8 bytes, so don't say encoding: .utf8. Those bytes do not form a string, so you should not use String.init(bytes:encoding:). You should get the value of those bytes, and get their description one way or another (e.g. by string interpolation).
You don't even need a byte array here. Just go straight to strings, since that's what you're after.
let imageData = Data([1, 2, 3, 4, 5]) // for example
let string = "[\(imageData.map { "\($0)" }.joined(separator: ","))]"
print(string) // prints [1,2,3,4,5]
What is the Kotlin 1.5 command to convert a 16 bit integer to a Byte of length 2? Secondary problem is that outputstream needs a string at the end so it can convert with toByteArray()
# Original Python Code
...
i = int((2**16-1)*ratio) # 16 bit int
i.to_bytes(2, byteorder='big')
output = (i).to_bytes(2, byteorder='big')
# Kotlin Code so far
var i = ((2.0.pow(16) - 1) * ratio).toInt() // Convert to 16 bit Integer
print("16 bit Int: " + i)
output = .....
....
...
val outputStream: OutputStream = socket.getOutputStream()
outputStream.write(output.toByteArray()) // write requires ByteArray for some reason
It is simple math, so it is probably the best to calculate manually and define as an extension function:
fun Int.to2ByteArray() : ByteArray = byteArrayOf(toByte(), shr(8).toByte())
Then you can use it:
output = i.to2ByteArray()
outputStream.write(output)
Note, this function writes the integer in little-endian. If you need big-endian the just reverse the order of items in the array. You can also add some min/max checks if you need them.
Also, if you only need 16-bit values then you can consider using Short or UShort instead of Int. It doesn't change much regarding the memory usage, but it could be a cleaner approach - we could name our extension just toByArray() and we would not need min/max checks.
I had tried to convert btye array to string in charset-8, but it's not working. Can someone guide me please.
Here is how I convert Bitmap to bytearray
private fun BitmapToByteArray(): ByteArray
{
val stream = ByteArrayOutputStream()
btm1!!.compress(Bitmap.CompressFormat.PNG, 100, stream)
val bitmapdata: ByteArray = stream.toByteArray()
return bitmapdata
}
Here is how I encrypt the data
private fun encrypting_data(bitmapdata: ByteArray): String {
val key = secretkey!!.text.toString()
val btm1 = bitmapdata.toString(Charsets.UTF_8)
val s = btm1
//generating key from given secret key
val skey: Key = SecretKeySpec(key.toByteArray(), "AES")
print(skey.toString())
val c: Cipher = Cipher.getInstance("AES")
c.init(Cipher.ENCRYPT_MODE, skey)
//encrypting text string
val re = c.doFinal(s.toByteArray())
//converting encrypted string to base64
val re_base64 = Base64.encodeToString(re, Base64.NO_WRAP or Base64.NO_PADDING)
Log.e("aaAA", re_base64.toString())
//converting each chr of base64 string to binary and combining it
for (i in re_base64) {
var single_b_string = Integer.toBinaryString((i.toInt()))
//if binary str is less than 8 bit then making it 8 bit by adding 0's
if (single_b_string.length < 8) {
for (j in 1..(8 - single_b_string.length)) {
single_b_string = "0" + single_b_string
}
}
//final binary string to hide in image
b_string = b_string + single_b_string
}
Log.e("barraylength", b_string.toString())
Log.e("barray", b_string!!.length.toString())
return b_string.toString()
}
please guide me, thank you
Short answer: none.
Charsets are used to map characters to binary and vice-versa. It doesn't make sense to decode the bytes of an image into a string using a character encoding. There is even a chance that you find sequences of bytes that are not valid sequences in the character encoding that you choose, so they will not be converted to characters correctly.
Sometimes it's necessary to use text to represent binary data (e.g. when using text-only transports/media to store it).
In these cases, you can use other kinds of encodings, for instance Base64, but I guess you know about it because you're already sort of using base64 here as well.
Note that, in your current code, you are converting a ByteArray (bitmapdata) into a String (btm1/s) only to convert it back into a ByteArray (s.toByteArray()). Why do you even need to do so?
I getting a text input and writing it to a ble device. I don't have an issue for 1 Byte of data but I could not covert the text input value to 2 bytes and send it.
How can I convert a value like 3400 to 2 bytes of UInt8 array and what should I for values below 255?
For 1 byte I use:
let myInt = Int(textField.text)
let value: [UInt8] = [UInt8(myInt)]
self.bluetoothManager.writeValue(data: Data(bytes: value), forCharacteristic: myChar!, type: .withResponse)
I tried to convert like this but I can't send String with .writeValue:
https://stackoverflow.com/a/36967037/4704055
let d1 = 21
let b1 = String(d1, radix: 2)
print(b1) // "10101"
You probably want to convert the string to a 16-bit integer, then
convert the integer to data (compare round trip Swift number types to/from Data), and finally write the data to the device:
guard var value = Int16(textField.text) else {
// ... invalid number ...
}
// value = value.bigEndian (if big-endian is expected by the device)
let data = Data(buffer: UnsafeBufferPointer(start: &value, count: 1))
self.bluetoothManager.writeValue(data: data, ...)
As part of my projects, I have a binary data file consisting of a large series of 32 bit integers that one of my classes reads in on initialization. In my C++ library, I read it in with the following initializer:
Evaluator::Evaluator() {
m_HandNumbers.resize(32487834);
ifstream inputReader;
inputReader.open("/path/to/file/7CHands.dat", ios::binary);
int inputValue;
for (int x = 0; x < 32487834; ++x) {
inputReader.read((char *) &inputValue, sizeof (inputValue));
m_HandNumbers[x] = inputValue;
}
inputReader.close();
};
and in porting to Swift, I decided to read the entire file into one buffer (it's only about 130 MB) and then copy the bytes out of the buffer.
So, I've done the following:
public init() {
var inputStream = NSInputStream(fileAtPath: "/path/to/file/7CHands.dat")!
var inputBuffer = [UInt8](count: 32478734 * 4, repeatedValue: 0)
inputStream.open()
inputStream.read(&inputBuffer, maxLength: inputBuffer.count)
inputStream.close()
}
and it works fine in that when I debug it, I can see inputBuffer contains the same array of bytes that my hex editor says it should. Now, I'd like to get that data out of there effectively. I know it's stored in.. whatever format you call it where the least significant bytes are first (i.e. the number 0x00011D4A is represented as '4A1D 0100' in the file). I'm tempted to just iterate through it manually and calculate the byte values by hand, but I'm wondering if there's a quick way I can pass an array of [Int32] and have it read those bytes in. I tried using NSData, such as with:
let data = NSData(bytes: handNumbers, length: handNumbers.count * sizeof(Int32))
data.getBytes(&inputBuffer, length: inputBuffer.count)
but that didn't seem to load the values (all the values were still zero). Can anyone please help me convert this byte array into some Int32 values? Better yet would be to convert them to Int (i.e. 64 bit integer) just to keep my variable sizes the same across the project.
Not sure about your endian-ness, but I use the following function. The difference from your code is using NSRanges of the actual required type, rather than lengths of bytes. This routine reads one value at a time (it's for ESRI files whose contents vary field by field), but should be easily adaptable.
func getBigIntFromData(data: NSData, offset: Int) -> Int {
var rng = NSRange(location: offset, length: 4)
var i = [UInt32](count: 1, repeatedValue:0)
data.getBytes(&i, range: rng)
return Int(i[0].bigEndian)// return Int(i[0]) for littleEndian
}
Grimxn provided the backbone of the solution to my problem, which showed me how to read sections of the buffer into an array; he then showed me a way to read the entire buffer in all at once. Rather than convert all of the items of the array needlessly to Int, I simply read the array into the buffer as UInt32 and did the casting to Int in the function that accesses that array.
For now, since I don't have my utility class defined yet, I integrated Grimxn's code directly into my initializer. The class initializer now looks like this:
public class Evaluator {
let HandNumberArraySize = 32487834
var handNumbers: [Int32]
public init() {
let data = NSData(contentsOfFile: "/path/to/file/7CHands.dat")!
var dataRange = NSRange(location: 0, length: HandNumberArraySize * 4)
handNumbers = [Int32](count: HandNumberArraySize, repeatedValue: 0)
data.getBytes(&handNumbers, range: dataRange)
println("Evaluator loaded successfully")
}
...
}
... and the function that references them is now:
public func cardVectorToHandNumber(#cards: [Int], numberToUse: Int) -> Int {
var output: Int
output = Int(handNumbers[53 + cards[0] + 1])
for i in 1 ..< numberToUse {
output = Int(handNumbers[output + cards[i] + 1])
}
return Int(handNumbers[output])
}
Thanks to Grimxn and thanks once again to StackOverflow for helping me in a very real way!