file_metadata/mditem/
mod.rs1extern crate file_metadata_mditem_macros;
2
3use std::marker::PhantomData;
4
5use core_foundation_sys::base::{CFAllocatorRef, kCFAllocatorDefault};
6use core_foundation_sys::base::{TCFTypeRef, CFTypeID};
7use core_foundation::url::{CFURL, CFURLRef};
8use core_foundation::string::{CFString, CFStringRef};
9use core_foundation::array::{CFArray, CFArrayRef};
10use core_foundation::base::TCFType;
11use libc::c_void;
12
13#[repr(C)]
14pub struct __MDItemRef(c_void);
15pub type MDItemRef = *const __MDItemRef;
16
17#[link(name = "CoreServices", kind = "framework")]
18extern "C" {
19 fn MDItemCreate(allocator: CFAllocatorRef, path: CFStringRef) -> MDItemRef;
20 fn MDItemCreateWithURL(allocator: CFAllocatorRef, url: CFURLRef) -> MDItemRef;
21 fn MDItemCopyAttribute(item: MDItemRef, name: CFStringRef) -> *const c_void;
22 fn MDItemCopyAttributeNames(item: MDItemRef) -> CFArrayRef;
23 fn MDItemGetTypeID() -> CFTypeID;
24}
25
26pub struct Attribute<T> {
27 pub key_getter: fn() -> CFStringRef,
28 pub phantom: PhantomData<T>
29}
30
31impl<T: TCFType> Attribute<T> {
32 pub fn key(&self) -> CFStringRef {
33 (self.key_getter)()
34 }
35}
36
37pub mod attributes;
38
39declare_TCFType!{
40 MDItem, MDItemRef
41}
42impl_TCFType!(MDItem, MDItemRef, MDItemGetTypeID);
43
44impl MDItem {
45 pub fn from_string(path: CFString) -> Option<MDItem> {
46 let ptr = unsafe { MDItemCreate(kCFAllocatorDefault, path.as_concrete_TypeRef()) };
47
48 if ptr.is_null() {
49 None
50 } else {
51 Some(unsafe { TCFType::wrap_under_create_rule(ptr) })
52 }
53 }
54
55 pub fn from_url(url: CFURL) -> Option<MDItem> {
56 let ptr = unsafe { MDItemCreateWithURL(kCFAllocatorDefault, url.as_concrete_TypeRef()) };
57
58 if ptr.is_null() {
59 None
60 } else {
61 Some(unsafe { TCFType::wrap_under_create_rule(ptr) })
62 }
63 }
64
65 pub fn attributes(&self) -> CFArray<CFString> {
66 unsafe {
67 TCFType::wrap_under_create_rule(MDItemCopyAttributeNames(self.0))
68 }
69 }
70
71 #[inline]
72 pub fn get<T>(&self, attr: Attribute<T>) -> Option<T> where T: TCFType {
73 let value = unsafe { MDItemCopyAttribute(self.0, attr.key()) };
74
75 if value.is_null() {
76 None
77 } else {
78 Some(unsafe { T::wrap_under_create_rule(T::Ref::from_void_ptr(value)) })
79 }
80 }
81}
82
83#[cfg(test)]
84mod tests {
85 use super::{MDItem, attributes::{CFBundleIdentifier, DisplayName}};
86 use core_foundation::url::CFURL;
87 use core_foundation::string::CFString;
88 use std::path::Path;
89
90 #[test]
91 fn get_safari_bundle_id_and_display_name() {
92 let safari_url = CFURL::from_path(Path::new("/Applications/Safari.app"), true).unwrap();
93 let safari_item = MDItem::from_url(safari_url).unwrap();
94 assert_eq!(safari_item.get(CFBundleIdentifier), Some(CFString::new("com.apple.Safari")));
95 assert_eq!(safari_item.get(DisplayName), Some(CFString::new("Safari")));
96 }
97}