Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift - Convert UInt8 byte to array of bits

I'm trying to decode a protobuff encoded message, so I need to convert the first byte (the key) in the protobuff message into bits, so I can find the field number. How do I convert a UInt8 (the byte) into an array of bits?

Pseudo Code

private func findFieldNum(from byte: UInt8) -> Int {
    //Byte is 0001 1010
    var fieldNumBits = byte[1] ++ byte[2] ++ byte[3] ++ byte[4] //concatentates bits to get 0011
    getFieldNum(from: fieldNumBits) //Converts 0011 to field number, 2^1 + 2^0 = 3
}

I saw this question, which converts an array of bits into array of bytes.

like image 443
Amanda Avatar asked Jun 28 '17 15:06

Amanda


People also ask

What is a byte array in Swift?

String, byte array. In Swift a byte is called a UInt8—an unsigned 8 bit integer. A byte array is a UInt8 array. In ASCII we can treat chars as UInt8 values. With the utf8 String property, we get a UTF8View collection.

How do I convert a string to an array in Swift?

Swift Convert String to Byte Array: utf8 and UInt8 Converts String to a byte array with the utf8 property. Convert the UInt8 array back into a String. String, byte array. In Swift a byte is called a UInt8—an unsigned 8 bit integer. A byte array is a UInt8 array.

What is a uint8 in Swift?

In Swift a byte is called a UInt8—an unsigned 8 bit integer. A byte array is a UInt8 array. In ASCII we can treat chars as UInt8 values. With the utf8 String property, we get a UTF8View collection.

How to convert [uint8] to data?

As [UInt8] is stored in a contiguous region of memory, there's no need to convert it to Data, pointer can access all bytes directly. Int 's byte order is little endian currently on all Apple platform, but this is not garanteed on other platforms. say we want [0, 0, 0, 0x0e] to convert to 14. (big-endian byte order)


2 Answers

Here's a basic function to get a Bit array from a byte:

func bits(fromByte byte: UInt8) -> [Bit] {
    var byte = byte
    var bits = [Bit](repeating: .zero, count: 8)
    for i in 0..<8 {
        let currentBit = byte & 0x01
        if currentBit != 0 {
            bits[i] = .one
        }

        byte >>= 1
    }

    return bits
}

Here, Bit is a custom enum type that I have defined as follows:

enum Bit: UInt8, CustomStringConvertible {
    case zero, one

    var description: String {
        switch self {
        case .one:
            return "1"
        case .zero:
            return "0"
        }
    }
}

With this setup, the output of the following code:

let byte: UInt8 = 0x1f

print(bits(fromByte: byte))

would be:

[1, 1, 1, 1, 1, 0, 0, 0]
like image 79
mohak Avatar answered Sep 28 '22 01:09

mohak


Improving on mohak's answer. With a generic function or an extension to cater for more than just UInt8.

enum Bit: UInt8, CustomStringConvertible {
    case zero, one

    var description: String {
        switch self {
        case .one:
            return "1"
        case .zero:
            return "0"
        }
    }
}

func bits<T: FixedWidthInteger>(fromBytes bytes: T) -> [Bit] {
    // Make variable
    var bytes = bytes
    // Fill an array of bits with zeros to the fixed width integer length
    var bits = [Bit](repeating: .zero, count: T.bitWidth)
    // Run through each bit (LSB first)
    for i in 0..<T.bitWidth {
        let currentBit = bytes & 0x01
        if currentBit != 0 {
            bits[i] = .one
        }

        bytes >>= 1
    }

    return bits
}

extension FixedWidthInteger {
    var bits: [Bit] {
        // Make variable
        var bytes = self
        // Fill an array of bits with zeros to the fixed width integer length
        var bits = [Bit](repeating: .zero, count: self.bitWidth)
        // Run through each bit (LSB first)
        for i in 0..<self.bitWidth {
            let currentBit = bytes & 0x01
            if currentBit != 0 {
                bits[i] = .one
            }

            bytes >>= 1
        }

        return bits
    }
}
like image 39
jdelaune Avatar answered Sep 27 '22 23:09

jdelaune