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    import org.apache.directory.shared.i18n.I18n;
032    
033    
034    public class BERConstructedOctetString extends DEROctetString
035    {
036        private Vector<DEREncodable> octets;
037    
038    
039        /**
040         * @param string
041         *            the octets making up the octet string.
042         */
043        public BERConstructedOctetString(byte[] string)
044        {
045            super( string );
046        }
047    
048    
049        public BERConstructedOctetString(Vector<DEREncodable> octets)
050        {
051            super( toBytes( octets ) );
052    
053            this.octets = octets;
054        }
055    
056    
057        /**
058         * Convert a vector of octet strings into a single byte string.
059         */
060        private static byte[] toBytes( Vector<DEREncodable> octs )
061        {
062            ByteArrayOutputStream baos = new ByteArrayOutputStream();
063    
064            for ( int i = 0; i != octs.size(); i++ )
065            {
066                try
067                {
068                    DEROctetString o = ( DEROctetString ) octs.elementAt( i );
069    
070                    baos.write( o.getOctets() );
071                }
072                catch ( ClassCastException e )
073                {
074                    throw new IllegalArgumentException( I18n.err( I18n.ERR_00025, octs.elementAt( i ).getClass().getName() ) );
075                }
076                catch ( IOException e )
077                {
078                    throw new IllegalArgumentException( I18n.err( I18n.ERR_00026, e.toString() ) );
079                }
080            }
081    
082            return baos.toByteArray();
083        }
084    
085    
086        /**
087         * @return Enumeration the DER octets that make up this string.
088         */
089        public Enumeration<DEREncodable> getObjects()
090        {
091            if ( octets == null )
092            {
093                return generateOcts().elements();
094            }
095    
096            return octets.elements();
097        }
098    
099    
100        private Vector<DEREncodable> generateOcts()
101        {
102            int start = 0;
103            int end = 0;
104            Vector<DEREncodable> vector = new Vector<DEREncodable>();
105    
106            while ( ( end + 1 ) < value.length )
107            {
108                if ( value[end] == 0 && value[end + 1] == 0 )
109                {
110                    byte[] nStr = new byte[end - start + 1];
111    
112                    System.arraycopy( value, start, nStr, 0, nStr.length );
113    
114                    vector.addElement( new DEROctetString( nStr ) );
115                    start = end + 1;
116                }
117                end++;
118            }
119    
120            byte[] nStr = new byte[value.length - start];
121    
122            System.arraycopy( value, start, nStr, 0, nStr.length );
123    
124            vector.addElement( new DEROctetString( nStr ) );
125    
126            return vector;
127        }
128    
129    
130        public void encode( ASN1OutputStream out ) throws IOException
131        {
132            out.write( CONSTRUCTED | OCTET_STRING );
133    
134            out.write( DERObject.TAGGED );
135    
136            if ( octets != null )
137            {
138                for ( int i = 0; i != octets.size(); i++ )
139                {
140                    out.writeObject( octets.elementAt( i ) );
141                }
142            }
143            else
144            {
145                int start = 0;
146                int end = 0;
147    
148                while ( ( end + 1 ) < value.length )
149                {
150                    if ( value[end] == 0 && value[end + 1] == 0 )
151                    {
152                        byte[] newString = new byte[end - start + 1];
153    
154                        System.arraycopy( value, start, newString, 0, newString.length );
155    
156                        out.writeObject( new DEROctetString( newString ) );
157                        start = end + 1;
158                    }
159                    end++;
160                }
161    
162                byte[] newString = new byte[value.length - start];
163    
164                System.arraycopy( value, start, newString, 0, newString.length );
165    
166                out.writeObject( new DEROctetString( newString ) );
167            }
168    
169            out.write( TERMINATOR );
170            out.write( TERMINATOR );
171        }
172    }