OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / libcore / luni / src / main / java / org / apache / harmony / security / x501 / AttributeValue.java
1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17
18 /**
19 * @author Alexander V. Esin
20 * @version $Revision$
21 */
22
23 package org.apache.harmony.security.x501;
24
25 import java.io.IOException;
26 import org.apache.harmony.security.asn1.ASN1StringType;
27 import org.apache.harmony.security.asn1.DerInputStream;
28 import org.apache.harmony.security.x509.Utils;
29
30
31 /**
32  * X.501 Attribute Value
33  */
34 public class AttributeValue {
35
36     public final boolean wasEncoded;
37
38     public String escapedString;
39
40     private String hexString;
41
42     private int tag = -1;
43
44     public byte[] encoded;
45
46     public byte[] bytes; //FIXME remove??? bytes to be encoded
47
48     public boolean hasQE; // raw string contains '"' or '\'
49
50     public AttributeValue(String parsedString, boolean hasQorE) {
51
52         wasEncoded = false;
53
54         this.hasQE = hasQorE;
55
56         this.rawString = parsedString;
57         this.escapedString = makeEscaped(rawString);
58     }
59
60     public AttributeValue(String hexString, byte[] encoded) {
61
62         wasEncoded = true;
63
64         this.hexString = hexString;
65         this.encoded = encoded;
66
67         try {
68             DerInputStream in = new DerInputStream(encoded);
69
70             tag = in.tag;
71
72             if (DirectoryString.ASN1.checkTag(tag)) {
73                 // has string representation
74                 this.rawString = (String) DirectoryString.ASN1.decode(in);
75                 this.escapedString = makeEscaped(rawString);
76             } else {
77                 this.rawString = hexString;
78                 this.escapedString = hexString;
79             }
80         } catch (IOException e) {
81             IllegalArgumentException iae = new IllegalArgumentException(); //FIXME message
82             iae.initCause(e);
83             throw iae;
84         }
85     }
86
87     public String rawString;
88
89     public AttributeValue(String rawString, byte[] encoded, int tag) {
90
91         wasEncoded = true;
92
93         this.encoded = encoded;
94         this.tag = tag;
95
96         if (rawString == null) {
97             this.rawString = getHexString();
98             this.escapedString = hexString;
99         } else {
100             this.rawString = rawString;
101             this.escapedString = makeEscaped(rawString);
102         }
103     }
104
105     public int getTag() {
106         if (tag == -1) {
107             if (Utils.isPrintableString(rawString)) {
108                 tag = ASN1StringType.PRINTABLESTRING.id;
109             } else {
110                 tag = ASN1StringType.UTF8STRING.id;
111             }
112         }
113         return tag;
114     }
115
116     public String getHexString() {
117         if (hexString == null) {
118
119             if (!wasEncoded) {
120                 //FIXME optimize me: what about reusable OutputStream???
121                 if (Utils.isPrintableString(rawString)) {
122                     encoded = ASN1StringType.PRINTABLESTRING.encode(rawString);
123                 } else {
124                     encoded = ASN1StringType.UTF8STRING.encode(rawString);
125                 }
126             }
127
128             StringBuilder buf = new StringBuilder(encoded.length * 2 + 1);
129             buf.append('#');
130
131             for (int i = 0, c; i < encoded.length; i++) {
132                 c = (encoded[i] >> 4) & 0x0F;
133                 if (c < 10) {
134                     buf.append((char) (c + 48));
135                 } else {
136                     buf.append((char) (c + 87));
137                 }
138
139                 c = encoded[i] & 0x0F;
140                 if (c < 10) {
141                     buf.append((char) (c + 48));
142                 } else {
143                     buf.append((char) (c + 87));
144                 }
145             }
146             hexString = buf.toString();
147         }
148         return hexString;
149     }
150
151     public void appendQEString(StringBuffer buf) {
152         buf.append('"');
153         if (hasQE) {
154             char c;
155             for (int i = 0; i < rawString.length(); i++) {
156                 c = rawString.charAt(i);
157                 if (c == '"' || c == '\\') {
158                     buf.append('\\');
159                 }
160                 buf.append(c);
161             }
162         } else {
163             buf.append(rawString);
164         }
165         buf.append('"');
166     }
167
168     //
169     // Escapes:
170     // 1) chars ",", "+", """, "\", "<", ">", ";" (RFC 2253)
171     // 2) chars "#", "=" (required by RFC 1779)
172     // 3) a space char at the beginning or end
173     // 4) according to the requirement to be RFC 1779 compatible:
174     //    '#' char is escaped in any position
175     //
176     private String makeEscaped(String name) {
177
178         int length = name.length();
179         if (length == 0) {
180             return name;
181         }
182         StringBuilder buf = new StringBuilder(length * 2);
183
184         for (int index = 0; index < length; index++) {
185
186             char ch = name.charAt(index);
187
188             switch (ch) {
189
190             case ' ':
191                 if (index == 0 || index == (length - 1)) {
192                     // escape first or last space
193                     buf.append('\\');
194                 }
195                 buf.append(' ');
196                 break;
197
198             case '"':
199             case '\\':
200                 hasQE = true;
201
202             case ',':
203             case '+':
204             case '<':
205             case '>':
206             case ';':
207             case '#': // required by RFC 1779
208             case '=': // required by RFC 1779
209                 buf.append('\\');
210
211             default:
212                 buf.append(ch);
213             }
214         }
215
216         return buf.toString();
217     }
218
219     public String makeCanonical() {
220
221         int length = rawString.length();
222         if (length == 0) {
223             return rawString;
224         }
225         StringBuilder buf = new StringBuilder(length * 2);
226
227         int index = 0;
228         if (rawString.charAt(0) == '#') {
229             buf.append('\\');
230             buf.append('#');
231             index++;
232         }
233
234         int bufLength;
235         for (; index < length; index++) {
236
237             char ch = rawString.charAt(index);
238
239             switch (ch) {
240
241             case ' ':
242                 bufLength = buf.length();
243                 if (bufLength == 0 || buf.charAt(bufLength - 1) == ' ') {
244                     break;
245                 }
246                 buf.append(' ');
247                 break;
248
249             case '"':
250             case '\\':
251             case ',':
252             case '+':
253             case '<':
254             case '>':
255             case ';':
256                 buf.append('\\');
257
258             default:
259                 buf.append(ch);
260             }
261         }
262
263         //remove trailing spaces
264         for (bufLength = buf.length() - 1; bufLength > -1
265                 && buf.charAt(bufLength) == ' '; bufLength--) {
266         }
267         buf.setLength(bufLength + 1);
268
269         return buf.toString();
270     }
271 }