001    /*
002     *  Licensed to the Apache Software Foundation (ASF) under one
003     *  or more contributor license agreements.  See the NOTICE file
004     *  distributed with this work for additional information
005     *  regarding copyright ownership.  The ASF licenses this file
006     *  to you under the Apache License, Version 2.0 (the
007     *  "License"); you may not use this file except in compliance
008     *  with the License.  You may obtain a copy of the License at
009     *  
010     *    http://www.apache.org/licenses/LICENSE-2.0
011     *  
012     *  Unless required by applicable law or agreed to in writing,
013     *  software distributed under the License is distributed on an
014     *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     *  KIND, either express or implied.  See the License for the
016     *  specific language governing permissions and limitations
017     *  under the License. 
018     *  
019     */
020    package org.apache.directory.shared.ldap.util;
021    
022    
023    /**
024     * Utility class used by the DN Parser.
025     * 
026     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
027     * @version $Rev: 918756 $, $Date: 2010-03-04 00:05:29 +0100 (Thu, 04 Mar 2010) $
028     */
029    public class DNUtils
030    {
031        // ~ Static fields/initializers
032        // -----------------------------------------------------------------
033        /** A value if we got an error while parsing */
034        public static final int PARSING_ERROR = -1;
035    
036        /** A value if we got a correct parsing */
037        public static final int PARSING_OK = 0;
038    
039        /** If an hex pair contains only one char, this value is returned */
040        public static final int BAD_HEX_PAIR = -2;
041    
042        /** A constant representing one char length */
043        public static final int ONE_CHAR = 1;
044    
045        /** A constant representing two chars length */
046        public static final int TWO_CHARS = 2;
047    
048        /** A constant representing one byte length */
049        public static final int ONE_BYTE = 1;
050    
051        /** A constant representing two bytes length */
052        public static final int TWO_BYTES = 2;
053    
054        /**
055         * &lt;safe-init-char&gt; ::= [0x01-0x09] | 0x0B | 0x0C | [0x0E-0x1F] |
056         * [0x21-0x39] | 0x3B | [0x3D-0x7F]
057         */
058        private static final boolean[] SAFE_INIT_CHAR =
059            { 
060                false, true,  true,  true,  true,  true,  true,  true, 
061                true,  true,  false, true,  true,  false, true,  true, 
062                true,  true,  true,  true,  true,  true,  true,  true, 
063                true,  true,  true,  true,  true,  true,  true,  true, 
064                false, true,  true,  true,  true,  true,  true,  true, 
065                true,  true,  true,  true,  true,  true,  true,  true, 
066                true,  true,  true,  true,  true,  true,  true,  true, 
067                true,  true,  false, true,  false, true,  true,  true, 
068                true,  true,  true,  true,  true,  true,  true,  true, 
069                true,  true,  true,  true,  true,  true,  true,  true, 
070                true,  true,  true,  true,  true,  true,  true,  true, 
071                true,  true,  true,  true,  true,  true,  true,  true, 
072                true,  true,  true,  true,  true,  true,  true,  true, 
073                true,  true,  true,  true,  true,  true,  true,  true, 
074                true,  true,  true,  true,  true,  true,  true,  true, 
075                true,  true,  true,  true,  true,  true,  true,  true 
076            };
077    
078        /** &lt;safe-char&gt; ::= [0x01-0x09] | 0x0B | 0x0C | [0x0E-0x7F] */
079        private static final boolean[] SAFE_CHAR =
080            { 
081                false, true,  true,  true,  true,  true,  true,  true, 
082                true,  true,  false, true,  true,  false, true,  true, 
083                true,  true,  true,  true,  true,  true,  true,  true, 
084                true,  true,  true,  true,  true,  true,  true,  true, 
085                true,  true,  true,  true,  true,  true,  true,  true, 
086                true,  true,  true,  true,  true,  true,  true,  true, 
087                true,  true,  true,  true,  true,  true,  true,  true, 
088                true,  true,  true,  true,  true,  true,  true,  true, 
089                true,  true,  true,  true,  true,  true,  true,  true, 
090                true,  true,  true,  true,  true,  true,  true,  true, 
091                true,  true,  true,  true,  true,  true,  true,  true, 
092                true,  true,  true,  true,  true,  true,  true,  true, 
093                true,  true,  true,  true,  true,  true,  true,  true, 
094                true,  true,  true,  true,  true,  true,  true,  true, 
095                true,  true,  true,  true,  true,  true,  true,  true, 
096                true,  true,  true,  true,  true,  true,  true,  true, 
097            };
098    
099        /**
100         * &lt;base64-char&gt; ::= 0x2B | 0x2F | [0x30-0x39] | 0x3D | [0x41-0x5A] |
101         * [0x61-0x7A]
102         */
103        private static final boolean[] BASE64_CHAR =
104            { 
105                false, false, false, false, false, false, false, false, 
106                false, false, false, false, false, false, false, false, 
107                false, false, false, false, false, false, false, false, 
108                false, false, false, false, false, false, false, false, 
109                false, false, false, false, false, false, false, false, 
110                false, false, false, true,  false, false, false, true, 
111                true,  true,  true,  true,  true,  true,  true,  true, 
112                true,  true,  false, false, false, true,  false, false, 
113                false, true,  true,  true,  true,  true,  true,  true, 
114                true,  true,  true,  true,  true,  true,  true,  true, 
115                true,  true,  true,  true,  true,  true,  true,  true, 
116                true,  true,  true,  false, false, false, false, false,
117                false, true,  true,  true,  true,  true,  true,  true, 
118                true,  true,  true,  true,  true,  true,  true,  true, 
119                true,  true,  true,  true,  true,  true,  true,  true, 
120                true,  true,  true,  false, false, false, false, false 
121            };
122    
123        /**
124         * ' ' | '"' | '#' | '+' | ',' | [0-9] | ';' | '<' | '=' | '>' | [A-F] | '\' | [a-f]
125         * 0x22 | 0x23 | 0x2B | 0x2C | [0x30-0x39] | 0x3B | 0x3C | 0x3D | 0x3E |
126         * [0x41-0x46] | 0x5C | [0x61-0x66]
127         */
128        private static final boolean[] PAIR_CHAR =
129            { 
130                false, false, false, false, false, false, false, false, // 00 -> 07
131                false, false, false, false, false, false, false, false, // 08 -> 0F
132                false, false, false, false, false, false, false, false, // 10 -> 17
133                false, false, false, false, false, false, false, false, // 18 -> 1F
134                true,  false, true,  true,  false, false, false, false, // 20 -> 27 ( ' ', '"', '#' )
135                false, false, false, true,  true,  false, false, false, // 28 -> 2F ( '+', ',' )
136                true,  true,  true,  true,  true,  true,  true,  true,  // 30 -> 37 ( '0'..'7' )
137                true,  true,  false, true,  true,  true,  true,  false, // 38 -> 3F ( '8', '9', ';', '<', '=', '>' ) 
138                false, true,  true,  true,  true,  true,  true,  false, // 40 -> 47 ( 'A', 'B', 'C', 'D', 'E', 'F' )
139                false, false, false, false, false, false, false, false, // 48 -> 4F
140                false, false, false, false, false, false, false, false, // 50 -> 57
141                false, false, false, false, true,  false, false, false, // 58 -> 5F ( '\' )
142                false, true,  true,  true,  true,  true,  true,  false, // 60 -> 67 ( 'a', 'b', 'c', 'd', 'e', 'f' )
143                false, false, false, false, false, false, false, false, // 68 -> 6F
144                false, false, false, false, false, false, false, false, // 70 -> 77
145                false, false, false, false, false, false, false, false  // 78 -> 7F
146            };
147    
148    
149        /**
150         * [0x01-0x1F] | 0x21 | [0x24-0x2A] | [0x2D-0x3A] | 0x3D | [0x3F-0x5B] | [0x5D-0x7F]
151         */
152        private static final boolean[] LUTF1 =
153            { 
154                false, true,  true,  true,  true,  true,  true,  true, // 00 -> 07 '\0'
155                true,  true,  true,  true,  true,  true,  true,  true, // 08 -> 0F
156                true,  true,  true,  true,  true,  true,  true,  true, // 10 -> 17
157                true,  true,  true,  true,  true,  true,  true,  true, // 18 -> 1F
158                false, true,  false, false, true,  true,  true,  true, // 20 -> 27 ( ' ', '"', '#' )
159                true,  true,  true,  false, false, true,  true,  true, // 28 -> 2F ( '+', ',' )
160                true,  true,  true,  true,  true,  true,  true,  true, // 30 -> 37 
161                true,  true,  true,  false, false, true,  false, true, // 38 -> 3F ( ';', '<', '>' ) 
162                true,  true,  true,  true,  true,  true,  true,  true, // 40 -> 47 
163                true,  true,  true,  true,  true,  true,  true,  true, // 48 -> 4F
164                true,  true,  true,  true,  true,  true,  true,  true, // 50 -> 57
165                true,  true,  true,  true,  false, true,  true,  true, // 58 -> 5F ( '\' )
166                true,  true,  true,  true,  true,  true,  true,  true, // 60 -> 67 
167                true,  true,  true,  true,  true,  true,  true,  true, // 68 -> 6F
168                true,  true,  true,  true,  true,  true,  true,  true, // 70 -> 77
169                true,  true,  true,  true,  true,  true,  true,  true  // 78 -> 7F
170            };
171    
172    
173        /**
174         * [0x01-0x21] | [0x23-0x2A] | [0x2D-0x3A] | 0x3D | [0x3F-0x5B] | [0x5D-0x7F]
175         */
176        private static final boolean[] SUTF1 =
177            { 
178                false, true,  true,  true,  true,  true,  true,  true, // 00 -> 07 '\0'
179                true,  true,  true,  true,  true,  true,  true,  true, // 08 -> 0F
180                true,  true,  true,  true,  true,  true,  true,  true, // 10 -> 17
181                true,  true,  true,  true,  true,  true,  true,  true, // 18 -> 1F
182                true,  true,  false, true,  true,  true,  true,  true, // 20 -> 27 ( '"' )
183                true,  true,  true,  false, false, true,  true,  true, // 28 -> 2F ( '+', ',' )
184                true,  true,  true,  true,  true,  true,  true,  true, // 30 -> 37 
185                true,  true,  true,  false, false, true,  false, true, // 38 -> 3F ( ';', '<', '>' ) 
186                true,  true,  true,  true,  true,  true,  true,  true, // 40 -> 47 
187                true,  true,  true,  true,  true,  true,  true,  true, // 48 -> 4F
188                true,  true,  true,  true,  true,  true,  true,  true, // 50 -> 57
189                true,  true,  true,  true,  false, true,  true,  true, // 58 -> 5F ( '\' )
190                true,  true,  true,  true,  true,  true,  true,  true, // 60 -> 67 
191                true,  true,  true,  true,  true,  true,  true,  true, // 68 -> 6F
192                true,  true,  true,  true,  true,  true,  true,  true, // 70 -> 77
193                true,  true,  true,  true,  true,  true,  true,  true  // 78 -> 7F
194            };
195    
196    
197        /**
198         * ' ' | '"' | '#' | '+' | ',' | ';' | '<' | '=' | '>' | '\' |
199         * 0x22 | 0x23 | 0x2B | 0x2C | 0x3B | 0x3C | 0x3D | 0x3E | 0x5C
200         */
201        private static final boolean[] PAIR_CHAR_ONLY =
202            { 
203                false, false, false, false, false, false, false, false, // 00 -> 07
204                false, false, false, false, false, false, false, false, // 08 -> 0F
205                false, false, false, false, false, false, false, false, // 10 -> 17
206                false, false, false, false, false, false, false, false, // 18 -> 1F
207                true,  false, true,  true,  false, false, false, false, // 20 -> 27 ( ' ', '"', '#' )
208                false, false, false, true,  true,  false, false, false, // 28 -> 2F ( '+', ',' )
209                false, false, false, false, false, false, false, false, // 30 -> 37
210                false, false, false, true,  true,  true,  true,  false, // 38 -> 3F ( ';', '<', '=', '>' ) 
211                false, false, false, false, false, false, false, false, // 40 -> 47
212                false, false, false, false, false, false, false, false, // 48 -> 4F
213                false, false, false, false, false, false, false, false, // 50 -> 57
214                false, false, false, false, true,  false, false, false, // 58 -> 5F ( '\' )
215                false, false, false, false, false, false, false, false, // 60 -> 67
216                false, false, false, false, false, false, false, false, // 68 -> 6F
217                false, false, false, false, false, false, false, false, // 70 -> 77
218                false, false, false, false, false, false, false, false  // 78 -> 7F
219            };
220    
221        /**
222         * '"' | '#' | '+' | ',' | [0-9] | ';' | '<' | '=' | '>' | [A-F] | '\' |
223         * [a-f] 0x22 | 0x23 | 0x2B | 0x2C | [0x30-0x39] | 0x3B | 0x3C | 0x3D | 0x3E |
224         * [0x41-0x46] | 0x5C | [0x61-0x66]
225         */
226        private static final int[] STRING_CHAR =
227            { 
228                ONE_CHAR,      ONE_CHAR,      ONE_CHAR,      ONE_CHAR,     // 00 -> 03
229                ONE_CHAR,      ONE_CHAR,      ONE_CHAR,      ONE_CHAR,     // 04 -> 07
230                ONE_CHAR,      ONE_CHAR,      PARSING_ERROR, ONE_CHAR,     // 08 -> 0B
231                ONE_CHAR,      PARSING_ERROR, ONE_CHAR,      ONE_CHAR,     // 0C -> 0F
232                ONE_CHAR,      ONE_CHAR,      ONE_CHAR,      ONE_CHAR,     // 10 -> 13
233                ONE_CHAR,      ONE_CHAR,      ONE_CHAR,      ONE_CHAR,     // 14 -> 17
234                ONE_CHAR,      ONE_CHAR,      ONE_CHAR,      ONE_CHAR,     // 18 -> 1B
235                ONE_CHAR,      ONE_CHAR,      ONE_CHAR,      ONE_CHAR,     // 1C -> 1F
236                ONE_CHAR,      ONE_CHAR,      PARSING_ERROR, ONE_CHAR,     // 20 -> 23
237                ONE_CHAR,      ONE_CHAR,      ONE_CHAR,      ONE_CHAR,     // 24 -> 27
238                ONE_CHAR,      ONE_CHAR,      ONE_CHAR,      PARSING_ERROR,// 28 -> 2B
239                PARSING_ERROR, ONE_CHAR,      ONE_CHAR,      ONE_CHAR,     // 2C -> 2F
240                ONE_CHAR,      ONE_CHAR,      ONE_CHAR,      ONE_CHAR,     // 30 -> 33
241                ONE_CHAR,      ONE_CHAR,      ONE_CHAR,      ONE_CHAR,     // 34 -> 37
242                ONE_CHAR,      ONE_CHAR,      ONE_CHAR,      PARSING_ERROR,// 38 -> 3B
243                PARSING_ERROR, ONE_CHAR,      PARSING_ERROR, ONE_CHAR      // 3C -> 3F
244            };
245    
246        /** "oid." static */
247        public static final String OID_LOWER = "oid.";
248    
249        /** "OID." static */
250        public static final String OID_UPPER = "OID.";
251    
252        // ~ Methods
253        // ------------------------------------------------------------------------------------
254    
255        /**
256         * Walk the buffer while characters are Safe String characters :
257         * &lt;safe-string&gt; ::= &lt;safe-init-char&gt; &lt;safe-chars&gt; &lt;safe-init-char&gt; ::=
258         * [0x01-0x09] | 0x0B | 0x0C | [0x0E-0x1F] | [0x21-0x39] | 0x3B |
259         * [0x3D-0x7F] &lt;safe-chars&gt; ::= &lt;safe-char&gt; &lt;safe-chars&gt; | &lt;safe-char&gt; ::=
260         * [0x01-0x09] | 0x0B | 0x0C | [0x0E-0x7F]
261         * 
262         * @param bytes The buffer which contains the data
263         * @param index Current position in the buffer
264         * @return The position of the first character which is not a Safe Char
265         */
266        public static int parseSafeString( byte[] bytes, int index )
267        {
268            if ( ( bytes == null ) || ( bytes.length == 0 ) || ( index < 0 ) || ( index >= bytes.length ) )
269            {
270                return -1;
271            }
272            else
273            {
274                byte c = bytes[index];
275    
276                if ( ( ( c | 0x7F ) != 0x7F ) || ( !SAFE_INIT_CHAR[c] ) )
277                {
278                    return -1;
279                }
280    
281                index++;
282    
283                while ( index < bytes.length )
284                {
285                    c = bytes[index];
286    
287                    if ( ( ( c | 0x7F ) != 0x7F ) || ( !SAFE_CHAR[c] ) )
288                    {
289                        break;
290                    }
291    
292                    index++;
293                }
294    
295                return index;
296            }
297        }
298    
299    
300        /**
301         * Walk the buffer while characters are Alpha characters : &lt;alpha&gt; ::=
302         * [0x41-0x5A] | [0x61-0x7A]
303         * 
304         * @param bytes The buffer which contains the data
305         * @param index Current position in the buffer
306         * @return The position of the first character which is not an Alpha Char
307         */
308        public static int parseAlphaASCII( byte[] bytes, int index )
309        {
310            if ( ( bytes == null ) || ( bytes.length == 0 ) || ( index < 0 ) || ( index >= bytes.length ) )
311            {
312                return -1;
313            }
314            else
315            {
316                byte b = bytes[index++];
317    
318                if ( StringTools.isAlpha( b ) )
319                {
320                    return index-1;
321                }
322                else
323                {
324                    return -1;
325                }
326            }
327        }
328        
329        
330        /**
331         * Check if the current character is a LUTF1 (Lead UTF ascii char)<br/> 
332         * &lt;LUTF1&gt; ::= 0x01-1F | 0x21 | 0x24-2A | 0x2D-3A | 0x3D | 0x3F-5B | 0x5D-7F
333         * 
334         * @param bytes The buffer containing the data
335         * @param index Current position in the buffer
336         * @return <code>true</code> if the current character is a LUTF1
337         */
338        public static boolean isLUTF1( byte[] bytes, int index )
339        {
340            if ( ( bytes == null ) || ( bytes.length == 0 ) || ( index < 0 ) || ( index >= bytes.length ) )
341            {
342                return false;
343            }
344    
345            byte c = bytes[index];
346            return ( ( ( c | 0x7F ) == 0x7F ) && LUTF1[c & 0x7f] );
347        }
348    
349        
350        /**
351         * Check if the current character is a SUTF1 (Stringchar UTF ascii char)<br/> 
352         * &lt;LUTF1&gt; ::= 0x01-20 | 0x23-2A | 0x2D-3A | 0x3D | 0x3F-5B | 0x5D-7F
353         * 
354         * @param bytes The buffer containing the data
355         * @param index Current position in the buffer
356         * @return <code>true</code> if the current character is a SUTF1
357         */
358        public static boolean isSUTF1( byte[] bytes, int index )
359        {
360            if ( ( bytes == null ) || ( bytes.length == 0 ) || ( index < 0 ) || ( index >= bytes.length ) )
361            {
362                return false;
363            }
364    
365            byte c = bytes[index];
366            return ( ( ( c | 0x7F ) == 0x7F ) && SUTF1[c & 0x7f] );
367        }
368    
369        
370        /**
371         * Check if the given char is a pair char only
372         * &lt;pairCharOnly&gt; ::= ' ' | ',' | '=' | '+' | '<' | '>' | '#' | ';' | '\' | '"'
373         *
374         * @param c the char we want to test
375         * @return true if the char is a pair char only
376         */
377        public static boolean isPairCharOnly( char c )
378        {
379            return ( ( ( c | 0x7F ) == 0x7F ) && PAIR_CHAR_ONLY[c & 0x7f] );
380        }
381    
382    
383        /**
384         * Check if the current character is a Pair Char 
385         * &lt;pairchar&gt; ::= ' ' | ',' | '=' | '+' | '<' | '>' | '#' | ';' | '\' | '"' | [0-9a-fA-F] [0-9a-fA-F]
386         * 
387         * @param bytes The buffer which contains the data
388         * @param index Current position in the buffer
389         * @return <code>true</code> if the current character is a Pair Char
390         */
391        public static boolean isPairChar( byte[] bytes, int index )
392        {
393            if ( ( bytes == null ) || ( bytes.length == 0 ) || ( index < 0 ) || ( index >= bytes.length ) )
394            {
395                return false;
396            }
397            else
398            {
399                byte c = bytes[index];
400    
401                if ( ( ( c | 0x7F ) != 0x7F )  || ( !PAIR_CHAR[c] ) )
402                {
403                    return false;
404                }
405                else
406                {
407                    if ( PAIR_CHAR_ONLY[c] )
408                    {
409                        return true;
410                    }
411                    else if ( StringTools.isHex( bytes, index++ ) )
412                    {
413                        return StringTools.isHex( bytes, index );
414                    }
415                    else
416                    {
417                        return false;
418                    }
419                }
420            }
421        }
422    
423    
424        /**
425         * Check if the current character is a Pair Char 
426         * 
427         * &lt;pairchar&gt; ::= ' ' | ',' | '=' | '+' | '<' | '>' | '#' | ';' | 
428         *                  '\' | '"' | [0-9a-fA-F] [0-9a-fA-F]
429         * 
430         * @param bytes The byte array which contains the data
431         * @param index Current position in the byte array
432         * @return <code>true</code> if the current byte is a Pair Char
433         */
434        public static int countPairChar( byte[] bytes, int index )
435        {
436            if ( bytes == null )
437            {
438                return PARSING_ERROR;
439            }
440    
441            int length = bytes.length;
442            
443            if ( ( length == 0 ) || ( index < 0 ) || ( index >= length ) )
444            {
445                return PARSING_ERROR;
446            }
447            else
448            {
449                byte c = bytes[index];
450    
451                if ( ( ( c | 0x7F ) != 0x7F )  || ( !PAIR_CHAR[c] ) )
452                {
453                    return PARSING_ERROR;
454                }
455                else
456                {
457                    if ( PAIR_CHAR_ONLY[c] )
458                    {
459                        return 1;
460                    }
461                    else if ( StringTools.isHex( bytes, index++ ) )
462                    {
463                        return StringTools.isHex( bytes, index ) ? 2 : PARSING_ERROR;
464                    }
465                    else
466                    {
467                        return PARSING_ERROR;
468                    }
469                }
470            }
471        }
472    
473    
474        /**
475         * Check if the current character is a String Char. Chars are Unicode, not
476         * ASCII. &lt;stringchar&gt; ::= [0x00-0xFFFF] - [,=+<>#;\"\n\r]
477         * 
478         * @param bytes The buffer which contains the data
479         * @param index Current position in the buffer
480         * @return The current char if it is a String Char, or '#' (this is simpler
481         *         than throwing an exception :)
482         */
483        public static int isStringChar( byte[] bytes, int index )
484        {
485            if ( ( bytes == null ) || ( bytes.length == 0 ) || ( index < 0 ) || ( index >= bytes.length ) )
486            {
487                return -1;
488            }
489            else
490            {
491                byte c = bytes[index];
492    
493                if ( ( c | 0x3F ) == 0x3F )
494                {
495                    return STRING_CHAR[ c ];
496                }
497                else
498                {
499                    return StringTools.countBytesPerChar( bytes, index );
500                }
501            }
502        }
503    
504    
505        /**
506         * Check if the current character is an ascii String Char.<br/>
507         * <p> 
508         * &lt;asciistringchar&gt; ::= [0x00-0x7F] - [,=+<>#;\"\n\r]
509         * </p>
510         * 
511         * @param bytes The buffer which contains the data
512         * @param index Current position in the buffer
513         * @return The current char if it is a String Char, or '#' (this is simpler
514         *         than throwing an exception :)
515         */
516        public static int isAciiStringChar( byte[] bytes, int index )
517        {
518            if ( ( bytes == null ) || ( bytes.length == 0 ) || ( index < 0 ) || ( index >= bytes.length ) )
519            {
520                return -1;
521            }
522            else
523            {
524                byte c = bytes[index];
525    
526                if ( ( c | 0x3F ) == 0x3F )
527                {
528                    return STRING_CHAR[ c ];
529                }
530                else
531                {
532                    return StringTools.countBytesPerChar( bytes, index );
533                }
534            }
535        }
536    
537    
538        /**
539         * Check if the current character is a Quote Char We are testing Unicode
540         * chars &lt;quotechar&gt; ::= [0x00-0xFFFF] - [\"]
541         * 
542         * @param bytes The buffer which contains the data
543         * @param index Current position in the buffer
544         *
545         * @return <code>true</code> if the current character is a Quote Char
546         */
547        public static int isQuoteChar( byte[] bytes, int index )
548        {
549            if ( ( bytes == null ) || ( bytes.length == 0 ) || ( index < 0 ) || ( index >= bytes.length ) )
550            {
551                return -1;
552            }
553            else
554            {
555                byte c = bytes[index];
556    
557                if ( ( c == '\\' ) || ( c == '"' ) )
558                {
559                    return -1;
560                }
561                else
562                {
563                    return StringTools.countBytesPerChar( bytes, index );
564                }
565            }
566        }
567    
568    
569        /**
570         * Parse an hex pair &lt;hexpair&gt; ::= &lt;hex&gt; &lt;hex&gt;
571         * 
572         * @param bytes The buffer which contains the data
573         * @param index Current position in the buffer
574         * @return The new position, -1 if the buffer does not contain an HexPair,
575         *         -2 if the buffer contains an hex byte but not two.
576         */
577        public static int parseHexPair( byte[] bytes, int index )
578        {
579            if ( StringTools.isHex( bytes, index ) )
580            {
581                if ( StringTools.isHex( bytes, index + 1 ) )
582                {
583                    return index + 2;
584                }
585                else
586                {
587                    return -2;
588                }
589            }
590            else
591            {
592                return -1;
593            }
594        }
595    
596    
597        /**
598         * Parse an hex pair &lt;hexpair&gt; ::= &lt;hex&gt; &lt;hex&gt;
599         * 
600         * @param bytes The byte array which contains the data
601         * @param index Current position in the byte array
602         * @return The new position, -1 if the byte array does not contain an HexPair,
603         *         -2 if the byte array contains an hex byte but not two.
604         */
605        private static byte getHexPair( byte[] bytes, int index )
606        {
607            return StringTools.getHexValue( bytes[index], bytes[index + 1] );
608        }
609    
610        
611        /**
612         * Parse an hex string, which is a list of hex pairs &lt;hexstring&gt; ::=
613         * &lt;hexpair&gt; &lt;hexpairs&gt; &lt;hexpairs&gt; ::= &lt;hexpair&gt; &lt;hexpairs&gt; | e
614         * 
615         * @param bytes The buffer which contains the data
616         * @param index Current position in the buffer
617         * @return Return the first position which is not an hex pair, or -1 if
618         *         there is no hexpair at the beginning or if an hexpair is invalid
619         *         (if we have only one hex instead of 2)
620         */
621        public static int parseHexString( byte[] bytes, int index )
622        {
623            int result = parseHexPair( bytes, index );
624    
625            if ( result < 0 )
626            {
627                return -1;
628            }
629            else
630            {
631                index += 2;
632            }
633    
634            while ( ( result = parseHexPair( bytes, index ) ) >= 0 )
635            {
636                index += 2;
637            }
638    
639            return ( ( result == -2 ) ? -1 : index );
640        }
641    
642    
643        /**
644         * Parse an hex string, which is a list of hex pairs &lt;hexstring&gt; ::=
645         * &lt;hexpair&gt; &lt;hexpairs&gt; &lt;hexpairs&gt; ::= &lt;hexpair&gt; &lt;hexpairs&gt; | e
646         * 
647         * @param bytes The byte array which contains the data
648         * @param hex The result as a byte array
649         * @param pos Current position in the string
650         * @return Return the first position which is not an hex pair, or -1 if
651         *         there is no hexpair at the beginning or if an hexpair is invalid
652         *         (if we have only one hex instead of 2)
653         */
654        public static int parseHexString( byte[] bytes, byte[] hex, Position pos )
655        {
656            int i = 0;
657            pos.end = pos.start;
658            int result = parseHexPair( bytes, pos.start );
659    
660            if ( result < 0 )
661            {
662                return PARSING_ERROR;
663            }
664            else
665            {
666                hex[i++] = getHexPair( bytes, pos.end );
667                pos.end += TWO_CHARS;
668            }
669    
670            while ( ( result = parseHexPair( bytes, pos.end ) ) >= 0 )
671            {
672                hex[i++] = getHexPair( bytes, pos.end );
673                pos.end += TWO_CHARS;
674            }
675    
676            return ( ( result == BAD_HEX_PAIR ) ? PARSING_ERROR : PARSING_OK );
677        }
678    
679        
680        /**
681         * Walk the buffer while characters are Base64 characters : &lt;base64-string&gt;
682         * ::= &lt;base64-char&gt; &lt;base64-chars&gt; &lt;base64-chars&gt; ::= &lt;base64-char&gt;
683         * &lt;base64-chars&gt; | &lt;base64-char&gt; ::= 0x2B | 0x2F | [0x30-0x39] | 0x3D |
684         * [0x41-0x5A] | [0x61-0x7A]
685         * 
686         * @param bytes The buffer which contains the data
687         * @param index Current position in the buffer
688         * @return The position of the first character which is not a Base64 Char
689         */
690        public static int parseBase64String( byte[] bytes, int index )
691        {
692            if ( ( bytes == null ) || ( bytes.length == 0 ) || ( index < 0 ) || ( index >= bytes.length ) )
693            {
694                return -1;
695            }
696            else
697            {
698                byte c = bytes[index];
699    
700                if ( ( ( c | 0x7F ) != 0x7F )  || ( !BASE64_CHAR[c] ) )
701                {
702                    return -1;
703                }
704    
705                index++;
706    
707                while ( index < bytes.length )
708                {
709                    c = bytes[index];
710    
711                    if ( ( ( c | 0x7F ) != 0x7F )  || ( !BASE64_CHAR[c] ) )
712                    {
713                        break;
714                    }
715    
716                    index++;
717                }
718    
719                return index;
720            }
721        }
722    }