1 /*
2 LibRCC - interface to iconv library
3
4 Copyright (C) 2005-2008 Suren A. Chilingaryan <csa@dside.dyndns.org>
5
6 This library is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License version 2.1 or later
8 as published by the Free Software Foundation.
9
10 This library is distributed in the hope that it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
13 for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <errno.h>
23 #include <iconv.h>
24
25 #include <string.h>
26 #ifdef HAVE_STRINGS_H
27 # include <strings.h>
28 #endif /* HAVE_STRINGS_H */
29
30 #include "internal.h"
31 #include "rcciconv.h"
32
33 #define RCC_MAX_ERRORS 3
34
rccIConvCopySymbol(char ** in_buf,size_t * in_left,char ** out_buf,size_t * out_left)35 static void rccIConvCopySymbol(char **in_buf, size_t *in_left, char **out_buf, size_t *out_left) {
36 if ((out_left>0)&&(in_left>0)) {
37 /* (**out_buf)=(**in_buf);
38 (*out_buf)++;
39 (*out_left)--;*/
40 (*in_buf)++;
41 (*in_left)--;
42 }
43 }
44
rccIConvUTFBytes(unsigned char c)45 static int rccIConvUTFBytes(unsigned char c) {
46 int j;
47 if (c<128) return 1;
48
49 for (j=6;j>=0;j--)
50 if ((c&(1<<j))==0) break;
51
52 if ((j==0)||(j==6)) return 1;
53 return 6-j;
54 }
55
56
rccIConvOpen(const char * to,const char * from)57 rcc_iconv rccIConvOpen(const char *to, const char *from) {
58 rcc_iconv icnv;
59
60 if ((!from)||(!to)||(!strcasecmp(from,to))) return NULL;
61
62 icnv = (rcc_iconv)malloc(sizeof(rcc_iconv_s));
63 if (!icnv) return icnv;
64
65 icnv->icnv = iconv_open(to, from);
66 return icnv;
67 }
68
rccIConvClose(rcc_iconv icnv)69 void rccIConvClose(rcc_iconv icnv) {
70 if (icnv) {
71 if (icnv->icnv != (iconv_t)-1) iconv_close(icnv->icnv);
72 free(icnv);
73 }
74 }
75
rccIConvGetError(rcc_iconv icnv)76 int rccIConvGetError(rcc_iconv icnv) {
77 if ((!icnv)||(icnv->icnv == (iconv_t)-1)) return -1;
78 return 0;
79 }
80
rccIConvRecode(rcc_iconv icnv,char * outbuf,size_t outsize,const char * buf,size_t size)81 size_t rccIConvRecode(rcc_iconv icnv, char *outbuf, size_t outsize, const char *buf, size_t size) {
82 char *in_buf, *out_buf, err;
83 size_t in_left, out_left;
84 int ub, utf_mode=0;
85 int errors=0;
86
87 if ((!buf)||(!outbuf)||(!outsize)||(!icnv)||(icnv->icnv == (iconv_t)-1)) return (size_t)-1;
88 if (iconv(icnv->icnv, NULL, NULL, NULL, NULL) == -1) return (size_t)-1;
89
90 if (!size) size = strlen(buf);
91
92 loop_restart:
93 errors = 0;
94 in_buf = (char*)buf; /*DS*/
95 in_left = size;
96 out_buf = outbuf;
97 out_left = outsize;
98
99 loop:
100 err=iconv(icnv->icnv, (char**)&in_buf, &in_left, &out_buf, &out_left);
101 if (err<0) {
102 if (errno==E2BIG) {
103 *(int*)(outbuf+(RCC_MAX_STRING_CHARS-sizeof(int)))=0;
104 } else if (errno==EILSEQ) {
105 if (errors++<RCC_MAX_ERRORS) {
106 for (ub=utf_mode?rccIConvUTFBytes(*in_buf):1;ub>0;ub--)
107 rccIConvCopySymbol(&in_buf, &in_left, &out_buf, &out_left);
108 if (in_left>0) goto loop;
109 } else if (!utf_mode) {
110 utf_mode = 1;
111 goto loop_restart;
112 } else {
113 return (size_t)-1;
114 }
115 } else {
116 return (size_t)-1;
117 }
118 }
119
120 outbuf[outsize - out_left] = 0;
121
122 return outsize - out_left;
123 }
124
rccIConv(rcc_iconv icnv,const char * buf,size_t len,size_t * rlen)125 char *rccIConv(rcc_iconv icnv, const char *buf, size_t len, size_t *rlen) {
126 char *res;
127 size_t size;
128 char tmpbuffer[RCC_MAX_STRING_CHARS+1];
129
130 size = rccIConvRecode(icnv, tmpbuffer, RCC_MAX_STRING_CHARS, buf, len);
131 if (size != (size_t)-1) {
132 res = (char*)malloc((size+1)*sizeof(char));
133 if (!res) return res;
134
135 if (rlen) *rlen = size;
136 memcpy(res, tmpbuffer, size);
137 res[size] = 0;
138
139 return res;
140 }
141
142 return NULL;
143 }
144
rccIConvInternal(rcc_context ctx,rcc_iconv icnv,const char * buf,size_t len)145 size_t rccIConvInternal(rcc_context ctx, rcc_iconv icnv, const char *buf, size_t len) {
146 if (!ctx) return (size_t)-1;
147 return rccIConvRecode(icnv, ctx->tmpbuffer, RCC_MAX_STRING_CHARS, buf, len);
148 }
149
150