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