1 /*
2  *******************************************************************************
3  *
4  *   Copyright (C) 2003-2014, International Business Machines
5  *   Corporation and others.  All Rights Reserved.
6  *
7  *******************************************************************************
8  *   file name:  nfsprep.c
9  *   encoding:   US-ASCII
10  *   tab size:   8 (not used)
11  *   indentation:4
12  *
13  *   created on: 2003jul11
14  *   created by: Ram Viswanadha
15  */
16 
17 #include "unicode/utypes.h"
18 
19 #if !UCONFIG_NO_IDNA
20 
21 #include "nfsprep.h"
22 #include "ustr_imp.h"
23 #include "cintltst.h"
24 #include "cmemory.h"
25 
26 #define NFS4_MAX_BUFFER_SIZE 1000
27 #define PREFIX_SUFFIX_SEPARATOR 0x0040 /* '@' */
28 
29 
30 const char* NFS4DataFileNames[5] ={
31     "nfscss",
32     "nfscsi",
33     "nfscis",
34     "nfsmxp",
35     "nfsmxs"
36 };
37 
38 
39 int32_t
nfs4_prepare(const char * src,int32_t srcLength,char * dest,int32_t destCapacity,NFS4ProfileState state,UParseError * parseError,UErrorCode * status)40 nfs4_prepare( const char* src, int32_t srcLength,
41               char* dest, int32_t destCapacity,
42               NFS4ProfileState state,
43               UParseError* parseError,
44               UErrorCode*  status){
45 
46     UChar b1Stack[NFS4_MAX_BUFFER_SIZE],
47           b2Stack[NFS4_MAX_BUFFER_SIZE];
48     char  b3Stack[NFS4_MAX_BUFFER_SIZE];
49 
50     /* initialize pointers to stack buffers */
51     UChar *b1 = b1Stack, *b2 = b2Stack;
52     char  *b3=b3Stack;
53     int32_t b1Len=0, b2Len=0, b3Len=0,
54             b1Capacity = NFS4_MAX_BUFFER_SIZE,
55             b2Capacity = NFS4_MAX_BUFFER_SIZE,
56             b3Capacity = NFS4_MAX_BUFFER_SIZE,
57             reqLength=0;
58 
59     UStringPrepProfile* profile = NULL;
60     /* get the test data path */
61     const char *testdatapath = NULL;
62 
63     if(status==NULL || U_FAILURE(*status)){
64         return 0;
65     }
66     if((src==NULL) || (srcLength < -1) || (destCapacity<0) || (!dest && destCapacity > 0)){
67         *status = U_ILLEGAL_ARGUMENT_ERROR;
68         return 0;
69     }
70     testdatapath = loadTestData(status);
71 
72     /* convert the string from UTF-8 to UTF-16 */
73     u_strFromUTF8(b1,b1Capacity,&b1Len,src,srcLength,status);
74     if(*status == U_BUFFER_OVERFLOW_ERROR){
75 
76         /* reset the status */
77         *status = U_ZERO_ERROR;
78 
79         b1 = (UChar*) malloc(b1Len * U_SIZEOF_UCHAR);
80         if(b1==NULL){
81             *status = U_MEMORY_ALLOCATION_ERROR;
82             goto CLEANUP;
83         }
84 
85         b1Capacity = b1Len;
86         u_strFromUTF8(b1, b1Capacity, &b1Len, src, srcLength, status);
87     }
88 
89     /* open the profile */
90     profile = usprep_open(testdatapath, NFS4DataFileNames[state],  status);
91     /* prepare the string */
92     b2Len = usprep_prepare(profile, b1, b1Len, b2, b2Capacity, USPREP_DEFAULT, parseError, status);
93     if(*status == U_BUFFER_OVERFLOW_ERROR){
94         *status = U_ZERO_ERROR;
95         b2 = (UChar*) malloc(b2Len * U_SIZEOF_UCHAR);
96         if(b2== NULL){
97             *status = U_MEMORY_ALLOCATION_ERROR;
98             goto CLEANUP;
99         }
100         b2Len = usprep_prepare(profile, b1, b1Len, b2, b2Len, USPREP_DEFAULT, parseError, status);
101     }
102 
103     /* convert the string back to UTF-8 */
104     u_strToUTF8(b3,b3Capacity, &b3Len, b2, b2Len, status);
105     if(*status == U_BUFFER_OVERFLOW_ERROR){
106         *status = U_ZERO_ERROR;
107         b3 = (char*) malloc(b3Len);
108         if(b3== NULL){
109             *status = U_MEMORY_ALLOCATION_ERROR;
110             goto CLEANUP;
111         }
112         b3Capacity = b3Len;
113         u_strToUTF8(b3,b3Capacity, &b3Len, b2, b2Len, status);
114     }
115 
116     reqLength = b3Len;
117     if(dest!=NULL && reqLength <= destCapacity){
118         memmove(dest, b3, reqLength);
119     }
120 
121 CLEANUP:
122     if(b1!=b1Stack){
123         free(b1);
124     }
125     if(b2!=b2Stack){
126         free(b2);
127     }
128     if(b3!=b3Stack){
129         free(b3);
130     }
131 
132     return u_terminateChars(dest, destCapacity, reqLength, status);
133 }
134 
135 /* sorted array for binary search*/
136 static const char* special_prefixes[]={
137     "\x0041\x004e\x004f\x004e\x0059\x004d\x004f\x0055\x0053",
138     "\x0041\x0055\x0054\x0048\x0045\x004e\x0054\x0049\x0043\x0041\x0054\x0045\x0044",
139     "\x0042\x0041\x0054\x0043\x0048",
140     "\x0044\x0049\x0041\x004c\x0055\x0050",
141     "\x0045\x0056\x0045\x0052\x0059\x004f\x004e\x0045",
142     "\x0047\x0052\x004f\x0055\x0050",
143     "\x0049\x004e\x0054\x0045\x0052\x0041\x0043\x0054\x0049\x0056\x0045",
144     "\x004e\x0045\x0054\x0057\x004f\x0052\x004b",
145     "\x004f\x0057\x004e\x0045\x0052",
146 };
147 
148 
149 /* binary search the sorted array */
150 static int
findStringIndex(const char * const * sortedArr,int32_t sortedArrLen,const char * target,int32_t targetLen)151 findStringIndex(const char* const *sortedArr, int32_t sortedArrLen, const char* target, int32_t targetLen){
152 
153     int left, middle, right,rc;
154 
155     left =0;
156     right= sortedArrLen-1;
157 
158     while(left <= right){
159         middle = (left+right)/2;
160         rc=strncmp(sortedArr[middle],target, targetLen);
161 
162         if(rc<0){
163             left = middle+1;
164         }else if(rc >0){
165             right = middle -1;
166         }else{
167             return middle;
168         }
169     }
170     return -1;
171 }
172 
173 static void
getPrefixSuffix(const char * src,int32_t srcLength,const char ** prefix,int32_t * prefixLen,const char ** suffix,int32_t * suffixLen,UErrorCode * status)174 getPrefixSuffix(const char *src, int32_t srcLength,
175                 const char **prefix, int32_t *prefixLen,
176                 const char **suffix, int32_t *suffixLen,
177                 UErrorCode *status){
178 
179     int32_t i=0;
180     *prefix = src;
181     while(i<srcLength){
182         if(src[i] == PREFIX_SUFFIX_SEPARATOR){
183             if((i+1) == srcLength){
184                 /* we reached the end of the string */
185                 *suffix = NULL;
186                 i++;
187                 break;
188             }
189             i++;/* the prefix contains the separator */
190             *suffix = src + i;
191             break;
192         }
193         i++;
194     }
195     *prefixLen = i;
196     *suffixLen = srcLength - i;
197     /* special prefixes must not be followed by suffixes! */
198     if((findStringIndex(special_prefixes,UPRV_LENGTHOF(special_prefixes), *prefix, *prefixLen-1) != -1) && (*suffix != NULL)){
199         *status = U_PARSE_ERROR;
200         return;
201     }
202 
203 }
204 
205 int32_t
nfs4_mixed_prepare(const char * src,int32_t srcLength,char * dest,int32_t destCapacity,UParseError * parseError,UErrorCode * status)206 nfs4_mixed_prepare( const char* src, int32_t srcLength,
207                     char* dest, int32_t destCapacity,
208                     UParseError* parseError,
209                     UErrorCode*  status){
210 
211     const char *prefix = NULL, *suffix = NULL;
212     int32_t prefixLen=0, suffixLen=0;
213     char  pStack[NFS4_MAX_BUFFER_SIZE],
214           sStack[NFS4_MAX_BUFFER_SIZE];
215     char *p=pStack, *s=sStack;
216     int32_t pLen=0, sLen=0, reqLen=0,
217             pCapacity = NFS4_MAX_BUFFER_SIZE,
218             sCapacity = NFS4_MAX_BUFFER_SIZE;
219 
220 
221     if(status==NULL || U_FAILURE(*status)){
222         return 0;
223     }
224     if((src==NULL) || (srcLength < -1) || (destCapacity<0) || (!dest && destCapacity > 0)){
225         *status = U_ILLEGAL_ARGUMENT_ERROR;
226         return 0;
227     }
228     if(srcLength == -1){
229         srcLength = (int32_t)strlen(src);
230     }
231     getPrefixSuffix(src, srcLength, &prefix, &prefixLen, &suffix, &suffixLen, status);
232 
233     /* prepare the prefix */
234     pLen = nfs4_prepare(prefix, prefixLen, p, pCapacity, NFS4_MIXED_PREP_PREFIX, parseError, status);
235     if(*status == U_BUFFER_OVERFLOW_ERROR){
236         *status = U_ZERO_ERROR;
237         p = (char*) malloc(pLen);
238         if(p == NULL){
239            *status = U_MEMORY_ALLOCATION_ERROR;
240            goto CLEANUP;
241         }
242         pLen = nfs4_prepare(prefix, prefixLen, p, pLen, NFS4_MIXED_PREP_PREFIX, parseError, status);
243     }
244 
245     /* prepare the suffix */
246     if(suffix != NULL){
247         sLen = nfs4_prepare(suffix, suffixLen, s, sCapacity, NFS4_MIXED_PREP_SUFFIX, parseError, status);
248         if(*status == U_BUFFER_OVERFLOW_ERROR){
249             *status = U_ZERO_ERROR;
250             s = (char*) malloc(pLen);
251             if(s == NULL){
252                *status = U_MEMORY_ALLOCATION_ERROR;
253                goto CLEANUP;
254             }
255             sLen = nfs4_prepare(suffix, suffixLen, s, sLen, NFS4_MIXED_PREP_SUFFIX, parseError, status);
256         }
257     }
258     reqLen = pLen+sLen+1 /* for the delimiter */;
259     if(dest != NULL && reqLen <= destCapacity){
260         memmove(dest, p, pLen);
261         /* add the suffix */
262         if(suffix!=NULL){
263             dest[pLen++] = PREFIX_SUFFIX_SEPARATOR;
264             memmove(dest+pLen, s, sLen);
265         }
266     }
267 
268 CLEANUP:
269     if(p != pStack){
270         free(p);
271     }
272     if(s != sStack){
273         free(s);
274     }
275 
276     return u_terminateChars(dest, destCapacity, reqLen, status);
277 }
278 
279 int32_t
nfs4_cis_prepare(const char * src,int32_t srcLength,char * dest,int32_t destCapacity,UParseError * parseError,UErrorCode * status)280 nfs4_cis_prepare(   const char* src, int32_t srcLength,
281                     char* dest, int32_t destCapacity,
282                     UParseError* parseError,
283                     UErrorCode*  status){
284     return nfs4_prepare(src, srcLength, dest, destCapacity, NFS4_CIS_PREP, parseError, status);
285 }
286 
287 
288 int32_t
nfs4_cs_prepare(const char * src,int32_t srcLength,char * dest,int32_t destCapacity,UBool isCaseSensitive,UParseError * parseError,UErrorCode * status)289 nfs4_cs_prepare(    const char* src, int32_t srcLength,
290                     char* dest, int32_t destCapacity,
291                     UBool isCaseSensitive,
292                     UParseError* parseError,
293                     UErrorCode*  status){
294     if(isCaseSensitive){
295         return nfs4_prepare(src, srcLength, dest, destCapacity, NFS4_CS_PREP_CS, parseError, status);
296     }else{
297         return nfs4_prepare(src, srcLength, dest, destCapacity, NFS4_CS_PREP_CI, parseError, status);
298     }
299 }
300 
301 #endif
302 /*
303  * Hey, Emacs, please set the following:
304  *
305  * Local Variables:
306  * indent-tabs-mode: nil
307  * End:
308  *
309  */
310 
311