1use std::{
2 borrow::Cow,
3 ffi::{c_double, CStr},
4 fmt,
5};
6
7use libc::{c_char, c_uchar, c_ulong, c_void};
8
9use bitflags::bitflags;
10
11use crate::{
12 core_foundation::CFRange,
13 declare_CFType,
14 kernel::{Boolean, SInt32, UInt32, UInt8, UniChar},
15};
16
17use self::iter::Iter;
18
19use super::{
20 cf_array::CFArrayRef, kCFAllocatorDefault, CFAllocatorRef, CFArray, CFCharacterSetRef,
21 CFComparisonResult, CFData, CFDataRef, CFDictionaryRef, CFIndex, CFLocaleRef, CFOptionFlags,
22 CFTypeID, CFTypeObject,
23};
24
25pub type ConstStr255Param = *const c_uchar;
27
28pub type StringPtr = *mut c_uchar;
30
31pub type UTF32Char = u32;
33
34pub mod iter;
35
36#[derive(Debug)]
37#[repr(C)]
38pub struct __CFString(c_void);
39
40pub type CFStringRef = *const __CFString;
42
43pub type CFStringEncoding = u32;
45
46const KCF_STRING_INLINE_BUFFER_LENGTH: usize = 64;
47
48bitflags! {
49 pub struct KCFStringEncoding: CFStringEncoding {
51 const MAC_ROMAN = 0;
53 const WINDOWS_LATIN1 = 0x0500;
55 const ISOLATIN1 = 0x0201;
57 const NEXT_STEP_LATIN = 0x0B01;
59 const ASCII = 0x0600;
61 const UNICODE = 0x0100;
63 const UTF8 = 0x08000100;
65 const NON_LOSSY_ASCII = 0x0BFF;
67 const UTF16 = 0x0100;
69 const UTF16BE = 0x10000100;
71 const UTF16LE = 0x14000100;
73 const UTF32 = 0x0c000100;
75 const UTF32BE = 0x18000100;
77 const UTF32LE = 0x1c000100;
79
80 const MAC_JAPANESE = 1;
81 const MAC_CHINESE_TRAD = 2;
82 const MAC_KOREAN = 3;
83 const MAC_ARABIC = 4;
84 const MAC_HEBREW = 5;
85 const MAC_GREEK = 6;
86 const MAC_CYRILLIC = 7;
87 const MAC_DEVANAGARI = 9;
88 const MAC_GURMUKHI = 10;
89 const MAC_GUJARATI = 11;
90 const MAC_ORIYA = 12;
91 const MAC_BENGALI = 13;
92 const MAC_TAMIL = 14;
93 const MAC_TELUGU = 15;
94 const MAC_KANNADA = 16;
95 const MAC_MALAYALAM = 17;
96 const MAC_SINHALESE = 18;
97 const MAC_BURMESE = 19;
98 const MAC_KHMER = 20;
99 const MAC_THAI = 21;
100 const MAC_LAOTIAN = 22;
101 const MAC_GEORGIAN = 23;
102 const MAC_ARMENIAN = 24;
103 const MAC_CHINESE_SIMP = 25;
104 const MAC_TIBETAN = 26;
105 const MAC_MONGOLIAN = 27;
106 const MAC_ETHIOPIC = 28;
107 const MAC_CENTRAL_EUR_ROMAN = 29;
108 const MAC_VIETNAMESE = 30;
109 const MAC_EXT_ARABIC = 31;
110 const MAC_SYMBOL = 33;
112 const MAC_DINGBATS = 34;
113 const MAC_TURKISH = 35;
114 const MAC_CROATIAN = 36;
115 const MAC_ICELANDIC = 37;
116 const MAC_ROMANIAN = 38;
117 const MAC_CELTIC = 39;
118 const MAC_GAELIC = 40;
119 const MAC_FARSI = 0x8C; const MAC_UKRAINIAN = 0x98;
123 const MAC_INUIT = 0xEC;
125 const MAC_VT100 = 0xFC; const MAC_HFS = 0xFF; const ISO_LATIN2 = 0x0202; const ISO_LATIN3 = 0x0203; const ISO_LATIN4 = 0x0204; const ISO_LATIN_CYRILLIC = 0x0205; const ISO_LATIN_ARABIC = 0x0206; const ISO_LATIN_GREEK = 0x0207; const ISO_LATIN_HEBREW = 0x0208; const ISO_LATIN5 = 0x0209; const ISO_LATIN6 = 0x020A; const ISO_LATIN_THAI = 0x020B; const ISO_LATIN7 = 0x020D; const ISO_LATIN8 = 0x020E; const ISO_LATIN9 = 0x020F; const ISO_LATIN10 = 0x0210; const DOS_LATIN_US = 0x0400; const DOS_GREEK = 0x0405; const DOS_BALTIC_RIM = 0x0406; const DOS_LATIN1 = 0x0410; const DOS_GREEK1 = 0x0411; const DOS_LATIN2 = 0x0412; const DOS_CYRILLIC = 0x0413; const DOS_TURKISH = 0x0414; const DOS_PORTUGUESE = 0x0415; const DOS_ICELANDIC = 0x0416; const DOS_HEBREW = 0x0417; const DOS_CANADIAN_FRENCH = 0x0418; const DOS_ARABIC = 0x0419; const DOS_NORDIC = 0x041A; const DOS_RUSSIAN = 0x041B; const DOS_GREEK2 = 0x041C; const DOS_THAI = 0x041D; const DOS_JAPANESE = 0x0420; const DOS_CHINESE_SIMPLIFF = 0x0421; const DOS_KOREAN = 0x0422; const DOS_CHINESE_TRAD = 0x0423; const WINDOWS_LATIN2 = 0x0501; const WINDOWS_CYRILLIC = 0x0502; const WINDOWS_GREEK = 0x0503; const WINDOWS_LATIN5 = 0x0504; const WINDOWS_HEBREW = 0x0505; const WINDOWS_ARABICC = 0x0506; const WINDOWS_BALTIC_RIM = 0x0507; const WINDOWS_VIETNAMESE = 0x0508; const WINDOWS_KOREAN_JOHAB = 0x0510; const ANSEL = 0x0601; const JIS_X0201_76 = 0x0620;
182 const JIS_X0208_83 = 0x0621;
183 const JIS_X0208_90 = 0x0622;
184 const JIS_X0212_90 = 0x0623;
185 const JIS_C6226_78 = 0x0624;
186 const SHIFT_JIS_X0213 = 0x0628; const SHIFT_JIS_X0213_MEN_KU_TEN = 0x0629; const GB_2312_80 = 0x0630;
189 const GBK_95 = 0x0631; const GB_18030_2000 = 0x0632;
191 const KSC_5601_87 = 0x0640; const KSC_5601_92_JOHAB = 0x0641; const CNS_11643_92_P1 = 0x0651; const CNS_11643_92_P2 = 0x0652; const CNS_11643_92_P3 = 0x0653; const ISO_2022_JP = 0x0820;
199 const ISO_2022_JP_2 = 0x0821;
200 const ISO_2022_JP_1 = 0x0822; const ISO_2022_JP_3 = 0x0823; const ISO_2022_CN = 0x0830;
203 const ISO_2022_CN_EXT = 0x0831;
204 const ISO_2022_KR = 0x0840;
205
206 const EUC_JP = 0x0920; const EUC_CN = 0x0930; const EUC_TW = 0x0931; const EUC_KR = 0x0940; const SHIFT_JIS = 0x0A01; const KOI8_R = 0x0A02; const BIG5 = 0x0A03; const MAC_ROMAN_LATIN1 = 0x0A04; const HZ_GB_2312 = 0x0A05; const BIG5_HKSCS_1999 = 0x0A06; const VISCII = 0x0A07; const KOI8_U = 0x0A08; const BIG5_E = 0x0A09; const NEXT_STEP_JAPANESE = 0x0B02; const EBCDIC_US = 0x0C01; const EBCDIC_CP037 = 0x0C02; const UTF7 = 0x04000100; const UTF7_IMAP = 0x0A10; #[deprecated]
235 const SHIFT_JIS_X0213_00 = 0x0628; }
237}
238
239bitflags! {
240 pub struct CFStringCompareFlags: CFOptionFlags {
242 const DEFAULT = 0;
243 const CASE_INSENSITIVE = 1;
245 const BACKWARDS = 4;
247 const ANCHORED = 8;
249 const NONLITERAL = 16;
251 const LOCALIZED = 32;
253 const NUMERICALLY = 64;
255 const DIACRITIC_INSENSITIVE = 128;
257 const WIDTH_INSENSITIVE = 256;
259 const FORCED_ORDERING = 512;
261 }
262}
263
264declare_CFType! {
265 #[repr(C)]
267 CFString, CFStringRef
268}
269
270#[derive(Debug)]
272#[repr(C)]
273pub struct CFStringInlineBuffer {
274 pub buffer: [UniChar; KCF_STRING_INLINE_BUFFER_LENGTH],
275 pub string: CFStringRef,
276 pub direct_unichar_buffer: *const UniChar,
277 pub direct_c_string_buffer: *const c_char,
278 pub range_to_buffer: CFRange,
280 pub buffered_range_start: CFIndex,
282 pub buffered_range_end: CFIndex,
284}
285
286impl CFString {
287 pub fn with_str(s: &str) -> Self {
289 unsafe {
290 let cstr = CStr::from_ptr(s.as_ptr() as *const i8);
291
292 Self(CFStringCreateWithBytes(
293 kCFAllocatorDefault,
294 cstr.as_ptr() as *const u8,
295 s.len() as CFIndex,
296 0,
297 false,
298 ))
299 }
300 }
301
302 pub fn iter(&self) -> Iter<'_> {
304 Iter {
305 string: self,
306 index: 0,
307 }
308 }
309
310 pub unsafe fn create_array_by_separating_strings(
319 alloc: CFAllocatorRef,
320 string: CFStringRef,
321 separator: CFStringRef,
322 ) -> CFArray {
323 CFArray::create_with_ref(CFStringCreateArrayBySeparatingStrings(
324 alloc, string, separator,
325 ))
326 }
327
328 pub unsafe fn create_by_combining_strings(
334 alloc: CFAllocatorRef,
335 array: CFArrayRef,
336 separator: CFStringRef,
337 ) -> CFString {
338 CFString::create_with_ref(CFStringCreateByCombiningStrings(alloc, array, separator))
339 }
340
341 pub unsafe fn create_copy(alloc: CFAllocatorRef, string: CFStringRef) -> CFString {
347 CFString::create_with_ref(CFStringCreateCopy(alloc, string))
348 }
349
350 pub unsafe fn create_from_external_representation(
356 alloc: CFAllocatorRef,
357 data: CFDataRef,
358 encoding: CFStringEncoding,
359 ) -> CFString {
360 CFString::create_with_ref(CFStringCreateFromExternalRepresentation(
361 alloc, data, encoding,
362 ))
363 }
364
365 pub unsafe fn create_with_bytes(
371 alloc: CFAllocatorRef,
372 bytes: *const UInt8,
373 num_bytes: CFIndex,
374 encoding: CFStringEncoding,
375 is_external_representation: bool,
376 ) -> Self {
377 Self::create_with_ref(CFStringCreateWithBytes(
378 alloc,
379 bytes,
380 num_bytes,
381 encoding,
382 is_external_representation,
383 ))
384 }
385
386 pub unsafe fn create_with_bytes_no_copy(
392 alloc: CFAllocatorRef,
393 bytes: *const UInt8,
394 num_bytes: CFIndex,
395 encoding: CFStringEncoding,
396 is_external_representation: Boolean,
397 contents_deallocator: CFAllocatorRef,
398 ) -> CFString {
399 CFString::create_with_ref(CFStringCreateWithBytesNoCopy(
400 alloc,
401 bytes,
402 num_bytes,
403 encoding,
404 is_external_representation,
405 contents_deallocator,
406 ))
407 }
408
409 pub unsafe fn create_with_characters(
415 alloc: CFAllocatorRef,
416 chars: *const UniChar,
417 num_chars: CFIndex,
418 ) -> CFString {
419 CFString::create_with_ref(CFStringCreateWithCharacters(alloc, chars, num_chars))
420 }
421
422 pub unsafe fn create_with_characters_no_copy(
428 alloc: CFAllocatorRef,
429 chars: *const UniChar,
430 num_chars: CFIndex,
431 contents_deallocator: CFAllocatorRef,
432 ) -> CFString {
433 CFString::create_with_ref(CFStringCreateWithCharactersNoCopy(
434 alloc,
435 chars,
436 num_chars,
437 contents_deallocator,
438 ))
439 }
440
441 pub unsafe fn create_with_c_string(
447 alloc: CFAllocatorRef,
448 c_str: *const c_char,
449 encoding: CFStringEncoding,
450 ) -> CFString {
451 CFString::create_with_ref(CFStringCreateWithCString(alloc, c_str, encoding))
452 }
453
454 pub unsafe fn create_with_c_string_no_copy(
460 alloc: CFAllocatorRef,
461 c_str: *const c_char,
462 encoding: CFStringEncoding,
463 contents_deallocator: CFAllocatorRef,
464 ) -> CFString {
465 CFString::create_with_ref(CFStringCreateWithCStringNoCopy(
466 alloc,
467 c_str,
468 encoding,
469 contents_deallocator,
470 ))
471 }
472
473 pub unsafe fn create_with_format_and_arguments(
479 alloc: CFAllocatorRef,
480 format_options: CFDictionaryRef,
481 format: CFStringRef,
482 va_list: va_list::VaList,
483 ) -> CFString {
484 CFString::create_with_ref(CFStringCreateWithFormatAndArguments(
485 alloc,
486 format_options,
487 format,
488 va_list,
489 ))
490 }
491
492 pub unsafe fn create_with_pascal_string(
498 alloc: CFAllocatorRef,
499 p_str: ConstStr255Param,
500 encoding: CFStringEncoding,
501 ) -> CFString {
502 CFString::create_with_ref(CFStringCreateWithPascalString(alloc, p_str, encoding))
503 }
504
505 pub unsafe fn create_with_pascal_string_no_copy(
511 alloc: CFAllocatorRef,
512 p_str: ConstStr255Param,
513 encoding: CFStringEncoding,
514 contents_deallocator: CFAllocatorRef,
515 ) -> CFString {
516 CFString::create_with_ref(CFStringCreateWithPascalStringNoCopy(
517 alloc,
518 p_str,
519 encoding,
520 contents_deallocator,
521 ))
522 }
523
524 pub unsafe fn create_with_substring(
530 alloc: CFAllocatorRef,
531 s: CFStringRef,
532 range: CFRange,
533 ) -> CFString {
534 CFString::create_with_ref(CFStringCreateWithSubstring(alloc, s, range))
535 }
536
537 pub unsafe fn create_array_with_find_results(
546 alloc: CFAllocatorRef,
547 string: CFStringRef,
548 string_to_find: CFStringRef,
549 range_to_search: CFRange,
550 compare_options: CFStringCompareFlags,
551 ) -> CFArray {
552 CFArray::create_with_ref(CFStringCreateArrayWithFindResults(
553 alloc,
554 string,
555 string_to_find,
556 range_to_search,
557 compare_options,
558 ))
559 }
560
561 pub unsafe fn find(
567 string: CFStringRef,
568 string_to_find: CFStringRef,
569 compare_options: CFStringCompareFlags,
570 ) -> CFRange {
571 CFStringFind(string, string_to_find, compare_options)
572 }
573
574 pub unsafe fn find_character_from_set(
580 string: CFStringRef,
581 set: CFCharacterSetRef,
582 range_to_search: CFRange,
583 search_options: CFStringCompareFlags,
584 result: *mut CFRange,
585 ) -> bool {
586 CFStringFindCharacterFromSet(string, set, range_to_search, search_options, result)
587 }
588
589 pub unsafe fn find_with_options(
595 string: CFStringRef,
596 string_to_find: CFStringRef,
597 range_to_search: CFRange,
598 search_options: CFStringCompareFlags,
599 result: *mut CFRange,
600 ) -> bool {
601 CFStringFindWithOptions(
602 string,
603 string_to_find,
604 range_to_search,
605 search_options,
606 result,
607 )
608 }
609
610 pub unsafe fn find_with_options_and_locale(
616 string: CFStringRef,
617 string_to_find: CFStringRef,
618 range_to_search: CFRange,
619 search_options: CFStringCompareFlags,
620 locale: CFLocaleRef,
621 result: *mut CFRange,
622 ) -> bool {
623 CFStringFindWithOptionsAndLocale(
624 string,
625 string_to_find,
626 range_to_search,
627 search_options,
628 locale,
629 result,
630 )
631 }
632
633 pub unsafe fn get_line_bounds(
639 string: CFStringRef,
640 range: CFRange,
641 line_begin_index: *mut CFIndex,
642 line_end_index: *mut CFIndex,
643 contents_end_index: *mut CFIndex,
644 ) {
645 CFStringGetLineBounds(
646 string,
647 range,
648 line_begin_index,
649 line_end_index,
650 contents_end_index,
651 )
652 }
653
654 pub unsafe fn compare(
663 string1: CFStringRef,
664 string2: CFStringRef,
665 compare_options: CFStringCompareFlags,
666 ) -> CFComparisonResult {
667 CFStringCompare(string1, string2, compare_options)
668 }
669
670 pub unsafe fn compare_with_options(
676 string1: CFStringRef,
677 string2: CFStringRef,
678 range_to_compare: CFRange,
679 compare_options: CFStringCompareFlags,
680 ) -> CFComparisonResult {
681 CFStringCompareWithOptions(string1, string2, range_to_compare, compare_options)
682 }
683
684 pub unsafe fn compare_with_options_and_locale(
690 string1: CFStringRef,
691 string2: CFStringRef,
692 range_to_compare: CFRange,
693 compare_options: CFStringCompareFlags,
694 locale: CFLocaleRef,
695 ) -> CFComparisonResult {
696 CFStringCompareWithOptionsAndLocale(
697 string1,
698 string2,
699 range_to_compare,
700 compare_options,
701 locale,
702 )
703 }
704
705 pub unsafe fn has_prefix(string: CFStringRef, prefix: CFStringRef) -> bool {
711 CFStringHasPrefix(string, prefix)
712 }
713
714 pub unsafe fn has_suffix(string: CFStringRef, suffix: CFStringRef) -> bool {
720 CFStringHasSuffix(string, suffix)
721 }
722
723 pub unsafe fn create_external_representation(
732 alloc: CFStringRef,
733 string: CFStringEncoding,
734 encoding: CFStringEncoding,
735 loss_byte: UInt8,
736 ) -> CFData {
737 CFData::create_with_ref(CFStringCreateExternalRepresentation(
738 alloc, string, encoding, loss_byte,
739 ))
740 }
741
742 #[allow(clippy::too_many_arguments)]
748 pub unsafe fn get_bytes(
749 string: CFStringRef,
750 range: CFRange,
751 encoding: CFStringEncoding,
752 loss_byte: UInt8,
753 is_external_representation: Boolean,
754 buffer: *mut UInt8,
755 max_buf_len: CFIndex,
756 used_buf_len: *mut CFIndex,
757 ) -> CFIndex {
758 CFStringGetBytes(
759 string,
760 range,
761 encoding,
762 loss_byte,
763 is_external_representation,
764 buffer,
765 max_buf_len,
766 used_buf_len,
767 )
768 }
769
770 pub unsafe fn get_character_at_index(string: CFStringRef, idx: CFIndex) -> UniChar {
776 CFStringGetCharacterAtIndex(string, idx)
777 }
778
779 pub unsafe fn get_characters(string: CFStringRef, range: CFRange, buffer: &mut [UniChar]) {
785 CFStringGetCharacters(string, range, buffer)
786 }
787
788 pub unsafe fn get_characters_ptr(string: CFStringRef) -> *const UniChar {
794 CFStringGetCharactersPtr(string)
795 }
796
797 pub unsafe fn get_character_from_inline_buffer(
803 buf: *mut CFStringInlineBuffer,
804 idx: CFIndex,
805 ) -> UniChar {
806 CFStringGetCharacterFromInlineBuffer(buf, idx)
807 }
808
809 pub unsafe fn get_c_string(
815 string: CFStringRef,
816 buffer: &mut [c_char],
817 buffer_size: CFIndex,
818 encoding: CFStringEncoding,
819 ) -> bool {
820 CFStringGetCString(string, buffer, buffer_size, encoding)
821 }
822
823 pub unsafe fn get_c_string_ptr(
829 string: CFStringRef,
830 encoding: CFStringEncoding,
831 ) -> *const c_char {
832 CFStringGetCStringPtr(string, encoding)
833 }
834
835 pub unsafe fn get_length(string: CFStringRef) -> CFIndex {
841 CFStringGetLength(string)
842 }
843
844 pub unsafe fn get_pascal_string(
850 string: CFStringRef,
851 buffer: StringPtr,
852 buffer_size: CFIndex,
853 encoding: CFStringEncoding,
854 ) -> bool {
855 CFStringGetPascalString(string, buffer, buffer_size, encoding)
856 }
857
858 pub unsafe fn get_pascal_string_ptr(
864 string: CFStringRef,
865 encoding: CFStringEncoding,
866 ) -> ConstStr255Param {
867 CFStringGetPascalStringPtr(string, encoding)
868 }
869
870 pub unsafe fn get_range_of_composed_characters_at_index(
876 string: CFStringRef,
877 index: CFIndex,
878 ) -> CFRange {
879 CFStringGetRangeOfComposedCharactersAtIndex(string, index)
880 }
881
882 pub unsafe fn init_inline_buffer(
888 s: CFStringRef,
889 buf: *mut CFStringInlineBuffer,
890 range: CFRange,
891 ) {
892 CFStringInitInlineBuffer(s, buf, range)
893 }
894
895 pub unsafe fn get_hyphenation_location_before_index(
904 string: CFStringRef,
905 location: CFIndex,
906 limit_range: CFRange,
907 options: CFOptionFlags,
908 locale: CFLocaleRef,
909 character: *mut UTF32Char,
910 ) -> CFIndex {
911 CFStringGetHyphenationLocationBeforeIndex(
912 string,
913 location,
914 limit_range,
915 options,
916 locale,
917 character,
918 )
919 }
920
921 pub unsafe fn is_hyphenation_available_for_locale(locale: CFLocaleRef) -> Boolean {
927 CFStringIsHyphenationAvailableForLocale(locale)
928 }
929
930 pub unsafe fn convert_encoding_to_ianachar_set_name(encoding: CFStringEncoding) -> CFString {
939 CFString::create_with_ref(CFStringConvertEncodingToIANACharSetName(encoding))
940 }
941
942 pub unsafe fn convert_encoding_to_nsstring_encoding(encoding: CFStringEncoding) -> c_ulong {
948 CFStringConvertEncodingToNSStringEncoding(encoding)
949 }
950
951 pub unsafe fn convert_encoding_to_windows_codepage(encoding: CFStringEncoding) -> UInt32 {
957 CFStringConvertEncodingToWindowsCodepage(encoding)
958 }
959
960 pub unsafe fn convert_iana_char_set_name_to_encodingng(
966 string: CFStringRef,
967 ) -> CFStringEncoding {
968 CFStringConvertIANACharSetNameToEncoding(string)
969 }
970
971 pub unsafe fn convert_nsstring_encoding_to_encodingng(encoding: c_ulong) -> CFStringEncoding {
977 CFStringConvertNSStringEncodingToEncoding(encoding)
978 }
979
980 pub unsafe fn convert_windows_codepage_to_encoding(codepage: UInt32) -> CFStringEncoding {
986 CFStringConvertWindowsCodepageToEncoding(codepage)
987 }
988
989 pub unsafe fn get_fastest_encoding(string: CFStringRef) -> CFStringEncoding {
995 CFStringGetFastestEncoding(string)
996 }
997
998 pub unsafe fn get_list_of_available_encodings() -> *const CFStringEncoding {
1004 CFStringGetListOfAvailableEncodings()
1005 }
1006
1007 pub unsafe fn get_maximum_size_for_encoding(
1013 length: CFIndex,
1014 encoding: CFStringEncoding,
1015 ) -> CFIndex {
1016 CFStringGetMaximumSizeForEncoding(length, encoding)
1017 }
1018
1019 pub unsafe fn get_most_compatible_mac_string_encoding(
1025 encoding: CFStringEncoding,
1026 ) -> CFStringEncoding {
1027 CFStringGetMostCompatibleMacStringEncoding(encoding)
1028 }
1029
1030 pub unsafe fn get_name_of_encoding(encoding: CFStringEncoding) -> CFString {
1036 CFString::create_with_ref(CFStringGetNameOfEncoding(encoding))
1037 }
1038
1039 pub unsafe fn get_smallest_encoding(string: CFStringRef) -> CFStringEncoding {
1045 CFStringGetSmallestEncoding(string)
1046 }
1047
1048 pub unsafe fn get_system_encoding() -> CFStringEncoding {
1054 CFStringGetSystemEncoding()
1055 }
1056
1057 pub unsafe fn is_encoding_available(encoding: CFStringEncoding) -> bool {
1063 CFStringIsEncodingAvailable(encoding)
1064 }
1065
1066 pub unsafe fn get_double_value(s: CFStringRef) -> c_double {
1075 CFStringGetDoubleValue(s)
1076 }
1077
1078 pub unsafe fn get_int_value(s: CFStringRef) -> SInt32 {
1084 CFStringGetIntValue(s)
1085 }
1086
1087 pub unsafe fn cf_show_str(s: CFStringRef) {
1096 CFShowStr(s)
1097 }
1098
1099 pub unsafe fn get_type_id() -> CFTypeID {
1105 CFStringGetTypeID()
1106 }
1107
1108 pub unsafe fn create_with_file_system_representation(
1117 alloc: CFAllocatorRef,
1118 buffer: *const c_char,
1119 ) -> CFString {
1120 CFString::create_with_ref(CFStringCreateWithFileSystemRepresentation(alloc, buffer))
1121 }
1122
1123 pub unsafe fn get_file_system_representation(
1129 string: CFStringRef,
1130 buffer: &mut [c_char],
1131 max_buf_len: CFIndex,
1132 ) -> Boolean {
1133 CFStringGetFileSystemRepresentation(string, buffer, max_buf_len)
1134 }
1135
1136 pub unsafe fn get_maximum_size_of_file_system_representation(string: CFStringRef) -> CFIndex {
1142 CFStringGetMaximumSizeOfFileSystemRepresentation(string)
1143 }
1144
1145 pub unsafe fn get_paragraph_bounds(
1154 string: CFStringRef,
1155 range: CFRange,
1156 par_begin_index: *mut CFIndex,
1157 par_end_index: *mut CFIndex,
1158 contents_end_index: *mut CFIndex,
1159 ) {
1160 CFStringGetParagraphBounds(
1161 string,
1162 range,
1163 par_begin_index,
1164 par_end_index,
1165 contents_end_index,
1166 )
1167 }
1168
1169 pub unsafe fn get_long_character_for_surrogate_pair(
1178 surrogate_high: UniChar,
1179 surrogate_low: UniChar,
1180 ) -> UTF32Char {
1181 CFStringGetLongCharacterForSurrogatePair(surrogate_high, surrogate_low)
1182 }
1183
1184 pub unsafe fn get_surrogate_pair_for_long_character(
1190 character: UTF32Char,
1191 surrogates: &mut [UniChar],
1192 ) -> Boolean {
1193 CFStringGetSurrogatePairForLongCharacter(character, surrogates)
1194 }
1195
1196 pub unsafe fn is_surrogate_high_character(character: UniChar) -> Boolean {
1202 CFStringIsSurrogateHighCharacter(character)
1203 }
1204
1205 pub unsafe fn is_surrogate_low_character(character: UniChar) -> Boolean {
1211 CFStringIsSurrogateLowCharacter(character)
1212 }
1213}
1214
1215impl<'a> From<&'a CFString> for Cow<'a, str> {
1216 fn from(cf_str: &'a CFString) -> Cow<'a, str> {
1217 unsafe {
1218 let c_string =
1220 CFStringGetCStringPtr(cf_str.get_internal_object(), KCFStringEncoding::UTF8.bits);
1221 match c_string.is_null() {
1222 true => {
1223 let char_len = CFString::get_length(cf_str.get_internal_object());
1224
1225 let mut bytes_required: CFIndex = 0;
1227 let _ = CFStringGetBytes(
1228 cf_str.get_internal_object(),
1229 CFRange {
1230 location: 0,
1231 length: char_len,
1232 },
1233 KCFStringEncoding::UTF8.bits,
1234 0,
1235 false,
1236 std::ptr::null_mut(),
1237 0,
1238 &mut bytes_required,
1239 );
1240
1241 let mut buffer = vec![b'\x00'; bytes_required as usize];
1243
1244 let mut bytes_used: CFIndex = 0;
1245 let chars_written = CFStringGetBytes(
1246 cf_str.get_internal_object(),
1247 CFRange {
1248 location: 0,
1249 length: char_len,
1250 },
1251 KCFStringEncoding::UTF8.bits,
1252 0,
1253 false,
1254 buffer.as_mut_ptr(),
1255 buffer.len() as CFIndex,
1256 &mut bytes_used,
1257 );
1258 assert_eq!(chars_written, char_len);
1259
1260 assert_eq!(bytes_used, buffer.len() as CFIndex);
1263 Cow::Owned(String::from_utf8_unchecked(buffer))
1264 }
1265 _ => {
1266 let c_str = CStr::from_ptr(c_string);
1267 String::from_utf8_lossy(c_str.to_bytes())
1268 }
1269 }
1270 }
1271 }
1272}
1273
1274impl<'a> IntoIterator for &'a CFString {
1275 type Item = UniChar;
1276 type IntoIter = Iter<'a>;
1277
1278 fn into_iter(self) -> Self::IntoIter {
1279 self.iter()
1280 }
1281}
1282
1283impl fmt::Display for CFString {
1284 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1285 fmt.write_str(&Cow::from(self))
1286 }
1287}
1288
1289impl fmt::Debug for CFString {
1290 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1291 write!(f, "\"{self}\"")
1292 }
1293}
1294
1295impl PartialEq for CFString {
1296 fn eq(&self, other: &Self) -> bool {
1297 unsafe {
1298 matches!(
1299 CFStringCompare(
1300 self.get_internal_object(),
1301 other.get_internal_object(),
1302 CFStringCompareFlags::DEFAULT,
1303 ),
1304 CFComparisonResult::KCFCompareEqualTo
1305 )
1306 }
1307 }
1308}
1309
1310impl Eq for CFString {}
1311
1312impl PartialEq<&str> for CFString {
1313 fn eq(&self, other: &&str) -> bool {
1314 &self.to_string() == other
1315 }
1316}
1317
1318extern "C" {
1319 pub fn CFStringCreateArrayBySeparatingStrings(
1320 alloc: CFAllocatorRef,
1321 string: CFStringRef,
1322 separator: CFStringRef,
1323 ) -> CFArrayRef;
1324
1325 pub fn CFStringCreateByCombiningStrings(
1326 alloc: CFAllocatorRef,
1327 array: CFArrayRef,
1328 separator: CFStringRef,
1329 ) -> CFStringRef;
1330
1331 pub fn CFStringCreateCopy(alloc: CFAllocatorRef, string: CFStringRef) -> CFStringRef;
1332
1333 pub fn CFStringCreateFromExternalRepresentation(
1334 alloc: CFAllocatorRef,
1335 data: CFDataRef,
1336 encoding: CFStringEncoding,
1337 ) -> CFStringRef;
1338
1339 pub fn CFStringCreateWithBytes(
1340 alloc: CFAllocatorRef,
1341 bytes: *const UInt8,
1342 num_bytes: CFIndex,
1343 encoding: CFStringEncoding,
1344 is_external_representation: Boolean,
1345 ) -> CFStringRef;
1346
1347 pub fn CFStringCreateWithBytesNoCopy(
1348 alloc: CFAllocatorRef,
1349 bytes: *const UInt8,
1350 num_bytes: CFIndex,
1351 encoding: CFStringEncoding,
1352 is_external_representation: Boolean,
1353 contents_deallocator: CFAllocatorRef,
1354 ) -> CFStringRef;
1355
1356 pub fn CFStringCreateWithCharacters(
1357 alloc: CFAllocatorRef,
1358 chars: *const UniChar,
1359 num_chars: CFIndex,
1360 ) -> CFStringRef;
1361
1362 pub fn CFStringCreateWithCharactersNoCopy(
1363 alloc: CFAllocatorRef,
1364 chars: *const UniChar,
1365 num_chars: CFIndex,
1366 contents_deallocator: CFAllocatorRef,
1367 ) -> CFStringRef;
1368
1369 pub fn CFStringCreateWithCString(
1370 alloc: CFAllocatorRef,
1371 c_str: *const c_char,
1372 encoding: CFStringEncoding,
1373 ) -> CFStringRef;
1374
1375 pub fn CFStringCreateWithCStringNoCopy(
1376 alloc: CFAllocatorRef,
1377 c_str: *const c_char,
1378 encoding: CFStringEncoding,
1379 contents_deallocator: CFAllocatorRef,
1380 ) -> CFStringRef;
1381
1382 pub fn CFStringCreateWithFormat(
1383 alloc: CFAllocatorRef,
1384 format_options: CFDictionaryRef,
1385 format: CFStringRef,
1386 ...
1387 ) -> CFStringRef;
1388
1389 pub fn CFStringCreateWithFormatAndArguments(
1390 alloc: CFAllocatorRef,
1391 format_options: CFDictionaryRef,
1392 format: CFStringRef,
1393 va_list: va_list::VaList,
1394 ) -> CFStringRef;
1395
1396 pub fn CFStringCreateWithPascalString(
1397 alloc: CFAllocatorRef,
1398 p_str: ConstStr255Param,
1399 encoding: CFStringEncoding,
1400 ) -> CFStringRef;
1401
1402 pub fn CFStringCreateWithPascalStringNoCopy(
1403 alloc: CFAllocatorRef,
1404 p_str: ConstStr255Param,
1405 encoding: CFStringEncoding,
1406 contents_deallocator: CFAllocatorRef,
1407 ) -> CFStringRef;
1408
1409 pub fn CFStringCreateWithSubstring(
1410 alloc: CFAllocatorRef,
1411 s: CFStringRef,
1412 range: CFRange,
1413 ) -> CFStringRef;
1414
1415 pub fn CFStringCreateArrayWithFindResults(
1416 alloc: CFAllocatorRef,
1417 string: CFStringRef,
1418 string_to_find: CFStringRef,
1419 range_to_search: CFRange,
1420 compare_options: CFStringCompareFlags,
1421 ) -> CFArrayRef;
1422
1423 pub fn CFStringFind(
1424 string: CFStringRef,
1425 string_to_find: CFStringRef,
1426 compare_options: CFStringCompareFlags,
1427 ) -> CFRange;
1428
1429 pub fn CFStringFindCharacterFromSet(
1430 string: CFStringRef,
1431 set: CFCharacterSetRef,
1432 range_to_search: CFRange,
1433 search_options: CFStringCompareFlags,
1434 result: *mut CFRange,
1435 ) -> bool;
1436
1437 pub fn CFStringFindWithOptions(
1438 string: CFStringRef,
1439 string_to_find: CFStringRef,
1440 range_to_search: CFRange,
1441 search_options: CFStringCompareFlags,
1442 result: *mut CFRange,
1443 ) -> bool;
1444
1445 pub fn CFStringFindWithOptionsAndLocale(
1446 string: CFStringRef,
1447 string_to_find: CFStringRef,
1448 range_to_search: CFRange,
1449 search_options: CFStringCompareFlags,
1450 locale: CFLocaleRef,
1451 result: *mut CFRange,
1452 ) -> bool;
1453
1454 pub fn CFStringGetLineBounds(
1455 string: CFStringRef,
1456 range: CFRange,
1457 line_begin_index: *mut CFIndex,
1458 line_end_index: *mut CFIndex,
1459 contents_end_index: *mut CFIndex,
1460 );
1461
1462 pub fn CFStringCompare(
1463 string1: CFStringRef,
1464 string2: CFStringRef,
1465 compare_options: CFStringCompareFlags,
1466 ) -> CFComparisonResult;
1467
1468 pub fn CFStringCompareWithOptions(
1469 string1: CFStringRef,
1470 string2: CFStringRef,
1471 range_to_compare: CFRange,
1472 compare_options: CFStringCompareFlags,
1473 ) -> CFComparisonResult;
1474
1475 pub fn CFStringCompareWithOptionsAndLocale(
1476 string1: CFStringRef,
1477 string2: CFStringRef,
1478 range_to_compare: CFRange,
1479 compare_options: CFStringCompareFlags,
1480 locale: CFLocaleRef,
1481 ) -> CFComparisonResult;
1482
1483 pub fn CFStringHasPrefix(string: CFStringRef, prefix: CFStringRef) -> Boolean;
1484
1485 pub fn CFStringHasSuffix(string: CFStringRef, suffix: CFStringRef) -> Boolean;
1486
1487 pub fn CFStringCreateExternalRepresentation(
1488 alloc: CFStringRef,
1489 string: CFStringEncoding,
1490 encoding: CFStringEncoding,
1491 loss_byte: UInt8,
1492 ) -> CFDataRef;
1493
1494 pub fn CFStringGetBytes(
1495 string: CFStringRef,
1496 range: CFRange,
1497 encoding: CFStringEncoding,
1498 loss_byte: UInt8,
1499 is_external_representation: Boolean,
1500 buffer: *mut UInt8,
1501 max_buf_len: CFIndex,
1502 used_buf_len: *mut CFIndex,
1503 ) -> CFIndex;
1504
1505 pub fn CFStringGetCharacterAtIndex(string: CFStringRef, idx: CFIndex) -> UniChar;
1506
1507 pub fn CFStringGetCharacters(string: CFStringRef, range: CFRange, buffer: &mut [UniChar]);
1508
1509 pub fn CFStringGetCharactersPtr(string: CFStringRef) -> *const UniChar;
1510
1511 pub fn CFStringGetCharacterFromInlineBuffer(
1512 buf: *mut CFStringInlineBuffer,
1513 idx: CFIndex,
1514 ) -> UniChar;
1515
1516 pub fn CFStringGetCString(
1517 string: CFStringRef,
1518 buffer: &mut [c_char],
1519 buffer_size: CFIndex,
1520 encoding: CFStringEncoding,
1521 ) -> Boolean;
1522
1523 pub fn CFStringGetCStringPtr(string: CFStringRef, encoding: CFStringEncoding) -> *const c_char;
1524
1525 pub fn CFStringGetLength(string: CFStringRef) -> CFIndex;
1526
1527 pub fn CFStringGetPascalString(
1528 string: CFStringRef,
1529 buffer: StringPtr,
1530 buffer_size: CFIndex,
1531 encoding: CFStringEncoding,
1532 ) -> Boolean;
1533
1534 pub fn CFStringGetPascalStringPtr(
1535 string: CFStringRef,
1536 encoding: CFStringEncoding,
1537 ) -> ConstStr255Param;
1538
1539 pub fn CFStringGetRangeOfComposedCharactersAtIndex(
1540 string: CFStringRef,
1541 index: CFIndex,
1542 ) -> CFRange;
1543
1544 pub fn CFStringInitInlineBuffer(s: CFStringRef, buf: *mut CFStringInlineBuffer, range: CFRange);
1545
1546 pub fn CFStringGetHyphenationLocationBeforeIndex(
1547 string: CFStringRef,
1548 location: CFIndex,
1549 limit_range: CFRange,
1550 options: CFOptionFlags,
1551 locale: CFLocaleRef,
1552 character: *mut UTF32Char,
1553 ) -> CFIndex;
1554
1555 pub fn CFStringIsHyphenationAvailableForLocale(locale: CFLocaleRef) -> Boolean;
1556
1557 pub fn CFStringConvertEncodingToIANACharSetName(encoding: CFStringEncoding) -> CFStringRef;
1558
1559 pub fn CFStringConvertEncodingToNSStringEncoding(encoding: CFStringEncoding) -> c_ulong;
1560
1561 pub fn CFStringConvertEncodingToWindowsCodepage(encoding: CFStringEncoding) -> UInt32;
1562
1563 pub fn CFStringConvertIANACharSetNameToEncoding(string: CFStringRef) -> CFStringEncoding;
1564
1565 pub fn CFStringConvertNSStringEncodingToEncoding(encoding: c_ulong) -> CFStringEncoding;
1566
1567 pub fn CFStringConvertWindowsCodepageToEncoding(codepage: UInt32) -> CFStringEncoding;
1568
1569 pub fn CFStringGetFastestEncoding(string: CFStringRef) -> CFStringEncoding;
1570
1571 pub fn CFStringGetListOfAvailableEncodings() -> *const CFStringEncoding;
1572
1573 pub fn CFStringGetMaximumSizeForEncoding(
1574 length: CFIndex,
1575 encoding: CFStringEncoding,
1576 ) -> CFIndex;
1577
1578 pub fn CFStringGetMostCompatibleMacStringEncoding(
1579 encoding: CFStringEncoding,
1580 ) -> CFStringEncoding;
1581
1582 pub fn CFStringGetNameOfEncoding(encoding: CFStringEncoding) -> CFStringRef;
1583
1584 pub fn CFStringGetSmallestEncoding(string: CFStringRef) -> CFStringEncoding;
1585
1586 pub fn CFStringGetSystemEncoding() -> CFStringEncoding;
1587
1588 pub fn CFStringIsEncodingAvailable(encoding: CFStringEncoding) -> Boolean;
1589
1590 pub fn CFStringGetDoubleValue(s: CFStringRef) -> c_double;
1591
1592 pub fn CFStringGetIntValue(s: CFStringRef) -> SInt32;
1593
1594 pub fn CFShowStr(s: CFStringRef);
1595
1596 pub fn CFStringGetTypeID() -> CFTypeID;
1597
1598 pub fn CFStringCreateWithFileSystemRepresentation(
1599 alloc: CFAllocatorRef,
1600 buffer: *const c_char,
1601 ) -> CFStringRef;
1602
1603 pub fn CFStringGetFileSystemRepresentation(
1604 string: CFStringRef,
1605 buffer: &mut [c_char],
1606 max_buf_len: CFIndex,
1607 ) -> Boolean;
1608
1609 pub fn CFStringGetMaximumSizeOfFileSystemRepresentation(string: CFStringRef) -> CFIndex;
1610
1611 pub fn CFStringGetParagraphBounds(
1612 string: CFStringRef,
1613 range: CFRange,
1614 par_begin_index: *mut CFIndex,
1615 par_end_index: *mut CFIndex,
1616 contents_end_index: *mut CFIndex,
1617 );
1618
1619 pub fn CFStringGetLongCharacterForSurrogatePair(
1620 surrogate_high: UniChar,
1621 surrogate_low: UniChar,
1622 ) -> UTF32Char;
1623
1624 pub fn CFStringGetSurrogatePairForLongCharacter(
1625 character: UTF32Char,
1626 surrogates: &mut [UniChar],
1627 ) -> Boolean;
1628
1629 pub fn CFStringIsSurrogateHighCharacter(character: UniChar) -> Boolean;
1630
1631 pub fn CFStringIsSurrogateLowCharacter(character: UniChar) -> Boolean;
1632}
1633
1634#[cfg(test)]
1635mod tests {
1636
1637 use crate::core_foundation::{kCFAllocatorDefault, CFRange, CFTypeObject};
1638
1639 use super::{CFString, KCFStringEncoding};
1640
1641 #[test]
1642 fn test_to_string() {
1643 let original = "The quick brown fox jumped over the slow lazy dog.";
1644 let cfstr = CFString::with_str(original);
1645 let converted = cfstr.to_string();
1646 assert_eq!(converted, original);
1647 }
1648
1649 #[test]
1650 fn test_index() {
1651 let s = "Hello World!";
1652 let native_str = CFString::with_str(s);
1653
1654 for i in 0..s.len() {
1655 assert_eq!(
1656 s.chars().nth(i).unwrap(),
1657 native_str.iter().nth(i).unwrap() as u8 as char
1658 );
1659 }
1660 }
1661
1662 #[test]
1663 fn test_cmp_cf_string() {
1664 let native_str1 = CFString::with_str("Hello World!");
1665 let native_str2 = CFString::with_str("Hello World!");
1666 let native_str3 = CFString::with_str("Goodbye World!");
1667
1668 assert_eq!(native_str1, native_str2);
1669 assert_ne!(native_str1, native_str3);
1670 }
1671
1672 #[test]
1673 fn test_cmp_string() {
1674 let s = "Hello World!";
1675 let native_str = CFString::with_str(s);
1676
1677 assert_eq!(native_str, s);
1678 }
1679
1680 #[test]
1681 fn test_create_with_bytes() {
1682 unsafe {
1683 let original = "The quick brown fox jumped over the slow lazy dog.";
1684 let cfstr = CFString::create_with_bytes(
1685 kCFAllocatorDefault,
1686 original.as_ptr(),
1687 original.bytes().len() as u64,
1688 KCFStringEncoding::UTF8.bits,
1689 false,
1690 );
1691
1692 assert_eq!(cfstr, original);
1693 }
1694 }
1695
1696 #[test]
1697 fn test_get_characters() {
1698 let original = "The quick brown fox jumped over the slow lazy dog.";
1699 let cfstr = CFString::with_str(original);
1700
1701 unsafe {
1702 let mut buffer = vec![0; original.len()];
1703
1704 CFString::get_characters(
1705 cfstr.get_internal_object(),
1706 CFRange {
1707 location: 0,
1708 length: CFString::get_length(cfstr.get_internal_object()),
1709 },
1710 &mut buffer,
1711 );
1712
1713 assert_eq!(original, String::from_utf16(&buffer).unwrap())
1714 }
1715 }
1716
1717 #[test]
1718 fn test_get_length() {
1719 let original = "The quick brown fox jumped over the slow lazy dog.";
1720 let cfstr = CFString::with_str(original);
1721
1722 unsafe {
1723 assert_eq!(
1724 original.len(),
1725 CFString::get_length(cfstr.get_internal_object()) as usize
1726 )
1727 }
1728 }
1729}