Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift equivalent to Objective-C FourCharCode single quote literals (e.g. 'TEXT')

I am trying replicate some Objective C cocoa in Swift. All is good until I come across the following:

// Set a new type and creator:
unsigned long type = 'TEXT';
unsigned long creator = 'pdos';

How can I create Int64s (or the correct Swift equivalent) from single quote character literals like this?

Types:

public typealias AEKeyword = FourCharCode
public typealias OSType = FourCharCode
public typealias FourCharCode = UInt32
like image 960
James Alvarez Avatar asked Jul 09 '15 14:07

James Alvarez


3 Answers

Adopt the ExpressibleByStringLiteral protocol to use four-character string literals directly:

extension FourCharCode: ExpressibleByStringLiteral {
    
    public init(stringLiteral value: StringLiteralType) {
        if let data = value.data(using: .macOSRoman), data.count == 4 {
            self = data.reduce(0, {$0 << 8 + Self($1)})
        } else {
            self = 0
        }
    }
   
}

Now you can just pass a string literal as the FourCharCode / OSType / UInt32 parameter:

let record = NSAppleEventDescriptor.record()
record.setDescriptor(NSAppleEventDescriptor(boolean: true), forKeyword: "test")
like image 52
pkamb Avatar answered Oct 26 '22 02:10

pkamb


I found the following typealiases from the Swift API:

typealias FourCharCode = UInt32
typealias OSType = FourCharCode

And the following functions:

func NSFileTypeForHFSTypeCode(hfsFileTypeCode: OSType) -> String!
func NSHFSTypeCodeFromFileType(fileTypeString: String!) -> OSType

This should allow me to create the equivalent code:

let type : UInt32 = UInt32(NSHFSTypeCodeFromFileType("TEXT"))
let creator : UInt32 = UInt32(NSHFSTypeCodeFromFileType("pdos"))

But those 4-character strings doesn't work and return 0.

If you wrap each string in ' single quotes ' and call the same functions, you will get the correct return values:

let type : UInt32 = UInt32(NSHFSTypeCodeFromFileType("'TEXT'"))
let creator : UInt32 = UInt32(NSHFSTypeCodeFromFileType("'pdos'"))
like image 6
James Alvarez Avatar answered Nov 08 '22 13:11

James Alvarez


I'm using this in my Cocoa Scripting apps, it considers characters > 0x80 correctly

func OSTypeFrom(string : String) -> UInt {
  var result : UInt = 0
  if let data = string.dataUsingEncoding(NSMacOSRomanStringEncoding) {
    let bytes = UnsafePointer<UInt8>(data.bytes)
    for i in 0..<data.length {
      result = result << 8 + UInt(bytes[i])
    }
  }
  return result
}

Edit:

Alternatively

func fourCharCodeFrom(string : String) -> FourCharCode
{
  assert(string.count == 4, "String length must be 4")
  var result : FourCharCode = 0
  for char in string.utf16 {
    result = (result << 8) + FourCharCode(char)
  }
  return result
}

or still swiftier

func fourCharCode(from string : String) -> FourCharCode
{
  return string.utf16.reduce(0, {$0 << 8 + FourCharCode($1)})
}
like image 10
vadian Avatar answered Nov 08 '22 14:11

vadian