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 LdapDN Parser.
025 *
026 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
027 * @version $Rev: 686082 $, $Date: 2008-08-15 01:12:09 +0200 (Ven, 15 aoĆ» 2008) $
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 * <safe-init-char> ::= [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 /** <safe-char> ::= [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 * <base64-char> ::= 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 * <safe-string> ::= <safe-init-char> <safe-chars> <safe-init-char> ::=
258 * [0x01-0x09] | 0x0B | 0x0C | [0x0E-0x1F] | [0x21-0x39] | 0x3B |
259 * [0x3D-0x7F] <safe-chars> ::= <safe-char> <safe-chars> | <safe-char> ::=
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 : <alpha> ::=
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 * <LUTF1> ::= 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 * <LUTF1> ::= 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 * <pairCharOnly> ::= ' ' | ',' | '=' | '+' | '<' | '>' | '#' | ';' | '\' | '"'
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 * <pairchar> ::= ' ' | ',' | '=' | '+' | '<' | '>' | '#' | ';' | '\' | '"' | [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 * <pairchar> ::= ' ' | ',' | '=' | '+' | '<' | '>' | '#' | ';' |
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. <stringchar> ::= [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 * <asciistringchar> ::= [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 <quotechar> ::= [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 <hexpair> ::= <hex> <hex>
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 <hexpair> ::= <hex> <hex>
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 <hexstring> ::=
613 * <hexpair> <hexpairs> <hexpairs> ::= <hexpair> <hexpairs> | 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 <hexstring> ::=
645 * <hexpair> <hexpairs> <hexpairs> ::= <hexpair> <hexpairs> | 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 : <base64-string>
682 * ::= <base64-char> <base64-chars> <base64-chars> ::= <base64-char>
683 * <base64-chars> | <base64-char> ::= 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 }