/* * Copyright (C) 2000-2003 the xine project * * This file is part of xine, a free video player. * * xine is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * xine is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA * * stream metainfo helper functions * hide some xine engine details from demuxers and reduce code duplication */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #ifdef HAVE_ICONV # include #endif #define XINE_ENGINE_INTERNAL #include "info_helper.h" /* ******************* Stream Info *************************** */ /* * Compare stream_info, private and public values, * return 1 if it's identical, otherwirse 0. */ static int stream_info_is_identical(xine_stream_t *stream, int info) { if(stream->stream_info_public[info] == stream->stream_info[info]) return 1; return 0; } /* * Check if 'info' is in bounds. */ static int info_valid(int info) { if ((info >= 0) && (info < XINE_STREAM_INFO_MAX)) return 1; else { fprintf(stderr, "Error: invalid STREAM_INFO %d. Ignored.\n", info); return 0; } } static void stream_info_set_unlocked(xine_stream_t *stream, int info, int value) { if(info_valid(info)) stream->stream_info[info] = value; } /* * Reset private info. */ void _x_stream_info_reset(xine_stream_t *stream, int info) { pthread_mutex_lock(&stream->info_mutex); stream_info_set_unlocked(stream, info, 0); pthread_mutex_unlock(&stream->info_mutex); } /* * Reset public info value. */ void _x_stream_info_public_reset(xine_stream_t *stream, int info) { pthread_mutex_lock(&stream->info_mutex); if(info_valid(info)) stream->stream_info_public[info] = 0; pthread_mutex_unlock(&stream->info_mutex); } /* * Set private info value. */ void _x_stream_info_set(xine_stream_t *stream, int info, int value) { pthread_mutex_lock(&stream->info_mutex); stream_info_set_unlocked(stream, info, value); pthread_mutex_unlock(&stream->info_mutex); } /* * Retrieve private info value. */ uint32_t _x_stream_info_get(xine_stream_t *stream, int info) { uint32_t stream_info = 0; pthread_mutex_lock(&stream->info_mutex); stream_info = stream->stream_info[info]; pthread_mutex_unlock(&stream->info_mutex); return stream_info; } /* * Retrieve public info value */ uint32_t _x_stream_info_get_public(xine_stream_t *stream, int info) { uint32_t stream_info = 0; pthread_mutex_lock(&stream->info_mutex); stream_info = stream->stream_info_public[info]; if(info_valid(info) && (!stream_info_is_identical(stream, info))) stream_info = stream->stream_info_public[info] = stream->stream_info[info]; pthread_mutex_unlock(&stream->info_mutex); return stream_info; } /* **************** Meta Info *********************** */ /* * Remove trailing separator chars (\n,\r,\t, space,...) * at the end of the string */ static void meta_info_chomp(char *str) { int i, len; len = strlen(str); if (!len) return; i = len - 1; while ((i >= 0) && ((unsigned char)str[i] <= 32)) { str[i] = 0; i--; } } /* * Compare stream_info, public and private values, * return 1 if it's identical, otherwise 0. */ static int meta_info_is_identical(xine_stream_t *stream, int info) { if((!(stream->meta_info_public[info] && stream->meta_info[info])) || ((stream->meta_info_public[info] && stream->meta_info[info]) && strcmp(stream->meta_info_public[info], stream->meta_info[info]))) return 0; return 1; } /* * Check if 'info' is in bounds. */ static int meta_valid(int info) { if ((info >= 0) && (info < XINE_STREAM_INFO_MAX)) return 1; else { fprintf(stderr, "Error: invalid META_INFO %d. Ignored.\n", info); return 0; } } /* * Set private meta info to utf-8 string value (can be NULL). */ static void meta_info_set_unlocked_utf8(xine_stream_t *stream, int info, const char *value) { if(meta_valid(info)) { if(stream->meta_info[info]) free(stream->meta_info[info]); stream->meta_info[info] = (value) ? strdup(value) : NULL; if(stream->meta_info[info] && strlen(stream->meta_info[info])) meta_info_chomp(stream->meta_info[info]); } } #ifdef HAVE_ICONV static int meta_info_validate_utf8 (const char *value) { iconv_t cd; char *utf8_value; ICONV_CONST char *inbuf; char *outbuf; size_t inbytesleft, outbytesleft; if ((cd = iconv_open("UTF-8", "UTF-8")) == (iconv_t)-1) { return 0; } inbuf = (ICONV_CONST char *)value; inbytesleft = strlen(value); outbytesleft = 4 * inbytesleft; /* estimative (max) */ outbuf = utf8_value = malloc(outbytesleft+1); iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft ); free(utf8_value); iconv_close(cd); return (inbytesleft == 0); } #endif /* * Set private meta info to value (can be NULL) with a given encoding. * if encoding is NULL assume locale. */ static void meta_info_set_unlocked_encoding(xine_stream_t *stream, int info, const char *value, const char *enc) { #ifdef HAVE_ICONV iconv_t cd; char *system_enc = NULL; if (value) { if (enc == NULL) { if ((enc = system_enc = xine_get_system_encoding()) == NULL) { xprintf(stream->xine, XINE_VERBOSITY_LOG, _("info_helper: can't find out current locale character set\n")); } } if (enc && strcmp(enc, "UTF-8")) { /* Don't bother converting if it's already in UTF-8, but the encoding * is badly reported */ if (meta_info_validate_utf8(value)) { meta_info_set_unlocked_utf8(stream, info, value); return; } cd = iconv_open("UTF-8", enc); if (cd == (iconv_t)-1) xprintf(stream->xine, XINE_VERBOSITY_LOG, _("info_helper: unsupported conversion %s -> UTF-8, no conversion performed\n"), enc); if (system_enc) free(system_enc); if (cd != (iconv_t)-1) { char *utf8_value; ICONV_CONST char *inbuf; char *outbuf; size_t inbytesleft, outbytesleft; inbuf = (ICONV_CONST char *)value; inbytesleft = strlen(value); outbytesleft = 4 * inbytesleft; /* estimative (max) */ outbuf = utf8_value = malloc(outbytesleft+1); iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft ); *outbuf = '\0'; meta_info_set_unlocked_utf8(stream, info, utf8_value); free(utf8_value); iconv_close(cd); return; } } } #endif meta_info_set_unlocked_utf8(stream, info, value); } /* * Set private meta info to value (can be NULL) * value string must be provided with current locale encoding. */ static void meta_info_set_unlocked(xine_stream_t *stream, int info, const char *value) { meta_info_set_unlocked_encoding(stream, info, value, NULL); } /* * Reset (nullify) private info value. */ void _x_meta_info_reset(xine_stream_t *stream, int info) { pthread_mutex_lock(&stream->meta_mutex); meta_info_set_unlocked_utf8(stream, info, NULL); pthread_mutex_unlock(&stream->meta_mutex); } /* * Reset (nullify) public info value. */ static void meta_info_public_reset_unlocked(xine_stream_t *stream, int info) { if(meta_valid(info)) { if(stream->meta_info_public[info]) free(stream->meta_info_public[info]); stream->meta_info_public[info] = NULL; } } void _x_meta_info_public_reset(xine_stream_t *stream, int info) { pthread_mutex_lock(&stream->meta_mutex); meta_info_public_reset_unlocked(stream, info); pthread_mutex_unlock(&stream->meta_mutex); } /* * Set private meta info value using current locale. */ void _x_meta_info_set(xine_stream_t *stream, int info, const char *str) { pthread_mutex_lock(&stream->meta_mutex); if(str) meta_info_set_unlocked(stream, info, str); pthread_mutex_unlock(&stream->meta_mutex); } /* * Set private meta info value using specified encoding. */ void _x_meta_info_set_generic(xine_stream_t *stream, int info, const char *str, const char *enc) { pthread_mutex_lock(&stream->meta_mutex); if(str) meta_info_set_unlocked_encoding(stream, info, str, enc); pthread_mutex_unlock(&stream->meta_mutex); } /* * Set private meta info value using utf8. */ void _x_meta_info_set_utf8(xine_stream_t *stream, int info, const char *str) { pthread_mutex_lock(&stream->meta_mutex); if(str) meta_info_set_unlocked_utf8(stream, info, str); pthread_mutex_unlock(&stream->meta_mutex); } /* * Set private meta info from buf, 'len' bytes long. */ void _x_meta_info_n_set(xine_stream_t *stream, int info, const char *buf, int len) { pthread_mutex_lock(&stream->meta_mutex); if(meta_valid(info) && len) { char *str = xine_xmalloc(len + 1); snprintf(str, len + 1 , "%s", buf); meta_info_set_unlocked(stream, info, (const char *) &str[0]); free(str); } pthread_mutex_unlock(&stream->meta_mutex); } /* * Set private meta info value, from multiple arguments. */ void _x_meta_info_set_multi(xine_stream_t *stream, int info, ...) { pthread_mutex_lock(&stream->meta_mutex); if(meta_valid(info)) { va_list ap; char *args[1025]; char *buf; int n, len; len = n = 0; va_start(ap, info); while((buf = va_arg(ap, char *)) && (n < 1024)) { len += strlen(buf) + 1; args[n] = buf; n++; } va_end(ap); args[n] = NULL; if(len) { char *p, *meta; p = meta = (char *) xine_xmalloc(len + 1); n = 0; while(args[n]) { strcpy(meta, args[n]); meta += strlen(args[n]) + 1; n++; } *meta = '\0'; if(stream->meta_info[info]) free(stream->meta_info[info]); stream->meta_info[info] = p; if(stream->meta_info[info] && strlen(stream->meta_info[info])) meta_info_chomp(stream->meta_info[info]); } } pthread_mutex_unlock(&stream->meta_mutex); } /* * Retrieve private info value. */ const char *_x_meta_info_get(xine_stream_t *stream, int info) { const char *meta_info = NULL; pthread_mutex_lock(&stream->meta_mutex); meta_info = stream->meta_info[info]; pthread_mutex_unlock(&stream->meta_mutex); return meta_info; } /* * Retrieve public info value. */ const char *_x_meta_info_get_public(xine_stream_t *stream, int info) { const char *meta_info = NULL; pthread_mutex_lock(&stream->meta_mutex); meta_info = stream->meta_info_public[info]; if(meta_valid(info) && (!meta_info_is_identical(stream, info))) { meta_info_public_reset_unlocked(stream, info); if(stream->meta_info[info]) stream->meta_info_public[info] = strdup(stream->meta_info[info]); meta_info = stream->meta_info_public[info]; } pthread_mutex_unlock(&stream->meta_mutex); return meta_info; }