0

Here is the old Objective C code (token is NSData):

const unsigned *tokenBytes = [credentials.token bytes];
NSString *hexToken = [NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x",
                      ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]),
                      ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]),
                      ntohl(tokenBytes[6]), ntohl(tokenBytes[7])];

Here is how I converted it to Swift:

let tokenBytes = credentials.token.withUnsafeBytes { (bytes: UnsafePointer<[UInt]>) -> [UInt] in
        return bytes[0] // Crash here
    }

    let hexToken = String(format: "%08x%08x%08x%08x%08x%08x%08x%08x",
                          UInt(bigEndian: tokenBytes[0]), UInt(bigEndian: tokenBytes[1]),
                          UInt(bigEndian: tokenBytes[2]), UInt(bigEndian: tokenBytes[3]),
                          UInt(bigEndian: tokenBytes[4]), UInt(bigEndian: tokenBytes[5]),
                          UInt(bigEndian: tokenBytes[6]), UInt(bigEndian: tokenBytes[7])
    )

Does anyone know what I'm doing wrong? As far as I know I converted from bytes to withUnsafeBytes correctly, but it seems like I'm mistaken.

Eman Harout
  • 536
  • 7
  • 21
  • have u logged `bytes` to see what is in it? `print(bytes[0])` - i bet its undefined – ewizard Dec 25 '18 at 00:12
  • Just a bunch of numbers, not sure if that helps. To be honest, I'm way out of my league here, don't have much experience with bytes/low level stuff. EDIT: Just saw you wanted me to print the subscript. I'll do that and get back to you. – Eman Harout Dec 25 '18 at 00:16
  • paste the output for `print(bytes)` and `print(bytes[0])` – ewizard Dec 25 '18 at 00:18
  • 0x00000002815f6cb0 for the former, a crash for bytes[0] – Eman Harout Dec 25 '18 at 00:21
  • yah so I don't think you can treat `0x00000002815f6cb0` like an array, it is an `UnsafePointer`, and i am not super familiar with swift but it points to a place in memory. – ewizard Dec 25 '18 at 00:24
  • Got it, since we're accessing what its pointing to through subscripts, I'm assuming that's just the norm (array or not), so I'll try casting to other things. Thank you! – Eman Harout Dec 25 '18 at 00:30
  • try `.withUnsafeBytes { (bytes) in bytesPointer = UnsafeBufferPointer(start: UnsafePointer(bytes), count:.count) }` and then play with it a little...`print(bytes)` and `print(bytesPointer)`, see if either can help get what you want, no really sure the context of what you will receive, but I found this in another example https://stackoverflow.com/questions/9372815/how-can-i-convert-my-device-token-nsdata-into-an-nsstring/21046848 – ewizard Dec 25 '18 at 00:34
  • Probable duplicate of https://stackoverflow.com/questions/48438001/swift-4-convert-bytes-to-int-and-ntohl – matt Dec 25 '18 at 02:03
  • Be careful: UInt might well be 64 bits, whereas `ntohl` assumes 32 bits. – matt Dec 25 '18 at 04:18

1 Answers1

0

The reason you are crashing is this expression:

bytes : UnsafePointer<[UInt]>

You are assuming that the data represents a series of UInt. So a pointer to the start of the data is not as unsafe pointer to a [UInt], an array of UInt; it is an unsafe pointer to a UInt, i.e. the first in the series. You should be saying:

bytes : UnsafePointer<UInt>

So much for the crash. Now let's talk about the thing you are mostly trying to do here.

I'm uncertain what the string format is supposed to do, but I do grasp that the idea of ntohl is to guarantee the endianity of some C long ints (32 bits). So I'll omit the string format part and just talk about how you would take a stream of C long int received into a Data and reverse the endianity of the long ints.

Suppose d is a mutable Data (i.e. declared with var). Then, assuming it represents a sequence of UInt32 little-endian values and you want to convert those to big-endian, you would say:

let ct = d.count/4
d.withUnsafeMutableBytes{
    (ptr:UnsafeMutablePointer<UInt32>) in
    for ix in 0..<ct {
        ptr[ix] = ptr[ix].bigEndian
    }
}
matt
  • 515,959
  • 87
  • 875
  • 1,141