Merge from the pain train
[official-gcc.git] / libjava / gnu / java / security / der / DERWriter.java
blob5568b69bbad771fe53e26876eaa8382301167755
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., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 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 out.write(object.getExternalTag());
88 Object value = object.getValue();
89 if (value == null)
91 writeLength(out, 0);
92 return 0;
94 if (value instanceof Boolean)
95 return writeBoolean(out, (Boolean) value);
96 else if (value instanceof BigInteger)
97 return writeInteger(out, (BigInteger) value);
98 else if (value instanceof Date)
99 return writeDate(out, object.getExternalTag(), (Date) value);
100 else if (value instanceof String)
101 return writeString(out, object.getExternalTag(), (String) value);
102 else if (value instanceof List)
103 return writeSequence(out, (List) value);
104 else if (value instanceof Set)
105 return writeSet(out, (Set) value);
106 else if (value instanceof BitString)
107 return writeBitString(out, (BitString) value);
108 else if (value instanceof OID)
109 return writeOID(out, (OID) value);
110 else if (value instanceof byte[])
112 writeLength(out, ((byte[]) value).length);
113 out.write((byte[]) value);
114 return ((byte[]) value).length;
116 else if (value instanceof DERValue)
118 ByteArrayOutputStream bout = new ByteArrayOutputStream();
119 write(bout, (DERValue) value);
120 byte[] buf = bout.toByteArray();
121 writeLength(out, buf.length);
122 out.write(buf);
123 return buf.length;
125 else
126 throw new DEREncodingException("cannot encode " + value.getClass().getName());
129 public static int definiteEncodingSize(int length)
131 if (length < 128)
132 return 1;
133 else if (length < 256)
134 return 2;
135 else if (length < 65536)
136 return 3;
137 else if (length < 16777216)
138 return 4;
139 else
140 return 5;
143 // Own methods.
144 // ------------------------------------------------------------------------
147 * Write a BOOLEAN type to the given output stream.
149 * @param out The sink output stream.
150 * @param b The boolean value to write.
152 private static int writeBoolean(OutputStream out, Boolean b)
153 throws IOException
155 writeLength(out, 1);
156 if (b.booleanValue())
157 out.write(0xFF);
158 else
159 out.write(0);
160 return 1;
164 * Write an INTEGER type to the given output stream.
166 * @param out The sink output stream.
167 * @param integer The integer to write.
169 private static int writeInteger(OutputStream out, BigInteger integer)
170 throws IOException
172 byte[] bytes = integer.toByteArray();
173 writeLength(out, bytes.length);
174 out.write(bytes);
175 return bytes.length;
178 private static int writeSequence(OutputStream out, List sequence)
179 throws IOException
181 ByteArrayOutputStream bout = new ByteArrayOutputStream();
182 for (Iterator i = sequence.iterator(); i.hasNext(); )
184 write(bout, (DERValue) i.next());
186 byte[] buf = bout.toByteArray();
187 writeLength(out, buf.length);
188 out.write(buf);
189 return buf.length;
192 private static int writeSet(OutputStream out, Set set)
193 throws IOException
195 ByteArrayOutputStream bout = new ByteArrayOutputStream();
196 for (Iterator i = set.iterator(); i.hasNext(); )
198 write(bout, (DERValue) i.next());
200 byte[] buf = bout.toByteArray();
201 writeLength(out, buf.length);
202 out.write(buf);
203 return buf.length;
206 private static int writeOID(OutputStream out, OID oid)
207 throws IOException
209 byte[] der = oid.getDER();
210 writeLength(out, der.length);
211 out.write(der);
212 return der.length;
215 private static int writeBitString(OutputStream out, BitString bs)
216 throws IOException
218 byte[] buf = bs.getShiftedByteArray();
219 out.write(buf.length + 1);
220 out.write(bs.getIgnoredBits());
221 out.write(buf);
222 return buf.length;
225 private static int writeString(OutputStream out, int tag, String str)
226 throws IOException
228 byte[] b = null;
229 switch (tag & 0x1F)
231 case NUMERIC_STRING:
232 case PRINTABLE_STRING:
233 case T61_STRING:
234 case VIDEOTEX_STRING:
235 case IA5_STRING:
236 case GRAPHIC_STRING:
237 case ISO646_STRING:
238 case GENERAL_STRING:
239 b = toIso88591(str);
240 break;
242 case UNIVERSAL_STRING:
243 case BMP_STRING:
244 b = toUtf16Be(str);
245 break;
247 case UTF8_STRING:
248 default:
249 b = toUtf8(str);
250 break;
252 writeLength(out, b.length);
253 out.write(b);
254 return b.length;
257 private static byte[] toIso88591(String string)
259 byte[] result = new byte[string.length()];
260 for (int i = 0; i < string.length(); i++)
261 result[i] = (byte) string.charAt(i);
262 return result;
265 private static byte[] toUtf16Be(String string)
267 byte[] result = new byte[string.length() * 2];
268 for (int i = 0; i < string.length(); i++)
270 result[i*2 ] = (byte) ((string.charAt(i) >>> 8) & 0xFF);
271 result[i*2+1] = (byte) (string.charAt(i) & 0xFF);
273 return result;
276 private static byte[] toUtf8(String string)
278 ByteArrayOutputStream buf =
279 new ByteArrayOutputStream((int)(string.length() * 1.5));
280 for (int i = 0; i < string.length(); i++)
282 char c = string.charAt(i);
283 if (c < 0x0080)
284 buf.write(c & 0xFF);
285 else if (c < 0x0800)
287 buf.write(0xC0 | ((c >>> 6) & 0x3F));
288 buf.write(0x80 | (c & 0x3F));
290 else
292 buf.write(0xE0 | ((c >>> 12) & 0x0F));
293 buf.write(0x80 | ((c >>> 6) & 0x3F));
294 buf.write(0x80 | (c & 0x3F));
297 return buf.toByteArray();
300 private static int writeDate(OutputStream out, int tag, Date date)
301 throws IOException
303 SimpleDateFormat sdf = null;
304 if ((tag & 0x1F) == UTC_TIME)
305 sdf = new SimpleDateFormat("yyMMddHHmmss'Z'");
306 else
307 sdf = new SimpleDateFormat("yyyyMMddHHmmss'.'SSS'Z'");
308 sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
309 byte[] b = sdf.format(date).getBytes("ISO-8859-1");
310 writeLength(out, b.length);
311 out.write(b);
312 return b.length;
315 // Package method.
316 // ------------------------------------------------------------------------
318 static void writeLength(OutputStream out, int len) throws IOException
320 if (len < 128)
321 out.write(len);
322 else if (len < 256)
324 out.write(0x81);
325 out.write(len);
327 else if (len < 65536)
329 out.write(0x82);
330 out.write(len >> 8);
331 out.write(len);
333 else if (len < 16777216)
335 out.write(0x83);
336 out.write(len >> 16);
337 out.write(len >> 8);
338 out.write(len);
340 else
342 out.write(0x84);
343 out.write(len >> 24);
344 out.write(len >> 16);
345 out.write(len >> 8);
346 out.write(len);