2 Copyright (C) 2000-2007 SKYRIX Software AG
3 Copyright (C) 2007 Helge Hess
5 This file is part of SOPE.
7 SOPE is free software; you can redistribute it and/or modify it under
8 the terms of the GNU Lesser General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
12 SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with SOPE; see the file COPYING. If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
23 #include <NGExtensions/NSString+Encoding.h>
24 #include <NGExtensions/NSObject+Logs.h>
27 #if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY
28 # import <CoreFoundation/CoreFoundation.h>
31 # import <Foundation/NSByteOrder.h>
34 #if GNUSTEP_BASE_LIBRARY
35 #import <GNUstepBase/GSMime.h>
38 // TODO: should move different implementations to different files ...
41 #if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY
43 @interface NSString(Encoding_PrivateAPI)
44 + (NSStringEncoding)stringEncodingForEncodingNamed:(NSString *)encoding;
47 @implementation NSString(Encoding)
49 + (NSStringEncoding)stringEncodingForEncodingNamed:(NSString *)_encoding
51 CFStringEncoding cfEncoding;
56 _encoding = [_encoding lowercaseString];
57 cfEncoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)_encoding);
58 if(cfEncoding == kCFStringEncodingInvalidId)
60 return CFStringConvertEncodingToNSStringEncoding(cfEncoding);
63 + (NSString *)stringWithData:(NSData *)_data
64 usingEncodingNamed:(NSString *)_encoding
66 NSStringEncoding encoding;
68 encoding = [NSString stringEncodingForEncodingNamed:_encoding];
69 return [[[NSString alloc] initWithData:_data encoding:encoding] autorelease];
72 - (NSData *)dataUsingEncodingNamed:(NSString *)_encoding {
73 NSStringEncoding encoding;
75 encoding = [NSString stringEncodingForEncodingNamed:_encoding];
76 return [self dataUsingEncoding:encoding];
79 @end /* NSString(Encoding) */
82 #else /* ! NeXT_Foundation_LIBRARY */
85 @implementation NSString(Encoding)
87 #if GNUSTEP_BASE_LIBRARY
89 + (NSStringEncoding)stringEncodingForEncodingNamed:(NSString *)_encoding {
90 return [GSMimeDocument encodingFromCharset:_encoding];
95 #if LIB_FOUNDATION_LIBRARY
97 + (NSStringEncoding)stringEncodingForEncodingNamed:(NSString *)_encoding {
98 NSString *s = [_encoding lowercaseString];
99 unsigned len = [s length];
106 if ([s isEqualToString:@"utf8"])
107 return NSUTF8StringEncoding;
111 if ([s isEqualToString:@"utf-8"])
112 return NSUTF8StringEncoding;
113 if ([s isEqualToString:@"ascii"])
114 return NSASCIIStringEncoding;
118 if ([s isEqualToString:@"latin1"])
119 return NSISOLatin1StringEncoding;
120 if ([s isEqualToString:@"latin9"])
121 return NSISOLatin9StringEncoding;
125 if ([s isEqualToString:@"iso-8859-1"])
126 return NSISOLatin1StringEncoding;
130 if ([s isEqualToString:@"iso-8859-15"])
131 return NSISOLatin9StringEncoding;
135 NSLog(@"%s: could not derive NSStringEncoding from name: '%@'", _encoding);
143 static NSString *unicharEncoding = @"UCS-2LE";
145 static NSString *unicharEncoding = @"UCS-2-INTERNAL";
147 static int IconvLogEnabled = -1;
149 static void checkDefaults(void) {
152 if (IconvLogEnabled != -1)
154 ud = [NSUserDefaults standardUserDefaults];
155 IconvLogEnabled = [ud boolForKey:@"IconvLogEnabled"]?1:0;
158 if (NSHostByteOrder() == NS_BigEndian) {
159 NSLog(@"Note: using UCS-2 big endian on Linux.");
160 unicharEncoding = @"UCS-2BE";
163 NSLog(@"Note: using UCS-2 little endian on Linux.");
164 unicharEncoding = @"UCS-2LE";
169 static char *iconv_wrapper(id self, char *_src, unsigned _srcLen,
170 NSString *_fromEncode, NSString *_toEncode,
174 size_t inbytesleft, outbytesleft, write, outlen;
175 const char *fromEncode, *toEncode;
176 char *inbuf, *outbuf, *tm;
181 if (IconvLogEnabled) {
182 [self logWithFormat:@"FromEncode: %@; ToEncode: %@", _fromEncode,
186 _fromEncode = [_fromEncode uppercaseString];
187 _toEncode = [_toEncode uppercaseString];
189 if (0 && [_fromEncode isEqualToString:_toEncode]) {
191 outbuf = calloc(sizeof(char), outlen+1);
193 memcpy(outbuf, _src, _srcLen);
199 fromEncode = [_fromEncode cString];
200 toEncode = [_toEncode cString];
202 type = iconv_open(toEncode, fromEncode);
206 if ((type == (iconv_t)-1)) {
207 [self logWithFormat:@"%s: Could not handle iconv encoding. FromEncoding:%@"
208 @" to encoding:%@", __PRETTY_FUNCTION__, _fromEncode, _toEncode];
209 goto CLEAR_AND_RETURN;
211 inbytesleft = _srcLen;
213 outlen = inbytesleft * 3;
214 outbuf = calloc(outlen + 1, sizeof(char));;
216 outbytesleft = outlen;
218 write = iconv(type, &inbuf, &inbytesleft, &tm, &outbytesleft);
220 if (write == (size_t)-1) {
221 if (errno == EILSEQ) {
222 [self logWithFormat:@"Got invalid multibyte sequence. ToEncode: %@"
223 @" FromEncode: %@.", _toEncode, _fromEncode];
224 if (IconvLogEnabled) {
225 [self logWithFormat:@"ByteSequence:\n%s\n", _src];
227 goto CLEAR_AND_RETURN;
229 else if (errno == EINVAL) {
230 [self logWithFormat:@"Got incomplete multibyte sequence. ToEncode: %@"
231 @" FromEncode: %@", _toEncode, _fromEncode];
233 [self logWithFormat:@"ByteSequence:\n%s\n", _src];
236 else if (errno == E2BIG) {
238 @"Got to small outputbuffer (inbytesleft=%d, outbytesleft=%d, "
239 @"outlen=%d). ToEncode: %@ FromEncode: %@",
240 inbytesleft, outbytesleft, outlen,
241 _toEncode, _fromEncode];
243 [self logWithFormat:@"ByteSequence:\n%s\n", _src];
245 goto CLEAR_AND_RETURN;
248 [self logWithFormat:@"Got unexpected error. ToEncode: %@"
249 @" FromEncode: %@", _toEncode, _fromEncode];
250 goto CLEAR_AND_RETURN;
254 NSLogL(@"outlen %d outbytesleft %d", outlen, outbytesleft);
259 *outLen_ = outlen - outbytesleft;
268 free(outbuf); outbuf = NULL;
273 + (NSString *)stringWithData:(NSData *)_data
274 usingEncodingNamed:(NSString *)_encoding
277 unsigned len, inbufLen;
280 if (![_encoding length])
283 inbufLen = [_data length];
284 inbuf = calloc(sizeof(char), inbufLen + 4);
285 [_data getBytes:inbuf];
288 res = iconv_wrapper(self, inbuf, inbufLen, _encoding, unicharEncoding, &len);
290 result = [[NSString alloc] initWithCharacters:res length:(len / 2)];
291 free(res); res = NULL;
293 if (inbuf) free(inbuf); inbuf = NULL;
294 return [result autorelease];
297 - (NSData *)dataUsingEncodingNamed:(NSString *)_encoding {
300 unsigned inputLen, resLen;
303 if (![_encoding length])
307 inputLen = [self length];
308 chars = calloc(sizeof(unichar), inputLen + 4);
309 [self getCharacters:chars];
311 res = iconv_wrapper(self, (char *)chars, inputLen*2,
312 unicharEncoding, _encoding,
314 if (res) data = [NSData dataWithBytes:res length:resLen];
316 if (chars) free(chars); chars = NULL;
320 @end /* NSString(Encoding) */
322 #endif /* ! NeXT_Foundation_LIBRARY */