blob: b4032a5d91c2a0ebbf73468000c220a69eb21082 [file] [log] [blame]
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build darwin
// Package macOS provides cgo-less wrappers for Core Foundation and
// Security.framework, similarly to how package syscall provides access to
// libSystem.dylib.
package macOS
import (
"bytes"
"errors"
"internal/abi"
"runtime"
"time"
"unsafe"
)
// Core Foundation linker flags for the external linker. See Issue 42459.
//
//go:cgo_ldflag "-framework"
//go:cgo_ldflag "CoreFoundation"
// CFRef is an opaque reference to a Core Foundation object. It is a pointer,
// but to memory not owned by Go, so not an unsafe.Pointer.
type CFRef uintptr
// CFDataToSlice returns a copy of the contents of data as a bytes slice.
func CFDataToSlice(data CFRef) []byte {
length := CFDataGetLength(data)
ptr := CFDataGetBytePtr(data)
src := unsafe.Slice((*byte)(unsafe.Pointer(ptr)), length)
return bytes.Clone(src)
}
// CFStringToString returns a Go string representation of the passed
// in CFString, or an empty string if it's invalid.
func CFStringToString(ref CFRef) string {
data, err := CFStringCreateExternalRepresentation(ref)
if err != nil {
return ""
}
b := CFDataToSlice(data)
CFRelease(data)
return string(b)
}
// TimeToCFDateRef converts a time.Time into an apple CFDateRef.
func TimeToCFDateRef(t time.Time) CFRef {
secs := t.Sub(time.Date(2001, 1, 1, 0, 0, 0, 0, time.UTC)).Seconds()
ref := CFDateCreate(secs)
return ref
}
type CFString CFRef
const kCFAllocatorDefault = 0
const kCFStringEncodingUTF8 = 0x08000100
//go:cgo_import_dynamic x509_CFDataCreate CFDataCreate "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
func BytesToCFData(b []byte) CFRef {
p := unsafe.Pointer(unsafe.SliceData(b))
ret := syscall(abi.FuncPCABI0(x509_CFDataCreate_trampoline), kCFAllocatorDefault, uintptr(p), uintptr(len(b)), 0, 0, 0)
runtime.KeepAlive(p)
return CFRef(ret)
}
func x509_CFDataCreate_trampoline()
//go:cgo_import_dynamic x509_CFStringCreateWithBytes CFStringCreateWithBytes "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
// StringToCFString returns a copy of the UTF-8 contents of s as a new CFString.
func StringToCFString(s string) CFString {
p := unsafe.Pointer(unsafe.StringData(s))
ret := syscall(abi.FuncPCABI0(x509_CFStringCreateWithBytes_trampoline), kCFAllocatorDefault, uintptr(p),
uintptr(len(s)), uintptr(kCFStringEncodingUTF8), 0 /* isExternalRepresentation */, 0)
runtime.KeepAlive(p)
return CFString(ret)
}
func x509_CFStringCreateWithBytes_trampoline()
//go:cgo_import_dynamic x509_CFDictionaryGetValueIfPresent CFDictionaryGetValueIfPresent "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
func CFDictionaryGetValueIfPresent(dict CFRef, key CFString) (value CFRef, ok bool) {
ret := syscall(abi.FuncPCABI0(x509_CFDictionaryGetValueIfPresent_trampoline), uintptr(dict), uintptr(key),
uintptr(unsafe.Pointer(&value)), 0, 0, 0)
if ret == 0 {
return 0, false
}
return value, true
}
func x509_CFDictionaryGetValueIfPresent_trampoline()
const kCFNumberSInt32Type = 3
//go:cgo_import_dynamic x509_CFNumberGetValue CFNumberGetValue "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
func CFNumberGetValue(num CFRef) (int32, error) {
var value int32
ret := syscall(abi.FuncPCABI0(x509_CFNumberGetValue_trampoline), uintptr(num), uintptr(kCFNumberSInt32Type),
uintptr(unsafe.Pointer(&value)), 0, 0, 0)
if ret == 0 {
return 0, errors.New("CFNumberGetValue call failed")
}
return value, nil
}
func x509_CFNumberGetValue_trampoline()
//go:cgo_import_dynamic x509_CFDataGetLength CFDataGetLength "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
func CFDataGetLength(data CFRef) int {
ret := syscall(abi.FuncPCABI0(x509_CFDataGetLength_trampoline), uintptr(data), 0, 0, 0, 0, 0)
return int(ret)
}
func x509_CFDataGetLength_trampoline()
//go:cgo_import_dynamic x509_CFDataGetBytePtr CFDataGetBytePtr "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
func CFDataGetBytePtr(data CFRef) uintptr {
ret := syscall(abi.FuncPCABI0(x509_CFDataGetBytePtr_trampoline), uintptr(data), 0, 0, 0, 0, 0)
return ret
}
func x509_CFDataGetBytePtr_trampoline()
//go:cgo_import_dynamic x509_CFArrayGetCount CFArrayGetCount "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
func CFArrayGetCount(array CFRef) int {
ret := syscall(abi.FuncPCABI0(x509_CFArrayGetCount_trampoline), uintptr(array), 0, 0, 0, 0, 0)
return int(ret)
}
func x509_CFArrayGetCount_trampoline()
//go:cgo_import_dynamic x509_CFArrayGetValueAtIndex CFArrayGetValueAtIndex "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
func CFArrayGetValueAtIndex(array CFRef, index int) CFRef {
ret := syscall(abi.FuncPCABI0(x509_CFArrayGetValueAtIndex_trampoline), uintptr(array), uintptr(index), 0, 0, 0, 0)
return CFRef(ret)
}
func x509_CFArrayGetValueAtIndex_trampoline()
//go:cgo_import_dynamic x509_CFEqual CFEqual "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
func CFEqual(a, b CFRef) bool {
ret := syscall(abi.FuncPCABI0(x509_CFEqual_trampoline), uintptr(a), uintptr(b), 0, 0, 0, 0)
return ret == 1
}
func x509_CFEqual_trampoline()
//go:cgo_import_dynamic x509_CFRelease CFRelease "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
func CFRelease(ref CFRef) {
syscall(abi.FuncPCABI0(x509_CFRelease_trampoline), uintptr(ref), 0, 0, 0, 0, 0)
}
func x509_CFRelease_trampoline()
//go:cgo_import_dynamic x509_CFArrayCreateMutable CFArrayCreateMutable "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
func CFArrayCreateMutable() CFRef {
ret := syscall(abi.FuncPCABI0(x509_CFArrayCreateMutable_trampoline), kCFAllocatorDefault, 0, 0 /* kCFTypeArrayCallBacks */, 0, 0, 0)
return CFRef(ret)
}
func x509_CFArrayCreateMutable_trampoline()
//go:cgo_import_dynamic x509_CFArrayAppendValue CFArrayAppendValue "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
func CFArrayAppendValue(array CFRef, val CFRef) {
syscall(abi.FuncPCABI0(x509_CFArrayAppendValue_trampoline), uintptr(array), uintptr(val), 0, 0, 0, 0)
}
func x509_CFArrayAppendValue_trampoline()
//go:cgo_import_dynamic x509_CFDateCreate CFDateCreate "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
func CFDateCreate(seconds float64) CFRef {
ret := syscall(abi.FuncPCABI0(x509_CFDateCreate_trampoline), kCFAllocatorDefault, 0, 0, 0, 0, seconds)
return CFRef(ret)
}
func x509_CFDateCreate_trampoline()
//go:cgo_import_dynamic x509_CFErrorCopyDescription CFErrorCopyDescription "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
func CFErrorCopyDescription(errRef CFRef) CFRef {
ret := syscall(abi.FuncPCABI0(x509_CFErrorCopyDescription_trampoline), uintptr(errRef), 0, 0, 0, 0, 0)
return CFRef(ret)
}
func x509_CFErrorCopyDescription_trampoline()
//go:cgo_import_dynamic x509_CFErrorGetCode CFErrorGetCode "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
func CFErrorGetCode(errRef CFRef) int {
return int(syscall(abi.FuncPCABI0(x509_CFErrorGetCode_trampoline), uintptr(errRef), 0, 0, 0, 0, 0))
}
func x509_CFErrorGetCode_trampoline()
//go:cgo_import_dynamic x509_CFStringCreateExternalRepresentation CFStringCreateExternalRepresentation "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
func CFStringCreateExternalRepresentation(strRef CFRef) (CFRef, error) {
ret := syscall(abi.FuncPCABI0(x509_CFStringCreateExternalRepresentation_trampoline), kCFAllocatorDefault, uintptr(strRef), kCFStringEncodingUTF8, 0, 0, 0)
if ret == 0 {
return 0, errors.New("string can't be represented as UTF-8")
}
return CFRef(ret), nil
}
func x509_CFStringCreateExternalRepresentation_trampoline()
// syscall is implemented in the runtime package (runtime/sys_darwin.go)
func syscall(fn, a1, a2, a3, a4, a5 uintptr, f1 float64) uintptr
// ReleaseCFArray iterates through an array, releasing its contents, and then
// releases the array itself. This is necessary because we cannot, easily, set the
// CFArrayCallBacks argument when creating CFArrays.
func ReleaseCFArray(array CFRef) {
for i := 0; i < CFArrayGetCount(array); i++ {
ref := CFArrayGetValueAtIndex(array, i)
CFRelease(ref)
}
CFRelease(array)
}