View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    * 
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   * 
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   * 
19   */
20  package org.apache.directory.api.asn1.util;
21  
22  
23  import java.io.IOException;
24  import java.io.OutputStream;
25  import java.math.BigInteger;
26  import java.util.Arrays;
27  
28  import org.apache.directory.api.asn1.DecoderException;
29  import org.apache.directory.api.i18n.I18n;
30  
31  
32  /**
33   * An immutable representation of an object identifier that provides conversion 
34   * between their <code>String</code>, and encoded <code>byte[]</code> 
35   * representations.
36   * 
37   * <p> The encoding of OID values is performed according to 
38   * <a href='http://www.itu.int/rec/T-REC-X.690/en'>itu X.690</a> section 8.19.
39   * Specifically:</p>
40   * 
41   * <p><b>8.19.2</b> The contents octets shall be an (ordered) list of encodings
42   * of subidentifiers (see 8.19.3 and 8.19.4) concatenated together. Each 
43   * subidentifier is represented as a series of (one or more) octets. Bit 8 of 
44   * each octet indicates whether it is the last in the series: bit 8 of the last 
45   * octet is zero; bit 8 of each preceding octet is one. Bits 7 to 1 of the 
46   * octets in the series collectively encode the subidentifier. Conceptually, 
47   * these groups of bits are concatenated to form an unsigned binary number whose 
48   * most significant bit is bit 7 of the first octet and whose least significant 
49   * bit is bit 1 of the last octet. The subidentifier shall be encoded in the 
50   * fewest possible octets, that is, the leading octet of the subidentifier shall 
51   * not have the value 0x80. </p>
52   * 
53   * <p><b>8.19.3</b> The number of subidentifiers (N) shall be one less than the 
54   * number of object identifier components in the object identifier value being 
55   * encoded.</p>
56   * 
57   * <p><b>8.19.4</b> The numerical value of the first subidentifier is derived 
58   * from the values of the first two object identifier components in the object 
59   * identifier value being encoded, using the formula:
60   * <br><code>(X*40) + Y</code><br> 
61   * where X is the value of the first object identifier component and Y is the 
62   * value of the second object identifier component. <i>NOTE – This packing of 
63   * the first two object identifier components recognizes that only three values 
64   * are allocated from the root node, and at most 39 subsequent values from nodes 
65   * reached by X = 0 and X = 1.</i></p>
66   * 
67   * <p>For example, the OID "2.12.3456.7" would be turned into a list of 3 values:
68   * <code>[((2*40)+12), 3456, 7]</code>. The first of which, 
69   * <code>92</code>, would be encoded as the bytes <code>0x5C</code>, the second 
70   * would be <code>[0x9B, 0x00]</code>, and the third as <code>0x07</code>
71   * giving the final encoding <code>[0x5C, 0x9B, 0x00, 0x07]</code>.</p>
72   * 
73   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
74   */
75  public final class Oid
76  {
77      /** A byte[] representation of an OID */
78      private byte[] oidBytes;
79      
80      /** The OID as a String */
81      private String oidString;
82      
83      private static final BigInteger JOINT_ISO_ITU_T = new BigInteger( "80" );
84      
85      /**
86       * The OID FSA states. We have the following Finite State Automaton :
87       * 
88       * <pre>
89       * (Start) --['0','1']--> (A)
90       * (start) --['2']--> (F)
91       * 
92       * (A) --['.']--> (B)
93       * 
94       * (B) --['0']--> (D)
95       * (B) --['1'..'3']--> (C)
96       * (B) --['4'..'9']--> (E)
97       * 
98       * (C) --[]--> (End)
99       * (C) --['.']--> (K)
100      * (C) --['0'..'9']--> (E)
101      * 
102      * (D) --[]--> (End)
103      * (D) --['.']--> (K)
104      * 
105      * (E) --[]--> (End)
106      * (E) --['.']--> (K)
107      * 
108      * (F) --['.']--> (G)
109      * 
110      * (G) --['0']--> (I)
111      * (G) --['1'..'9']--> (H)
112      *
113      * (H) --[]--> (End)
114      * (H) --['.']--> (K)
115      * (H) --['0'..'9']--> (J)
116      * 
117      * (I) --[]--> (End)
118      * (I) --['.']--> (K)
119      *
120      * (J) --[]--> (End)
121      * (J) --['.']--> (K)
122      * (J) --['0'..'9']--> (J)
123      * 
124      * (K) --['0']--> (M) 
125      * (K) --['1'..'9']--> (L)
126      * 
127      * (L) --[]--> (End)
128      * (L) --['.']--> (K)
129      * (L) --['0'..'9']--> (L)
130      * 
131      * (M) --[]--> (End)
132      * (M) --['.']--> (K)
133      * </pre>
134      */
135     private enum OidFSAState 
136     {
137         START,
138         STATE_A,
139         STATE_B,
140         STATE_C,
141         STATE_D,
142         STATE_E,
143         STATE_F,
144         STATE_G,
145         STATE_H,
146         STATE_I,
147         STATE_J,
148         STATE_K,
149         STATE_L,
150         STATE_M,
151     }
152 
153 
154     /**
155      * Creates a new instance of Oid.
156      *
157      * @param oidString The OID as a String
158      * @param oidBytes The OID as a byte[]
159      */
160     private Oid( String oidString, byte[] oidBytes )
161     {
162         this.oidString = oidString;
163         this.oidBytes = new byte[oidBytes.length];
164         System.arraycopy( oidBytes, 0, this.oidBytes, 0, oidBytes.length );
165     }
166 
167 
168     /**
169      * {@inheritDoc}
170      */
171     @Override
172     public boolean equals( Object other )
173     {
174         return ( other instanceof Oid )
175             && oidString.equals( ( ( Oid ) other ).oidString );
176     }
177 
178 
179     /**
180      * Decodes an OID from a <code>byte[]</code>.
181      * 
182      * @param oidBytes The encoded<code>byte[]</code>
183      * @return A new Oid
184      * @throws DecoderException When the OID is not valid
185      */
186     public static Oid fromBytes( byte[] oidBytes ) throws DecoderException
187     {
188         if ( ( oidBytes == null ) || ( oidBytes.length < 1 ) )
189         {
190             throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, Arrays.toString( oidBytes ) ) );
191         }
192 
193         StringBuilder builder = new StringBuilder();
194         long value = 0;
195         int valStart = 0;
196         int valLength = 0;
197         boolean firstArc = true;
198         
199         for ( int i = 0; i < oidBytes.length; i++ )
200         {
201             value |= oidBytes[i] & 0x7F;
202 
203             if ( oidBytes[i] < 0 )
204             {
205                 // leading 1, so value continues
206                 value = value << 7;
207                 valLength++;
208             }
209             else
210             {
211                 valLength++;
212                 
213                 if ( valLength > 8 )
214                 {
215                     // Above 9 bytes, we won't be able to store the value in a long...
216                     // Compute the number of necessary bytes
217                     int nbBytes = valLength * 7 / 8;
218                     
219                     if ( valLength % 7 != 0 )
220                     {
221                         nbBytes++;
222                     }
223                     
224                     byte[] result = new byte[nbBytes];
225                     
226                     // Now iterate on the incoming bytes
227                     int pos = nbBytes - 1;
228                     int valEnd = valStart + valLength - 1;
229                     int j = 0;
230                     
231                     while ( j < valLength - 8 )
232                     {
233                         result[pos--] = ( byte ) ( ( oidBytes[valEnd - j - 1] << 7 ) | ( oidBytes[valEnd - j] & 0x7F ) );
234                         result[pos--] = ( byte ) ( ( oidBytes[valEnd - j - 2] << 6 ) | ( ( oidBytes[valEnd - j - 1] & 0x7E ) >> 1 ) );
235                         result[pos--] = ( byte ) ( ( oidBytes[valEnd - j - 3] << 5 ) | ( ( oidBytes[valEnd - j - 2] & 0x7C ) >> 2 ) );
236                         result[pos--] = ( byte ) ( ( oidBytes[valEnd - j - 4] << 4 ) | ( ( oidBytes[valEnd - j - 3] & 0x78 ) >> 3 ) );
237                         result[pos--] = ( byte ) ( ( oidBytes[valEnd - j - 5] << 3 ) | ( ( oidBytes[valEnd - j - 4] & 0x70 ) >> 4 ) );
238                         result[pos--] = ( byte ) ( ( oidBytes[valEnd - j - 6] << 2 ) | ( ( oidBytes[valEnd - j - 5] & 0x60 ) >> 5 ) );
239                         result[pos--] = ( byte ) ( ( oidBytes[valEnd - j - 7] << 1 ) | ( ( oidBytes[valEnd - j - 6] & 0x40 ) >> 6 ) );
240                         j += 8;
241                     }
242                     
243                     switch ( valLength - j )
244                     {
245                         case 7 :
246                             result[pos--] = ( byte ) ( ( oidBytes[5] << 7 ) | ( oidBytes[6] & 0x7F ) );
247                             result[pos--] = ( byte ) ( ( oidBytes[4] << 6 ) | ( ( oidBytes[5] & 0x7E ) >> 1 ) );
248                             result[pos--] = ( byte ) ( ( oidBytes[3] << 5 ) | ( ( oidBytes[4] & 0x7C ) >> 2 ) );
249                             result[pos--] = ( byte ) ( ( oidBytes[2] << 4 ) | ( ( oidBytes[3] & 0x78 ) >> 3 ) );
250                             result[pos--] = ( byte ) ( ( oidBytes[1] << 3 ) | ( ( oidBytes[2] & 0x70 ) >> 4 ) );
251                             result[pos--] = ( byte ) ( ( oidBytes[0] << 2 ) | ( ( oidBytes[1] & 0x60 ) >> 5 ) );
252                             result[pos] = ( byte ) ( ( oidBytes[0] & 0x40 ) >> 6 );
253                             break;
254                             
255                         case 6 :
256                             result[pos--] = ( byte ) ( ( oidBytes[4] << 7 ) | ( oidBytes[5] & 0x7F ) );
257                             result[pos--] = ( byte ) ( ( oidBytes[3] << 6 ) | ( ( oidBytes[4] & 0x7E ) >> 1 ) );
258                             result[pos--] = ( byte ) ( ( oidBytes[2] << 5 ) | ( ( oidBytes[3] & 0x7C ) >> 2 ) );
259                             result[pos--] = ( byte ) ( ( oidBytes[1] << 4 ) | ( ( oidBytes[2] & 0x78 ) >> 3 ) );
260                             result[pos--] = ( byte ) ( ( oidBytes[0] << 3 ) | ( ( oidBytes[1] & 0x70 ) >> 4 ) );
261                             result[pos] = ( byte ) ( ( oidBytes[0] & 0x60 ) >> 5 );
262                             break;
263 
264                         case 5 :
265                             result[pos--] = ( byte ) ( ( oidBytes[3] << 7 ) | ( oidBytes[4] & 0x7F ) );
266                             result[pos--] = ( byte ) ( ( oidBytes[2] << 6 ) | ( ( oidBytes[3] & 0x7E ) >> 1 ) );
267                             result[pos--] = ( byte ) ( ( oidBytes[1] << 5 ) | ( ( oidBytes[2] & 0x7C ) >> 2 ) );
268                             result[pos--] = ( byte ) ( ( oidBytes[0] << 4 ) | ( ( oidBytes[1] & 0x78 ) >> 3 ) );
269                             result[pos] = ( byte ) ( ( oidBytes[0] & 0x70 ) >> 4 );
270                             break;
271                             
272                         case 4 :
273                             result[pos--] = ( byte ) ( ( oidBytes[2] << 7 ) | ( oidBytes[3] & 0x7F ) );
274                             result[pos--] = ( byte ) ( ( oidBytes[1] << 6 ) | ( ( oidBytes[2] & 0x7E ) >> 1 ) );
275                             result[pos--] = ( byte ) ( ( oidBytes[0] << 5 ) | ( ( oidBytes[1] & 0x7C ) >> 2 ) );
276                             result[pos] = ( byte ) ( ( oidBytes[0] & 0x78 ) >> 3 );
277                             break;
278                             
279                         case 3 :
280                             result[pos--] = ( byte ) ( ( oidBytes[1] << 7 ) | ( oidBytes[2] & 0x7F ) );
281                             result[pos--] = ( byte ) ( ( oidBytes[0] << 6 ) | ( ( oidBytes[1] & 0x7E ) >> 1 ) );
282                             result[pos] = ( byte ) ( ( oidBytes[0] & 0x7C ) >> 2 );
283                             break;
284 
285                         case 2 :
286                             result[pos--] = ( byte ) ( ( oidBytes[0] << 7 ) | ( oidBytes[1] & 0x7F ) );
287                             result[pos] = ( byte ) ( ( oidBytes[0] & 0x7E ) >> 1 );
288                             break;
289                             
290                         case 1 :
291                             result[pos] = ( byte ) ( oidBytes[0] & 0x7F );
292                             break;
293                             
294                         default :
295                             // Exist to please checkstyle...
296                             break;
297                     }
298                     
299                     BigInteger bigInteger;
300                     
301                     if ( ( result[0] & 0x80 ) == 0x80 )
302                     {
303                         byte[] newResult = new byte[result.length + 1];
304                         System.arraycopy( result, 0, newResult, 1, result.length );
305                         result = newResult;
306                     }
307                     
308                     bigInteger = new BigInteger( result );
309                     
310                     if ( firstArc )
311                     {
312                         // This is a joint-iso-itu-t(2) arc
313                         bigInteger = bigInteger.subtract( JOINT_ISO_ITU_T );
314                         builder.append( '2' );
315                     }
316                     
317                     builder.append( '.' ).append( bigInteger.toString() );
318                 }
319                 else
320                 {
321                     // value completed
322                     if ( firstArc )
323                     {
324                         // first value special processing
325                         if ( value >= 80 )
326                         {
327                             // starts with 2
328                             builder.append( '2' );
329                             value = value - 80;
330                         }
331                         else
332                         {
333                             // starts with 0 or 1
334                             long one = value / 40;
335                             long two = value % 40;
336     
337                             if ( ( one < 0 ) || ( one > 2 ) || ( two < 0 ) || ( ( one < 2 ) && ( two > 39 ) ) )
338                             {
339                                 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID,
340                                     Arrays.toString( oidBytes ) ) );
341                             }
342     
343                             if ( one < 2 )
344                             {
345                                 builder.append( one );
346                                 value = two;
347                             }
348                         }
349                         
350                         firstArc = false;
351                     }
352     
353                     // normal processing
354                     builder.append( '.' ).append( value );
355                 }
356                 
357                 valStart = i;
358                 valLength = 0;
359                 value = 0;
360             }
361         }
362     
363         return new Oid( builder.toString(), oidBytes );
364     }
365 
366 
367     /**
368      * Process state A
369      * <pre>
370      * (Start) --['0','1']--> (A)
371      * (start) --['2']--> (F)
372      * </pre>
373      */
374     private static OidFSAState processStateStart( String oid, byte[] buffer, int pos ) throws DecoderException
375     {
376         char c = oid.charAt( pos );
377         
378         switch ( c )
379         {
380             case '0' :
381             case '1' :
382                 buffer[0] = ( byte ) ( ( c - '0' ) * 40 );
383                 return OidFSAState.STATE_A;
384                 
385             case '2' :
386                 return OidFSAState.STATE_F;
387                 
388             default :
389                 // This is an error
390                 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "Should start with 0, 1 or 2" ) );
391         }
392     }
393     
394     
395     /**
396      * Process state B
397      * <pre>
398      * (A) --['.']--> (B)
399      * </pre>
400      */
401     private static OidFSAState processStateA( String oid, int pos ) throws DecoderException
402     {
403         if ( oid.charAt( pos ) != '.' )
404         {
405             // Expecting a Dot here
406             throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "a '.' is expected" ) );
407         }
408         
409         return OidFSAState.STATE_B;
410     }
411     
412     
413     /**
414      * Process state B
415      * <pre>
416      * (B) --['0']--> (D)
417      * (B) --['1'..'3']--> (C)
418      * (B) --['4'..'9']--> (E)
419      * </pre>
420      */
421     private static OidFSAState processStateB( String oid, byte[] buffer, int pos ) throws DecoderException
422     {
423         char c = oid.charAt( pos );
424         
425         switch ( c )
426         {
427             case '0' :
428                 return OidFSAState.STATE_D;
429                 
430             case '1' :
431             case '2' :
432             case '3' :
433                 // We may have a second digit. Atm, store the current one in the second psotion
434                 buffer[1] = ( byte ) ( c - '0' );
435                 
436                 return  OidFSAState.STATE_C;
437                 
438             case '4' :
439             case '5' :
440             case '6' :
441             case '7' :
442             case '8' :
443             case '9' :
444                 buffer[0] += ( byte ) ( c - '0' );
445                 return OidFSAState.STATE_E;
446                 
447             default :
448                 // Expecting a digit here
449                 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "a digit is expected" ) );
450         }
451     }
452     
453     
454     /**
455      * Process state C
456      * <pre>
457      * (C) --['.']--> (K)
458      * (C) --['0'..'9']--> (E)
459      * </pre>
460      */
461     private static OidFSAState processStateC( String oid, byte[] buffer, int pos ) throws DecoderException
462     {
463         char c = oid.charAt( pos );
464         
465         switch ( c )
466         {
467             case '0' :
468             case '1' :
469             case '2' :
470             case '3' :
471             case '4' :
472             case '5' :
473             case '6' :
474             case '7' :
475             case '8' :
476             case '9' :
477                 buffer[0] += ( byte ) ( buffer[1] * 10 + ( c - '0' ) );
478                 buffer[1] = 0;
479                 return OidFSAState.STATE_E;
480 
481             case '.' :
482                 buffer[0] += buffer[1];
483                 buffer[1] = 0;
484                 return OidFSAState.STATE_K;
485                 
486             default :
487                 // Expecting a digit here
488                 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "a digit is expected" ) );
489         }
490     }
491     
492     
493     /**
494      * Process state D and E
495      * <pre>
496      * (D) --['.']--> (K)
497      * (E) --['.']--> (K)
498      * </pre>
499      */
500     private static OidFSAState processStateDE( String oid, byte[] buffer, int pos ) throws DecoderException
501     {
502         char c = oid.charAt( pos );
503         
504         if ( c != '.' )
505         {
506             // Expecting a '.' here
507             throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "a dot is expected" ) );
508         }
509         
510         // Store the first byte into it
511         buffer[0] = ( byte ) ( buffer[0] | buffer[1] );
512         buffer[1] = 0;
513         
514         return OidFSAState.STATE_K;
515     }
516     
517     
518     /**
519      * Process state F
520      * <pre>
521      * (F) --['.']--> (G)
522      * </pre>
523      */
524     private static OidFSAState processStateF( String oid, int pos ) throws DecoderException
525     {
526         if ( oid.charAt( pos ) != '.' )
527         {
528             // Expecting a Dot here
529             throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "a '.' is expected" ) );
530         }
531         
532         return OidFSAState.STATE_G;
533     }
534     
535     
536     /**
537      * Process state G
538      * <pre>
539      * (G) --['0']--> (I)
540      * (G) --['1'..'9']--> (H)
541      * </pre>
542      */
543     private static OidFSAState processStateG( String oid, byte[] buffer, int pos ) throws DecoderException
544     {
545         char c = oid.charAt( pos );
546         
547         switch ( c )
548         {
549             case '0' :
550                 buffer[0] = ( byte ) 80;
551                 return OidFSAState.STATE_I;
552                 
553             case '1' :
554             case '2' :
555             case '3' :
556             case '4' :
557             case '5' :
558             case '6' :
559             case '7' :
560             case '8' :
561             case '9' :
562                 // Store the read digit in the second position in the buffer
563                 buffer[0] = ( byte ) ( c - '0' );
564                 return OidFSAState.STATE_H;
565 
566             default :
567                 // Expecting a digit here
568                 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "a digit is expected" ) );
569         }
570     }
571     
572     
573     /**
574      * Process state H
575      * <pre>
576      * (H) --['.']--> (K)
577      * (H) --['0'..'9']--> (J)
578      * </pre>
579      */
580     private static OidFSAState processStateH( String oid, byte[] buffer, int pos ) throws DecoderException
581     {
582         char c = oid.charAt( pos );
583         
584         switch ( c )
585         {
586             case '0' :
587             case '1' :
588             case '2' :
589             case '3' :
590             case '4' :
591             case '5' :
592             case '6' :
593             case '7' :
594             case '8' :
595             case '9' :
596                 // Store the read digit in the first position in the buffer
597                 buffer[1] = ( byte ) ( c - '0' );
598                 return OidFSAState.STATE_J;
599 
600             case '.' :
601                 // The first 2 arcs are single digit, we can collapse them in one byte.
602                 buffer[0] = ( byte ) ( 80 + buffer[0] );
603                 
604                 return OidFSAState.STATE_K;
605                 
606             default :
607                 // Expecting a digit here
608                 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "a digit is expected" ) );
609         }
610     }
611     
612     
613     /**
614      * Process state I
615      * <pre>
616      * (I) --['.']--> (K)
617      * </pre>
618      */
619     private static OidFSAState processStateI( String oid, byte[] buffer, int pos ) throws DecoderException
620     {
621         char c = oid.charAt( pos );
622         
623         if ( c == '.' )
624         {
625             // The first 2 arcs are single digit, we can collapse them in one byte.
626             buffer[0] = ( byte ) ( 80 + buffer[1] );
627             
628             return OidFSAState.STATE_K;
629         }
630         else
631         {
632             // Expecting a digit here
633             throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "a digit is expected" ) );
634         }
635     }
636     
637     
638     /**
639      * Process state J
640      * <pre>
641      * (J) --['.']--> (K)
642      * (J) --['0'..'9']--> (J)
643      * </pre>
644      */
645     private static OidFSAState processStateJ( String oid, byte[] buffer, int bufferPos, int pos ) throws DecoderException
646     {
647         char c = oid.charAt( pos );
648         
649         switch ( c )
650         {
651             case '.' :
652                 return OidFSAState.STATE_K;
653                 
654             case '0' :
655             case '1' :
656             case '2' :
657             case '3' :
658             case '4' :
659             case '5' :
660             case '6' :
661             case '7' :
662             case '8' :
663             case '9' :
664                 // Store the new digit at the right position in the buffer
665                 buffer[bufferPos] = ( byte ) ( c - '0' );
666                 return OidFSAState.STATE_J;
667                 
668             default :
669                 // Expecting a digit here
670                 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "a digit is expected" ) );
671         }
672     }
673     
674     
675     /**
676      * Process state J
677      * <pre>
678      * (K) --['0']--> (M)
679      * (K) --['1'..'9']--> (L)
680      * </pre>
681      */
682     private static OidFSAState processStateK( String oid, byte[] buffer, int bufferPos, int pos ) throws DecoderException
683     {
684         char c = oid.charAt( pos );
685         
686         switch ( c )
687         {
688             case '0' :
689                 buffer[bufferPos] = 0x00;
690                 return OidFSAState.STATE_M;
691                 
692             case '1' :
693             case '2' :
694             case '3' :
695             case '4' :
696             case '5' :
697             case '6' :
698             case '7' :
699             case '8' :
700             case '9' :
701                 // Store the new digit at the right position in the buffer
702                 return OidFSAState.STATE_L;
703                 
704             default :
705                 // Expecting a digit here
706                 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "a digit is expected" ) );
707         }
708     }
709     
710     
711     /**
712      * Process state J
713      * <pre>
714      * (L) --['.']--> (K)
715      * (L) --['0'..'9']--> (L)
716      * </pre>
717      */
718     private static OidFSAState processStateL( String oid, byte[] buffer, int bufferPos, int pos ) throws DecoderException
719     {
720         char c = oid.charAt( pos );
721         
722         switch ( c )
723         {
724             case '.' :
725                 return OidFSAState.STATE_K;
726                 
727             case '0' :
728             case '1' :
729             case '2' :
730             case '3' :
731             case '4' :
732             case '5' :
733             case '6' :
734             case '7' :
735             case '8' :
736             case '9' :
737                 // Store the new digit at the right position in the buffer
738                 buffer[bufferPos] = ( byte ) ( c - '0' );
739                 
740                 return OidFSAState.STATE_L;
741                 
742             default :
743                 // Expecting a digit here
744                 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "a digit or a dot is expected" ) );
745         }
746     }
747 
748     
749     /**
750      * Process state J
751      * <pre>
752      * (M) --['.']--> (K)
753      * </pre>
754      */
755     private static OidFSAState processStateM( String oid, int pos ) throws DecoderException
756     {
757         char c = oid.charAt( pos );
758         
759         if ( c == '.' )
760         {
761                 return OidFSAState.STATE_K;
762         }
763         else
764         {
765             // Expecting a '.' here
766             throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "a '.' is expected" ) );
767         }
768     }
769 
770     
771     /**
772      * Convert a list of digits to a list of 7 bits bytes. We must start by the end, and we don't
773      * know how many bytes we will need, except when we will be done with the conversion.
774      */
775     private static int convert( String oid, byte[] buffer, int start, int nbDigits, int posBuffer, boolean isJointIsoItuT )
776     {
777         if ( nbDigits < 3 )
778         {
779             // Speedup when we have a number in [0..99] : it's guaranteed to be hold
780             // by a single byte.
781             if ( isJointIsoItuT )
782             {
783                 // Another special case : this is an OID that starts with '2.'
784                 buffer[0] =  ( byte ) ( 80 + ( oid.charAt( 2 ) - '0' ) * 10 + ( oid.charAt( 3 ) - '0' ) );
785                 
786                 if ( buffer[0] < 0 )
787                 {
788                     // Here, we need 2 bytes
789                     buffer[1] = ( byte ) ( buffer[0] & 0x007F );
790                     buffer[0] = ( byte ) 0x81;
791                     
792                     return 2;
793                 }
794                 else
795                 {
796                     return 1;
797                 }
798             }
799             else
800             {
801                 if ( nbDigits == 1 )
802                 {
803                     buffer[posBuffer] = ( byte ) ( oid.charAt( start ) - '0' );
804                 }
805                 else
806                 {
807                     buffer[posBuffer] = ( byte ) ( ( oid.charAt( start ) - '0' ) * 10 + ( oid.charAt( start + 1 ) - '0' ) );
808                     
809                 }
810                 return 1;
811             }
812 
813         }
814         else if ( nbDigits < 19 )
815         {
816             // The value can be hold in a Long if it's up to 999999999999999999 
817             // Convert the String to a long :
818             String number = oid.substring( start, start + nbDigits );
819 
820             long value = Long.parseLong( number );
821 
822             if ( isJointIsoItuT )
823             {
824                 value += 80L;
825             }
826             
827             // Convert the long to a byte array
828             if ( ( value & 0xFFFFFFFFFFFFFF80L ) == 0 )
829             {
830                 // The value will be hold in one byte
831                 buffer[posBuffer] = ( byte ) ( value );
832                 
833                 return 1;
834             }
835             
836             if ( ( value & 0xFFFFFFFFFFFFC000L ) == 0 )
837             {
838                 // The value is between 0x80 and 0x3FFF : it will be hold in 2 bytes
839                 buffer[posBuffer] = ( byte ) ( ( byte ) ( ( value & 0x0000000000003F80L ) >> 7 ) | 0x80 );
840                 buffer[posBuffer + 1] = ( byte ) ( value & 0x000000000000007FL );
841                 
842                 return 2;
843             }
844             
845             if ( ( value & 0xFFFFFFFFFFE00000L ) == 0 )
846             {
847                 // The value is between 0x4000 and 0x1FFFFF : it will be hold in 3 bytes
848                 buffer[posBuffer] = ( byte ) ( ( byte ) ( ( value & 0x00000000001FC000L ) >> 14 ) | 0x80 );
849                 buffer[posBuffer + 1] = ( byte ) ( ( byte ) ( ( value & 0x0000000000003F80L ) >> 7 ) | 0x80 );
850                 buffer[posBuffer + 2] = ( byte ) ( value & 0x000000000000007FL );
851                 
852                 return 3;
853             }
854             
855             if ( ( value & 0xFFFFFFFFF0000000L ) == 0 )
856             {
857                 // The value is between 0x200000 and 0xFFFFFFF : it will be hold in 4 bytes
858                 buffer[posBuffer] = ( byte ) ( ( byte ) ( ( value & 0x000000000FE00000L ) >> 21 ) | 0x80 );
859                 buffer[posBuffer + 1] = ( byte ) ( ( byte ) ( ( value & 0x00000000001FC000L ) >> 14 ) | 0x80 );
860                 buffer[posBuffer + 2] = ( byte ) ( ( byte ) ( ( value & 0x0000000000003F80L ) >> 7 ) | 0x80 );
861                 buffer[posBuffer + 3] = ( byte ) ( value & 0x000000000000007FL );
862                 
863                 return 4;
864             }
865 
866             if ( ( value & 0xFFFFFFF800000000L ) == 0 )
867             {
868                 // The value is between 0x10000000 and 0x7FFFFFFFF : it will be hold in 5 bytes
869                 buffer[posBuffer] = ( byte ) ( ( byte ) ( ( value & 0x00000007F0000000L ) >> 28 ) | 0x80 );
870                 buffer[posBuffer + 1] = ( byte ) ( ( byte ) ( ( value & 0x000000000FE00000L ) >> 21 ) | 0x80 );
871                 buffer[posBuffer + 2] = ( byte ) ( ( byte ) ( ( value & 0x00000000001FC000L ) >> 14 ) | 0x80 );
872                 buffer[posBuffer + 3] = ( byte ) ( ( byte ) ( ( value & 0x0000000000003F80L ) >> 7 ) | 0x80 );
873                 buffer[posBuffer + 4] = ( byte ) ( value & 0x000000000000007FL );
874                 
875                 return 5;
876             }
877 
878             if ( ( value & 0xFFFFFC0000000000L ) == 0 )
879             {
880                 // The value is between 0x800000000 and 0x3FFFFFFFFFF : it will be hold in 6 bytes
881                 buffer[posBuffer] = ( byte ) ( ( byte ) ( ( value & 0x000003F800000000L ) >> 35 ) | 0x80 );
882                 buffer[posBuffer + 1] = ( byte ) ( ( byte ) ( ( value & 0x00000007F0000000L ) >> 28 ) | 0x80 );
883                 buffer[posBuffer + 2] = ( byte ) ( ( byte ) ( ( value & 0x000000000FE00000L ) >> 21 ) | 0x80 );
884                 buffer[posBuffer + 3] = ( byte ) ( ( byte ) ( ( value & 0x00000000001FC000L ) >> 14 ) | 0x80 );
885                 buffer[posBuffer + 4] = ( byte ) ( ( byte ) ( ( value & 0x0000000000003F80L ) >> 7 ) | 0x80 );
886                 buffer[posBuffer + 5] = ( byte ) ( value & 0x000000000000007FL );
887                 
888                 return 6;
889             }
890 
891             if ( ( value & 0xFFFE000000000000L ) == 0 )
892             {
893                 // The value is between 0x40000000000 and 0x1FFFFFFFFFFFF : it will be hold in 7 bytes
894                 buffer[posBuffer] = ( byte ) ( ( byte ) ( ( value & 0x0001FC0000000000L ) >> 42 ) | 0x80 );
895                 buffer[posBuffer + 1] = ( byte ) ( ( byte ) ( ( value & 0x000003F800000000L ) >> 35 ) | 0x80 );
896                 buffer[posBuffer + 2] = ( byte ) ( ( byte ) ( ( value & 0x00000007F0000000L ) >> 28 ) | 0x80 );
897                 buffer[posBuffer + 3] = ( byte ) ( ( byte ) ( ( value & 0x000000000FE00000L ) >> 21 ) | 0x80 );
898                 buffer[posBuffer + 4] = ( byte ) ( ( byte ) ( ( value & 0x00000000001FC000L ) >> 14 ) | 0x80 );
899                 buffer[posBuffer + 5] = ( byte ) ( ( byte ) ( ( value & 0x0000000000003F80L ) >> 7 ) | 0x80 );
900                 buffer[posBuffer + 6] = ( byte ) ( value & 0x000000000000007FL );
901                 
902                 return 7;
903             }
904 
905             if ( ( value & 0xFF00000000000000L ) == 0 )
906             {
907                 // The value is between 0x2000000000000 and 0xFF000000000000 : it will be hold in 8 bytes
908                 buffer[posBuffer] = ( byte ) ( ( byte ) ( ( value & 0x00FE000000000000L ) >> 49 ) | 0x80 );
909                 buffer[posBuffer + 1] = ( byte ) ( ( byte ) ( ( value & 0x0001FC0000000000L ) >> 42 ) | 0x80 );
910                 buffer[posBuffer + 2] = ( byte ) ( ( byte ) ( ( value & 0x000003F800000000L ) >> 35 ) | 0x80 );
911                 buffer[posBuffer + 3] = ( byte ) ( ( byte ) ( ( value & 0x00000007F0000000L ) >> 28 ) | 0x80 );
912                 buffer[posBuffer + 4] = ( byte ) ( ( byte ) ( ( value & 0x000000000FE00000L ) >> 21 ) | 0x80 );
913                 buffer[posBuffer + 5] = ( byte ) ( ( byte ) ( ( value & 0x00000000001FC000L ) >> 14 ) | 0x80 );
914                 buffer[posBuffer + 6] = ( byte ) ( ( byte ) ( ( value & 0x0000000000003F80L ) >> 7 ) | 0x80 );
915                 buffer[posBuffer + 7] = ( byte ) ( value & 0x000000000000007FL );
916                 
917                 return 8;
918             }
919             else
920             {
921                 // The value is between 0x100000000000000 and 0x7F00000000000000 : it will be hold in 9 bytes
922                 buffer[posBuffer] = ( byte ) ( ( byte ) ( ( value & 0x7F00000000000000L ) >> 56 ) | 0x80 );
923                 buffer[posBuffer + 1] = ( byte ) ( ( byte ) ( ( value & 0x00FE000000000000L ) >> 49 ) | 0x80 );
924                 buffer[posBuffer + 2] = ( byte ) ( ( byte ) ( ( value & 0x0001FC0000000000L ) >> 42 ) | 0x80 );
925                 buffer[posBuffer + 3] = ( byte ) ( ( byte ) ( ( value & 0x000003F800000000L ) >> 35 ) | 0x80 );
926                 buffer[posBuffer + 4] = ( byte ) ( ( byte ) ( ( value & 0x00000007F0000000L ) >> 28 ) | 0x80 );
927                 buffer[posBuffer + 5] = ( byte ) ( ( byte ) ( ( value & 0x000000000FE00000L ) >> 21 ) | 0x80 );
928                 buffer[posBuffer + 6] = ( byte ) ( ( byte ) ( ( value & 0x00000000001FC000L ) >> 14 ) | 0x80 );
929                 buffer[posBuffer + 7] = ( byte ) ( ( byte ) ( ( value & 0x0000000000003F80L ) >> 7 ) | 0x80 );
930                 buffer[posBuffer + 8] = ( byte ) ( value & 0x000000000000007FL );
931                 
932                 return 9;
933             }
934         }
935         else
936         {
937             // The value is bigger than 9999999999999999999, we need to use a BigInteger
938             // First, get the number of bytes we need to store the value in base 16
939             String number = oid.substring( start, start + nbDigits );
940             BigInteger bigInteger = new BigInteger( number );
941             
942             if ( isJointIsoItuT )
943             {
944                 bigInteger = bigInteger.add( JOINT_ISO_ITU_T );
945                 posBuffer = 0;
946             }
947             
948             byte[] bytes = bigInteger.toByteArray();
949             
950             // Now, convert this value to the ASN.1 OID format : we store the value
951             // as 7 bits bytes 
952             int nbNeededBytes = ( bytes.length * 8 ) / 7;
953             
954             switch ( ( bytes.length - 1 ) % 7 )
955             {
956                 case 0 :
957                     if ( ( bytes[0] & 0x0080 ) != 0 )
958                     {
959                         nbNeededBytes++;
960                     }
961                     
962                     break;
963                     
964                 case 1 :
965                     if ( ( bytes[0] & 0x00C0 ) != 0 )
966                     {
967                         nbNeededBytes++;
968                     }
969                     
970                     break;
971                     
972                 case 2 :
973                     if ( ( bytes[0] & 0x00E0 ) != 0 )
974                     {
975                         nbNeededBytes++;
976                     }
977                     
978                     break;
979                     
980                 case 3 : 
981                     if ( ( bytes[0] & 0x00F0 ) != 0 )
982                     {
983                         nbNeededBytes++;
984                     }
985                     
986                     break;
987                     
988                 case 4 :
989                     if ( ( bytes[0] & 0x00F8 ) != 0 )
990                     {
991                         nbNeededBytes++;
992                     }
993                     
994                     break;
995                     
996                 case 5 :
997                     if ( ( bytes[0] & 0x00FC ) != 0 )
998                     {
999                         nbNeededBytes++;
1000                     }
1001                     
1002                     break;
1003                     
1004                 case 6 : 
1005                     if ( ( bytes[0] & 0x00FE ) != 0 )
1006                     {
1007                         nbNeededBytes++;
1008                     }
1009                     
1010                     break;
1011                     
1012                 default :
1013                     // Exist to please checkstyle...
1014                     break;
1015             }
1016             
1017             byte[] converted = new byte[nbNeededBytes];
1018             
1019             int posConverted = nbNeededBytes - 1;
1020             int posBytes = bytes.length - 1;
1021             int counter = 0;
1022             byte reminder = 0;
1023             
1024             while ( posBytes >= 0 )
1025             {
1026                 byte newByte = ( byte ) ( ( bytes[posBytes] & 0x00FF ) << counter );
1027                 converted[posConverted] = ( byte ) ( reminder | newByte | 0x0080 );
1028                 reminder = ( byte ) ( ( bytes[posBytes] & 0x00FF ) >> ( 7 - counter ) );
1029                 counter =  ( counter + 1 ) % 8; 
1030                 posConverted--;
1031                 
1032                 if ( counter != 0 )
1033                 {
1034                     posBytes--;
1035                 }
1036                 else
1037                 {
1038                     reminder = 0;
1039                 }
1040             }
1041             
1042             converted[nbNeededBytes - 1] &= 0x7F;
1043             
1044             // Copy the converted bytes in the buffer
1045             System.arraycopy( converted, 0, buffer, posBuffer, nbNeededBytes );
1046             
1047             return nbNeededBytes;
1048         }
1049     }
1050     
1051     
1052     /**
1053      * Returns an OID object representing <code>oidString</code>.  
1054      *  
1055      * @param oidString The string representation of the OID
1056      * @return A new Oid
1057      * @throws DecoderException  When the OID is not valid
1058      */
1059     public static Oid fromString( String oidString ) throws DecoderException
1060     {
1061         if ( ( oidString == null ) || oidString.isEmpty() )
1062         {
1063             throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "empty" ) );
1064         }
1065 
1066         // Create a buffer that is wide enough to contain all the values
1067         byte[] buffer = new byte[oidString.length()];
1068 
1069         OidFSAState state = OidFSAState.START;
1070         
1071         // A counter of chars used for an arc. In 1.2.45345, this counter will be 5 for the '45345' arc.
1072         int arcNbChars = 0;
1073         
1074         // The position in the buffer where we accumulate the result. 
1075         int bufPos = 0;
1076         
1077         // The position in the OID string where we started to read an arc
1078         int startArc = 0;
1079         
1080         // The number of bytes in the resulting OID byte[]
1081         int nbBytes;
1082         
1083         for ( int i = 0; i < oidString.length(); i++ )
1084         {
1085             switch ( state )
1086             {
1087                 case START :
1088                     // (Start) --['0'..'1']--> (A)
1089                     // (start) --['2']--> (F)
1090                     state = processStateStart( oidString, buffer, i );
1091                     break;
1092                     
1093                 case STATE_A :
1094                     // (A) --['.']--> (B)
1095                     state = processStateA( oidString, i );
1096 
1097                     
1098                     break;
1099                     
1100                 case STATE_B :
1101                     // (B) --['0']--> (D)
1102                     // (B) --['1'..'3']--> (C)
1103                     // (B) --['4'..'9']--> (E)
1104                     state = processStateB( oidString, buffer, i );
1105                     
1106                     break;
1107                     
1108                 case STATE_C :
1109                     // (C) --['.']--> (K)
1110                     // (C) --['0'..'9']--> (E)
1111                     state = processStateC( oidString, buffer, i );
1112 
1113                     // the next arc will be store at position 1 in the buffer
1114                     bufPos = 1;
1115 
1116                     break;
1117                     
1118                 case STATE_D :
1119                     // (D) --['.']--> (K)
1120                     // Fallthrough
1121                     
1122                 case STATE_E :
1123                     // (E) --['.']--> (K)
1124                     state = processStateDE( oidString, buffer, i );
1125                     
1126                     // the next arc will be store at position 1 in teh buffer
1127                     bufPos = 1;
1128 
1129                     break;
1130                     
1131                 case STATE_F :
1132                     // (F) --['.']--> (G)
1133                     state = processStateF( oidString, i );
1134                     
1135                     break;
1136                     
1137                 case STATE_G :
1138                     // (G) --['0']--> (I)
1139                     // (G) --['1'..'9']--> (H)
1140                     state = processStateG( oidString, buffer, i );
1141                     arcNbChars = 1;
1142                     startArc = i;
1143 
1144                     break;
1145 
1146                 case STATE_H :
1147                     // (H) --['.']--> (K)
1148                     // (H) --['0'..'9']--> (J)
1149                     state = processStateH( oidString, buffer, i );
1150                     
1151                     if ( state == OidFSAState.STATE_J )
1152                     {
1153                         // We have already two digits
1154                         arcNbChars = 2;
1155                         bufPos = 0;
1156                     }
1157                     
1158                     break;
1159 
1160                 case STATE_I :
1161                     // (I) --['.']--> (K)
1162                     state = processStateI( oidString, buffer, i );
1163                     
1164                     // Set the arc position to buffer[1], we haven't yet accumulated digits.
1165                     bufPos = 1;
1166                     
1167                     break;
1168 
1169                 case STATE_J :
1170                     // (J) --['.']--> (K)
1171                     // (J) --['0'..'9']--> (J)
1172                     state = processStateJ( oidString, buffer, arcNbChars + bufPos, i );
1173                     
1174                     if ( state == OidFSAState.STATE_J )
1175                     {
1176                         // We can increment the number of digit for this arc
1177                         arcNbChars++;
1178                     }
1179                     else
1180                     {
1181                         // We are done with the first arc : convert it
1182                         bufPos += convert( oidString, buffer, bufPos, arcNbChars, 0, true );
1183                     }
1184                     
1185                     break;
1186 
1187                 case STATE_K :
1188                     startArc = i;
1189                     state = processStateK( oidString, buffer, bufPos, i );
1190                     
1191                     if ( state == OidFSAState.STATE_M )
1192                     { 
1193                         bufPos++;
1194                     }
1195                     else
1196                     {
1197                         arcNbChars = 1;
1198                     }
1199                     
1200                     break;
1201 
1202                 case STATE_L :
1203                     state = processStateL( oidString, buffer, arcNbChars + bufPos, i );
1204                     
1205                     if ( state == OidFSAState.STATE_L )
1206                     {
1207                         arcNbChars++;
1208                         break;
1209                     }
1210                     else
1211                     {
1212                         // We are done with the arc : convert it
1213                         bufPos += convert( oidString, buffer, startArc, arcNbChars, bufPos, false );
1214                     }
1215 
1216                     break;
1217                     
1218                 case STATE_M :
1219                     state = processStateM( oidString, i );
1220                     break;
1221                     
1222                 default :
1223                     // Exist to please checkstyle...
1224                     break;
1225             }
1226         }
1227         
1228         // End of the string : check that we are in a correct state for a completion
1229         // The only valid exit states are :
1230         // (C) --[]--> (End)
1231         // (D) --[]--> (End)
1232         // (E) --[]--> (End)
1233         // (H) --[]--> (End)
1234         // (I) --[]--> (End)
1235         // (J) --[]--> (End)
1236         // (L) --[]--> (End)
1237         // (M) --[]--> (End)
1238         switch ( state )
1239         {
1240             case STATE_C :
1241                 // (C) --[]--> (End)
1242                 // fallthrough
1243                 
1244             case STATE_D :
1245                 // (D) --[]--> (End)
1246                 // fallthrough
1247                 
1248             case STATE_E :
1249                 // (E) --[]--> (End)
1250                 // fallthrough
1251 
1252             case STATE_H :
1253                 // (H) --[]--> (End)
1254                 // fallthrough
1255                 
1256             case STATE_I :
1257                 // (I) --[]--> (End)
1258                 byte[] bytes = new byte[1];
1259                 bytes[0] = ( byte ) ( buffer[0] | buffer[1] );
1260 
1261                 return new Oid( oidString, bytes );
1262                 
1263             case STATE_J :
1264                 // (J) --[]--> (End)
1265                 nbBytes = convert( oidString, buffer, 2, arcNbChars, 0, true );
1266                 bytes = new byte[nbBytes];
1267                 System.arraycopy( buffer, 0, bytes, 0, nbBytes );
1268                 
1269                 return new Oid( oidString, bytes );
1270 
1271             case STATE_L :
1272                 bufPos += convert( oidString, buffer, startArc, arcNbChars, bufPos, false );
1273                 bytes = new byte[bufPos];
1274                 System.arraycopy( buffer, 0, bytes, 0, bufPos );
1275                 
1276                 return new Oid( oidString, bytes );
1277                 
1278             case STATE_M :
1279                 bytes = new byte[bufPos];
1280                 System.arraycopy( buffer, 0, bytes, 0, bufPos );
1281                 
1282                 return new Oid( oidString, bytes );
1283                 
1284             default :
1285                 // This should never happen...
1286                 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "Wrong OID" ) );
1287         }
1288     }
1289 
1290     
1291     /**
1292      * Returns the length of the encoded <code>byte[]</code> representation.
1293      * 
1294      * @return The length of the byte[]
1295      */
1296     public int getEncodedLength()
1297     {
1298         return oidBytes.length;
1299     }
1300 
1301 
1302     /**
1303      * {@inheritDoc}
1304      */
1305     @Override
1306     public int hashCode()
1307     {
1308         return oidString.hashCode();
1309     }
1310 
1311 
1312     /**
1313      * Returns true if <code>oidString</code> is a valid string representation
1314      * of an OID.  This method simply calls {@link #fromString(String)} and 
1315      * returns true if no exception was thrown.  As such, it should not be used 
1316      * in an attempt to check if a string is a valid OID before calling 
1317      * {@link #fromString(String)}.
1318      * 
1319      * @param oidString The string to test
1320      * @return True, if <code>oidString</code> is valid
1321      */
1322     public static boolean isOid( String oidString )
1323     {
1324         try
1325         {
1326             Oid.fromString( oidString );
1327 
1328             return true;
1329         }
1330         catch ( DecoderException e )
1331         {
1332             return false;
1333         }
1334     }
1335 
1336 
1337     /**
1338      * Returns the <code>byte[]</code> representation of the OID. The 
1339      * <code>byte[]</code> that is returned is <i>copied</i> from the internal
1340      * value so as to preserve the immutability of an OID object.  If the 
1341      * output of a call to this method is intended to be written to a stream,
1342      * the {@link #writeBytesTo(OutputStream)} should be used instead as it will
1343      * avoid creating this copy. 
1344      * 
1345      * @return The encoded <code>byte[]</code> representation of the OID.
1346      */
1347     public byte[] toBytes()
1348     {
1349         return Arrays.copyOf( oidBytes, oidBytes.length );
1350     }
1351 
1352 
1353     /**
1354      * Returns the string representation of the OID.
1355      * 
1356      * @return The string representation of the OID
1357      */
1358     @Override
1359     public String toString()
1360     {
1361         return oidString;
1362     }
1363 
1364 
1365     /**
1366      * Writes the bytes respresenting this OID to the provided buffer.  This 
1367      * should be used in preference to the {@link #toBytes()} method in order
1368      * to prevent the creation of copies of the actual <code>byte[]</code>.
1369      * 
1370      * @param buffer The buffer to write the bytes into
1371      */
1372     public void writeBytesTo( java.nio.ByteBuffer buffer )
1373     {
1374         buffer.put( oidBytes );
1375     }
1376 
1377 
1378     /**
1379      * Writes the bytes respresenting this OID to the provided stream.  This 
1380      * should be used in preference to the {@link #toBytes()} method in order
1381      * to prevent the creation of copies of the actual <code>byte[]</code>.
1382      * 
1383      * @param outputStream The stream to write the bytes to
1384      * @throws IOException When we can't write the OID into a Stream
1385      */
1386     public void writeBytesTo( OutputStream outputStream ) throws IOException
1387     {
1388         outputStream.write( oidBytes );
1389     }
1390 }