1/*
2 *******************************************************************************
3 *
4 *   Copyright (C) 2003-2007, 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
25#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
26#define NFS4_MAX_BUFFER_SIZE 1000
27#define PREFIX_SUFFIX_SEPARATOR 0x0040 /* '@' */
28
29
30const char* NFS4DataFileNames[5] ={
31    "nfscss",
32    "nfscsi",
33    "nfscis",
34    "nfsmxp",
35    "nfsmxs"
36};
37
38
39int32_t
40nfs4_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
121CLEANUP:
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*/
136static 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 */
150static int
151findStringIndex(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
173static void
174getPrefixSuffix(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,LENGTHOF(special_prefixes), *prefix, *prefixLen-1) != -1) && (*suffix != NULL)){
199        *status = U_PARSE_ERROR;
200        return;
201    }
202
203}
204
205int32_t
206nfs4_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
268CLEANUP:
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
279int32_t
280nfs4_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
288int32_t
289nfs4_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