qt: playlist: use item title if available
[vlc.git] / src / text / strings.c
blob9676687aae02e5084b02a19c31c704acae9a1556
1 /*****************************************************************************
2 * strings.c: String related functions
3 *****************************************************************************
4 * Copyright (C) 2006 VLC authors and VideoLAN
5 * Copyright (C) 2008-2009 Rémi Denis-Courmont
7 * Authors: Antoine Cellerier <dionoea at videolan dot org>
8 * Daniel Stranger <vlc at schmaller dot de>
9 * Rémi Denis-Courmont
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 2.1 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program; if not, write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
26 /*****************************************************************************
27 * Preamble
28 *****************************************************************************/
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
33 #include <vlc_common.h>
34 #include <assert.h>
36 /* Needed by vlc_strftime */
37 #include <time.h>
38 #include <limits.h>
39 #include <math.h>
40 #include <string.h>
41 #ifndef HAVE_STRCOLL
42 # define strcoll strcasecmp
43 #endif
45 /* Needed by vlc_strfplayer */
46 #include <vlc_meta.h>
47 #include <vlc_aout.h>
48 #include <vlc_memstream.h>
50 #include <vlc_strings.h>
51 #include <vlc_charset.h>
52 #include <vlc_arrays.h>
53 #include <vlc_player.h>
54 #include <libvlc.h>
55 #include <errno.h>
57 static const struct xml_entity_s
59 char psz_entity[8];
60 char psz_char[4];
61 } xml_entities[] = {
62 /* Important: this list has to be in alphabetical order (psz_entity-wise) */
63 { "AElig;", "Æ" },
64 { "Aacute;", "Á" },
65 { "Acirc;", "Â" },
66 { "Agrave;", "À" },
67 { "Aring;", "Å" },
68 { "Atilde;", "Ã" },
69 { "Auml;", "Ä" },
70 { "Ccedil;", "Ç" },
71 { "Dagger;", "‡" },
72 { "ETH;", "Ð" },
73 { "Eacute;", "É" },
74 { "Ecirc;", "Ê" },
75 { "Egrave;", "È" },
76 { "Euml;", "Ë" },
77 { "Iacute;", "Í" },
78 { "Icirc;", "Î" },
79 { "Igrave;", "Ì" },
80 { "Iuml;", "Ï" },
81 { "Ntilde;", "Ñ" },
82 { "OElig;", "Œ" },
83 { "Oacute;", "Ó" },
84 { "Ocirc;", "Ô" },
85 { "Ograve;", "Ò" },
86 { "Oslash;", "Ø" },
87 { "Otilde;", "Õ" },
88 { "Ouml;", "Ö" },
89 { "Scaron;", "Š" },
90 { "THORN;", "Þ" },
91 { "Uacute;", "Ú" },
92 { "Ucirc;", "Û" },
93 { "Ugrave;", "Ù" },
94 { "Uuml;", "Ü" },
95 { "Yacute;", "Ý" },
96 { "Yuml;", "Ÿ" },
97 { "aacute;", "á" },
98 { "acirc;", "â" },
99 { "acute;", "´" },
100 { "aelig;", "æ" },
101 { "agrave;", "à" },
102 { "amp;", "&" },
103 { "apos;", "'" },
104 { "aring;", "å" },
105 { "atilde;", "ã" },
106 { "auml;", "ä" },
107 { "bdquo;", "„" },
108 { "brvbar;", "¦" },
109 { "ccedil;", "ç" },
110 { "cedil;", "¸" },
111 { "cent;", "¢" },
112 { "circ;", "ˆ" },
113 { "copy;", "©" },
114 { "curren;", "¤" },
115 { "dagger;", "†" },
116 { "deg;", "°" },
117 { "divide;", "÷" },
118 { "eacute;", "é" },
119 { "ecirc;", "ê" },
120 { "egrave;", "è" },
121 { "eth;", "ð" },
122 { "euml;", "ë" },
123 { "euro;", "€" },
124 { "frac12;", "½" },
125 { "frac14;", "¼" },
126 { "frac34;", "¾" },
127 { "gt;", ">" },
128 { "hellip;", "…" },
129 { "iacute;", "í" },
130 { "icirc;", "î" },
131 { "iexcl;", "¡" },
132 { "igrave;", "ì" },
133 { "iquest;", "¿" },
134 { "iuml;", "ï" },
135 { "laquo;", "«" },
136 { "ldquo;", "“" },
137 { "lsaquo;", "‹" },
138 { "lsquo;", "‘" },
139 { "lt;", "<" },
140 { "macr;", "¯" },
141 { "mdash;", "—" },
142 { "micro;", "µ" },
143 { "middot;", "·" },
144 { "nbsp;", "\xc2\xa0" },
145 { "ndash;", "–" },
146 { "not;", "¬" },
147 { "ntilde;", "ñ" },
148 { "oacute;", "ó" },
149 { "ocirc;", "ô" },
150 { "oelig;", "œ" },
151 { "ograve;", "ò" },
152 { "ordf;", "ª" },
153 { "ordm;", "º" },
154 { "oslash;", "ø" },
155 { "otilde;", "õ" },
156 { "ouml;", "ö" },
157 { "para;", "¶" },
158 { "permil;", "‰" },
159 { "plusmn;", "±" },
160 { "pound;", "£" },
161 { "quot;", "\"" },
162 { "raquo;", "»" },
163 { "rdquo;", "”" },
164 { "reg;", "®" },
165 { "rsaquo;", "›" },
166 { "rsquo;", "’" },
167 { "sbquo;", "‚" },
168 { "scaron;", "š" },
169 { "sect;", "§" },
170 { "shy;", "­" },
171 { "sup1;", "¹" },
172 { "sup2;", "²" },
173 { "sup3;", "³" },
174 { "szlig;", "ß" },
175 { "thorn;", "þ" },
176 { "tilde;", "˜" },
177 { "times;", "×" },
178 { "trade;", "™" },
179 { "uacute;", "ú" },
180 { "ucirc;", "û" },
181 { "ugrave;", "ù" },
182 { "uml;", "¨" },
183 { "uuml;", "ü" },
184 { "yacute;", "ý" },
185 { "yen;", "¥" },
186 { "yuml;", "ÿ" },
189 static int cmp_entity (const void *key, const void *elem)
191 const struct xml_entity_s *ent = elem;
192 const char *name = key;
194 return strncmp (name, ent->psz_entity, strlen (ent->psz_entity));
197 void vlc_xml_decode( char *psz_value )
199 char *p_pos = psz_value;
201 while ( *psz_value )
203 if( *psz_value == '&' )
205 if( psz_value[1] == '#' )
206 { /* &#DDD; or &#xHHHH; Unicode code point */
207 char *psz_end;
208 unsigned long cp;
210 if( psz_value[2] == 'x' ) /* The x must be lower-case. */
211 cp = strtoul( psz_value + 3, &psz_end, 16 );
212 else
213 cp = strtoul( psz_value + 2, &psz_end, 10 );
215 if( *psz_end == ';' )
217 psz_value = psz_end + 1;
218 if( cp == 0 )
219 (void)0; /* skip nulls */
220 else
221 if( cp <= 0x7F )
223 *p_pos = cp;
225 else
226 /* Unicode code point outside ASCII.
227 * &#xxx; representation is longer than UTF-8 :) */
228 if( cp <= 0x7FF )
230 *p_pos++ = 0xC0 | (cp >> 6);
231 *p_pos = 0x80 | (cp & 0x3F);
233 else
234 if( cp <= 0xFFFF )
236 *p_pos++ = 0xE0 | (cp >> 12);
237 *p_pos++ = 0x80 | ((cp >> 6) & 0x3F);
238 *p_pos = 0x80 | (cp & 0x3F);
240 else
241 if( cp <= 0x1FFFFF ) /* Outside the BMP */
242 { /* Unicode stops at 10FFFF, but who cares? */
243 *p_pos++ = 0xF0 | (cp >> 18);
244 *p_pos++ = 0x80 | ((cp >> 12) & 0x3F);
245 *p_pos++ = 0x80 | ((cp >> 6) & 0x3F);
246 *p_pos = 0x80 | (cp & 0x3F);
249 else
251 /* Invalid entity number */
252 *p_pos = *psz_value;
253 psz_value++;
256 else
257 { /* Well-known XML entity */
258 const struct xml_entity_s *ent;
260 ent = bsearch (psz_value + 1, xml_entities,
261 ARRAY_SIZE (xml_entities),
262 sizeof (*ent), cmp_entity);
263 if (ent != NULL)
265 size_t olen = strlen (ent->psz_char);
266 memcpy (p_pos, ent->psz_char, olen);
267 p_pos += olen - 1;
268 psz_value += strlen (ent->psz_entity) + 1;
270 else
271 { /* No match */
272 *p_pos = *psz_value;
273 psz_value++;
277 else
279 *p_pos = *psz_value;
280 psz_value++;
283 p_pos++;
286 *p_pos = '\0';
289 char *vlc_xml_encode (const char *str)
291 struct vlc_memstream stream;
292 size_t n;
293 uint32_t cp;
295 assert(str != NULL);
296 vlc_memstream_open(&stream);
298 while ((n = vlc_towc (str, &cp)) != 0)
300 if (unlikely(n == (size_t)-1))
302 if (vlc_memstream_close(&stream) == 0)
303 free(stream.ptr);
304 errno = EILSEQ;
305 return NULL;
308 switch (cp)
310 case '\"':
311 vlc_memstream_puts(&stream, "&quot;");
312 break;
313 case '&':
314 vlc_memstream_puts(&stream, "&amp;");
315 break;
316 case '\'':
317 vlc_memstream_puts(&stream, "&#39;");
318 break;
319 case '<':
320 vlc_memstream_puts(&stream, "&lt;");
321 break;
322 case '>':
323 vlc_memstream_puts(&stream, "&gt;");
324 break;
325 default:
326 if (cp < 32) /* C0 code not allowed (except 9, 10 and 13) */
327 break;
328 if (cp >= 128 && cp < 160) /* C1 code encoded (except 133) */
330 vlc_memstream_printf(&stream, "&#%"PRIu32";", cp);
331 break;
333 /* fall through */
334 case 9:
335 case 10:
336 case 13:
337 case 133:
338 vlc_memstream_write(&stream, str, n);
339 break;
341 str += n;
344 if (vlc_memstream_close(&stream))
345 return NULL;
346 return stream.ptr;
349 /* Hex encoding */
350 void vlc_hex_encode_binary(const void *input, size_t size, char *output)
352 const unsigned char *buffer = input;
354 for (size_t i = 0; i < size; i++) {
355 sprintf(&output[i * 2], "%02hhx", buffer[i]);
359 /* Base64 encoding */
360 char *vlc_b64_encode_binary(const void *src, size_t length)
362 static const char b64[] =
363 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
364 const unsigned char *in = src;
365 char *dst = malloc((((length + 2) / 3) * 4) + 1);
366 char *out = dst;
368 if (unlikely(dst == NULL))
369 return NULL;
371 while (length >= 3) { /* pops (up to) 3 bytes of input, push 4 bytes */
372 uint_fast32_t v = (in[0] << 16) | (in[1] << 8) | in[2];
374 *(out++) = b64[(v >> 18)];
375 *(out++) = b64[(v >> 12) & 0x3f];
376 *(out++) = b64[(v >> 6) & 0x3f];
377 *(out++) = b64[(v >> 0) & 0x3f];
378 in += 3;
379 length -= 3;
382 switch (length) {
383 case 2: {
384 uint_fast16_t v = (in[0] << 8) | in[1];
386 *(out++) = b64[(v >> 10)];
387 *(out++) = b64[(v >> 4) & 0x3f];
388 *(out++) = b64[(v << 2) & 0x3f];
389 *(out++) = '=';
390 break;
393 case 1: {
394 uint_fast8_t v = in[0];
396 *(out++) = b64[(v >> 2)];
397 *(out++) = b64[(v << 4) & 0x3f];
398 *(out++) = '=';
399 *(out++) = '=';
400 break;
404 *out = '\0';
405 return dst;
408 char *vlc_b64_encode(const char *src)
410 if (src == NULL)
411 src = "";
412 return vlc_b64_encode_binary(src, strlen(src));
415 /* Base64 decoding */
416 size_t vlc_b64_decode_binary_to_buffer(void *dst, size_t size,
417 const char *restrict src)
419 static const signed char b64[256] = {
420 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 00-0F */
421 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 10-1F */
422 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, /* 20-2F */
423 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, /* 30-3F */
424 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, /* 40-4F */
425 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, /* 50-5F */
426 -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, /* 60-6F */
427 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, /* 70-7F */
428 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 80-8F */
429 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 90-9F */
430 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* A0-AF */
431 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* B0-BF */
432 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* C0-CF */
433 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* D0-DF */
434 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* E0-EF */
435 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* F0-FF */
437 const unsigned char *in = (const unsigned char *)src;
438 unsigned char *out = dst;
439 signed char prev;
440 int shift = 0;
442 static_assert (CHAR_BIT == 8, "Oops");
444 while (size > 0) {
445 const signed char cur = b64[*(in++)];
446 if (cur < 0)
447 break;
449 if (shift != 0) {
450 *(out++) = (prev << shift) | (cur >> (6 - shift));
451 size--;
454 prev = cur;
455 shift = (shift + 2) & 7;
458 return out - (unsigned char *)dst;
461 size_t vlc_b64_decode_binary( uint8_t **pp_dst, const char *psz_src )
463 const int i_src = strlen( psz_src );
464 uint8_t *p_dst;
466 *pp_dst = p_dst = malloc( i_src );
467 if( !p_dst )
468 return 0;
469 return vlc_b64_decode_binary_to_buffer( p_dst, i_src, psz_src );
471 char *vlc_b64_decode( const char *psz_src )
473 const int i_src = strlen( psz_src );
474 char *p_dst = malloc( i_src + 1 );
475 size_t i_dst;
476 if( !p_dst )
477 return NULL;
479 i_dst = vlc_b64_decode_binary_to_buffer( (uint8_t*)p_dst, i_src, psz_src );
480 p_dst[i_dst] = '\0';
482 return p_dst;
485 char *vlc_strftime( const char *tformat )
487 time_t curtime;
488 struct tm loctime;
490 if (strcmp (tformat, "") == 0)
491 return strdup (""); /* corner case w.r.t. strftime() return value */
493 /* Get the current time. */
494 time( &curtime );
496 /* Convert it to local time representation. */
497 localtime_r( &curtime, &loctime );
498 for (size_t buflen = strlen (tformat) + 32;; buflen += 32)
500 char *str = malloc (buflen);
501 if (str == NULL)
502 return NULL;
504 size_t len = strftime (str, buflen, tformat, &loctime);
505 if (len > 0)
507 char *ret = realloc (str, len + 1);
508 return ret ? ret : str; /* <- this cannot fail */
510 free (str);
512 vlc_assert_unreachable ();
515 static void write_duration(struct vlc_memstream *stream, vlc_tick_t duration)
517 lldiv_t d;
518 long long sec;
520 duration /= CLOCK_FREQ;
521 d = lldiv(duration, 60);
522 sec = d.rem;
523 d = lldiv(d.quot, 60);
524 vlc_memstream_printf(stream, "%02lld:%02lld:%02lld", d.quot, d.rem, sec);
527 static int write_meta(struct vlc_memstream *stream, input_item_t *item,
528 vlc_meta_type_t type)
530 if (item == NULL)
531 return EOF;
533 char *value = input_item_GetMeta(item, type);
534 if (value == NULL)
535 return EOF;
537 vlc_memstream_puts(stream, value);
538 free(value);
539 return 0;
542 char *vlc_strfplayer(vlc_player_t *player, input_item_t *item, const char *s)
544 struct vlc_memstream stream[1];
546 char c;
547 bool b_is_format = false;
548 bool b_empty_if_na = false;
550 assert(s != NULL);
552 if (!item && player)
553 item = vlc_player_GetCurrentMedia(player);
555 vlc_memstream_open(stream);
557 while ((c = *s) != '\0')
559 s++;
561 if (!b_is_format)
563 if (c == '$')
565 b_is_format = true;
566 b_empty_if_na = false;
567 continue;
570 vlc_memstream_putc(stream, c);
571 continue;
574 b_is_format = false;
576 switch (c)
578 case 'a':
579 write_meta(stream, item, vlc_meta_Artist);
580 break;
581 case 'b':
582 write_meta(stream, item, vlc_meta_Album);
583 break;
584 case 'c':
585 write_meta(stream, item, vlc_meta_Copyright);
586 break;
587 case 'd':
588 write_meta(stream, item, vlc_meta_Description);
589 break;
590 case 'e':
591 write_meta(stream, item, vlc_meta_EncodedBy);
592 break;
593 case 'f':
594 if (item != NULL)
596 vlc_mutex_lock(&item->lock);
597 if (item->p_stats != NULL)
598 vlc_memstream_printf(stream, "%"PRIi64,
599 item->p_stats->i_displayed_pictures);
600 else if (!b_empty_if_na)
601 vlc_memstream_putc(stream, '-');
602 vlc_mutex_unlock(&item->lock);
604 else if (!b_empty_if_na)
605 vlc_memstream_putc(stream, '-');
606 break;
607 case 'g':
608 write_meta(stream, item, vlc_meta_Genre);
609 break;
610 case 'l':
611 write_meta(stream, item, vlc_meta_Language);
612 break;
613 case 'n':
614 write_meta(stream, item, vlc_meta_TrackNumber);
615 break;
616 case 'o':
617 write_meta(stream, item, vlc_meta_TrackTotal);
618 break;
619 case 'p':
620 if (item == NULL)
621 break;
623 char *value = input_item_GetNowPlayingFb(item);
624 if (value == NULL)
625 break;
627 vlc_memstream_puts(stream, value);
628 free(value);
630 break;
631 case 'r':
632 write_meta(stream, item, vlc_meta_Rating);
633 break;
634 case 's':
636 char *lang = NULL;
638 if (player != NULL)
639 lang = vlc_player_GetCategoryLanguage(player, SPU_ES);
640 if (lang != NULL)
642 vlc_memstream_puts(stream, lang);
643 free(lang);
645 else if (!b_empty_if_na)
646 vlc_memstream_putc(stream, '-');
647 break;
649 case 't':
650 write_meta(stream, item, vlc_meta_Title);
651 break;
652 case 'u':
653 write_meta(stream, item, vlc_meta_URL);
654 break;
655 case 'A':
656 write_meta(stream, item, vlc_meta_Date);
657 break;
658 case 'B':
660 if (player)
662 const struct vlc_player_track *track =
663 vlc_player_GetSelectedTrack(player, AUDIO_ES);
664 if (track)
666 vlc_memstream_printf(stream, "%u",
667 track->fmt.i_bitrate);
668 break;
671 if (!b_empty_if_na)
672 vlc_memstream_putc(stream, '-');
673 break;
675 case 'C':
676 if (player)
678 ssize_t chapter = vlc_player_GetSelectedChapterIdx(player);
679 if (chapter != -1)
681 vlc_memstream_printf(stream, "%zd", chapter);
682 break;
685 if (!b_empty_if_na)
686 vlc_memstream_putc(stream, '-');
687 break;
688 case 'D':
689 if (item != NULL)
690 write_duration(stream, input_item_GetDuration(item));
691 else if (!b_empty_if_na)
692 vlc_memstream_puts(stream, "--:--:--");
693 break;
694 case 'F':
695 if (item != NULL)
697 char *uri = input_item_GetURI(item);
698 if (uri != NULL)
700 vlc_memstream_puts(stream, uri);
701 free(uri);
704 break;
705 case 'I':
706 if (player)
708 ssize_t title = vlc_player_GetSelectedTitleIdx(player);
709 if (title != -1)
711 vlc_memstream_printf(stream, "%zd", title);
712 break;
715 if (!b_empty_if_na)
716 vlc_memstream_putc(stream, '-');
717 break;
718 case 'L':
719 if (player)
721 vlc_tick_t length = vlc_player_GetLength(player);
722 vlc_tick_t time = vlc_player_GetTime(player);
723 if (length != VLC_TICK_INVALID && time != VLC_TICK_INVALID)
724 write_duration(stream, length - time);
726 if (!b_empty_if_na)
727 vlc_memstream_puts(stream, "--:--:--");
728 break;
729 case 'N':
730 if (item != NULL)
732 char *name = input_item_GetName(item);
733 if (name != NULL)
735 vlc_memstream_puts(stream, name);
736 free(name);
739 break;
740 case 'O':
742 char *lang = NULL;
744 if (player != NULL)
745 lang = vlc_player_GetCategoryLanguage(player, AUDIO_ES);
746 if (lang != NULL)
748 vlc_memstream_puts(stream, lang);
749 free(lang);
751 else if (!b_empty_if_na)
752 vlc_memstream_putc(stream, '-');
753 break;
755 case 'P':
756 if (player)
758 float pos = vlc_player_GetPosition(player);
759 if (pos >= 0)
761 vlc_memstream_printf(stream, "%2.1f", pos);
762 break;
765 if (!b_empty_if_na)
766 vlc_memstream_puts(stream, "--.-%");
767 break;
768 case 'R':
769 if (player)
770 vlc_memstream_printf(stream, "%.3f",
771 vlc_player_GetRate(player));
772 else if (!b_empty_if_na)
773 vlc_memstream_putc(stream, '-');
774 break;
775 case 'S':
776 if (player)
778 const struct vlc_player_track *track =
779 vlc_player_GetSelectedTrack(player, AUDIO_ES);
780 if (track)
782 div_t dr = div((track->fmt.audio.i_rate + 50) / 100, 10);
783 vlc_memstream_printf(stream, "%d.%01d", dr.quot, dr.rem);
784 break;
787 if (!b_empty_if_na)
788 vlc_memstream_putc(stream, '-');
789 break;
790 case 'T':
791 if (player)
793 vlc_tick_t time = vlc_player_GetTime(player);
794 if (time != VLC_TICK_INVALID)
796 write_duration(stream, time);
797 break;
800 if (!b_empty_if_na)
801 vlc_memstream_puts(stream, "--:--:--");
802 break;
803 case 'U':
804 write_meta(stream, item, vlc_meta_Publisher);
805 break;
806 case 'V':
808 float vol = 0.f;
810 if (player)
812 audio_output_t *aout = vlc_player_aout_Hold(player);
813 if (aout != NULL)
815 vol = aout_VolumeGet(aout);
816 aout_Release(aout);
819 if (vol >= 0.f)
820 vlc_memstream_printf(stream, "%ld", lroundf(vol * 256.f));
821 else if (!b_empty_if_na)
822 vlc_memstream_puts(stream, "---");
823 break;
825 case '_':
826 vlc_memstream_putc(stream, '\n');
827 break;
828 case 'Z':
829 if (item == NULL)
830 break;
832 char *value = input_item_GetNowPlayingFb(item);
833 if (value != NULL)
835 vlc_memstream_puts(stream, value);
836 free(value);
838 else
840 char *title = input_item_GetTitleFbName(item);
842 if (write_meta(stream, item, vlc_meta_Artist) >= 0
843 && title != NULL)
844 vlc_memstream_puts(stream, " - ");
846 if (title != NULL)
848 vlc_memstream_puts(stream, title);
849 free(title);
853 break;
854 case ' ':
855 b_empty_if_na = true;
856 b_is_format = true;
857 break;
858 default:
859 vlc_memstream_putc(stream, c);
860 break;
864 if (vlc_memstream_close(stream))
865 return NULL;
866 return stream->ptr;
869 int vlc_filenamecmp(const char *a, const char *b)
871 size_t i;
872 char ca, cb;
874 /* Attempt to guess if the sorting algorithm should be alphabetic
875 * (i.e. collation) or numeric:
876 * - If the first mismatching characters are not both digits,
877 * then collation is the only option.
878 * - If one of the first mismatching characters is 0 and the other is also
879 * a digit, the comparands are probably left-padded numerical values.
880 * It does not matter which algorithm is used: the zero will be smaller
881 * than non-zero either way.
882 * - Otherwise, the comparands are numerical values, and might not be
883 * aligned (i.e. not same order of magnitude). If so, collation would
884 * fail. So numerical comparison is performed. */
885 for (i = 0; (ca = a[i]) == (cb = b[i]); i++)
886 if (ca == '\0')
887 return 0; /* strings are exactly identical */
889 if ((unsigned)(ca - '0') > 9 || (unsigned)(cb - '0') > 9)
890 return strcoll(a, b);
892 unsigned long long ua = strtoull(a + i, NULL, 10);
893 unsigned long long ub = strtoull(b + i, NULL, 10);
895 /* The number may be identical in two cases:
896 * - leading zero (e.g. "012" and "12")
897 * - overflow on both sides (#ULLONG_MAX) */
898 if (ua == ub)
899 return strcoll(a, b);
901 return (ua > ub) ? +1 : -1;
905 * Sanitize a file name.
907 * Remove forbidden, potentially forbidden and otherwise evil characters from
908 * file names. That includes slashes, and popular characters like colon
909 * (on Unix anyway).
911 * \warning This function should only be used for automatically generated
912 * file names. Do not use this on full paths, only single file names without
913 * any directory separator!
915 void filename_sanitize( char *str )
917 unsigned char c;
919 /* Special file names, not allowed */
920 if( !strcmp( str, "." ) || !strcmp( str, ".." ) )
922 while( *str )
923 *(str++) = '_';
924 return;
927 /* On platforms not using UTF-8, VLC cannot access non-Unicode paths.
928 * Also, some file systems require Unicode file names.
929 * NOTE: This may inserts '?' thus is done replacing '?' with '_'. */
930 EnsureUTF8( str );
932 /* Avoid leading spaces to please Windows. */
933 while( (c = *str) != '\0' )
935 if( c != ' ' )
936 break;
937 *(str++) = '_';
940 char *start = str;
942 while( (c = *str) != '\0' )
944 /* Non-printable characters are not a good idea */
945 if( c < 32 )
946 *str = '_';
947 /* This is the list of characters not allowed by Microsoft.
948 * We also black-list them on Unix as they may be confusing, and are
949 * not supported by some file system types (notably CIFS). */
950 else if( strchr( "/:\\*\"?|<>", c ) != NULL )
951 *str = '_';
952 str++;
955 /* Avoid trailing spaces also to please Windows. */
956 while( str > start )
958 if( *(--str) != ' ' )
959 break;
960 *str = '_';