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