Fixed a crash caused by yadif deinterlacer on Windows XP
[vlc/solaris.git] / src / text / strings.c
blob4b51a6bcad01843e393d9408747f4048a3e7e6ca
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
6 * $Id$
8 * Authors: Antoine Cellerier <dionoea at videolan dot org>
9 * Daniel Stranger <vlc at schmaller dot de>
10 * Rémi Denis-Courmont <rem # videolan org>
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU Lesser General Public License as published by
14 * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public License
23 * along with this program; if not, write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25 *****************************************************************************/
27 /*****************************************************************************
28 * Preamble
29 *****************************************************************************/
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
34 #include <vlc_common.h>
35 #include <assert.h>
37 /* Needed by str_format_time */
38 #include <time.h>
39 #include <limits.h>
41 /* Needed by str_format_meta */
42 #include <vlc_input.h>
43 #include <vlc_meta.h>
44 #include <vlc_playlist.h>
45 #include <vlc_aout_intf.h>
47 #include <vlc_strings.h>
48 #include <vlc_url.h>
49 #include <vlc_charset.h>
50 #include <vlc_fs.h>
51 #include <libvlc.h>
52 #include <errno.h>
54 /**
55 * Decode encoded URI component. See also decode_URI().
56 * \return decoded duplicated string
58 char *decode_URI_duplicate( const char *psz )
60 char *psz_dup = strdup( psz );
61 decode_URI( psz_dup );
62 return psz_dup;
65 /**
66 * Decode an encoded URI component in place.
67 * <b>This function does NOT decode entire URIs.</b>
68 * It decodes components (e.g. host name, directory, file name).
69 * Decoded URIs do not exist in the real world (see RFC3986 §2.4).
70 * Complete URIs are always "encoded" (or they are syntaxically invalid).
72 * Note that URI encoding is different from Javascript escaping. Especially,
73 * white spaces and Unicode non-ASCII code points are encoded differently.
75 * \return psz on success, NULL if it was not properly encoded
77 char *decode_URI( char *psz )
79 unsigned char *in = (unsigned char *)psz, *out = in, c;
81 if( psz == NULL )
82 return NULL;
84 while( ( c = *in++ ) != '\0' )
86 switch( c )
88 case '%':
90 char hex[3];
92 if( ( ( hex[0] = *in++ ) == 0 )
93 || ( ( hex[1] = *in++ ) == 0 ) )
94 return NULL;
96 hex[2] = '\0';
97 *out++ = (unsigned char)strtoul( hex, NULL, 0x10 );
98 break;
101 default:
102 /* Inserting non-ASCII or non-printable characters is unsafe,
103 * and no sane browser will send these unencoded */
104 if( ( c < 32 ) || ( c > 127 ) )
105 *out++ = '?';
106 else
107 *out++ = c;
110 *out = '\0';
111 return psz;
114 static inline bool isurisafe( int c )
116 /* These are the _unreserved_ URI characters (RFC3986 §2.3) */
117 return ( (unsigned char)( c - 'a' ) < 26 )
118 || ( (unsigned char)( c - 'A' ) < 26 )
119 || ( (unsigned char)( c - '0' ) < 10 )
120 || ( strchr( "-._~", c ) != NULL );
123 static char *encode_URI_bytes (const char *psz_uri, size_t len)
125 char *psz_enc = malloc (3 * len + 1), *out = psz_enc;
126 if (psz_enc == NULL)
127 return NULL;
129 for (size_t i = 0; i < len; i++)
131 static const char hex[16] = "0123456789ABCDEF";
132 uint8_t c = *psz_uri;
134 if( isurisafe( c ) )
135 *out++ = c;
136 /* This is URI encoding, not HTTP forms:
137 * Space is encoded as '%20', not '+'. */
138 else
140 *out++ = '%';
141 *out++ = hex[c >> 4];
142 *out++ = hex[c & 0xf];
144 psz_uri++;
146 *out++ = '\0';
148 out = realloc (psz_enc, out - psz_enc);
149 return out ? out : psz_enc; /* realloc() can fail (safe) */
153 * Encodes a URI component (RFC3986 §2).
155 * @param psz_uri nul-terminated UTF-8 representation of the component.
156 * Obviously, you can't pass a URI containing a nul character, but you don't
157 * want to do that, do you?
159 * @return encoded string (must be free()'d), or NULL for ENOMEM.
161 char *encode_URI_component( const char *psz_uri )
163 return encode_URI_bytes (psz_uri, strlen (psz_uri));
167 static const struct xml_entity_s
169 char psz_entity[8];
170 char psz_char[4];
171 } xml_entities[] = {
172 /* Important: this list has to be in alphabetical order (psz_entity-wise) */
173 { "AElig;", "Æ" },
174 { "Aacute;", "Á" },
175 { "Acirc;", "Â" },
176 { "Agrave;", "À" },
177 { "Aring;", "Å" },
178 { "Atilde;", "Ã" },
179 { "Auml;", "Ä" },
180 { "Ccedil;", "Ç" },
181 { "Dagger;", "‡" },
182 { "ETH;", "Ð" },
183 { "Eacute;", "É" },
184 { "Ecirc;", "Ê" },
185 { "Egrave;", "È" },
186 { "Euml;", "Ë" },
187 { "Iacute;", "Í" },
188 { "Icirc;", "Î" },
189 { "Igrave;", "Ì" },
190 { "Iuml;", "Ï" },
191 { "Ntilde;", "Ñ" },
192 { "OElig;", "Œ" },
193 { "Oacute;", "Ó" },
194 { "Ocirc;", "Ô" },
195 { "Ograve;", "Ò" },
196 { "Oslash;", "Ø" },
197 { "Otilde;", "Õ" },
198 { "Ouml;", "Ö" },
199 { "Scaron;", "Š" },
200 { "THORN;", "Þ" },
201 { "Uacute;", "Ú" },
202 { "Ucirc;", "Û" },
203 { "Ugrave;", "Ù" },
204 { "Uuml;", "Ü" },
205 { "Yacute;", "Ý" },
206 { "Yuml;", "Ÿ" },
207 { "aacute;", "á" },
208 { "acirc;", "â" },
209 { "acute;", "´" },
210 { "aelig;", "æ" },
211 { "agrave;", "à" },
212 { "amp;", "&" },
213 { "apos;", "'" },
214 { "aring;", "å" },
215 { "atilde;", "ã" },
216 { "auml;", "ä" },
217 { "bdquo;", "„" },
218 { "brvbar;", "¦" },
219 { "ccedil;", "ç" },
220 { "cedil;", "¸" },
221 { "cent;", "¢" },
222 { "circ;", "ˆ" },
223 { "copy;", "©" },
224 { "curren;", "¤" },
225 { "dagger;", "†" },
226 { "deg;", "°" },
227 { "divide;", "÷" },
228 { "eacute;", "é" },
229 { "ecirc;", "ê" },
230 { "egrave;", "è" },
231 { "eth;", "ð" },
232 { "euml;", "ë" },
233 { "euro;", "€" },
234 { "frac12;", "½" },
235 { "frac14;", "¼" },
236 { "frac34;", "¾" },
237 { "gt;", ">" },
238 { "hellip;", "…" },
239 { "iacute;", "í" },
240 { "icirc;", "î" },
241 { "iexcl;", "¡" },
242 { "igrave;", "ì" },
243 { "iquest;", "¿" },
244 { "iuml;", "ï" },
245 { "laquo;", "«" },
246 { "ldquo;", "“" },
247 { "lsaquo;", "‹" },
248 { "lsquo;", "‘" },
249 { "lt;", "<" },
250 { "macr;", "¯" },
251 { "mdash;", "—" },
252 { "micro;", "µ" },
253 { "middot;", "·" },
254 { "nbsp;", "\xc2\xa0" },
255 { "ndash;", "–" },
256 { "not;", "¬" },
257 { "ntilde;", "ñ" },
258 { "oacute;", "ó" },
259 { "ocirc;", "ô" },
260 { "oelig;", "œ" },
261 { "ograve;", "ò" },
262 { "ordf;", "ª" },
263 { "ordm;", "º" },
264 { "oslash;", "ø" },
265 { "otilde;", "õ" },
266 { "ouml;", "ö" },
267 { "para;", "¶" },
268 { "permil;", "‰" },
269 { "plusmn;", "±" },
270 { "pound;", "£" },
271 { "quot;", "\"" },
272 { "raquo;", "»" },
273 { "rdquo;", "”" },
274 { "reg;", "®" },
275 { "rsaquo;", "›" },
276 { "rsquo;", "’" },
277 { "sbquo;", "‚" },
278 { "scaron;", "š" },
279 { "sect;", "§" },
280 { "shy;", "­" },
281 { "sup1;", "¹" },
282 { "sup2;", "²" },
283 { "sup3;", "³" },
284 { "szlig;", "ß" },
285 { "thorn;", "þ" },
286 { "tilde;", "˜" },
287 { "times;", "×" },
288 { "trade;", "™" },
289 { "uacute;", "ú" },
290 { "ucirc;", "û" },
291 { "ugrave;", "ù" },
292 { "uml;", "¨" },
293 { "uuml;", "ü" },
294 { "yacute;", "ý" },
295 { "yen;", "¥" },
296 { "yuml;", "ÿ" },
299 static int cmp_entity (const void *key, const void *elem)
301 const struct xml_entity_s *ent = elem;
302 const char *name = key;
304 return strncmp (name, ent->psz_entity, strlen (ent->psz_entity));
308 * Converts "&lt;", "&gt;" and "&amp;" to "<", ">" and "&"
309 * \param string to convert
311 void resolve_xml_special_chars( char *psz_value )
313 char *p_pos = psz_value;
315 while ( *psz_value )
317 if( *psz_value == '&' )
319 if( psz_value[1] == '#' )
320 { /* &#xxx; Unicode code point */
321 char *psz_end;
322 unsigned long cp = strtoul( psz_value+2, &psz_end, 10 );
323 if( *psz_end == ';' )
325 psz_value = psz_end + 1;
326 if( cp == 0 )
327 (void)0; /* skip nuls */
328 else
329 if( cp <= 0x7F )
331 *p_pos = cp;
333 else
334 /* Unicode code point outside ASCII.
335 * &#xxx; representation is longer than UTF-8 :) */
336 if( cp <= 0x7FF )
338 *p_pos++ = 0xC0 | (cp >> 6);
339 *p_pos = 0x80 | (cp & 0x3F);
341 else
342 if( cp <= 0xFFFF )
344 *p_pos++ = 0xE0 | (cp >> 12);
345 *p_pos++ = 0x80 | ((cp >> 6) & 0x3F);
346 *p_pos = 0x80 | (cp & 0x3F);
348 else
349 if( cp <= 0x1FFFFF ) /* Outside the BMP */
350 { /* Unicode stops at 10FFFF, but who cares? */
351 *p_pos++ = 0xF0 | (cp >> 18);
352 *p_pos++ = 0x80 | ((cp >> 12) & 0x3F);
353 *p_pos++ = 0x80 | ((cp >> 6) & 0x3F);
354 *p_pos = 0x80 | (cp & 0x3F);
357 else
359 /* Invalid entity number */
360 *p_pos = *psz_value;
361 psz_value++;
364 else
365 { /* Well-known XML entity */
366 const struct xml_entity_s *ent;
368 ent = bsearch (psz_value + 1, xml_entities,
369 sizeof (xml_entities) / sizeof (*ent),
370 sizeof (*ent), cmp_entity);
371 if (ent != NULL)
373 size_t olen = strlen (ent->psz_char);
374 memcpy (p_pos, ent->psz_char, olen);
375 p_pos += olen - 1;
376 psz_value += strlen (ent->psz_entity) + 1;
378 else
379 { /* No match */
380 *p_pos = *psz_value;
381 psz_value++;
385 else
387 *p_pos = *psz_value;
388 psz_value++;
391 p_pos++;
394 *p_pos = '\0';
398 * XML-encode an UTF-8 string
399 * \param str nul-terminated UTF-8 byte sequence to XML-encode
400 * \return XML encoded string or NULL on error
401 * (errno is set to ENOMEM or EILSEQ as appropriate)
403 char *convert_xml_special_chars (const char *str)
405 assert (str != NULL);
407 const size_t len = strlen (str);
408 char *const buf = malloc (6 * len + 1), *ptr = buf;
409 if (unlikely(buf == NULL))
410 return NULL;
412 size_t n;
413 uint32_t cp;
415 while ((n = vlc_towc (str, &cp)) != 0)
417 if (unlikely(n == (size_t)-1))
419 free (buf);
420 errno = EILSEQ;
421 return NULL;
424 if ((cp & ~0x0080) < 32 /* C0/C1 control codes */
425 && strchr ("\x09\x0A\x0D\x85", cp) == NULL)
426 ptr += sprintf (ptr, "&#%"PRIu32";", cp);
427 else
428 switch (cp)
430 case '\"': strcpy (ptr, "&quot;"); ptr += 6; break;
431 case '&': strcpy (ptr, "&amp;"); ptr += 5; break;
432 case '\'': strcpy (ptr, "&#39;"); ptr += 5; break;
433 case '<': strcpy (ptr, "&lt;"); ptr += 4; break;
434 case '>': strcpy (ptr, "&gt;"); ptr += 4; break;
435 default: memcpy (ptr, str, n); ptr += n; break;
437 str += n;
439 *(ptr++) = '\0';
441 ptr = realloc (buf, ptr - buf);
442 return likely(ptr != NULL) ? ptr : buf; /* cannot fail */
445 /* Base64 encoding */
446 char *vlc_b64_encode_binary( const uint8_t *src, size_t i_src )
448 static const char b64[] =
449 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
451 char *ret = malloc( ( i_src + 4 ) * 4 / 3 );
452 char *dst = ret;
454 if( dst == NULL )
455 return NULL;
457 while( i_src > 0 )
459 /* pops (up to) 3 bytes of input, push 4 bytes */
460 uint32_t v;
462 /* 1/3 -> 1/4 */
463 v = *src++ << 24;
464 *dst++ = b64[v >> 26];
465 v = v << 6;
467 /* 2/3 -> 2/4 */
468 if( i_src >= 2 )
469 v |= *src++ << 22;
470 *dst++ = b64[v >> 26];
471 v = v << 6;
473 /* 3/3 -> 3/4 */
474 if( i_src >= 3 )
475 v |= *src++ << 20; // 3/3
476 *dst++ = ( i_src >= 2 ) ? b64[v >> 26] : '='; // 3/4
477 v = v << 6;
479 /* -> 4/4 */
480 *dst++ = ( i_src >= 3 ) ? b64[v >> 26] : '='; // 4/4
482 if( i_src <= 3 )
483 break;
484 i_src -= 3;
487 *dst = '\0';
489 return ret;
492 char *vlc_b64_encode( const char *src )
494 if( src )
495 return vlc_b64_encode_binary( (const uint8_t*)src, strlen(src) );
496 else
497 return vlc_b64_encode_binary( (const uint8_t*)"", 0 );
500 /* Base64 decoding */
501 size_t vlc_b64_decode_binary_to_buffer( uint8_t *p_dst, size_t i_dst, const char *p_src )
503 static const int b64[256] = {
504 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 00-0F */
505 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 10-1F */
506 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, /* 20-2F */
507 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, /* 30-3F */
508 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, /* 40-4F */
509 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, /* 50-5F */
510 -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, /* 60-6F */
511 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, /* 70-7F */
512 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 80-8F */
513 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 90-9F */
514 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* A0-AF */
515 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* B0-BF */
516 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* C0-CF */
517 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* D0-DF */
518 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* E0-EF */
519 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 /* F0-FF */
521 uint8_t *p_start = p_dst;
522 uint8_t *p = (uint8_t *)p_src;
524 int i_level;
525 int i_last;
527 for( i_level = 0, i_last = 0; (size_t)( p_dst - p_start ) < i_dst && *p != '\0'; p++ )
529 const int c = b64[(unsigned int)*p];
530 if( c == -1 )
531 continue;
533 switch( i_level )
535 case 0:
536 i_level++;
537 break;
538 case 1:
539 *p_dst++ = ( i_last << 2 ) | ( ( c >> 4)&0x03 );
540 i_level++;
541 break;
542 case 2:
543 *p_dst++ = ( ( i_last << 4 )&0xf0 ) | ( ( c >> 2 )&0x0f );
544 i_level++;
545 break;
546 case 3:
547 *p_dst++ = ( ( i_last &0x03 ) << 6 ) | c;
548 i_level = 0;
550 i_last = c;
553 return p_dst - p_start;
555 size_t vlc_b64_decode_binary( uint8_t **pp_dst, const char *psz_src )
557 const int i_src = strlen( psz_src );
558 uint8_t *p_dst;
560 *pp_dst = p_dst = malloc( i_src );
561 if( !p_dst )
562 return 0;
563 return vlc_b64_decode_binary_to_buffer( p_dst, i_src, psz_src );
565 char *vlc_b64_decode( const char *psz_src )
567 const int i_src = strlen( psz_src );
568 char *p_dst = malloc( i_src + 1 );
569 size_t i_dst;
570 if( !p_dst )
571 return NULL;
573 i_dst = vlc_b64_decode_binary_to_buffer( (uint8_t*)p_dst, i_src, psz_src );
574 p_dst[i_dst] = '\0';
576 return p_dst;
580 * Formats current time into a heap-allocated string.
581 * @param tformat time format (as with C strftime())
582 * @return an allocated string (must be free()'d), or NULL on memory error.
584 char *str_format_time( const char *tformat )
586 time_t curtime;
587 struct tm loctime;
589 if (strcmp (tformat, "") == 0)
590 return strdup (""); /* corner case w.r.t. strftime() return value */
592 /* Get the current time. */
593 time( &curtime );
595 /* Convert it to local time representation. */
596 localtime_r( &curtime, &loctime );
597 for (size_t buflen = strlen (tformat) + 32;; buflen += 32)
599 char *str = malloc (buflen);
600 if (str == NULL)
601 return NULL;
603 size_t len = strftime (str, buflen, tformat, &loctime);
604 if (len > 0)
606 char *ret = realloc (str, len + 1);
607 return ret ? ret : str; /* <- this cannot fail */
610 assert (0);
613 static void format_duration (char *buf, size_t len, int64_t duration)
615 lldiv_t d;
616 int sec;
618 duration /= CLOCK_FREQ;
619 d = lldiv (duration, 60);
620 sec = d.rem;
621 d = lldiv (d.quot, 60);
622 snprintf (buf, len, "%02lld:%02d:%02d", d.quot, (int)d.rem, sec);
625 #define INSERT_STRING( string ) \
626 if( string != NULL ) \
628 int len = strlen( string ); \
629 dst = xrealloc( dst, i_size = i_size + len );\
630 memcpy( (dst+d), string, len ); \
631 d += len; \
632 free( string ); \
635 /* same than INSERT_STRING, except that string won't be freed */
636 #define INSERT_STRING_NO_FREE( string ) \
638 int len = strlen( string ); \
639 dst = xrealloc( dst, i_size = i_size + len );\
640 memcpy( dst+d, string, len ); \
641 d += len; \
643 #undef str_format_meta
644 char *str_format_meta( vlc_object_t *p_object, const char *string )
646 const char *s = string;
647 bool b_is_format = false;
648 bool b_empty_if_na = false;
649 char buf[10];
650 int i_size = strlen( string ) + 1; /* +1 to store '\0' */
651 char *dst = strdup( string );
652 if( !dst ) return NULL;
653 int d = 0;
655 input_thread_t *p_input = playlist_CurrentInput( pl_Get(p_object) );
656 input_item_t *p_item = NULL;
657 if( p_input )
659 p_item = input_GetItem(p_input);
662 while( *s )
664 if( b_is_format )
666 switch( *s )
668 case 'a':
669 if( p_item )
671 INSERT_STRING( input_item_GetArtist( p_item ) );
673 break;
674 case 'b':
675 if( p_item )
677 INSERT_STRING( input_item_GetAlbum( p_item ) );
679 break;
680 case 'c':
681 if( p_item )
683 INSERT_STRING( input_item_GetCopyright( p_item ) );
685 break;
686 case 'd':
687 if( p_item )
689 INSERT_STRING( input_item_GetDescription( p_item ) );
691 break;
692 case 'e':
693 if( p_item )
695 INSERT_STRING( input_item_GetEncodedBy( p_item ) );
697 break;
698 case 'f':
699 if( p_item && p_item->p_stats )
701 vlc_mutex_lock( &p_item->p_stats->lock );
702 snprintf( buf, 10, "%"PRIi64,
703 p_item->p_stats->i_displayed_pictures );
704 vlc_mutex_unlock( &p_item->p_stats->lock );
706 else
707 strcpy( buf, b_empty_if_na ? "" : "-" );
708 INSERT_STRING_NO_FREE( buf );
709 break;
710 case 'g':
711 if( p_item )
713 INSERT_STRING( input_item_GetGenre( p_item ) );
715 break;
716 case 'l':
717 if( p_item )
719 INSERT_STRING( input_item_GetLanguage( p_item ) );
721 break;
722 case 'n':
723 if( p_item )
725 INSERT_STRING( input_item_GetTrackNum( p_item ) );
727 break;
728 case 'p':
729 if( p_item )
731 INSERT_STRING( input_item_GetNowPlaying( p_item ) );
733 break;
734 case 'r':
735 if( p_item )
737 INSERT_STRING( input_item_GetRating( p_item ) );
739 break;
740 case 's':
742 char *psz_lang = NULL;
743 if( p_input )
744 psz_lang = var_GetNonEmptyString( p_input, "sub-language" );
745 if( psz_lang == NULL )
746 psz_lang = strdup( b_empty_if_na ? "" : "-" );
747 INSERT_STRING( psz_lang );
748 break;
750 case 't':
751 if( p_item )
753 INSERT_STRING( input_item_GetTitle( p_item ) );
755 break;
756 case 'u':
757 if( p_item )
759 INSERT_STRING( input_item_GetURL( p_item ) );
761 break;
762 case 'A':
763 if( p_item )
765 INSERT_STRING( input_item_GetDate( p_item ) );
767 break;
768 case 'B':
769 if( p_input )
771 snprintf( buf, 10, "%"PRId64,
772 var_GetInteger( p_input, "bit-rate" )/1000 );
774 else
775 strcpy( buf, b_empty_if_na ? "" : "-" );
776 INSERT_STRING_NO_FREE( buf );
777 break;
778 case 'C':
779 if( p_input )
781 snprintf( buf, 10, "%"PRId64,
782 var_GetInteger( p_input, "chapter" ) );
784 else
785 strcpy( buf, b_empty_if_na ? "" : "-" );
786 INSERT_STRING_NO_FREE( buf );
787 break;
788 case 'D':
789 if( p_item )
791 mtime_t i_duration = input_item_GetDuration( p_item );
792 format_duration (buf, sizeof (buf), i_duration);
794 else
795 strcpy( buf, b_empty_if_na ? "" : "--:--:--" );
796 INSERT_STRING_NO_FREE( buf );
797 break;
798 case 'F':
799 if( p_item )
801 INSERT_STRING( input_item_GetURI( p_item ) );
803 break;
804 case 'I':
805 if( p_input )
807 snprintf( buf, 10, "%"PRId64,
808 var_GetInteger( p_input, "title" ) );
810 else
811 strcpy( buf, b_empty_if_na ? "" : "-" );
812 INSERT_STRING_NO_FREE( buf );
813 break;
814 case 'L':
815 if( p_item && p_input )
817 mtime_t i_duration = input_item_GetDuration( p_item );
818 int64_t i_time = var_GetTime( p_input, "time" );
819 format_duration( buf, sizeof(buf),
820 i_duration - i_time );
822 else
823 strcpy( buf, b_empty_if_na ? "" : "--:--:--" );
824 INSERT_STRING_NO_FREE( buf );
825 break;
826 case 'N':
827 if( p_item )
829 INSERT_STRING( input_item_GetName( p_item ) );
831 break;
832 case 'O':
834 char *lang = NULL;
835 if( p_input )
836 lang = var_GetNonEmptyString( p_input,
837 "audio-language" );
838 if( lang == NULL )
839 lang = strdup( b_empty_if_na ? "" : "-" );
840 INSERT_STRING( lang );
841 break;
843 case 'P':
844 if( p_input )
846 snprintf( buf, 10, "%2.1lf",
847 var_GetFloat( p_input, "position" ) * 100. );
849 else
851 snprintf( buf, 10, b_empty_if_na ? "" : "--.-%%" );
853 INSERT_STRING_NO_FREE( buf );
854 break;
855 case 'R':
856 if( p_input )
858 float f = var_GetFloat( p_input, "rate" );
859 snprintf( buf, 10, "%.3f", f );
861 else
862 strcpy( buf, b_empty_if_na ? "" : "-" );
863 INSERT_STRING_NO_FREE( buf );
864 break;
865 case 'S':
866 if( p_input )
868 int r = var_GetInteger( p_input, "sample-rate" );
869 snprintf( buf, 10, "%d.%d", r/1000, (r/100)%10 );
871 else
872 strcpy( buf, b_empty_if_na ? "" : "-" );
873 INSERT_STRING_NO_FREE( buf );
874 break;
875 case 'T':
876 if( p_input )
878 int64_t i_time = var_GetTime( p_input, "time" );
879 format_duration( buf, sizeof(buf), i_time );
881 else
882 strcpy( buf, b_empty_if_na ? "" : "--:--:--" );
883 INSERT_STRING_NO_FREE( buf );
884 break;
885 case 'U':
886 if( p_item )
888 INSERT_STRING( input_item_GetPublisher( p_item ) );
890 break;
891 case 'V':
893 audio_volume_t volume = aout_VolumeGet( p_object );
894 snprintf( buf, 10, "%d", volume );
895 INSERT_STRING_NO_FREE( buf );
896 break;
898 case '_':
899 *(dst+d) = '\n';
900 d++;
901 break;
902 case 'Z':
903 if( p_item )
905 char *psz_now_playing = input_item_GetNowPlaying( p_item );
906 if ( psz_now_playing == NULL )
908 char *psz_temp = input_item_GetTitleFbName( p_item );
909 char *psz_artist = input_item_GetArtist( p_item );
910 if( !EMPTY_STR( psz_temp ) )
912 INSERT_STRING( psz_temp );
913 if ( !EMPTY_STR( psz_artist ) )
914 INSERT_STRING_NO_FREE( " - " );
916 INSERT_STRING( psz_artist );
918 else
919 INSERT_STRING( psz_now_playing );
921 break;
923 case ' ':
924 b_empty_if_na = true;
925 break;
927 default:
928 *(dst+d) = *s;
929 d++;
930 break;
932 if( *s != ' ' )
933 b_is_format = false;
935 else if( *s == '$' )
937 b_is_format = true;
938 b_empty_if_na = false;
940 else
942 *(dst+d) = *s;
943 d++;
945 s++;
947 *(dst+d) = '\0';
949 if( p_input )
950 vlc_object_release( p_input );
952 return dst;
954 #undef INSERT_STRING
955 #undef INSERT_STRING_NO_FREE
957 #undef str_format
959 * Apply str format time and str format meta
961 char *str_format( vlc_object_t *p_this, const char *psz_src )
963 char *psz_buf1, *psz_buf2;
964 psz_buf1 = str_format_time( psz_src );
965 psz_buf2 = str_format_meta( p_this, psz_buf1 );
966 free( psz_buf1 );
967 return psz_buf2;
971 * Remove forbidden, potentially forbidden and otherwise evil characters from
972 * filenames. This includes slashes, and popular characters like colon
973 * (on Unix anyway), so this should only be used for automatically generated
974 * filenames.
975 * \warning Do not use this on full paths,
976 * only single file names without any directory separator!
978 void filename_sanitize( char *str )
980 unsigned char c;
982 /* Special file names, not allowed */
983 if( !strcmp( str, "." ) || !strcmp( str, ".." ) )
985 while( *str )
986 *(str++) = '_';
987 return;
990 /* On platforms not using UTF-7, VLC cannot access non-Unicode paths.
991 * Also, some file systems require Unicode file names.
992 * NOTE: This may inserts '?' thus is done replacing '?' with '_'. */
993 EnsureUTF8( str );
995 /* Avoid leading spaces to please Windows. */
996 while( (c = *str) != '\0' )
998 if( c != ' ' )
999 break;
1000 *(str++) = '_';
1003 char *start = str;
1005 while( (c = *str) != '\0' )
1007 /* Non-printable characters are not a good idea */
1008 if( c < 32 )
1009 *str = '_';
1010 /* This is the list of characters not allowed by Microsoft.
1011 * We also black-list them on Unix as they may be confusing, and are
1012 * not supported by some file system types (notably CIFS). */
1013 else if( strchr( "/:\\*\"?|<>", c ) != NULL )
1014 *str = '_';
1015 str++;
1018 /* Avoid trailing spaces also to please Windows. */
1019 while( str > start )
1021 if( *(--str) != ' ' )
1022 break;
1023 *str = '_';
1028 * Remove forbidden characters from full paths (leaves slashes)
1030 void path_sanitize( char *str )
1032 #if defined( WIN32 ) || defined( __OS2__ )
1033 /* check drive prefix if path is absolute */
1034 if( (((unsigned char)(str[0] - 'A') < 26)
1035 || ((unsigned char)(str[0] - 'a') < 26)) && (':' == str[1]) )
1036 str += 2;
1037 #endif
1038 while( *str )
1040 #if defined( __APPLE__ )
1041 if( *str == ':' )
1042 *str = '_';
1043 #elif defined( WIN32 ) || defined( __OS2__ )
1044 if( strchr( "*\"?:|<>", *str ) )
1045 *str = '_';
1046 if( *str == '/' )
1047 *str = DIR_SEP_CHAR;
1048 #endif
1049 str++;
1053 #include <vlc_url.h>
1054 #ifdef WIN32
1055 # include <io.h>
1056 #endif
1059 * Convert a file path to a URI.
1060 * If already a URI, return a copy of the string.
1061 * @param path path to convert (or URI to copy)
1062 * @param scheme URI scheme to use (default is auto: "file", "fd" or "smb")
1063 * @return a nul-terminated URI string (use free() to release it),
1064 * or NULL in case of error
1066 char *make_URI (const char *path, const char *scheme)
1068 if (path == NULL)
1069 return NULL;
1070 if (scheme == NULL && !strcmp (path, "-"))
1071 return strdup ("fd://0"); // standard input
1072 if (strstr (path, "://") != NULL)
1073 return strdup (path); /* Already a URI */
1074 /* Note: VLC cannot handle URI schemes without double slash after the
1075 * scheme name (such as mailto: or news:). */
1077 char *buf;
1079 #ifdef __OS2__
1080 char p[strlen (path) + 1];
1082 for (buf = p; *path; buf++, path++)
1083 *buf = (*path == '/') ? DIR_SEP_CHAR : *path;
1084 *buf = '\0';
1086 path = p;
1087 #endif
1089 #if defined( WIN32 ) || defined( __OS2__ )
1090 /* Drive letter */
1091 if (isalpha ((unsigned char)path[0]) && (path[1] == ':'))
1093 if (asprintf (&buf, "%s:///%c:", scheme ? scheme : "file",
1094 path[0]) == -1)
1095 buf = NULL;
1096 path += 2;
1097 # warning Drive letter-relative path not implemented!
1098 if (path[0] != DIR_SEP_CHAR)
1099 return NULL;
1101 else
1102 #endif
1103 if (!strncmp (path, "\\\\", 2))
1104 { /* Windows UNC paths */
1105 #if !defined( WIN32 ) && !defined( __OS2__ )
1106 if (scheme != NULL)
1107 return NULL; /* remote files not supported */
1109 /* \\host\share\path -> smb://host/share/path */
1110 if (strchr (path + 2, '\\') != NULL)
1111 { /* Convert backslashes to slashes */
1112 char *dup = strdup (path);
1113 if (dup == NULL)
1114 return NULL;
1115 for (size_t i = 2; dup[i]; i++)
1116 if (dup[i] == '\\')
1117 dup[i] = DIR_SEP_CHAR;
1119 char *ret = make_URI (dup, scheme);
1120 free (dup);
1121 return ret;
1123 # define SMB_SCHEME "smb"
1124 #else
1125 /* \\host\share\path -> file://host/share/path */
1126 # define SMB_SCHEME "file"
1127 #endif
1128 size_t hostlen = strcspn (path + 2, DIR_SEP);
1130 buf = malloc (sizeof (SMB_SCHEME) + 3 + hostlen);
1131 if (buf != NULL)
1132 snprintf (buf, sizeof (SMB_SCHEME) + 3 + hostlen,
1133 SMB_SCHEME"://%s", path + 2);
1134 path += 2 + hostlen;
1136 if (path[0] == '\0')
1137 return buf; /* Hostname without path */
1139 else
1140 if (path[0] != DIR_SEP_CHAR)
1141 { /* Relative path: prepend the current working directory */
1142 char *cwd, *ret;
1144 if ((cwd = vlc_getcwd ()) == NULL)
1145 return NULL;
1146 if (asprintf (&buf, "%s"DIR_SEP"%s", cwd, path) == -1)
1147 buf = NULL;
1149 free (cwd);
1150 ret = (buf != NULL) ? make_URI (buf, scheme) : NULL;
1151 free (buf);
1152 return ret;
1154 else
1155 if (asprintf (&buf, "%s://", scheme ? scheme : "file") == -1)
1156 buf = NULL;
1157 if (buf == NULL)
1158 return NULL;
1160 assert (path[0] == DIR_SEP_CHAR);
1162 /* Absolute file path */
1163 for (const char *ptr = path + 1;; ptr++)
1165 size_t len = strcspn (ptr, DIR_SEP);
1166 char *component = encode_URI_bytes (ptr, len);
1167 if (component == NULL)
1169 free (buf);
1170 return NULL;
1172 char *uri;
1173 int val = asprintf (&uri, "%s/%s", buf, component);
1174 free (component);
1175 free (buf);
1176 if (val == -1)
1177 return NULL;
1178 buf = uri;
1179 ptr += len;
1180 if (*ptr == '\0')
1181 return buf;
1186 * Tries to convert a URI to a local (UTF-8-encoded) file path.
1187 * @param url URI to convert
1188 * @return NULL on error, a nul-terminated string otherwise
1189 * (use free() to release it)
1191 char *make_path (const char *url)
1193 char *ret = NULL;
1194 char *end;
1196 char *path = strstr (url, "://");
1197 if (path == NULL)
1198 return NULL; /* unsupported scheme or invalid syntax */
1200 end = memchr (url, '/', path - url);
1201 size_t schemelen = ((end != NULL) ? end : path) - url;
1202 path += 3; /* skip "://" */
1204 /* Remove HTML anchor if present */
1205 end = strchr (path, '#');
1206 if (end)
1207 path = strndup (path, end - path);
1208 else
1209 path = strdup (path);
1210 if (unlikely(path == NULL))
1211 return NULL; /* boom! */
1213 /* Decode path */
1214 decode_URI (path);
1216 if (schemelen == 4 && !strncasecmp (url, "file", 4))
1218 #if (!defined (WIN32) && !defined (__OS2__)) || defined (UNDER_CE)
1219 /* Leading slash => local path */
1220 if (*path == '/')
1221 return path;
1222 /* Local path disguised as a remote one */
1223 if (!strncasecmp (path, "localhost/", 10))
1224 return memmove (path, path + 9, strlen (path + 9) + 1);
1225 #else
1226 for (char *p = strchr (path, '/'); p; p = strchr (p + 1, '/'))
1227 *p = '\\';
1229 /* Leading backslash => local path */
1230 if (*path == '\\')
1231 return memmove (path, path + 1, strlen (path + 1) + 1);
1232 /* Local path disguised as a remote one */
1233 if (!strncasecmp (path, "localhost\\", 10))
1234 return memmove (path, path + 10, strlen (path + 10) + 1);
1235 /* UNC path */
1236 if (*path && asprintf (&ret, "\\\\%s", path) == -1)
1237 ret = NULL;
1238 #endif
1239 /* non-local path :-( */
1241 else
1242 if (schemelen == 2 && !strncasecmp (url, "fd", 2))
1244 int fd = strtol (path, &end, 0);
1246 if (*end)
1247 goto out;
1249 #if !defined( WIN32 ) && !defined( __OS2__ )
1250 switch (fd)
1252 case 0:
1253 ret = strdup ("/dev/stdin");
1254 break;
1255 case 1:
1256 ret = strdup ("/dev/stdout");
1257 break;
1258 case 2:
1259 ret = strdup ("/dev/stderr");
1260 break;
1261 default:
1262 if (asprintf (&ret, "/dev/fd/%d", fd) == -1)
1263 ret = NULL;
1265 #else
1266 /* XXX: Does this work on WinCE? */
1267 if (fd < 2)
1268 ret = strdup ("CON");
1269 else
1270 ret = NULL;
1271 #endif
1274 out:
1275 free (path);
1276 return ret; /* unknown scheme */
1280 Decodes a duration as defined by ISO 8601
1281 http://en.wikipedia.org/wiki/ISO_8601#Durations
1282 @param str A null-terminated string to convert
1283 @return: The duration in seconds. -1 if an error occured.
1285 Exemple input string: "PT0H9M56.46S"
1287 time_t str_duration( const char *psz_duration )
1289 bool timeDesignatorReached = false;
1290 time_t res = 0;
1291 char* end_ptr;
1293 if ( psz_duration == NULL )
1294 return -1;
1295 if ( ( *(psz_duration++) ) != 'P' )
1296 return -1;
1299 double number = strtod( psz_duration, &end_ptr );
1300 double mul = 0;
1301 if ( psz_duration != end_ptr )
1302 psz_duration = end_ptr;
1303 switch( *psz_duration )
1305 case 'M':
1307 //M can mean month or minutes, if the 'T' flag has been reached.
1308 //We don't handle months though.
1309 if ( timeDesignatorReached == true )
1310 mul = 60.0;
1311 break ;
1313 case 'Y':
1314 case 'W':
1315 break ; //Don't handle this duration.
1316 case 'D':
1317 mul = 86400.0;
1318 break ;
1319 case 'T':
1320 timeDesignatorReached = true;
1321 break ;
1322 case 'H':
1323 mul = 3600.0;
1324 break ;
1325 case 'S':
1326 mul = 1.0;
1327 break ;
1328 default:
1329 break ;
1331 res += (time_t)(mul * number);
1332 if ( *psz_duration )
1333 psz_duration++;
1334 } while ( *psz_duration );
1335 return res;