1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.api.asn1.util;
21
22
23 import java.util.Arrays;
24
25 import org.apache.directory.api.asn1.DecoderException;
26 import org.apache.directory.api.i18n.I18n;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 public class Oid
67 {
68
69 private long[] oidValues;
70
71
72 private int hash;
73
74
75
76
77
78 public Oid()
79 {
80
81
82 hash = 0;
83 }
84
85
86
87
88
89
90
91
92
93 public Oid( byte[] oid ) throws DecoderException
94 {
95 setOid( oid );
96 hash = computeHashCode();
97 }
98
99
100
101
102
103
104
105
106
107 public Oid( String oid ) throws DecoderException
108 {
109 setOid( oid );
110 hash = computeHashCode();
111 }
112
113
114
115
116
117
118
119
120
121 public void setOid( byte[] oid ) throws DecoderException
122 {
123 if ( oid == null )
124 {
125 throw new DecoderException( I18n.err( I18n.ERR_00032_NULL_OID ) );
126 }
127
128 if ( oid.length < 1 )
129 {
130 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, Asn1StringUtils.dumpBytes( oid ) ) );
131 }
132
133
134 int nbValues = 1;
135 int pos = 0;
136
137 while ( pos < oid.length )
138 {
139
140 if ( oid[pos] >= 0 )
141 {
142 nbValues++;
143 }
144
145 pos++;
146 }
147
148 oidValues = new long[nbValues];
149
150 nbValues = 0;
151 pos = 0;
152
153 int accumulator = 0;
154
155 if ( ( oid[0] < 0 ) || ( oid[0] >= 80 ) )
156 {
157 oidValues[nbValues++] = 2;
158
159 while ( pos < oid.length )
160 {
161
162 if ( oid[pos] >= 0 )
163 {
164 oidValues[nbValues++] = ( ( accumulator << 7 ) + oid[pos] ) - 80;
165 accumulator = 0;
166 pos++;
167 break;
168 }
169 else
170 {
171 accumulator = ( accumulator << 7 ) + ( oid[pos] & 0x007F );
172 }
173
174 pos++;
175 }
176 }
177 else if ( oid[0] < 40 )
178 {
179 oidValues[nbValues++] = 0;
180 oidValues[nbValues++] = oid[pos++];
181 }
182 else
183
184 {
185 oidValues[nbValues++] = 1;
186 oidValues[nbValues++] = oid[pos++] - 40;
187 }
188
189 while ( pos < oid.length )
190 {
191 if ( oid[pos] >= 0 )
192 {
193 oidValues[nbValues++] = ( accumulator << 7 ) + oid[pos];
194 accumulator = 0;
195 }
196 else
197 {
198 accumulator = ( accumulator << 7 ) + ( oid[pos] & 0x007F );
199 }
200
201 pos++;
202 }
203
204 hash = computeHashCode();
205 }
206
207
208
209
210
211
212
213
214
215
216
217
218 public void setOid( String oid ) throws DecoderException
219 {
220 if ( ( oid == null ) || ( oid.length() == 0 ) )
221 {
222 throw new DecoderException( I18n.err( I18n.ERR_00032_NULL_OID ) );
223 }
224
225 int nbValues = 1;
226 char[] chars = oid.toCharArray();
227 boolean dotSeen = false;
228
229
230 for ( char c : chars )
231 {
232 if ( c == '.' )
233 {
234 if ( dotSeen )
235 {
236
237 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, oid ) );
238 }
239
240 nbValues++;
241 dotSeen = true;
242 }
243 else
244 {
245 dotSeen = false;
246 }
247 }
248
249
250 if ( nbValues < 2 )
251 {
252 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, oid ) );
253 }
254
255 oidValues = new long[nbValues];
256
257 int pos = 0;
258 int intPos = 0;
259
260
261
262 boolean ituOrIso = false;
263
264
265 switch ( chars[pos] )
266 {
267 case '0':
268 case '1':
269 case '2':
270 ituOrIso = true;
271 oidValues[intPos++] = chars[pos++] - '0';
272 break;
273
274 default:
275 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, oid ) );
276 }
277
278
279 if ( chars[pos++] != '.' )
280 {
281 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, oid ) );
282 }
283
284 dotSeen = true;
285
286 int value = 0;
287
288 for ( int i = pos; i < chars.length; i++ )
289 {
290 if ( chars[i] == '.' )
291 {
292 if ( dotSeen )
293 {
294
295 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, oid ) );
296 }
297
298 if ( ituOrIso && ( value > 39 ) )
299 {
300 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, oid ) );
301 }
302 else
303 {
304 ituOrIso = false;
305 }
306
307 nbValues++;
308 dotSeen = true;
309 oidValues[intPos++] = value;
310 value = 0;
311 }
312 else if ( ( chars[i] >= 0x30 ) && ( chars[i] <= 0x39 ) )
313 {
314 dotSeen = false;
315 value = ( ( value * 10 ) + chars[i] ) - '0';
316 }
317 else
318 {
319
320 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, oid ) );
321 }
322 }
323
324 oidValues[intPos] = value;
325 hash = computeHashCode();
326 }
327
328
329
330
331
332
333
334 public long[] getOidValues()
335 {
336 long[] copy = new long[oidValues.length];
337
338 System.arraycopy( oidValues, 0, copy, 0, oidValues.length );
339
340 return copy;
341 }
342
343
344
345
346
347
348
349 public int getOidLength()
350 {
351 long value = oidValues[0] * 40 + oidValues[1];
352 int nbBytes = 0;
353
354 if ( value < 128 )
355 {
356 nbBytes = 1;
357 }
358 else if ( value < 16384 )
359 {
360 nbBytes = 2;
361 }
362 else if ( value < 2097152 )
363 {
364 nbBytes = 3;
365 }
366 else if ( value < 268435456 )
367 {
368 nbBytes = 4;
369 }
370 else
371 {
372 nbBytes = 5;
373 }
374
375 for ( int i = 2; i < oidValues.length; i++ )
376 {
377 value = oidValues[i];
378
379 if ( value < 128 )
380 {
381 nbBytes += 1;
382 }
383 else if ( value < 16384 )
384 {
385 nbBytes += 2;
386 }
387 else if ( value < 2097152 )
388 {
389 nbBytes += 3;
390 }
391 else if ( value < 268435456 )
392 {
393 nbBytes += 4;
394 }
395 else
396 {
397 nbBytes += 5;
398 }
399 }
400
401 return nbBytes;
402 }
403
404
405
406
407
408
409
410 public byte[] getOid()
411 {
412 long value = oidValues[0] * 40 + oidValues[1];
413 long firstValues = value;
414
415 byte[] bytes = new byte[getOidLength()];
416 int pos = 0;
417
418 if ( oidValues[0] < 2 )
419 {
420 bytes[pos++] = ( byte ) ( oidValues[0] * 40 + oidValues[1] );
421 }
422 else
423 {
424 if ( firstValues < 128 )
425 {
426 bytes[pos++] = ( byte ) ( firstValues );
427 }
428 else if ( firstValues < 16384 )
429 {
430 bytes[pos++] = ( byte ) ( ( firstValues >> 7 ) | 0x0080 );
431 bytes[pos++] = ( byte ) ( firstValues & 0x007F );
432 }
433 else if ( value < 2097152 )
434 {
435 bytes[pos++] = ( byte ) ( ( firstValues >> 14 ) | 0x0080 );
436 bytes[pos++] = ( byte ) ( ( ( firstValues >> 7 ) & 0x007F ) | 0x0080 );
437 bytes[pos++] = ( byte ) ( firstValues & 0x007F );
438 }
439 else if ( value < 268435456 )
440 {
441 bytes[pos++] = ( byte ) ( ( firstValues >> 21 ) | 0x0080 );
442 bytes[pos++] = ( byte ) ( ( ( firstValues >> 14 ) & 0x007F ) | 0x0080 );
443 bytes[pos++] = ( byte ) ( ( ( firstValues >> 7 ) & 0x007F ) | 0x0080 );
444 bytes[pos++] = ( byte ) ( firstValues & 0x007F );
445 }
446 else
447 {
448 bytes[pos++] = ( byte ) ( ( firstValues >> 28 ) | 0x0080 );
449 bytes[pos++] = ( byte ) ( ( ( firstValues >> 21 ) & 0x007F ) | 0x0080 );
450 bytes[pos++] = ( byte ) ( ( ( firstValues >> 14 ) & 0x007F ) | 0x0080 );
451 bytes[pos++] = ( byte ) ( ( ( firstValues >> 7 ) & 0x007F ) | 0x0080 );
452 bytes[pos++] = ( byte ) ( firstValues & 0x007F );
453 }
454 }
455
456 for ( int i = 2; i < oidValues.length; i++ )
457 {
458 value = oidValues[i];
459
460 if ( value < 128 )
461 {
462 bytes[pos++] = ( byte ) ( value );
463 }
464 else if ( value < 16384 )
465 {
466 bytes[pos++] = ( byte ) ( ( value >> 7 ) | 0x0080 );
467 bytes[pos++] = ( byte ) ( value & 0x007F );
468 }
469 else if ( value < 2097152 )
470 {
471 bytes[pos++] = ( byte ) ( ( value >> 14 ) | 0x0080 );
472 bytes[pos++] = ( byte ) ( ( ( value >> 7 ) & 0x007F ) | 0x0080 );
473 bytes[pos++] = ( byte ) ( value & 0x007F );
474 }
475 else if ( value < 268435456 )
476 {
477 bytes[pos++] = ( byte ) ( ( value >> 21 ) | 0x0080 );
478 bytes[pos++] = ( byte ) ( ( ( value >> 14 ) & 0x007F ) | 0x0080 );
479 bytes[pos++] = ( byte ) ( ( ( value >> 7 ) & 0x007F ) | 0x0080 );
480 bytes[pos++] = ( byte ) ( value & 0x007F );
481 }
482 else
483 {
484 bytes[pos++] = ( byte ) ( ( value >> 28 ) | 0x0080 );
485 bytes[pos++] = ( byte ) ( ( ( value >> 21 ) & 0x007F ) | 0x0080 );
486 bytes[pos++] = ( byte ) ( ( ( value >> 14 ) & 0x007F ) | 0x0080 );
487 bytes[pos++] = ( byte ) ( ( ( value >> 7 ) & 0x007F ) | 0x0080 );
488 bytes[pos++] = ( byte ) ( value & 0x007F );
489 }
490 }
491
492 return bytes;
493 }
494
495
496
497
498
499
500
501
502
503 private int computeHashCode()
504 {
505 int h = 37;
506
507 for ( long val : oidValues )
508 {
509 int low = ( int ) ( val & 0x0000FFFFL );
510 int high = ( int ) ( val >> 32 );
511 h = h * 17 + high;
512 h = h * 17 + low;
513 }
514
515 return h;
516 }
517
518
519
520
521
522
523
524 public static boolean isOid( String oid )
525 {
526 if ( ( oid == null ) || ( oid.length() == 0 ) )
527 {
528 return false;
529 }
530
531 int nbValues = 1;
532 byte[] bytes = oid.getBytes();
533 boolean dotSeen = false;
534
535
536 for ( byte b : bytes )
537 {
538 if ( b == '.' )
539 {
540 if ( dotSeen )
541 {
542
543 return false;
544 }
545
546 nbValues++;
547 dotSeen = true;
548 }
549 else
550 {
551 dotSeen = false;
552 }
553 }
554
555
556 if ( nbValues < 2 )
557 {
558 return false;
559 }
560
561 int pos = 0;
562
563
564
565 boolean ituOrIso = false;
566
567
568 switch ( bytes[pos++] )
569 {
570 case '0':
571 case '1':
572 case '2':
573 ituOrIso = true;
574 break;
575
576 default:
577 return false;
578 }
579
580
581 if ( bytes[pos++] != '.' )
582 {
583 return false;
584 }
585
586 dotSeen = true;
587
588 long value = 0;
589
590 for ( int i = pos; i < bytes.length; i++ )
591 {
592 if ( bytes[i] == '.' )
593 {
594 if ( dotSeen )
595 {
596
597 return false;
598 }
599
600 if ( ituOrIso && ( value > 39 ) )
601 {
602 return false;
603 }
604 else
605 {
606 ituOrIso = false;
607 }
608
609 nbValues++;
610 dotSeen = true;
611 value = 0;
612 }
613 else if ( ( bytes[i] >= 0x30 ) && ( bytes[i] <= 0x39 ) )
614 {
615 dotSeen = false;
616
617 value = ( ( value * 10 ) + bytes[i] ) - '0';
618 }
619 else
620 {
621
622 return false;
623 }
624 }
625
626 return !dotSeen;
627 }
628
629
630
631
632
633
634
635 @Override
636 public String toString()
637 {
638 StringBuffer sb = new StringBuffer();
639
640 if ( oidValues != null )
641 {
642 sb.append( oidValues[0] );
643
644 for ( int i = 1; i < oidValues.length; i++ )
645 {
646 sb.append( '.' ).append( oidValues[i] );
647 }
648 }
649
650 return sb.toString();
651 }
652
653
654
655
656
657 @Override
658 public int hashCode()
659 {
660 return hash;
661 }
662
663
664
665
666
667 @Override
668 public boolean equals( Object oid )
669 {
670 if ( this == oid )
671 {
672 return true;
673 }
674
675 if ( oid == null )
676 {
677 return false;
678 }
679
680 if ( oid.getClass() != this.getClass() )
681 {
682 return false;
683 }
684
685 Oid instance = ( Oid ) oid;
686
687 if ( instance.hash != hash )
688 {
689 return false;
690 }
691 else
692 {
693 return Arrays.equals( instance.oidValues, oidValues );
694 }
695 }
696 }