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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 * @author Alexander V. Esin
23 package org.apache.harmony.security.x501;
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;
32 * X.501 Attribute Value
34 public class AttributeValue {
36 public final boolean wasEncoded;
38 public String escapedString;
40 private String hexString;
44 public byte[] encoded;
46 public byte[] bytes; //FIXME remove??? bytes to be encoded
48 public boolean hasQE; // raw string contains '"' or '\'
50 public AttributeValue(String parsedString, boolean hasQorE) {
56 this.rawString = parsedString;
57 this.escapedString = makeEscaped(rawString);
60 public AttributeValue(String hexString, byte[] encoded) {
64 this.hexString = hexString;
65 this.encoded = encoded;
68 DerInputStream in = new DerInputStream(encoded);
72 if (DirectoryString.ASN1.checkTag(tag)) {
73 // has string representation
74 this.rawString = (String) DirectoryString.ASN1.decode(in);
75 this.escapedString = makeEscaped(rawString);
77 this.rawString = hexString;
78 this.escapedString = hexString;
80 } catch (IOException e) {
81 IllegalArgumentException iae = new IllegalArgumentException(); //FIXME message
87 public String rawString;
89 public AttributeValue(String rawString, byte[] encoded, int tag) {
93 this.encoded = encoded;
96 if (rawString == null) {
97 this.rawString = getHexString();
98 this.escapedString = hexString;
100 this.rawString = rawString;
101 this.escapedString = makeEscaped(rawString);
105 public int getTag() {
107 if (Utils.isPrintableString(rawString)) {
108 tag = ASN1StringType.PRINTABLESTRING.id;
110 tag = ASN1StringType.UTF8STRING.id;
116 public String getHexString() {
117 if (hexString == null) {
120 //FIXME optimize me: what about reusable OutputStream???
121 if (Utils.isPrintableString(rawString)) {
122 encoded = ASN1StringType.PRINTABLESTRING.encode(rawString);
124 encoded = ASN1StringType.UTF8STRING.encode(rawString);
128 StringBuilder buf = new StringBuilder(encoded.length * 2 + 1);
131 for (int i = 0, c; i < encoded.length; i++) {
132 c = (encoded[i] >> 4) & 0x0F;
134 buf.append((char) (c + 48));
136 buf.append((char) (c + 87));
139 c = encoded[i] & 0x0F;
141 buf.append((char) (c + 48));
143 buf.append((char) (c + 87));
146 hexString = buf.toString();
151 public void appendQEString(StringBuffer buf) {
155 for (int i = 0; i < rawString.length(); i++) {
156 c = rawString.charAt(i);
157 if (c == '"' || c == '\\') {
163 buf.append(rawString);
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
176 private String makeEscaped(String name) {
178 int length = name.length();
182 StringBuilder buf = new StringBuilder(length * 2);
184 for (int index = 0; index < length; index++) {
186 char ch = name.charAt(index);
191 if (index == 0 || index == (length - 1)) {
192 // escape first or last space
207 case '#': // required by RFC 1779
208 case '=': // required by RFC 1779
216 return buf.toString();
219 public String makeCanonical() {
221 int length = rawString.length();
225 StringBuilder buf = new StringBuilder(length * 2);
228 if (rawString.charAt(0) == '#') {
235 for (; index < length; index++) {
237 char ch = rawString.charAt(index);
242 bufLength = buf.length();
243 if (bufLength == 0 || buf.charAt(bufLength - 1) == ' ') {
263 //remove trailing spaces
264 for (bufLength = buf.length() - 1; bufLength > -1
265 && buf.charAt(bufLength) == ' '; bufLength--) {
267 buf.setLength(bufLength + 1);
269 return buf.toString();