1 /*
2  * util.c -  Miscellaneous support
3  *
4  * Copyright (C) 1997,1999 Martin von L�wis
5  * Copyright (C) 1997 R�gis Duchesne
6  * Copyright (C) 2001 Anton Altaparmakov (AIA)
7  *
8  * The utf8 routines are copied from Python wstrop module.
9  */
10 
11 #include "ntfstypes.h"
12 #include "struct.h"
13 #include "util.h"
14 #include <linux/string.h>
15 #include <linux/errno.h>
16 #include <asm/div64.h>		/* For do_div(). */
17 #include "support.h"
18 
19 /*
20  * Converts a single wide character to a sequence of utf8 bytes.
21  * The character is represented in host byte order.
22  * Returns the number of bytes, or 0 on error.
23  */
to_utf8(ntfs_u16 c,unsigned char * buf)24 static int to_utf8(ntfs_u16 c, unsigned char *buf)
25 {
26 	if (c == 0)
27 		return 0; /* No support for embedded 0 runes. */
28 	if (c < 0x80) {
29 		if (buf)
30 			buf[0] = (unsigned char)c;
31 		return 1;
32 	}
33 	if (c < 0x800) {
34 		if (buf) {
35 			buf[0] = 0xc0 | (c >> 6);
36 			buf[1] = 0x80 | (c & 0x3f);
37 		}
38 		return 2;
39 	}
40 	/* c < 0x10000 */
41 	if (buf) {
42 		buf[0] = 0xe0 | (c >> 12);
43 		buf[1] = 0x80 | ((c >> 6) & 0x3f);
44 		buf[2] = 0x80 | (c & 0x3f);
45 	}
46 	return 3;
47 }
48 
49 /*
50  * Decodes a sequence of utf8 bytes into a single wide character.
51  * The character is returned in host byte order.
52  * Returns the number of bytes consumed, or 0 on error.
53  */
from_utf8(const unsigned char * str,ntfs_u16 * c)54 static int from_utf8(const unsigned char *str, ntfs_u16 *c)
55 {
56 	int l = 0, i;
57 
58 	if (*str < 0x80) {
59 		*c = *str;
60 		return 1;
61 	}
62 	if (*str < 0xc0)	/* Lead byte must not be 10xxxxxx. */
63 		return 0;	/* Is c0 a possible lead byte? */
64 	if (*str < 0xe0) {		/* 110xxxxx */
65 		*c = *str & 0x1f;
66 		l = 2;
67 	} else if (*str < 0xf0) {	/* 1110xxxx */
68 		*c = *str & 0xf;
69 		l = 3;
70 	} else if (*str < 0xf8) {   	/* 11110xxx */
71 		*c = *str & 7;
72 		l = 4;
73 	} else /* We don't support characters above 0xFFFF in NTFS. */
74 		return 0;
75 	for (i = 1; i < l; i++) {
76 		/* All other bytes must be 10xxxxxx. */
77 		if ((str[i] & 0xc0) != 0x80)
78 			return 0;
79 		*c <<= 6;
80 		*c |= str[i] & 0x3f;
81 	}
82 	return l;
83 }
84 
85 /*
86  * Converts wide string to UTF-8. Expects two in- and two out-parameters.
87  * Returns 0 on success, or error code.
88  * The caller has to free the result string.
89  */
ntfs_dupuni2utf8(ntfs_u16 * in,int in_len,char ** out,int * out_len)90 static int ntfs_dupuni2utf8(ntfs_u16 *in, int in_len, char **out, int *out_len)
91 {
92 	int i, tmp;
93 	int len8;
94 	unsigned char *result;
95 
96 	ntfs_debug(DEBUG_NAME1, "converting l = %d\n", in_len);
97 	/* Count the length of the resulting UTF-8. */
98 	for (i = len8 = 0; i < in_len; i++) {
99 		tmp = to_utf8(NTFS_GETU16(in + i), 0);
100 		if (!tmp)
101 			/* Invalid character. */
102 			return -EILSEQ;
103 		len8 += tmp;
104 	}
105 	*out = result = ntfs_malloc(len8 + 1); /* allow for zero-termination */
106 	if (!result)
107 		return -ENOMEM;
108 	result[len8] = '\0';
109 	*out_len = len8;
110 	for (i = len8 = 0; i < in_len; i++)
111 		len8 += to_utf8(NTFS_GETU16(in + i), result + len8);
112 	ntfs_debug(DEBUG_NAME1, "result %p:%s\n", result, result);
113 	return 0;
114 }
115 
116 /*
117  * Converts an UTF-8 sequence to a wide string. Same conventions as the
118  * previous function.
119  */
ntfs_duputf82uni(unsigned char * in,int in_len,ntfs_u16 ** out,int * out_len)120 static int ntfs_duputf82uni(unsigned char* in, int in_len, ntfs_u16** out,
121 		int *out_len)
122 {
123 	int i, tmp;
124 	int len16;
125 	ntfs_u16* result;
126 	ntfs_u16 wtmp;
127 
128 	for (i = len16 = 0; i < in_len; i += tmp, len16++) {
129 		tmp = from_utf8(in + i, &wtmp);
130 		if (!tmp)
131 			return -EILSEQ;
132 	}
133 	*out = result = ntfs_malloc(2 * (len16 + 1));
134 	if (!result)
135 		return -ENOMEM;
136 	result[len16] = 0;
137 	*out_len = len16;
138 	for (i = len16 = 0; i < in_len; i += tmp, len16++) {
139 		tmp = from_utf8(in + i, &wtmp);
140 		NTFS_PUTU16(result + len16, wtmp);
141 	}
142 	return 0;
143 }
144 
145 /* Encodings dispatchers. */
ntfs_encodeuni(ntfs_volume * vol,ntfs_u16 * in,int in_len,char ** out,int * out_len)146 int ntfs_encodeuni(ntfs_volume *vol, ntfs_u16 *in, int in_len, char **out,
147 		int *out_len)
148 {
149 	if (vol->nls_map)
150 		return ntfs_dupuni2map(vol, in, in_len, out, out_len);
151 	else
152 		return ntfs_dupuni2utf8(in, in_len, out, out_len);
153 }
154 
ntfs_decodeuni(ntfs_volume * vol,char * in,int in_len,ntfs_u16 ** out,int * out_len)155 int ntfs_decodeuni(ntfs_volume *vol, char *in, int in_len, ntfs_u16 **out,
156 		int *out_len)
157 {
158 	if (vol->nls_map)
159 		return ntfs_dupmap2uni(vol, in, in_len, out, out_len);
160 	else
161 		return ntfs_duputf82uni(in, in_len, out, out_len);
162 }
163 
164 /* Same address space copies. */
ntfs_put(ntfs_io * dest,void * src,ntfs_size_t n)165 void ntfs_put(ntfs_io *dest, void *src, ntfs_size_t n)
166 {
167 	ntfs_memcpy(dest->param, src, n);
168 	dest->param = (char*)dest->param + n;
169 }
170 
ntfs_get(void * dest,ntfs_io * src,ntfs_size_t n)171 void ntfs_get(void* dest, ntfs_io *src, ntfs_size_t n)
172 {
173 	ntfs_memcpy(dest, src->param, n);
174 	src->param = (char*)src->param + n;
175 }
176 
ntfs_calloc(int size)177 void *ntfs_calloc(int size)
178 {
179 	void *result = ntfs_malloc(size);
180 	if (result)
181 		ntfs_bzero(result, size);
182 	return result;
183 }
184 
185 /* Copy len ascii characters from from to to. :) */
ntfs_ascii2uni(short int * to,char * from,int len)186 void ntfs_ascii2uni(short int *to, char *from, int len)
187 {
188 	int i;
189 
190 	for (i = 0; i < len; i++)
191 		NTFS_PUTU16(to + i, from[i]);
192 	to[i] = 0;
193 }
194 
195 /* strncmp for Unicode strings. */
ntfs_uni_strncmp(short int * a,short int * b,int n)196 int ntfs_uni_strncmp(short int* a, short int *b, int n)
197 {
198 	int i;
199 
200 	for(i = 0; i < n; i++)
201 	{
202 		if (NTFS_GETU16(a + i) < NTFS_GETU16(b + i))
203 			return -1;
204 		if (NTFS_GETU16(b + i) < NTFS_GETU16(a + i))
205 			return 1;
206 		if (NTFS_GETU16(a + i) == 0)
207 			break;
208 	}
209 	return 0;
210 }
211 
212 /* strncmp between Unicode and ASCII strings. */
ntfs_ua_strncmp(short int * a,char * b,int n)213 int ntfs_ua_strncmp(short int* a, char* b, int n)
214 {
215 	int i;
216 
217 	for (i = 0; i < n; i++)	{
218 		if(NTFS_GETU16(a + i) < b[i])
219 			return -1;
220 		if(b[i] < NTFS_GETU16(a + i))
221 			return 1;
222 		if (b[i] == 0)
223 			return 0;
224 	}
225 	return 0;
226 }
227 
228 #define NTFS_TIME_OFFSET ((ntfs_time64_t)(369*365 + 89) * 24 * 3600 * 10000000)
229 
230 /* Convert the NT UTC (based 1.1.1601, in hundred nanosecond units)
231  * into Unix UTC (based 1.1.1970, in seconds). */
ntfs_ntutc2unixutc(ntfs_time64_t ntutc)232 ntfs_time_t ntfs_ntutc2unixutc(ntfs_time64_t ntutc)
233 {
234 	/* Subtract the NTFS time offset, then convert to 1s intervals. */
235 	ntfs_time64_t t = ntutc - NTFS_TIME_OFFSET;
236 	do_div(t, 10000000);
237 	return (ntfs_time_t)t;
238 }
239 
240 /* Convert the Unix UTC into NT UTC. */
ntfs_unixutc2ntutc(ntfs_time_t t)241 ntfs_time64_t ntfs_unixutc2ntutc(ntfs_time_t t)
242 {
243 	/* Convert to 100ns intervals and then add the NTFS time offset. */
244 	return (ntfs_time64_t)t * 10000000 + NTFS_TIME_OFFSET;
245 }
246 
247 #undef NTFS_TIME_OFFSET
248 
249 /* Fill index name. */
ntfs_indexname(char * buf,int type)250 void ntfs_indexname(char *buf, int type)
251 {
252 	char hex[] = "0123456789ABCDEF";
253 	int index;
254 	*buf++ = '$';
255 	*buf++ = 'I';
256 	for (index = 24; index > 0; index -= 4)
257 		if ((0xF << index) & type)
258 			break;
259 	while (index >= 0) {
260 		*buf++ = hex[(type >> index) & 0xF];
261 		index -= 4;
262 	}
263 	*buf = '\0';
264 }
265 
266