Imported GNU Classpath 0.90
[official-gcc.git] / libjava / classpath / gnu / java / security / der / DERWriter.java
blob0c26336053cfd693118acbab8fce7c72c6a5479a
1 /* DERWriter.java -- write Java types in DER format.
2 Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package gnu.java.security.der;
41 import gnu.java.security.OID;
43 import java.io.ByteArrayOutputStream;
44 import java.io.IOException;
45 import java.io.OutputStream;
47 import java.math.BigInteger;
49 import java.text.SimpleDateFormat;
51 import java.util.Date;
52 import java.util.Iterator;
53 import java.util.List;
54 import java.util.Set;
55 import java.util.TimeZone;
57 /**
58 * Methods that allow various Java types to be written as a DER
59 * (Distinguished Encoding Rules) stream to the specified output stream.
60 * DER is used to encode ASN.1 constructions, but this class provides no
61 * methods for interacting with ASN.1. Rather, callers should construct
62 * their output objects properly for whatever ASN.1 construct is being
63 * output.
65 * <p>This class only defines static methods; there are no instance
66 * variables needed.
68 * @author Casey Marshall (csm@gnu.org)
70 public class DERWriter implements DER
73 // Constructors.
74 // ------------------------------------------------------------------------
76 /** This class only has static methods. */
77 private DERWriter()
81 // Class methods.
82 // ------------------------------------------------------------------------
84 public static int write(OutputStream out, DERValue object)
85 throws IOException
87 if (DER.CONSTRUCTED_VALUE.equals (object.getValue ()))
89 out.write (object.getEncoded ());
90 return object.getLength ();
93 out.write(object.getExternalTag());
94 Object value = object.getValue();
95 if (value == null)
97 writeLength(out, 0);
98 return 0;
100 if (value instanceof Boolean)
101 return writeBoolean(out, (Boolean) value);
102 else if (value instanceof BigInteger)
103 return writeInteger(out, (BigInteger) value);
104 else if (value instanceof Date)
105 return writeDate(out, object.getExternalTag(), (Date) value);
106 else if (value instanceof String)
107 return writeString(out, object.getExternalTag(), (String) value);
108 else if (value instanceof List)
109 return writeSequence(out, (List) value);
110 else if (value instanceof Set)
111 return writeSet(out, (Set) value);
112 else if (value instanceof BitString)
113 return writeBitString(out, (BitString) value);
114 else if (value instanceof OID)
115 return writeOID(out, (OID) value);
116 else if (value instanceof byte[])
118 writeLength(out, ((byte[]) value).length);
119 out.write((byte[]) value);
120 return ((byte[]) value).length;
122 else if (value instanceof DERValue)
124 ByteArrayOutputStream bout = new ByteArrayOutputStream();
125 write(bout, (DERValue) value);
126 byte[] buf = bout.toByteArray();
127 writeLength(out, buf.length);
128 out.write(buf);
129 return buf.length;
131 else
132 throw new DEREncodingException("cannot encode " + value.getClass().getName());
135 public static int definiteEncodingSize(int length)
137 if (length < 128)
138 return 1;
139 else if (length < 256)
140 return 2;
141 else if (length < 65536)
142 return 3;
143 else if (length < 16777216)
144 return 4;
145 else
146 return 5;
149 // Own methods.
150 // ------------------------------------------------------------------------
153 * Write a BOOLEAN type to the given output stream.
155 * @param out The sink output stream.
156 * @param b The boolean value to write.
158 private static int writeBoolean(OutputStream out, Boolean b)
159 throws IOException
161 writeLength(out, 1);
162 if (b.booleanValue())
163 out.write(0xFF);
164 else
165 out.write(0);
166 return 1;
170 * Write an INTEGER type to the given output stream.
172 * @param out The sink output stream.
173 * @param integer The integer to write.
175 private static int writeInteger(OutputStream out, BigInteger integer)
176 throws IOException
178 byte[] bytes = integer.toByteArray();
179 writeLength(out, bytes.length);
180 out.write(bytes);
181 return bytes.length;
184 private static int writeSequence(OutputStream out, List sequence)
185 throws IOException
187 ByteArrayOutputStream bout = new ByteArrayOutputStream();
188 for (Iterator i = sequence.iterator(); i.hasNext(); )
190 write(bout, (DERValue) i.next());
192 byte[] buf = bout.toByteArray();
193 writeLength(out, buf.length);
194 out.write(buf);
195 return buf.length;
198 private static int writeSet(OutputStream out, Set set)
199 throws IOException
201 ByteArrayOutputStream bout = new ByteArrayOutputStream();
202 for (Iterator i = set.iterator(); i.hasNext(); )
204 write(bout, (DERValue) i.next());
206 byte[] buf = bout.toByteArray();
207 writeLength(out, buf.length);
208 out.write(buf);
209 return buf.length;
212 private static int writeOID(OutputStream out, OID oid)
213 throws IOException
215 byte[] der = oid.getDER();
216 writeLength(out, der.length);
217 out.write(der);
218 return der.length;
221 private static int writeBitString(OutputStream out, BitString bs)
222 throws IOException
224 byte[] buf = bs.getShiftedByteArray();
225 writeLength(out, buf.length + 1);
226 out.write(bs.getIgnoredBits());
227 out.write(buf);
228 return buf.length + 1;
231 private static int writeString(OutputStream out, int tag, String str)
232 throws IOException
234 byte[] b = null;
235 switch (tag & 0x1F)
237 case NUMERIC_STRING:
238 case PRINTABLE_STRING:
239 case T61_STRING:
240 case VIDEOTEX_STRING:
241 case IA5_STRING:
242 case GRAPHIC_STRING:
243 case ISO646_STRING:
244 case GENERAL_STRING:
245 b = toIso88591(str);
246 break;
248 case UNIVERSAL_STRING:
249 case BMP_STRING:
250 b = toUtf16Be(str);
251 break;
253 case UTF8_STRING:
254 default:
255 b = toUtf8(str);
256 break;
258 writeLength(out, b.length);
259 out.write(b);
260 return b.length;
263 private static byte[] toIso88591(String string)
265 byte[] result = new byte[string.length()];
266 for (int i = 0; i < string.length(); i++)
267 result[i] = (byte) string.charAt(i);
268 return result;
271 private static byte[] toUtf16Be(String string)
273 byte[] result = new byte[string.length() * 2];
274 for (int i = 0; i < string.length(); i++)
276 result[i*2 ] = (byte) ((string.charAt(i) >>> 8) & 0xFF);
277 result[i*2+1] = (byte) (string.charAt(i) & 0xFF);
279 return result;
282 private static byte[] toUtf8(String string)
284 ByteArrayOutputStream buf =
285 new ByteArrayOutputStream((int)(string.length() * 1.5));
286 for (int i = 0; i < string.length(); i++)
288 char c = string.charAt(i);
289 if (c < 0x0080)
290 buf.write(c & 0xFF);
291 else if (c < 0x0800)
293 buf.write(0xC0 | ((c >>> 6) & 0x3F));
294 buf.write(0x80 | (c & 0x3F));
296 else
298 buf.write(0xE0 | ((c >>> 12) & 0x0F));
299 buf.write(0x80 | ((c >>> 6) & 0x3F));
300 buf.write(0x80 | (c & 0x3F));
303 return buf.toByteArray();
306 private static int writeDate(OutputStream out, int tag, Date date)
307 throws IOException
309 SimpleDateFormat sdf = null;
310 if ((tag & 0x1F) == UTC_TIME)
311 sdf = new SimpleDateFormat("yyMMddHHmmss'Z'");
312 else
313 sdf = new SimpleDateFormat("yyyyMMddHHmmss'.'SSS'Z'");
314 sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
315 byte[] b = sdf.format(date).getBytes("ISO-8859-1");
316 writeLength(out, b.length);
317 out.write(b);
318 return b.length;
321 // Package method.
322 // ------------------------------------------------------------------------
324 static void writeLength(OutputStream out, int len) throws IOException
326 if (len < 128)
327 out.write(len);
328 else if (len < 256)
330 out.write(0x81);
331 out.write(len);
333 else if (len < 65536)
335 out.write(0x82);
336 out.write(len >> 8);
337 out.write(len);
339 else if (len < 16777216)
341 out.write(0x83);
342 out.write(len >> 16);
343 out.write(len >> 8);
344 out.write(len);
346 else
348 out.write(0x84);
349 out.write(len >> 24);
350 out.write(len >> 16);
351 out.write(len >> 8);
352 out.write(len);