1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#![allow(non_upper_case_globals, non_camel_case_types)]

extern crate libc;

use std::ffi::CString;
use std::ptr;
use std::str;

pub type CFRef = *mut ::std::os::raw::c_void;

pub type CFIndex = ::std::os::raw::c_long;
pub type CFTimeInterval = f64;

#[doc(hidden)]
pub enum CFError {}

pub type CFMutableArrayRef = CFRef;
pub type CFURLRef = CFRef;
pub type CFErrorRef = *mut CFError;
pub type CFStringRef = CFRef;
pub type CFRunLoopRef = CFRef;

pub const NULL: CFRef = 0 as CFRef;
pub const NULL_REF_PTR: *mut CFRef = 0 as *mut CFRef;

pub type CFURLPathStyle = ::std::os::raw::c_uint;

pub const kCFAllocatorDefault: CFRef = NULL;
pub const kCFURLPOSIXPathStyle: CFURLPathStyle = 0;
pub const kCFURLHFSPathStyle: CFURLPathStyle = 1;
pub const kCFURLWindowsPathStyle: CFURLPathStyle = 2;

pub const kCFStringEncodingUTF8: u32 = 0x08000100;
pub type CFStringEncoding = u32;

pub const kCFCompareEqualTo: i32 = 0;
pub type CFComparisonResult = i32;

// MacOS uses Case Insensitive path
pub const kCFCompareCaseInsensitive: u32 = 1;
pub type CFStringCompareFlags = u32;

// CFStringEncoding
pub type kCFStringEncoding = u32;
pub const UTF8: kCFStringEncoding = 0x08000100;

#[repr(C)]
pub struct CFArrayCallBacks {
    version: CFIndex,
    retain: CFRef,
    release: CFRef,
    cp: CFRef,
    equal: CFRef,
}
//impl Clone for CFArrayCallBacks { }

#[link(name = "CoreServices", kind = "framework")]
extern "C" {
    pub static kCFTypeArrayCallBacks: CFArrayCallBacks;
    pub static kCFRunLoopDefaultMode: CFStringRef;

    pub fn CFRelease(res: CFRef);
    pub fn CFShow(res: CFRef);
    pub fn CFCopyDescription(cf: CFRef) -> CFStringRef;

    pub fn CFRunLoopRun();
    pub fn CFRunLoopStop(run_loop: CFRunLoopRef);
    pub fn CFRunLoopGetCurrent() -> CFRunLoopRef;

    pub fn CFArrayCreateMutable(
        allocator: CFRef,
        capacity: CFIndex,
        callbacks: *const CFArrayCallBacks,
    ) -> CFMutableArrayRef;
    pub fn CFArrayInsertValueAtIndex(arr: CFMutableArrayRef, position: CFIndex, element: CFRef);
    pub fn CFArrayAppendValue(aff: CFMutableArrayRef, element: CFRef);
    pub fn CFArrayGetCount(arr: CFMutableArrayRef) -> CFIndex;
    pub fn CFArrayGetValueAtIndex(arr: CFMutableArrayRef, index: CFIndex) -> CFRef;

    pub fn CFURLCreateFileReferenceURL(
        allocator: CFRef,
        url: CFURLRef,
        err: *mut CFErrorRef,
    ) -> CFURLRef;
    pub fn CFURLCreateFilePathURL(
        allocator: CFRef,
        url: CFURLRef,
        err: *mut CFErrorRef,
    ) -> CFURLRef;
    pub fn CFURLCreateFromFileSystemRepresentation(
        allocator: CFRef,
        path: *const ::std::os::raw::c_char,
        len: CFIndex,
        is_directory: bool,
    ) -> CFURLRef;
    pub fn CFURLCopyAbsoluteURL(res: CFURLRef) -> CFURLRef;
    pub fn CFURLCopyLastPathComponent(res: CFURLRef) -> CFStringRef;
    pub fn CFURLCreateCopyDeletingLastPathComponent(allocator: CFRef, url: CFURLRef) -> CFURLRef;
    pub fn CFURLCreateCopyAppendingPathComponent(
        allocation: CFRef,
        url: CFURLRef,
        path: CFStringRef,
        is_directory: bool,
    ) -> CFURLRef;
    pub fn CFURLCopyFileSystemPath(anUrl: CFURLRef, path_style: CFURLPathStyle) -> CFStringRef;

    pub fn CFURLResourceIsReachable(res: CFURLRef, err: *mut CFErrorRef) -> bool;

    pub fn CFShowStr(str: CFStringRef);
    pub fn CFStringGetCString(
        theString: CFStringRef,
        buffer: *mut ::std::os::raw::c_char,
        buffer_size: CFIndex,
        encoding: CFStringEncoding,
    ) -> bool;
    pub fn CFStringGetCStringPtr(
        theString: CFStringRef,
        encoding: CFStringEncoding,
    ) -> *const ::std::os::raw::c_char;
    pub fn CFStringCreateWithCString(
        alloc: CFRef,
        source: *const ::std::os::raw::c_char,
        encoding: kCFStringEncoding,
    ) -> CFStringRef;

    pub fn CFStringCompare(
        theString1: CFStringRef,
        theString2: CFStringRef,
        compareOptions: CFStringCompareFlags,
    ) -> CFComparisonResult;
    pub fn CFArrayRemoveValueAtIndex(theArray: CFMutableArrayRef, idx: CFIndex);

}

pub unsafe fn str_path_to_cfstring_ref(source: &str, err: &mut CFErrorRef) -> CFStringRef {
    let c_path = CString::new(source).unwrap();
    let c_len = libc::strlen(c_path.as_ptr());
    let mut url = CFURLCreateFromFileSystemRepresentation(
        kCFAllocatorDefault,
        c_path.as_ptr(),
        c_len as CFIndex,
        false,
    );
    let mut placeholder = CFURLCopyAbsoluteURL(url);
    CFRelease(url);

    let imaginary: CFRef = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);

    while !CFURLResourceIsReachable(placeholder, ptr::null_mut()) {
        let child = CFURLCopyLastPathComponent(placeholder);
        CFArrayInsertValueAtIndex(imaginary, 0, child);
        CFRelease(child);

        url = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, placeholder);
        CFRelease(placeholder);
        placeholder = url;
    }

    url = CFURLCreateFileReferenceURL(kCFAllocatorDefault, placeholder, err);
    if !err.is_null() {
        return ptr::null_mut();
    }

    CFRelease(placeholder);
    placeholder = CFURLCreateFilePathURL(kCFAllocatorDefault, url, err);
    if !err.is_null() {
        return ptr::null_mut();
    }

    CFRelease(url);

    if imaginary != kCFAllocatorDefault {
        let mut count = 0;
        while count < CFArrayGetCount(imaginary) {
            let component = CFArrayGetValueAtIndex(imaginary, count);
            url = CFURLCreateCopyAppendingPathComponent(
                kCFAllocatorDefault,
                placeholder,
                component,
                false,
            );
            CFRelease(placeholder);
            placeholder = url;
            count += 1;
        }
        CFRelease(imaginary);
    }

    let cf_path = CFURLCopyFileSystemPath(placeholder, kCFURLPOSIXPathStyle);
    CFRelease(placeholder);
    cf_path
}