internal static byte[] CFGetData(SafeCFDataHandle cfData)
        {
            bool addedRef = false;

            try
            {
                cfData.DangerousAddRef(ref addedRef);
                byte[] bytes = new byte[CFDataGetLength(cfData).ToInt64()];

                unsafe
                {
                    byte *dataBytes = CFDataGetBytePtr(cfData);
                    Marshal.Copy((IntPtr)dataBytes, bytes, 0, bytes.Length);
                }

                return(bytes);
            }
            finally
            {
                if (addedRef)
                {
                    cfData.DangerousRelease();
                }
            }
        }
        internal static unsafe bool TryCFWriteData(SafeCFDataHandle cfData, Span <byte> destination, out int bytesWritten)
        {
            bool addedRef = false;

            try
            {
                cfData.DangerousAddRef(ref addedRef);

                long length = CFDataGetLength(cfData).ToInt64();
                if (destination.Length < length)
                {
                    bytesWritten = 0;
                    return(false);
                }

                byte *dataBytes = CFDataGetBytePtr(cfData);
                fixed(byte *destinationPtr = &MemoryMarshal.GetReference(destination))
                {
                    Buffer.MemoryCopy(dataBytes, destinationPtr, destination.Length, length);
                }

                bytesWritten = (int)length;
                return(true);
            }
            finally
            {
                if (addedRef)
                {
                    cfData.DangerousRelease();
                }
            }
        }
        internal static string CFStringToString(SafeCFStringHandle cfString)
        {
            Debug.Assert(cfString != null);
            Debug.Assert(!cfString.IsInvalid);
            Debug.Assert(!cfString.IsClosed);

            // If the string is already stored internally as UTF-8 we can (usually)
            // get the raw pointer to the data blob, then we can Marshal in the string
            // via pointer semantics, avoiding a copy.
            IntPtr interiorPointer = CFStringGetCStringPtr(
                cfString,
                CFStringBuiltInEncodings.kCFStringEncodingUTF8);

            if (interiorPointer != IntPtr.Zero)
            {
                return(Marshal.PtrToStringUTF8(interiorPointer) !);
            }

            SafeCFDataHandle cfData = CFStringCreateExternalRepresentation(
                IntPtr.Zero,
                cfString,
                CFStringBuiltInEncodings.kCFStringEncodingUTF8,
                0);

            using (cfData)
            {
                bool addedRef = false;

                try
                {
                    cfData.DangerousAddRef(ref addedRef);

                    unsafe
                    {
                        // Note that CFDataGetLength(cfData).ToInt32() will throw on
                        // too large of an input. Since a >2GB string is pretty unlikely,
                        // that's considered a good thing here.
                        return(Encoding.UTF8.GetString(
                                   CFDataGetBytePtr(cfData),
                                   CFDataGetLength(cfData).ToInt32()));
                    }
                }
                finally
                {
                    if (addedRef)
                    {
                        cfData.DangerousRelease();
                    }
                }
            }
        }
        internal static string CFStringToString(SafeCFStringHandle cfString)
        {
            Debug.Assert(cfString != null);
            Debug.Assert(!cfString.IsInvalid);
            Debug.Assert(!cfString.IsClosed);

#if HAVE_PTRTOSTRINGUTF8
            IntPtr interiorPointer = CFStringGetCStringPtr(
                cfString,
                CFStringBuiltInEncodings.kCFStringEncodingUTF8);

            if (interiorPointer != IntPtr.Zero)
            {
                return(Marshal.PtrToStringUTF8(interiorPointer));
            }
#endif

            SafeCFDataHandle cfData = CFStringCreateExternalRepresentation(
                IntPtr.Zero,
                cfString,
                CFStringBuiltInEncodings.kCFStringEncodingUTF8,
                0);

            using (cfData)
            {
                bool addedRef = false;

                try
                {
                    cfData.DangerousAddRef(ref addedRef);

                    unsafe
                    {
                        // Note that CFDataGetLength(cfData).ToInt32() will throw on
                        // too large of an input. Since a >2GB string is pretty unlikely,
                        // that's considered a good thing here.
                        return(Encoding.UTF8.GetString(
                                   CFDataGetBytePtr(cfData),
                                   CFDataGetLength(cfData).ToInt32()));
                    }
                }
                finally
                {
                    if (addedRef)
                    {
                        cfData.DangerousRelease();
                    }
                }
            }
        }
        internal static byte[] CFGetData(SafeCFDataHandle cfData)
        {
            bool addedRef = false;

            try
            {
                cfData.DangerousAddRef(ref addedRef);
                return(CFDataDangerousGetSpan(cfData).ToArray());
            }
            finally
            {
                if (addedRef)
                {
                    cfData.DangerousRelease();
                }
            }
        }