001    /*
002     * Copyright (c) 2000 - 2006 The Legion Of The Bouncy Castle (http://www.bouncycastle.org)
003     * 
004     * Permission is hereby granted, free of charge, to any person obtaining a copy of this
005     * software and associated documentation files (the "Software"), to deal in the Software
006     * without restriction, including without limitation the rights to use, copy, modify,
007     * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
008     * permit persons to whom the Software is furnished to do so, subject to the following
009     * conditions:
010     * 
011     * The above copyright notice and this permission notice shall be included in all copies
012     * or substantial portions of the Software.
013     * 
014     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
015     * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
016     * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
017     * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
018     * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
019     * DEALINGS IN THE SOFTWARE.
020     * 
021     */
022    
023    package org.apache.directory.shared.asn1.der;
024    
025    
026    import java.io.ByteArrayOutputStream;
027    import java.io.IOException;
028    import java.util.Enumeration;
029    import java.util.Vector;
030    
031    
032    public class BERConstructedOctetString extends DEROctetString
033    {
034        private Vector<DEREncodable> octets;
035    
036    
037        /**
038         * @param string
039         *            the octets making up the octet string.
040         */
041        public BERConstructedOctetString(byte[] string)
042        {
043            super( string );
044        }
045    
046    
047        public BERConstructedOctetString(Vector<DEREncodable> octets)
048        {
049            super( toBytes( octets ) );
050    
051            this.octets = octets;
052        }
053    
054    
055        /**
056         * Convert a vector of octet strings into a single byte string.
057         */
058        private static byte[] toBytes( Vector<DEREncodable> octs )
059        {
060            ByteArrayOutputStream baos = new ByteArrayOutputStream();
061    
062            for ( int i = 0; i != octs.size(); i++ )
063            {
064                try
065                {
066                    DEROctetString o = ( DEROctetString ) octs.elementAt( i );
067    
068                    baos.write( o.getOctets() );
069                }
070                catch ( ClassCastException e )
071                {
072                    throw new IllegalArgumentException( octs.elementAt( i ).getClass().getName()
073                        + " found in input should only contain DEROctetString." );
074                }
075                catch ( IOException e )
076                {
077                    throw new IllegalArgumentException( "Exception converting octets " + e.toString() );
078                }
079            }
080    
081            return baos.toByteArray();
082        }
083    
084    
085        /**
086         * @return Enumeration the DER octets that make up this string.
087         */
088        public Enumeration<DEREncodable> getObjects()
089        {
090            if ( octets == null )
091            {
092                return generateOcts().elements();
093            }
094    
095            return octets.elements();
096        }
097    
098    
099        private Vector<DEREncodable> generateOcts()
100        {
101            int start = 0;
102            int end = 0;
103            Vector<DEREncodable> vector = new Vector<DEREncodable>();
104    
105            while ( ( end + 1 ) < value.length )
106            {
107                if ( value[end] == 0 && value[end + 1] == 0 )
108                {
109                    byte[] nStr = new byte[end - start + 1];
110    
111                    System.arraycopy( value, start, nStr, 0, nStr.length );
112    
113                    vector.addElement( new DEROctetString( nStr ) );
114                    start = end + 1;
115                }
116                end++;
117            }
118    
119            byte[] nStr = new byte[value.length - start];
120    
121            System.arraycopy( value, start, nStr, 0, nStr.length );
122    
123            vector.addElement( new DEROctetString( nStr ) );
124    
125            return vector;
126        }
127    
128    
129        public void encode( ASN1OutputStream out ) throws IOException
130        {
131            out.write( CONSTRUCTED | OCTET_STRING );
132    
133            out.write( DERObject.TAGGED );
134    
135            if ( octets != null )
136            {
137                for ( int i = 0; i != octets.size(); i++ )
138                {
139                    out.writeObject( octets.elementAt( i ) );
140                }
141            }
142            else
143            {
144                int start = 0;
145                int end = 0;
146    
147                while ( ( end + 1 ) < value.length )
148                {
149                    if ( value[end] == 0 && value[end + 1] == 0 )
150                    {
151                        byte[] newString = new byte[end - start + 1];
152    
153                        System.arraycopy( value, start, newString, 0, newString.length );
154    
155                        out.writeObject( new DEROctetString( newString ) );
156                        start = end + 1;
157                    }
158                    end++;
159                }
160    
161                byte[] newString = new byte[value.length - start];
162    
163                System.arraycopy( value, start, newString, 0, newString.length );
164    
165                out.writeObject( new DEROctetString( newString ) );
166            }
167    
168            out.write( TERMINATOR );
169            out.write( TERMINATOR );
170        }
171    }