1/*
2 * Copyright (c) 2001 - 2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23#include <stdlib.h>
24#include <string.h>
25#include <netsmb/smb_lib.h>
26#include "charsets.h"
27
28/*
29 * We now use CFStringUppercase
30 */
31void str_upper(char *dst, size_t maxDstLen, CFStringRef srcRef)
32{
33	CFMutableStringRef upperRef = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, srcRef);
34	if (upperRef == NULL) {
35		/* Nothing else we can do here */
36		CFStringGetCString(srcRef, dst, maxDstLen, kCFStringEncodingUTF8);
37		return;
38	}
39	CFStringUppercase(upperRef, NULL);
40	CFStringGetCString(upperRef, dst, maxDstLen, kCFStringEncodingUTF8);
41	CFRelease(upperRef);
42}
43
44/*
45 * %%% - Change all strings to CFStringRef, once we remove the UI code.
46 */
47char *
48convert_wincs_to_utf8(const char *windows_string, CFStringEncoding codePage)
49{
50	CFStringRef s;
51	CFIndex maxlen;
52	char *result;
53
54	s = CFStringCreateWithCString(NULL, windows_string, codePage);
55	if (s == NULL) {
56		smb_log_info("CFStringCreateWithCString for Windows code page failed on \"%s\", syserr = %s",
57						ASL_LEVEL_DEBUG,  windows_string, strerror(errno));
58
59		/* kCFStringEncodingMacRoman should always succeed */
60		s = CFStringCreateWithCString(NULL, windows_string,
61		    kCFStringEncodingMacRoman);
62		if (s == NULL) {
63			smb_log_info("CFStringCreateWithCString for Windows code page failed on \"%s\" with kCFStringEncodingMacRoman - skipping, syserr = %s",
64						ASL_LEVEL_DEBUG, windows_string, strerror(errno));
65			return NULL;
66		}
67	}
68
69	maxlen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(s),
70	    kCFStringEncodingUTF8) + 1;
71
72	result = malloc(maxlen);
73	if (result == NULL) {
74		smb_log_info("Couldn't allocate buffer for UTF-8 string for \"%s\" - skipping, syserr = %s",
75					ASL_LEVEL_DEBUG, windows_string, strerror(errno));
76		CFRelease(s);
77		return NULL;
78	}
79
80	if (!CFStringGetCString(s, result, maxlen, kCFStringEncodingUTF8)) {
81		smb_log_info("CFStringGetCString for UTF-8 failed on \"%s\" - skipping, syserr = %s",
82					ASL_LEVEL_DEBUG, windows_string, strerror(errno));
83		CFRelease(s);
84		free(result);
85		return NULL;
86	}
87
88	CFRelease(s);
89	return result;
90}
91
92/*
93 * This routine assumes the inbound c-style string is really a UTF8 string.
94 * We create a CFString, uppercase if the flag is set, convert it to the code
95 * page and then return a c-style string containing the new converted string.
96 */
97char *convert_utf8_to_wincs(const char *utf8_string, CFStringEncoding codePage, int uppercase)
98{
99	CFStringRef utfStr;
100	CFMutableStringRef utfMutableStr = NULL;
101	CFIndex maxlen;
102	char *result = NULL;
103
104	utfStr = CFStringCreateWithCString(NULL, utf8_string, kCFStringEncodingUTF8);
105	if (utfStr) {
106		utfMutableStr = CFStringCreateMutableCopy(NULL, 0, utfStr);
107		CFRelease(utfStr);
108	}
109
110	if (utfMutableStr == NULL) {
111		smb_log_info("CFStringCreateWithCString for UTF-8 failed on \"%s\", syserr = %s",
112					ASL_LEVEL_DEBUG, utf8_string, strerror(errno));
113		goto done;
114	}
115
116	if (uppercase) {
117		CFStringUppercase(utfMutableStr, CFLocaleGetSystem());
118	}
119
120	maxlen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(utfMutableStr), codePage) + 1;
121	result = malloc(maxlen);
122	if (result == NULL) {
123		smb_log_info("Couldn't allocate buffer for Windows code page string for \"%s\" - skipping, syserr = %s",
124					ASL_LEVEL_DEBUG, utf8_string, strerror(errno));
125		goto done;
126	}
127	if (!CFStringGetCString(utfMutableStr, result, maxlen, codePage)) {
128		smb_log_info("CFStringGetCString for Windows code page failed on \"%s\" - skipping, syserr = %s",
129					ASL_LEVEL_DEBUG, utf8_string, strerror(errno));
130		free(result);
131		result =  NULL;
132		goto done;
133	}
134
135done:
136	if (utfMutableStr)
137		CFRelease(utfMutableStr);
138	return result;
139}
140
141/*
142 * Convert little-endian Unicode string to UTF-8.
143 * Converts the Unicode string to host byte order in place.
144 * XXX - <rdar://problem/7518600>  will clean this up
145 */
146char *
147convert_leunicode_to_utf8(unsigned short *unicode_string, size_t maxLen)
148{
149	unsigned short *unicode_charp, unicode_char;
150
151	for (unicode_charp = unicode_string;
152	    (unicode_char = *unicode_charp) != 0;
153	    unicode_charp++)
154		*unicode_charp = CFSwapInt16LittleToHost(unicode_char);
155	return convert_unicode_to_utf8(unicode_string, maxLen);
156}
157
158/*
159 * Convert Unicode string to UTF-8.
160 * XXX - <rdar://problem/7518600>  will clean this up
161 */
162char *
163convert_unicode_to_utf8(const uint16_t *unicode_string, size_t maxLen)
164{
165	size_t uslen;
166	CFStringRef s;
167	char *result;
168
169	 /* Number of characters not bytes */
170	maxLen = maxLen / 2;
171	for (uslen = 0; (unicode_string[uslen] != 0) && (uslen < maxLen); uslen++)
172		;
173	s = CFStringCreateWithCharacters(kCFAllocatorDefault, unicode_string, uslen);
174	if (s == NULL) {
175		smb_log_info("CFStringCreateWithCharacters failed, syserr = %s",
176					 ASL_LEVEL_DEBUG, strerror(errno));
177		return NULL;
178	}
179	maxLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(s),
180	    kCFStringEncodingUTF8) + 1;
181	result = calloc(maxLen, 1);
182	if (result == NULL) {
183		smb_log_info("Couldn't allocate buffer for Unicode string - skipping, syserr = %s",
184					 ASL_LEVEL_DEBUG, strerror(errno));
185		CFRelease(s);
186		return NULL;
187	}
188	if (!CFStringGetCString(s, result, maxLen, kCFStringEncodingUTF8)) {
189		smb_log_info("CFStringGetCString failed on Unicode string - skipping, syserr = %s",
190					 ASL_LEVEL_DEBUG, strerror(errno));
191		CFRelease(s);
192		free(result);
193		return NULL;
194	}
195	CFRelease(s);
196	return result;
197}
198
199/*
200 * Convert UTF-8 string to little-endian Unicode.
201 * XXX - <rdar://problem/7518600>  will clean this up
202*/
203unsigned short *
204convert_utf8_to_leunicode(const char *utf8_string)
205{
206	CFStringRef s;
207	CFIndex maxlen;
208	unsigned short *result;
209	CFRange range;
210	int i;
211
212	s = CFStringCreateWithCString(NULL, utf8_string,
213	     kCFStringEncodingUTF8);
214	if (s == NULL) {
215		smb_log_info("CFStringCreateWithCString for UTF-8 failed on \"%s\", syserr = %s",
216					 ASL_LEVEL_DEBUG, utf8_string, strerror(errno));
217		return NULL;
218	}
219
220	maxlen = CFStringGetLength(s);
221	result = malloc(2*(maxlen + 1));
222	if (result == NULL) {
223		smb_log_info("Couldn't allocate buffer for Unicode string for \"%s\" - skipping, syserr = %s",
224				ASL_LEVEL_DEBUG, utf8_string, strerror(errno));
225		CFRelease(s);
226		return NULL;
227	}
228	range.location = 0;
229	range.length = maxlen;
230	CFStringGetCharacters(s, range, result);
231	for (i = 0; i < maxlen; i++)
232		result[i] = CFSwapInt16HostToLittle(result[i]);
233	result[maxlen] = 0;
234	CFRelease(s);
235	return result;
236}
237