d87e32f01ae5c1854a5710c6726987f1de272161
[flac.git] / src / plugin_common / charset.c
1 /* plugin_common - Routines common to several plugins
2  * Copyright (C) 2002  Josh Coalson
3  *
4  * Only slightly modified charset.c from:
5  *  EasyTAG - Tag editor for MP3 and OGG files
6  *  Copyright (C) 1999-2001  Håvard Kvålen <havardk@xmms.org>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  */
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26
27 #ifdef HAVE_ICONV
28 #include <iconv.h>
29 #endif
30
31 #ifdef HAVE_LANGINFO_CODESET
32 #include <langinfo.h>
33 #endif
34
35 #include "charset.h"
36
37
38 /*************
39  * Functions *
40  *************/
41
42 char* FLAC_plugin__charset_get_current (void)
43 {
44         char *charset = getenv("CHARSET");
45
46 #ifdef HAVE_LANGINFO_CODESET
47         if (!charset)
48                 charset = nl_langinfo(CODESET);
49 #endif
50         if (!charset)
51                 charset = "ISO-8859-1";
52
53         return charset;
54 }
55
56
57 #ifdef HAVE_ICONV
58 char* FLAC_plugin__charset_convert_string (const char *string, char *from, char *to)
59 {
60         size_t outleft, outsize, length;
61         iconv_t cd;
62         char *out, *outptr;
63         const char *input = string;
64
65         if (!string)
66                 return NULL;
67
68         length = strlen(string);
69
70         if ((cd = iconv_open(to, from)) == (iconv_t)-1)
71         {
72 #ifdef DEBUG
73                 fprintf(stderr, "convert_string(): Conversion not supported. Charsets: %s -> %s", from, to);
74 #endif
75                 return strdup(string);
76         }
77
78         /* Due to a GLIBC bug, round outbuf_size up to a multiple of 4 */
79         /* + 1 for nul in case len == 1 */
80         outsize = ((length + 3) & ~3) + 1;
81         out = malloc(outsize);
82         outleft = outsize - 1;
83         outptr = out;
84
85 retry:
86         if (iconv(cd, &input, &length, &outptr, &outleft) == -1)
87         {
88                 int used;
89                 switch (errno)
90                 {
91                         case E2BIG:
92                                 used = outptr - out;
93                                 outsize = (outsize - 1) * 2 + 1;
94                                 out = realloc(out, outsize);
95                                 outptr = out + used;
96                                 outleft = outsize - 1 - used;
97                                 goto retry;
98                         case EINVAL:
99                                 break;
100                         case EILSEQ:
101                                 /* Invalid sequence, try to get the rest of the string */
102                                 input++;
103                                 length = strlen(input);
104                                 goto retry;
105                         default:
106 #ifdef DEBUG
107                                 fprintf(stderr, "convert_string(): Conversion failed. Inputstring: %s; Error: %s", string, strerror(errno));
108 #endif
109                                 break;
110                 }
111         }
112         *outptr = '\0';
113
114         iconv_close(cd);
115         return out;
116 }
117 #else
118 char* FLAC_plugin__charset_convert_string (const char *string, char *from, char *to)
119 {
120         (void)from, (void)to;
121         if (!string)
122                 return NULL;
123         return strdup(string);
124 }
125 #endif
126
127 #ifdef HAVE_ICONV
128 int FLAC_plugin__charset_test_conversion (char *from, char *to)
129 {
130         iconv_t cd;
131
132         if ((cd=iconv_open(to,from)) == (iconv_t)-1)
133         {
134                 /* Conversion not supported */
135                 return 0;
136         }
137         iconv_close(cd);
138         return ;
139 }
140 #else
141 int FLAC_plugin__charset_test_conversion (char *from, char *to)
142 {
143         (void)from, (void)to;
144         return 1;
145 }
146 #endif