1 use super::*;
2 use std::fmt;
3 use std::ffi::CString;
4 use crate::ffi::wchar_t;
5 use std::iter::repeat;
6 use std::ptr;
7 use std::mem;
8 use std::char::{decode_utf16, REPLACEMENT_CHARACTER};
9 use foreign_types::{ForeignType, ForeignTypeRef};
10
11 foreign_type! {
12 /// This represents owned Multi Localized Unicode type. Most methods are implemented on `MLURef`.
13 /// This is a borrwed Multi Localized Unicode type. It holds Unicode strings associated with `Locale`.
14 pub unsafe type MLU {
15 type CType = ffi::MLU;
16 fn drop = ffi::cmsMLUfree;
17 }
18 }
19
20 impl MLU {
21 /// Allocates an empty multilocalized unicode object.
new(items: usize) -> Self22 pub fn new(items: usize) -> Self {
23 unsafe {
24 let handle = ffi::cmsMLUalloc(ptr::null_mut(), items as u32);
25 assert!(!handle.is_null());
26 MLU::from_ptr(handle)
27 }
28 }
29 }
30
31 impl MLURef {
32 /// Fills an ASCII (7 bit) entry for the given Language and country.
set_text_ascii(&mut self, text: &str, locale: Locale) -> bool33 pub fn set_text_ascii(&mut self, text: &str, locale: Locale) -> bool {
34 let cstr = CString::new(text).unwrap();
35 unsafe {
36 ffi::cmsMLUsetASCII(self.as_ptr(),
37 locale.language_ptr(),
38 locale.country_ptr(),
39 cstr.as_ptr()) != 0
40 }
41 }
42
43 /// Fills a UNICODE wide char (16 bit) entry for the given Language and country.
set_text(&mut self, text: &str, locale: Locale) -> bool44 pub fn set_text(&mut self, text: &str, locale: Locale) -> bool {
45 let chars: Vec<_> = text.chars()
46 .map(|c| c as wchar_t)
47 .chain(repeat(0 as wchar_t).take(1))
48 .collect();
49
50 unsafe {
51 ffi::cmsMLUsetWide(self.as_ptr(),
52 locale.language_ptr(),
53 locale.country_ptr(),
54 chars[..].as_ptr()) != 0
55 }
56 }
57
58 /// Gets an ASCII (7 bit) entry for the given Language and country.
text_ascii(&self, locale: Locale) -> LCMSResult<CString>59 pub fn text_ascii(&self, locale: Locale) -> LCMSResult<CString> {
60 let len = unsafe {
61 ffi::cmsMLUgetASCII(self.as_ptr(),
62 locale.language_ptr(),
63 locale.country_ptr(),
64 ptr::null_mut(), 0)
65 };
66 if len == 0 {
67 return Err(Error::MissingData);
68 }
69 let mut buf = vec![0u8; len as usize];
70 unsafe {
71 ffi::cmsMLUgetASCII(self.as_ptr(),
72 locale.language_ptr(),
73 locale.country_ptr(),
74 buf[..].as_ptr() as *mut _, len);
75 if let Some(0) = buf.pop() { // terminating zero
76 for c in &mut buf {
77 if *c > 127 {*c = b'?'}
78 }
79 CString::new(buf).map_err(|_| Error::InvalidString)
80 } else {
81 Err(Error::InvalidString)
82 }
83 }
84 }
85
86 /// Gets a Unicode entry for the given Language and country
text(&self, locale: Locale) -> LCMSResult<String>87 pub fn text(&self, locale: Locale) -> LCMSResult<String> {
88 let len_bytes = unsafe {
89 ffi::cmsMLUgetWide(self.as_ptr(),
90 locale.language_ptr(),
91 locale.country_ptr(),
92 ptr::null_mut(), 0)
93 };
94 let len_wchars = len_bytes as usize / mem::size_of::<wchar_t>();
95 if len_wchars == 0 || (len_bytes&1) != 0 {
96 return Err(Error::MissingData);
97 }
98 let mut buf = vec![0 as wchar_t; len_wchars];
99 unsafe {
100 ffi::cmsMLUgetWide(self.as_ptr(),
101 locale.language_ptr(),
102 locale.country_ptr(),
103 buf[..].as_ptr() as *mut wchar_t, len_bytes);
104 if let Some(0) = buf.pop() { // terminating zero
105 Ok(decode_utf16(buf.into_iter().map(|c| c as u16))
106 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
107 .collect())
108 } else {
109 Err(Error::InvalidString)
110 }
111 }
112 }
113
114 /// Obtains the translations stored in a given multilocalized unicode object.
tanslations(&self) -> Vec<Locale>115 pub fn tanslations(&self) -> Vec<Locale> {
116 let count = unsafe { ffi::cmsMLUtranslationsCount(self.as_ptr()) };
117 let mut out = Vec::with_capacity(count as usize);
118 for i in 0..count {
119 let mut locale = Locale::none();
120 if unsafe {
121 ffi::cmsMLUtranslationsCodes(self.as_ptr(), i,
122 locale.language_ptr_mut(),
123 locale.country_ptr_mut()) != 0
124 } {
125 out.push(locale);
126 }
127 }
128 out
129 }
130
131 /// Obtains the translation rule for given multilocalized unicode object.
tanslation(&self, locale: Locale) -> LCMSResult<Locale>132 pub fn tanslation(&self, locale: Locale) -> LCMSResult<Locale> {
133 let mut out = Locale::none();
134 if unsafe {
135 ffi::cmsMLUgetTranslation(self.as_ptr(),
136 locale.language_ptr(),
137 locale.country_ptr(),
138 out.language_ptr_mut(),
139 out.country_ptr_mut()) != 0
140 } {
141 Ok(out)
142 } else {
143 Err(Error::MissingData)
144 }
145 }
146 }
147
148 impl fmt::Debug for MLURef {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result149 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150 let t = self.text(Locale::none());
151 write!(f, "MLU({:?} {:?})", if let Ok(ref t) = t { &t } else { "None" }, self.tanslations())
152 }
153 }
154
155 #[test]
mlu()156 fn mlu() {
157 let _ = MLU::new(0);
158 let mut m = MLU::new(1);
159 assert!(m.set_text("Hello 世界!", Locale::none()));
160 assert_eq!(Ok("Hello 世界!".to_owned()), m.text(Locale::none()));
161 assert!(!m.set_text_ascii("エッロル", Locale::none()));
162
163 let mut m = MLU::new(1);
164 assert!(m.set_text_ascii("OK", Locale::none()));
165 assert_eq!(Ok(CString::new("OK").unwrap()), m.text_ascii(Locale::none()));
166 }
167