diff --git a/libobs/CMakeLists.txt b/libobs/CMakeLists.txt index bddfa5c22..09f7cc08d 100644 --- a/libobs/CMakeLists.txt +++ b/libobs/CMakeLists.txt @@ -116,7 +116,8 @@ elseif(APPLE) util/platform-nix.c util/platform-cocoa.m) set(libobs_PLATFORM_HEADERS - util/threading-posix.h) + util/threading-posix.h + util/apple/cfstring-utils.h) set(libobs_audio_monitoring_SOURCES audio-monitoring/osx/coreaudio-enum-devices.c audio-monitoring/osx/coreaudio-output.c diff --git a/libobs/util/apple/cfstring-utils.h b/libobs/util/apple/cfstring-utils.h new file mode 100644 index 000000000..d131fbb48 --- /dev/null +++ b/libobs/util/apple/cfstring-utils.h @@ -0,0 +1,17 @@ +#pragma once + +#include "../c99defs.h" +#include "../dstr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +EXPORT char *cfstr_copy_cstr(CFStringRef cfstr, CFStringEncoding cfstr_enc); + +EXPORT bool cfstr_copy_dstr(CFStringRef cfstr, CFStringEncoding cfstr_enc, + struct dstr *str); + +#ifdef __cplusplus +} +#endif diff --git a/libobs/util/platform-cocoa.m b/libobs/util/platform-cocoa.m index f93341cc0..de48cdb0c 100644 --- a/libobs/util/platform-cocoa.m +++ b/libobs/util/platform-cocoa.m @@ -1,6 +1,7 @@ /* - * Copyright (c) 2013-2014 Ruwen Hahn + * Copyright (c) 2013-2018 Ruwen Hahn * Hugh "Jim" Bailey + * Marvin Scholz * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -33,6 +34,8 @@ #import +#include "apple/cfstring-utils.h" + /* clock function selection taken from libc++ */ static uint64_t ns_time_simple() { @@ -417,3 +420,90 @@ uint64_t os_get_proc_virtual_size(void) return 0; return taskinfo.virtual_size; } + +/* Obtains a copy of the contents of a CFString in specified encoding. + * Returns char* (must be bfree'd by caller) or NULL on failure. + */ +char *cfstr_copy_cstr(CFStringRef cfstring, CFStringEncoding cfstring_encoding) +{ + if (!cfstring) + return NULL; + + // Try the quick way to obtain the buffer + const char *tmp_buffer = CFStringGetCStringPtr(cfstring, + cfstring_encoding); + + if (tmp_buffer != NULL) + return bstrdup(tmp_buffer); + + // The quick way did not work, try the more expensive one + CFIndex length = CFStringGetLength(cfstring); + CFIndex max_size = + CFStringGetMaximumSizeForEncoding(length, cfstring_encoding); + + // If result would exceed LONG_MAX, kCFNotFound is returned + if (max_size == kCFNotFound) + return NULL; + + // Account for the null terminator + max_size++; + + char *buffer = bmalloc(max_size); + + if (buffer == NULL) { + return NULL; + } + + // Copy CFString in requested encoding to buffer + Boolean success = + CFStringGetCString(cfstring, buffer, max_size, cfstring_encoding); + + if (!success) { + bfree(buffer); + buffer = NULL; + } + return buffer; +} + +/* Copies the contents of a CFString in specified encoding to a given dstr. + * Returns true on success or false on failure. + * In case of failure, the dstr capacity but not size is changed. + */ +bool cfstr_copy_dstr(CFStringRef cfstring, + CFStringEncoding cfstring_encoding, struct dstr *str) +{ + if (!cfstring) + return false; + + // Try the quick way to obtain the buffer + const char *tmp_buffer = CFStringGetCStringPtr(cfstring, + cfstring_encoding); + + if (tmp_buffer != NULL) { + dstr_copy(str, tmp_buffer); + return true; + } + + // The quick way did not work, try the more expensive one + CFIndex length = CFStringGetLength(cfstring); + CFIndex max_size = + CFStringGetMaximumSizeForEncoding(length, cfstring_encoding); + + // If result would exceed LONG_MAX, kCFNotFound is returned + if (max_size == kCFNotFound) + return NULL; + + // Account for the null terminator + max_size++; + + dstr_ensure_capacity(str, max_size); + + // Copy CFString in requested encoding to dstr buffer + Boolean success = CFStringGetCString( + cfstring, str->array, max_size, cfstring_encoding); + + if (success) + dstr_resize(str, max_size); + + return (bool)success; +}