001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package javax.swing.text.html.parser;
019:
020: import java.io.IOException;
021: import java.math.BigInteger;
022: import java.util.ArrayList;
023: import java.util.BitSet;
024: import java.util.Iterator;
025: import java.util.List;
026:
027: import org.apache.harmony.security.asn1.ASN1Boolean;
028: import org.apache.harmony.security.asn1.ASN1Implicit;
029: import org.apache.harmony.security.asn1.ASN1Integer;
030: import org.apache.harmony.security.asn1.ASN1Sequence;
031: import org.apache.harmony.security.asn1.ASN1SetOf;
032: import org.apache.harmony.security.asn1.ASN1StringType;
033: import org.apache.harmony.security.asn1.ASN1Type;
034: import org.apache.harmony.security.asn1.BerInputStream;
035:
036: /**
037: * It implements ASN.1 codification tools for
038: * <code>javax.swing.text.html.parser.Element</code>. Given an
039: * <code>Element</code>, its values are codified in ASN.1 according to the
040: * following rule:
041: *
042: * <pre>
043: * HTMLElement ::= SEQUENCE {
044: * index INTEGER,
045: * name UTF8String,
046: * type INTEGER,
047: * oStart BOOLEAN,
048: * oEnd BOOLEAN,
049: * exclusions [0] IMPLICIT SET OF INTEGER OPTIONAL,
050: * inclusions [1] IMPLICIT SET OF INTEGER OPTIONAL,
051: * attributes SET OF HTMLElementAttributes OPTIONAL,
052: * contentModel HTMLContentModel
053: * }
054: * </pre>
055: *
056: * The class can be used to obtain a byte array representing the codification of
057: * an <code>Element</code>, as well as an <code>Element</code> from a byte
058: * array (previously obtained codifying an <code>Element</code>). In fact, it
059: * serves as a wrapper for the codification and the <code>Element</code>
060: * itself.
061: */
062: class Asn1Element {
063:
064: /**
065: * It stores the definition of an <code>Element</code> as an ASN.1 valid
066: * type according to the ASN.1 framework.
067: */
068: private static ASN1Type ASN1_ELEMENT;
069:
070: /**
071: * The definition of the ASN1_ELEMENT type according to the rule defined for
072: * an <code>Element</code>. It also defines a custom encoder/decoder for
073: * this type.
074: */
075: static {
076: ASN1_ELEMENT = new ASN1Sequence(new ASN1Type[] {
077: ASN1Integer.getInstance(), // 0 Index
078: ASN1StringType.UTF8STRING, // 1 Name
079: ASN1Integer.getInstance(), // 2 Type
080: ASN1Boolean.getInstance(), // 3 OStart
081: ASN1Boolean.getInstance(), // 4 OEnd
082: new ASN1Implicit(0, new ASN1SetOf(ASN1Integer
083: .getInstance())), // 5 Exclusions
084: new ASN1Implicit(1, new ASN1SetOf(ASN1Integer
085: .getInstance())), // 6 Inclusions
086: new ASN1SetOf(Asn1Attributes.getInstance()), // 7 Attributes
087: Asn1ContentModel.getInstance() // 8 ContentModel
088: }) {
089:
090: {
091: setOptional(5); // Exclusions Optional
092: setOptional(6); // Inclusions Optional
093: setOptional(7); // Attributes Optional
094: }
095:
096: /**
097: * Overrided method used to decodified the information that
098: * represents an <code>Element</code>. It makes a completely new
099: * <code>Element</code> with the information interpreted from the
100: * stream.
101: * <p>
102: * Note that the data field is ignored, and thus always set to null.
103: *
104: * @param in
105: * The <code>BerInputStream</code> where the
106: * codificated information will be read from.
107: * @return An <code>Element</code> filled with the information
108: * read from the stream.
109: */
110: public Object getDecodedObject(BerInputStream in) {
111: Object values[] = (Object[]) in.content;
112:
113: int index = new BigInteger((byte[]) values[0])
114: .intValue();
115: String name = (String) values[1];
116: int type = new BigInteger((byte[]) values[2])
117: .intValue();
118: boolean oStart = ((Boolean) values[3]).booleanValue();
119: boolean oEnd = ((Boolean) values[4]).booleanValue();
120: BitSet exclusions = values[5] != null ? list2bitset(((List) values[5]))
121: : null;
122: BitSet inclusions = values[6] != null ? list2bitset(((List) values[6]))
123: : null;
124: AttributeList att = values[7] != null ? list2att((List) values[7])
125: : null;
126: ContentModel model = values[8] == null ? null
127: : ((ContentModel) values[8]);
128:
129: // XXX data is always null, we ignore it
130: return new Element(index, name, oStart, oEnd,
131: exclusions, inclusions, type, model, att, null);
132: }
133:
134: /**
135: * Overrided method used to codify the information stored in an
136: * <code>Element</code> into an array of bytes, according to its
137: * ASN.1 specification.
138: * <p>
139: * Note that the <code>data</code> field is not taken in
140: * consideration.
141: *
142: * @param object
143: * The object where the information to be codified is
144: * stored. It actually consists of an
145: * <code>Asn1Element</code> object which contains the
146: * <code>Element</code> to be codified.
147: *
148: * @param values
149: * An array of objects where the element's index, name,
150: * type, omitting properties, attribute list, element
151: * inclusions and exclusions and its content model
152: * information will be stored, ready for codification.
153: */
154: public void getValues(Object object, Object values[]) {
155: Asn1Element asn1 = (Asn1Element) object;
156:
157: try {
158: values[0] = BigInteger.valueOf(
159: asn1.getElement().getIndex()).toByteArray(); // Index
160: values[1] = asn1.getElement().getName(); // Name
161: values[2] = BigInteger.valueOf(
162: asn1.getElement().getType()).toByteArray(); // Type
163: values[3] = Boolean.valueOf(asn1.getElement()
164: .omitStart()); // OStart
165: values[4] = Boolean.valueOf(asn1.getElement()
166: .omitEnd()); // OEnd
167: values[5] = asn1.getElement().exclusions != null ? // Exclusions
168: bitset2list(asn1.getElement().exclusions)
169: : new ArrayList();
170: values[6] = asn1.getElement().inclusions != null ? // Inclusions
171: bitset2list(asn1.getElement().inclusions)
172: : new ArrayList();
173: values[7] = asn1.getElement().getAttributes() != null ? // AttributeList
174: att2list(asn1.getElement().getAttributes())
175: : null;
176: values[8] = new Asn1ContentModel(asn1.getElement()
177: .getContent());
178:
179: } catch (IOException e) {
180: throw new AssertionError(e); // this should not happen
181: }
182: }
183: };
184: }
185:
186: /**
187: * It returns an <code>ASN1Type</code> value that contains the ASN.1
188: * codification rules for an <code>Element</code> with its encoder and
189: * decoder.
190: * <p>
191: * Among other things, this method can be used to declare the types of new
192: * fields in other structures, as for example, in an <code>Asn1DTD</code>.
193: *
194: * @return The value that defines an ASN.1 <code>Element</code>
195: * representation with its encoder/decoder.
196: */
197: static ASN1Type getInstance() {
198: return ASN1_ELEMENT;
199: }
200:
201: /**
202: * An internal copy of the <code>Element</code> to be codified.
203: */
204: private Element element;
205:
206: /**
207: * An internal copy of the byte array which contains the codification of an
208: * <code>Element</code>. From this variable, the information used to
209: * decodify an <code>Element</code> is read from.
210: */
211: private byte[] encoded;
212:
213: /**
214: * Constructs a new instance of an <code>Asn1Element</code> class from a
215: * byte array. The byte array received as argument can be later decodified
216: * into an <code>Element</code>.
217: *
218: * @param encoded
219: * A byte array containing the codified information of an
220: * <code>Element</code>.
221: */
222: public Asn1Element(byte[] encoded) {
223: byte[] copy = new byte[encoded.length];
224: System.arraycopy(encoded, 0, copy, 0, copy.length);
225: this .encoded = copy;
226: }
227:
228: /**
229: * Constructs a new instance of an <code>Asn1Element</code> class from an
230: * <code>Element</code>. The <code>Element</code> received as argument
231: * can be then codified into a byte array.
232: * <p>
233: * The value received as argument should not be null. If so, a
234: * <code>NullPointerException</code> is thrown.
235: *
236: * @param element
237: * The <code>Element</code> to be codified.
238: */
239: public Asn1Element(Element element) {
240: if (element == null) {
241: throw new NullPointerException();
242: }
243: this .element = element;
244: }
245:
246: /**
247: * Returns the representation of an <code>Element</code> in ASN.1
248: * codification.
249: * <p>
250: * If the <code >Asn1Element</code> object was created with an
251: * <code>Element</code>, then the <code>Element</code> is codified and
252: * returned as a byte array. On the other hand, if the instance was created
253: * using a byte array, then no codification process is made.
254: *
255: * @return If at construction time an <code>Element</code> was given, its
256: * representation in ASN.1 codification. If at construction time a
257: * byte array was given, a copy of the same array is returned.
258: */
259: public byte[] getEncoded() {
260: if (encoded == null) {
261: return ASN1_ELEMENT.encode(element);
262: } else {
263: return encoded;
264: }
265: }
266:
267: /**
268: * Returns the <code>Element</code> obtained from the decodification of an
269: * ASN.1 codified byte array.
270: * <p>
271: * If the <code>Asn1Element</code> was created giving an
272: * <code>Element</code>, a reference to the same <code>Element</code>
273: * is obtained. Otherwise, the byte array given at construction time is
274: * decodificated into a new <code>Element</code> object.
275: *
276: * @return If at construction time an <code>Element</code> was given, the
277: * same <code>Element</code> is returned. If at construction time
278: * a byte array was given, an <code>Element</code> constructed
279: * with the information stored in that byte array is returned.
280: * @throws IOException
281: * If the decodification process could not be carried out
282: * properly.
283: */
284: public Element getElement() throws IOException {
285: if (element == null) {
286: return (Element) ASN1_ELEMENT.decode(encoded);
287: } else {
288: return element;
289: }
290: }
291:
292: /**
293: * Converts an <code>AttributeList</code> into a <code>List</code>.
294: *
295: * @param att
296: * The <code>AttributeList</code> to be converted.
297: * @return A <code>List</code> with the same nodes that composed the
298: * <code>AttributeList</code>, ordered by the
299: * <code>AttributeList</code>'s next field.
300: */
301: private static List att2list(AttributeList att) {
302: ArrayList<Asn1Attributes> lstAttribute = new ArrayList<Asn1Attributes>();
303: for (AttributeList attNext = att; attNext != null; attNext = attNext
304: .getNext()) {
305: lstAttribute.add(new Asn1Attributes(attNext));
306: }
307: return lstAttribute;
308: }
309:
310: /**
311: * Converts a <code>List</code> into an <code>AttributeList</code>
312: *
313: * @param lst
314: * The <code>List</code> to be converted.
315: * @return An <code>AttributeList</code> made of the nodes contained in
316: * the <code>List</code> given as argument. The
317: * <code>AttributeList</code>'s <code>next</code> field is set
318: * according to <code>List</code> order.
319: */
320: private static AttributeList list2att(List lst) {
321: AttributeList attReturn;
322: attReturn = (AttributeList) lst.get(0);
323: for (int i = 0; i < lst.size(); i++) {
324: AttributeList first = (AttributeList) lst.get(i);
325: if (i != lst.size() - 1) { // last element ?
326: AttributeList second = (AttributeList) lst.get(i + 1);
327: first.next = second;
328: }
329: }
330: return attReturn;
331: }
332:
333: /**
334: * Converts a <code>BitSet</code> into a <code>List</code> of
335: * <code>byte[]</code>. The elements that compose the <code>List</code>
336: * are actually byte arrays that represents the values of the
337: * <code>BitSet</code> which were set.
338: * <p>
339: * For example, if the <code>BitSet</code> has its <code>i</code>
340: * position set, then the <code>List</code> will contain as element the
341: * value: <code>BigInteger.valueOf(i).toByteArray()</code>.
342: *
343: * @param bs
344: * The <code>BitSet</code> to be converted.
345: * @return A <code>List</code> with each of the <code>BitSet</code>
346: * values which were set, codified as a byte array.
347: */
348: private static List bitset2list(BitSet bs) {
349: ArrayList<byte[]> lst = new ArrayList<byte[]>();
350: for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) {
351: lst.add(BigInteger.valueOf(i).toByteArray());
352: }
353: return lst;
354: }
355:
356: /**
357: * Converts a <code>List</code> of <code>byte[]</code> into a
358: * <code>BitSet</code>.
359: * <p>
360: * The byte array contained into the <code>List</code> are representations
361: * of the values which should be set in the <code>BitSet</code>.
362: *
363: * @param lst
364: * The <code>List</code> of <code>byte[]</code> to be
365: * converted.
366: * @return A <code>BitSet</code> with the values specified by the nodes of
367: * the <code>List</code>.
368: */
369: private static BitSet list2bitset(List lst) {
370: BitSet bs = null;
371: if (!lst.isEmpty()) {
372: bs = new BitSet();
373: }
374: for (Iterator iter = lst.iterator(); iter.hasNext();) {
375: byte[] element = (byte[]) iter.next();
376: BigInteger bi = new BigInteger(element);
377: bs.set(bi.intValue());
378: }
379: return bs;
380: }
381: }
|