| /* plugin_common - Routines common to several plugins |
| * Copyright (C) 2002-2009 Josh Coalson |
| * Copyright (C) 2011-2016 Xiph.Org Foundation |
| * |
| * Only slightly modified charset.c from: |
| * EasyTAG - Tag editor for MP3 and OGG files |
| * Copyright (C) 1999-2001 Håvard Kvålen <havardk@xmms.org> |
| * |
| * This program 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. |
| * |
| * This program 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-1301 USA. |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| # include <config.h> |
| #endif |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <errno.h> |
| |
| #ifdef HAVE_ICONV |
| #include <iconv.h> |
| #endif |
| |
| #ifdef HAVE_LANGINFO_CODESET |
| #include <langinfo.h> |
| #endif |
| |
| #include "charset.h" |
| |
| |
| /************* |
| * Functions * |
| *************/ |
| |
| char* FLAC_plugin__charset_get_current (void) |
| { |
| char *charset = getenv("CHARSET"); |
| |
| #ifdef HAVE_LANGINFO_CODESET |
| if (!charset) |
| charset = nl_langinfo(CODESET); |
| #endif |
| if (!charset) |
| charset = "ISO-8859-1"; |
| |
| return charset; |
| } |
| |
| |
| #ifdef HAVE_ICONV |
| char* FLAC_plugin__charset_convert_string (const char *string, char *from, char *to) |
| { |
| size_t outleft, outsize, length; |
| iconv_t cd; |
| char *out, *outptr; |
| const char *input = string; |
| |
| if (!string) |
| return NULL; |
| |
| length = strlen(string); |
| |
| if ((cd = iconv_open(to, from)) == (iconv_t)-1) |
| { |
| #ifndef NDEBUG |
| fprintf(stderr, "convert_string(): Conversion not supported. Charsets: %s -> %s", from, to); |
| #endif |
| return strdup(string); |
| } |
| |
| /* Due to a GLIBC bug, round outbuf_size up to a multiple of 4 */ |
| /* + 1 for nul in case len == 1 */ |
| outsize = ((length + 3) & ~3) + 1; |
| if(outsize < length) /* overflow check */ |
| return NULL; |
| out = malloc(outsize); |
| outleft = outsize - 1; |
| outptr = out; |
| |
| retry: |
| if (iconv(cd, (char**)&input, &length, &outptr, &outleft) == (size_t)(-1)) |
| { |
| int used; |
| switch (errno) |
| { |
| case E2BIG: |
| used = outptr - out; |
| if((outsize - 1) * 2 + 1 <= outsize) { /* overflow check */ |
| free(out); |
| return NULL; |
| } |
| outsize = (outsize - 1) * 2 + 1; |
| out = realloc(out, outsize); |
| outptr = out + used; |
| outleft = outsize - 1 - used; |
| goto retry; |
| case EINVAL: |
| break; |
| case EILSEQ: |
| /* Invalid sequence, try to get the rest of the string */ |
| input++; |
| length = strlen(input); |
| goto retry; |
| default: |
| #ifndef NDEBUG |
| fprintf(stderr, "convert_string(): Conversion failed. Inputstring: %s; Error: %s", string, strerror(errno)); |
| #endif |
| break; |
| } |
| } |
| *outptr = '\0'; |
| |
| iconv_close(cd); |
| return out; |
| } |
| #else |
| char* FLAC_plugin__charset_convert_string (const char *string, char *from, char *to) |
| { |
| (void)from, (void)to; |
| if (!string) |
| return NULL; |
| return strdup(string); |
| } |
| #endif |
| |
| #ifdef HAVE_ICONV |
| int FLAC_plugin__charset_test_conversion (char *from, char *to) |
| { |
| iconv_t cd; |
| |
| if ((cd=iconv_open(to,from)) == (iconv_t)-1) |
| { |
| /* Conversion not supported */ |
| return 0; |
| } |
| iconv_close(cd); |
| return 1; |
| } |
| #else |
| int FLAC_plugin__charset_test_conversion (char *from, char *to) |
| { |
| (void)from, (void)to; |
| return 1; |
| } |
| #endif |