]> git.sesse.net Git - vlc/blob - modules/gui/macosx/StringUtility.m
macosx: lock access to addon_entry_t
[vlc] / modules / gui / macosx / StringUtility.m
1 /*****************************************************************************
2  * StringUtility.m: MacOS X interface module
3  *****************************************************************************
4  * Copyright (C) 2002-2014 VLC authors and VideoLAN
5  * $Id$
6  *
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>
11  *
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.
16  *
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.
21  *
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  *****************************************************************************/
26
27 #import <vlc_input.h>
28 #import <vlc_keys.h>
29 #import <vlc_strings.h>
30
31 #import "StringUtility.h"
32 #import "intf.h"
33
34 @implementation VLCStringUtility
35
36 static VLCStringUtility *_o_sharedInstance = nil;
37
38 + (VLCStringUtility *)sharedInstance
39 {
40     return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
41 }
42
43 - (id)init
44 {
45     if (_o_sharedInstance)
46         [self dealloc];
47     else
48         _o_sharedInstance = [super init];
49
50     return _o_sharedInstance;
51 }
52
53 #pragma mark -
54 #pragma mark String utility
55
56 - (NSString *)localizedString:(const char *)psz
57 {
58     NSString * stringObject = nil;
59
60     if (psz != NULL) {
61         stringObject = [NSString stringWithCString: _(psz) encoding:NSUTF8StringEncoding];
62
63         if (stringObject == NULL) {
64             msg_Err(VLCIntf, "could not translate: %s", psz);
65             return @"";
66         }
67     } else
68         return @"";
69
70     return stringObject;
71 }
72
73 /* i_width is in pixels */
74 - (NSString *)wrapString:(NSString *)o_in_string toWidth:(int)i_width
75 {
76     NSMutableString *o_wrapped;
77     NSString *o_out_string;
78     NSRange glyphRange, effectiveRange, charRange;
79     NSRect lineFragmentRect;
80     unsigned glyphIndex, breaksInserted = 0;
81
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)];
88
89     [o_layout_manager addTextContainer: o_container];
90     [o_container release];
91     [o_storage addLayoutManager: o_layout_manager];
92     [o_layout_manager release];
93
94     o_wrapped = [o_in_string mutableCopy];
95     glyphRange = [o_layout_manager glyphRangeForTextContainer: o_container];
96
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];
106             breaksInserted++;
107         }
108     }
109     o_out_string = [NSString stringWithString: o_wrapped];
110     [o_wrapped release];
111     [o_storage release];
112
113     return o_out_string;
114 }
115
116 - (NSString *)getCurrentTimeAsString:(input_thread_t *)p_input negative:(BOOL)b_negative
117 {
118     assert(p_input != nil);
119
120     vlc_value_t time;
121     char psz_time[MSTRTIME_MAX_SIZE];
122
123     var_Get(p_input, "time", &time);
124
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))];
131     } else
132         return [NSString stringWithUTF8String:secstotimestr(psz_time, (time.i_time / 1000000))];
133 }
134
135 - (NSString *)stringForTime:(long long int)time
136 {
137     if (time > 0) {
138         long long positiveDuration = llabs(time);
139         if (positiveDuration > 3600)
140             return [NSString stringWithFormat:@"%s%01ld:%02ld:%02ld",
141                     time < 0 ? "-" : "",
142                     (long) (positiveDuration / 3600),
143                     (long)((positiveDuration / 60) % 60),
144                     (long) (positiveDuration % 60)];
145         else
146             return [NSString stringWithFormat:@"%s%02ld:%02ld",
147                     time < 0 ? "-" : "",
148                     (long)((positiveDuration / 60) % 60),
149                     (long) (positiveDuration % 60)];
150     } else {
151         // Return a string that represents an undefined time.
152         return @"--:--";
153     }
154 }
155
156 #pragma mark -
157 #pragma mark Key Shortcuts
158
159 static struct
160 {
161     unichar i_nskey;
162     unsigned int i_vlckey;
163 } nskeys_to_vlckeys[] =
164 {
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 },
192     {0,0}
193 };
194
195 /*
196  * Takes the first value of an cocoa key string, and converts it to VLCs int representation.
197  */
198 unsigned int CocoaKeyToVLC(unichar i_key)
199 {
200     unsigned int i;
201
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;
205         }
206     }
207     return (unsigned int)i_key;
208 }
209
210 /* takes a good old const c string and converts it to NSString without UTF8 loss */
211
212 NSString *toNSStr(const char *str) {
213     return str != NULL ? [NSString stringWithUTF8String:str] : @"";
214 }
215
216 /*
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
219  * key to menu items.
220  */
221 - (NSString *)OSXStringKeyToString:(NSString *)theString
222 {
223     if (![theString isEqualToString:@""]) {
224         /* remove cruft */
225         if ([theString characterAtIndex:([theString length] - 1)] != 0x2b)
226             theString = [theString stringByReplacingOccurrencesOfString:@"+" withString:@""];
227         else {
228             theString = [theString stringByReplacingOccurrencesOfString:@"+" withString:@""];
229             theString = [NSString stringWithFormat:@"%@+", theString];
230         }
231         if ([theString characterAtIndex:([theString length] - 1)] != 0x2d)
232             theString = [theString stringByReplacingOccurrencesOfString:@"-" withString:@""];
233         else {
234             theString = [theString stringByReplacingOccurrencesOfString:@"-" withString:@""];
235             theString = [NSString stringWithFormat:@"%@-", theString];
236         }
237         /* modifiers */
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];
253     }
254     else
255         theString = [NSString stringWithString:_NS("Not Set")];
256     return theString;
257 }
258
259 /*
260  * Converts VLC key string to cocoa modifiers which can be used as setKeyEquivalent for menu items
261  */
262 - (unsigned int)VLCModifiersToCocoa:(NSString *)theString
263 {
264     unsigned int new = 0;
265
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;
274     return new;
275 }
276
277 /*
278  * Converts VLC key to cocoa string which can be used as setKeyEquivalentModifierMask for menu items
279  */
280 - (NSString *)VLCKeyToString:(NSString *)theString
281 {
282     if (![theString isEqualToString:@""]) {
283         if ([theString characterAtIndex:([theString length] - 1)] != 0x2b)
284             theString = [theString stringByReplacingOccurrencesOfString:@"+" withString:@""];
285         else {
286             theString = [theString stringByReplacingOccurrencesOfString:@"+" withString:@""];
287             theString = [NSString stringWithFormat:@"%@+", theString];
288         }
289         if ([theString characterAtIndex:([theString length] - 1)] != 0x2d)
290             theString = [theString stringByReplacingOccurrencesOfString:@"-" withString:@""];
291         else {
292             theString = [theString stringByReplacingOccurrencesOfString:@"-" withString:@""];
293             theString = [NSString stringWithFormat:@"%@-", theString];
294         }
295         theString = [theString stringByReplacingOccurrencesOfString:@"Command" withString:@""];
296         theString = [theString stringByReplacingOccurrencesOfString:@"Alt" withString:@""];
297         theString = [theString stringByReplacingOccurrencesOfString:@"Shift" withString:@""];
298         theString = [theString stringByReplacingOccurrencesOfString:@"Ctrl" withString:@""];
299     }
300
301 #ifdef __clang__
302 #pragma GCC diagnostic ignored "-Wformat"
303 #endif
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)
358             return @" ";
359         /* note that we don't support esc here, since it is reserved for leaving fullscreen */
360     }
361 #ifdef __clang__
362 #pragma GCC diagnostic warning "-Wformat"
363 #endif
364
365     return theString;
366 }
367
368 #pragma mark -
369 #pragma mark base64 helpers
370
371 - (NSString *)b64Decode:(NSString *)string
372 {
373     char *psz_decoded_string = vlc_b64_decode([string UTF8String]);
374     if(!psz_decoded_string)
375         return @"";
376
377     NSString *returnStr = [NSString stringWithFormat:@"%s", psz_decoded_string];
378     free(psz_decoded_string);
379
380     return returnStr;
381 }
382
383 - (NSString *)b64EncodeAndFree:(char *)psz_string
384 {
385     char *psz_encoded_string = vlc_b64_encode(psz_string);
386     free(psz_string);
387     if(!psz_encoded_string)
388         return @"";
389
390     NSString *returnStr = [NSString stringWithFormat:@"%s", psz_encoded_string];
391     free(psz_encoded_string);
392
393     return returnStr;
394 }
395
396
397 @end