1package org.bouncycastle.asn1.cms;
2
3import java.util.Enumeration;
4import java.util.Hashtable;
5import java.util.Vector;
6
7import org.bouncycastle.asn1.ASN1Encodable;
8import org.bouncycastle.asn1.ASN1EncodableVector;
9import org.bouncycastle.asn1.ASN1ObjectIdentifier;
10import org.bouncycastle.asn1.ASN1Set;
11import org.bouncycastle.asn1.DERSet;
12
13/**
14 * This is helper tool to construct {@link Attributes} sets.
15 */
16public class AttributeTable
17{
18    private Hashtable attributes = new Hashtable();
19
20    public AttributeTable(
21        Hashtable  attrs)
22    {
23        attributes = copyTable(attrs);
24    }
25
26    public AttributeTable(
27        ASN1EncodableVector v)
28    {
29        for (int i = 0; i != v.size(); i++)
30        {
31            Attribute   a = Attribute.getInstance(v.get(i));
32
33            addAttribute(a.getAttrType(), a);
34        }
35    }
36
37    public AttributeTable(
38        ASN1Set    s)
39    {
40        for (int i = 0; i != s.size(); i++)
41        {
42            Attribute   a = Attribute.getInstance(s.getObjectAt(i));
43
44            addAttribute(a.getAttrType(), a);
45        }
46    }
47
48    public AttributeTable(
49        Attribute    attr)
50    {
51        addAttribute(attr.getAttrType(), attr);
52    }
53
54    public AttributeTable(
55        Attributes    attrs)
56    {
57        this(ASN1Set.getInstance(attrs.toASN1Primitive()));
58    }
59
60    private void addAttribute(
61        ASN1ObjectIdentifier oid,
62        Attribute           a)
63    {
64        Object value = attributes.get(oid);
65
66        if (value == null)
67        {
68            attributes.put(oid, a);
69        }
70        else
71        {
72            Vector v;
73
74            if (value instanceof Attribute)
75            {
76                v = new Vector();
77
78                v.addElement(value);
79                v.addElement(a);
80            }
81            else
82            {
83                v = (Vector)value;
84
85                v.addElement(a);
86            }
87
88            attributes.put(oid, v);
89        }
90    }
91
92    /**
93     * Return the first attribute matching the OBJECT IDENTIFIER oid.
94     *
95     * @param oid type of attribute required.
96     * @return first attribute found of type oid.
97     */
98    public Attribute get(
99        ASN1ObjectIdentifier oid)
100    {
101        Object value = attributes.get(oid);
102
103        if (value instanceof Vector)
104        {
105            return (Attribute)((Vector)value).elementAt(0);
106        }
107
108        return (Attribute)value;
109    }
110
111    /**
112     * Return all the attributes matching the OBJECT IDENTIFIER oid. The vector will be
113     * empty if there are no attributes of the required type present.
114     *
115     * @param oid type of attribute required.
116     * @return a vector of all the attributes found of type oid.
117     */
118    public ASN1EncodableVector getAll(
119        ASN1ObjectIdentifier oid)
120    {
121        ASN1EncodableVector v = new ASN1EncodableVector();
122
123        Object value = attributes.get(oid);
124
125        if (value instanceof Vector)
126        {
127            Enumeration e = ((Vector)value).elements();
128
129            while (e.hasMoreElements())
130            {
131                v.add((Attribute)e.nextElement());
132            }
133        }
134        else if (value != null)
135        {
136            v.add((Attribute)value);
137        }
138
139        return v;
140    }
141
142    public int size()
143    {
144        int size = 0;
145
146        for (Enumeration en = attributes.elements(); en.hasMoreElements();)
147        {
148            Object o = en.nextElement();
149
150            if (o instanceof Vector)
151            {
152                size += ((Vector)o).size();
153            }
154            else
155            {
156                size++;
157            }
158        }
159
160        return size;
161    }
162
163    public Hashtable toHashtable()
164    {
165        return copyTable(attributes);
166    }
167
168    public ASN1EncodableVector toASN1EncodableVector()
169    {
170        ASN1EncodableVector  v = new ASN1EncodableVector();
171        Enumeration          e = attributes.elements();
172
173        while (e.hasMoreElements())
174        {
175            Object value = e.nextElement();
176
177            if (value instanceof Vector)
178            {
179                Enumeration en = ((Vector)value).elements();
180
181                while (en.hasMoreElements())
182                {
183                    v.add(Attribute.getInstance(en.nextElement()));
184                }
185            }
186            else
187            {
188                v.add(Attribute.getInstance(value));
189            }
190        }
191
192        return v;
193    }
194
195    public Attributes toASN1Structure()
196    {
197        return new Attributes(this.toASN1EncodableVector());
198    }
199
200    private Hashtable copyTable(
201        Hashtable in)
202    {
203        Hashtable   out = new Hashtable();
204        Enumeration e = in.keys();
205
206        while (e.hasMoreElements())
207        {
208            Object key = e.nextElement();
209
210            out.put(key, in.get(key));
211        }
212
213        return out;
214    }
215
216    /**
217     * Return a new table with the passed in attribute added.
218     *
219     * @param attrType the type of the attribute to add.
220     * @param attrValue the value corresponding to the attribute (will be wrapped in a SET).
221     * @return a new table with the extra attribute in it.
222     */
223    public AttributeTable add(ASN1ObjectIdentifier attrType, ASN1Encodable attrValue)
224    {
225        AttributeTable newTable = new AttributeTable(attributes);
226
227        newTable.addAttribute(attrType, new Attribute(attrType, new DERSet(attrValue)));
228
229        return newTable;
230    }
231
232    public AttributeTable remove(ASN1ObjectIdentifier attrType)
233    {
234        AttributeTable newTable = new AttributeTable(attributes);
235
236        newTable.attributes.remove(attrType);
237
238        return newTable;
239    }
240}
241