1 /*****************************************************************************
2 * StringUtility.m: MacOS X interface module
3 *****************************************************************************
4 * Copyright (C) 2002-2014 VLC authors and VideoLAN
7 * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
8 * Christophe Massiot <massiot@via.ecp.fr>
9 * Derk-Jan Hartman <hartman at videolan dot org>
10 * Felix Paul Kühne <fkuehne at videolan dot org>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25 *****************************************************************************/
29 #import <vlc_strings.h>
31 #import "StringUtility.h"
34 @implementation VLCStringUtility
36 static VLCStringUtility *_o_sharedInstance = nil;
38 + (VLCStringUtility *)sharedInstance
40 return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
45 if (_o_sharedInstance)
48 _o_sharedInstance = [super init];
50 return _o_sharedInstance;
54 #pragma mark String utility
56 - (NSString *)localizedString:(const char *)psz
58 NSString * stringObject = nil;
61 stringObject = [NSString stringWithCString: _(psz) encoding:NSUTF8StringEncoding];
63 if (stringObject == NULL) {
64 msg_Err(VLCIntf, "could not translate: %s", psz);
73 /* i_width is in pixels */
74 - (NSString *)wrapString:(NSString *)o_in_string toWidth:(int)i_width
76 NSMutableString *o_wrapped;
77 NSString *o_out_string;
78 NSRange glyphRange, effectiveRange, charRange;
79 NSRect lineFragmentRect;
80 unsigned glyphIndex, breaksInserted = 0;
82 NSTextStorage *o_storage = [[NSTextStorage alloc] initWithString: o_in_string
83 attributes: [NSDictionary dictionaryWithObjectsAndKeys:
84 [NSFont labelFontOfSize: 0.0], NSFontAttributeName, nil]];
85 NSLayoutManager *o_layout_manager = [[NSLayoutManager alloc] init];
86 NSTextContainer *o_container = [[NSTextContainer alloc]
87 initWithContainerSize: NSMakeSize(i_width, 2000)];
89 [o_layout_manager addTextContainer: o_container];
90 [o_container release];
91 [o_storage addLayoutManager: o_layout_manager];
92 [o_layout_manager release];
94 o_wrapped = [o_in_string mutableCopy];
95 glyphRange = [o_layout_manager glyphRangeForTextContainer: o_container];
97 for (glyphIndex = glyphRange.location ; glyphIndex < NSMaxRange(glyphRange) ;
98 glyphIndex += effectiveRange.length) {
99 lineFragmentRect = [o_layout_manager lineFragmentRectForGlyphAtIndex: glyphIndex
100 effectiveRange: &effectiveRange];
101 charRange = [o_layout_manager characterRangeForGlyphRange: effectiveRange
102 actualGlyphRange: &effectiveRange];
103 if ([o_wrapped lineRangeForRange:
104 NSMakeRange(charRange.location + breaksInserted, charRange.length)].length > charRange.length) {
105 [o_wrapped insertString: @"\n" atIndex: NSMaxRange(charRange) + breaksInserted];
109 o_out_string = [NSString stringWithString: o_wrapped];
116 - (NSString *)getCurrentTimeAsString:(input_thread_t *)p_input negative:(BOOL)b_negative
118 assert(p_input != nil);
121 char psz_time[MSTRTIME_MAX_SIZE];
123 var_Get(p_input, "time", &time);
125 mtime_t dur = input_item_GetDuration(input_GetItem(p_input));
126 if (b_negative && dur > 0) {
127 mtime_t remaining = 0;
128 if (dur > time.i_time)
129 remaining = dur - time.i_time;
130 return [NSString stringWithFormat: @"-%s", secstotimestr(psz_time, (remaining / 1000000))];
132 return [NSString stringWithUTF8String:secstotimestr(psz_time, (time.i_time / 1000000))];
135 - (NSString *)stringForTime:(long long int)time
138 long long positiveDuration = llabs(time);
139 if (positiveDuration > 3600)
140 return [NSString stringWithFormat:@"%s%01ld:%02ld:%02ld",
142 (long) (positiveDuration / 3600),
143 (long)((positiveDuration / 60) % 60),
144 (long) (positiveDuration % 60)];
146 return [NSString stringWithFormat:@"%s%02ld:%02ld",
148 (long)((positiveDuration / 60) % 60),
149 (long) (positiveDuration % 60)];
151 // Return a string that represents an undefined time.
157 #pragma mark Key Shortcuts
162 unsigned int i_vlckey;
163 } nskeys_to_vlckeys[] =
165 { NSUpArrowFunctionKey, KEY_UP },
166 { NSDownArrowFunctionKey, KEY_DOWN },
167 { NSLeftArrowFunctionKey, KEY_LEFT },
168 { NSRightArrowFunctionKey, KEY_RIGHT },
169 { NSF1FunctionKey, KEY_F1 },
170 { NSF2FunctionKey, KEY_F2 },
171 { NSF3FunctionKey, KEY_F3 },
172 { NSF4FunctionKey, KEY_F4 },
173 { NSF5FunctionKey, KEY_F5 },
174 { NSF6FunctionKey, KEY_F6 },
175 { NSF7FunctionKey, KEY_F7 },
176 { NSF8FunctionKey, KEY_F8 },
177 { NSF9FunctionKey, KEY_F9 },
178 { NSF10FunctionKey, KEY_F10 },
179 { NSF11FunctionKey, KEY_F11 },
180 { NSF12FunctionKey, KEY_F12 },
181 { NSInsertFunctionKey, KEY_INSERT },
182 { NSHomeFunctionKey, KEY_HOME },
183 { NSEndFunctionKey, KEY_END },
184 { NSPageUpFunctionKey, KEY_PAGEUP },
185 { NSPageDownFunctionKey, KEY_PAGEDOWN },
186 { NSMenuFunctionKey, KEY_MENU },
187 { NSTabCharacter, KEY_TAB },
188 { NSCarriageReturnCharacter, KEY_ENTER },
189 { NSEnterCharacter, KEY_ENTER },
190 { NSBackspaceCharacter, KEY_BACKSPACE },
191 { NSDeleteCharacter, KEY_DELETE },
196 * Takes the first value of an cocoa key string, and converts it to VLCs int representation.
198 unsigned int CocoaKeyToVLC(unichar i_key)
202 for (i = 0; nskeys_to_vlckeys[i].i_nskey != 0; i++) {
203 if (nskeys_to_vlckeys[i].i_nskey == i_key) {
204 return nskeys_to_vlckeys[i].i_vlckey;
207 return (unsigned int)i_key;
210 /* takes a good old const c string and converts it to NSString without UTF8 loss */
212 NSString *toNSStr(const char *str) {
213 return str != NULL ? [NSString stringWithUTF8String:str] : @"";
217 * Converts VLC key string to a prettified version, for hotkey settings.
218 * The returned string adapts similar how its done within the cocoa framework when setting this
221 - (NSString *)OSXStringKeyToString:(NSString *)theString
223 if (![theString isEqualToString:@""]) {
225 if ([theString characterAtIndex:([theString length] - 1)] != 0x2b)
226 theString = [theString stringByReplacingOccurrencesOfString:@"+" withString:@""];
228 theString = [theString stringByReplacingOccurrencesOfString:@"+" withString:@""];
229 theString = [NSString stringWithFormat:@"%@+", theString];
231 if ([theString characterAtIndex:([theString length] - 1)] != 0x2d)
232 theString = [theString stringByReplacingOccurrencesOfString:@"-" withString:@""];
234 theString = [theString stringByReplacingOccurrencesOfString:@"-" withString:@""];
235 theString = [NSString stringWithFormat:@"%@-", theString];
238 theString = [theString stringByReplacingOccurrencesOfString:@"Command" withString: [NSString stringWithUTF8String:"\xE2\x8C\x98"]];
239 theString = [theString stringByReplacingOccurrencesOfString:@"Alt" withString: [NSString stringWithUTF8String:"\xE2\x8C\xA5"]];
240 theString = [theString stringByReplacingOccurrencesOfString:@"Shift" withString: [NSString stringWithUTF8String:"\xE2\x87\xA7"]];
241 theString = [theString stringByReplacingOccurrencesOfString:@"Ctrl" withString: [NSString stringWithUTF8String:"\xE2\x8C\x83"]];
242 /* show non-character keys correctly */
243 theString = [theString stringByReplacingOccurrencesOfString:@"Right" withString:[NSString stringWithUTF8String:"\xE2\x86\x92"]];
244 theString = [theString stringByReplacingOccurrencesOfString:@"Left" withString:[NSString stringWithUTF8String:"\xE2\x86\x90"]];
245 theString = [theString stringByReplacingOccurrencesOfString:@"Page Up" withString:[NSString stringWithUTF8String:"\xE2\x87\x9E"]];
246 theString = [theString stringByReplacingOccurrencesOfString:@"Page Down" withString:[NSString stringWithUTF8String:"\xE2\x87\x9F"]];
247 theString = [theString stringByReplacingOccurrencesOfString:@"Up" withString:[NSString stringWithUTF8String:"\xE2\x86\x91"]];
248 theString = [theString stringByReplacingOccurrencesOfString:@"Down" withString:[NSString stringWithUTF8String:"\xE2\x86\x93"]];
249 theString = [theString stringByReplacingOccurrencesOfString:@"Enter" withString:[NSString stringWithUTF8String:"\xe2\x86\xb5"]];
250 theString = [theString stringByReplacingOccurrencesOfString:@"Tab" withString:[NSString stringWithUTF8String:"\xe2\x87\xa5"]];
251 theString = [theString stringByReplacingOccurrencesOfString:@"Delete" withString:[NSString stringWithUTF8String:"\xe2\x8c\xab"]]; /* capitalize plain characters to suit the menubar's look */
252 theString = [theString capitalizedString];
255 theString = [NSString stringWithString:_NS("Not Set")];
260 * Converts VLC key string to cocoa modifiers which can be used as setKeyEquivalent for menu items
262 - (unsigned int)VLCModifiersToCocoa:(NSString *)theString
264 unsigned int new = 0;
266 if ([theString rangeOfString:@"Command"].location != NSNotFound)
267 new |= NSCommandKeyMask;
268 if ([theString rangeOfString:@"Alt"].location != NSNotFound)
269 new |= NSAlternateKeyMask;
270 if ([theString rangeOfString:@"Shift"].location != NSNotFound)
271 new |= NSShiftKeyMask;
272 if ([theString rangeOfString:@"Ctrl"].location != NSNotFound)
273 new |= NSControlKeyMask;
278 * Converts VLC key to cocoa string which can be used as setKeyEquivalentModifierMask for menu items
280 - (NSString *)VLCKeyToString:(NSString *)theString
282 if (![theString isEqualToString:@""]) {
283 if ([theString characterAtIndex:([theString length] - 1)] != 0x2b)
284 theString = [theString stringByReplacingOccurrencesOfString:@"+" withString:@""];
286 theString = [theString stringByReplacingOccurrencesOfString:@"+" withString:@""];
287 theString = [NSString stringWithFormat:@"%@+", theString];
289 if ([theString characterAtIndex:([theString length] - 1)] != 0x2d)
290 theString = [theString stringByReplacingOccurrencesOfString:@"-" withString:@""];
292 theString = [theString stringByReplacingOccurrencesOfString:@"-" withString:@""];
293 theString = [NSString stringWithFormat:@"%@-", theString];
295 theString = [theString stringByReplacingOccurrencesOfString:@"Command" withString:@""];
296 theString = [theString stringByReplacingOccurrencesOfString:@"Alt" withString:@""];
297 theString = [theString stringByReplacingOccurrencesOfString:@"Shift" withString:@""];
298 theString = [theString stringByReplacingOccurrencesOfString:@"Ctrl" withString:@""];
302 #pragma GCC diagnostic ignored "-Wformat"
304 if ([theString length] > 1) {
305 if ([theString rangeOfString:@"Page Up"].location != NSNotFound)
306 return [NSString stringWithFormat:@"%C", NSPageUpFunctionKey];
307 else if ([theString rangeOfString:@"Page Down"].location != NSNotFound)
308 return [NSString stringWithFormat:@"%C", NSPageDownFunctionKey];
309 else if ([theString rangeOfString:@"Up"].location != NSNotFound)
310 return [NSString stringWithFormat:@"%C", NSUpArrowFunctionKey];
311 else if ([theString rangeOfString:@"Down"].location != NSNotFound)
312 return [NSString stringWithFormat:@"%C", NSDownArrowFunctionKey];
313 else if ([theString rangeOfString:@"Right"].location != NSNotFound)
314 return [NSString stringWithFormat:@"%C", NSRightArrowFunctionKey];
315 else if ([theString rangeOfString:@"Left"].location != NSNotFound)
316 return [NSString stringWithFormat:@"%C", NSLeftArrowFunctionKey];
317 else if ([theString rangeOfString:@"Enter"].location != NSNotFound)
318 return [NSString stringWithFormat:@"%C", NSEnterCharacter]; // we treat NSCarriageReturnCharacter as aquivalent
319 else if ([theString rangeOfString:@"Insert"].location != NSNotFound)
320 return [NSString stringWithFormat:@"%C", NSInsertFunctionKey];
321 else if ([theString rangeOfString:@"Home"].location != NSNotFound)
322 return [NSString stringWithFormat:@"%C", NSHomeFunctionKey];
323 else if ([theString rangeOfString:@"End"].location != NSNotFound)
324 return [NSString stringWithFormat:@"%C", NSEndFunctionKey];
325 else if ([theString rangeOfString:@"Menu"].location != NSNotFound)
326 return [NSString stringWithFormat:@"%C", NSMenuFunctionKey];
327 else if ([theString rangeOfString:@"Tab"].location != NSNotFound)
328 return [NSString stringWithFormat:@"%C", NSTabCharacter];
329 else if ([theString rangeOfString:@"Backspace"].location != NSNotFound)
330 return [NSString stringWithFormat:@"%C", NSBackspaceCharacter];
331 else if ([theString rangeOfString:@"Delete"].location != NSNotFound)
332 return [NSString stringWithFormat:@"%C", NSDeleteCharacter];
333 else if ([theString rangeOfString:@"F12"].location != NSNotFound)
334 return [NSString stringWithFormat:@"%C", NSF12FunctionKey];
335 else if ([theString rangeOfString:@"F11"].location != NSNotFound)
336 return [NSString stringWithFormat:@"%C", NSF11FunctionKey];
337 else if ([theString rangeOfString:@"F10"].location != NSNotFound)
338 return [NSString stringWithFormat:@"%C", NSF10FunctionKey];
339 else if ([theString rangeOfString:@"F9"].location != NSNotFound)
340 return [NSString stringWithFormat:@"%C", NSF9FunctionKey];
341 else if ([theString rangeOfString:@"F8"].location != NSNotFound)
342 return [NSString stringWithFormat:@"%C", NSF8FunctionKey];
343 else if ([theString rangeOfString:@"F7"].location != NSNotFound)
344 return [NSString stringWithFormat:@"%C", NSF7FunctionKey];
345 else if ([theString rangeOfString:@"F6"].location != NSNotFound)
346 return [NSString stringWithFormat:@"%C", NSF6FunctionKey];
347 else if ([theString rangeOfString:@"F5"].location != NSNotFound)
348 return [NSString stringWithFormat:@"%C", NSF5FunctionKey];
349 else if ([theString rangeOfString:@"F4"].location != NSNotFound)
350 return [NSString stringWithFormat:@"%C", NSF4FunctionKey];
351 else if ([theString rangeOfString:@"F3"].location != NSNotFound)
352 return [NSString stringWithFormat:@"%C", NSF3FunctionKey];
353 else if ([theString rangeOfString:@"F2"].location != NSNotFound)
354 return [NSString stringWithFormat:@"%C", NSF2FunctionKey];
355 else if ([theString rangeOfString:@"F1"].location != NSNotFound)
356 return [NSString stringWithFormat:@"%C", NSF1FunctionKey];
357 else if ([theString rangeOfString:@"Space"].location != NSNotFound)
359 /* note that we don't support esc here, since it is reserved for leaving fullscreen */
362 #pragma GCC diagnostic warning "-Wformat"
369 #pragma mark base64 helpers
371 - (NSString *)b64Decode:(NSString *)string
373 char *psz_decoded_string = vlc_b64_decode([string UTF8String]);
374 if(!psz_decoded_string)
377 NSString *returnStr = [NSString stringWithFormat:@"%s", psz_decoded_string];
378 free(psz_decoded_string);
383 - (NSString *)b64EncodeAndFree:(char *)psz_string
385 char *psz_encoded_string = vlc_b64_encode(psz_string);
387 if(!psz_encoded_string)
390 NSString *returnStr = [NSString stringWithFormat:@"%s", psz_encoded_string];
391 free(psz_encoded_string);