1/***
2 * ASM XML Adapter
3 * Copyright (c) 2004, Eugene Kuleshov
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the copyright holders nor the names of its
15 *    contributors may be used to endorse or promote products derived from
16 *    this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28 * THE POSSIBILITY OF SUCH DAMAGE.
29 */
30package org.objectweb.asm.xml;
31
32import org.objectweb.asm.AnnotationVisitor;
33import org.objectweb.asm.Attribute;
34import org.objectweb.asm.ClassVisitor;
35import org.objectweb.asm.TypeAnnotationVisitor;
36import org.objectweb.asm.FieldVisitor;
37import org.objectweb.asm.MethodVisitor;
38import org.objectweb.asm.Opcodes;
39import org.xml.sax.ContentHandler;
40import org.xml.sax.helpers.AttributesImpl;
41
42/**
43 * A {@link org.objectweb.asm.ClassVisitor ClassVisitor} that generates SAX 2.0
44 * events from the visited class. It can feed any kind of
45 * {@link org.xml.sax.ContentHandler ContentHandler}, e.g. XML serializer, XSLT
46 * or XQuery engines.
47 *
48 * @see org.objectweb.asm.xml.Processor
49 * @see org.objectweb.asm.xml.ASMContentHandler
50 *
51 * @author Eugene Kuleshov
52 */
53public final class SAXClassAdapter extends SAXAdapter implements ClassVisitor {
54    private boolean singleDocument;
55
56    /**
57     * Constructs a new {@link SAXClassAdapter SAXClassAdapter} object.
58     *
59     * @param h content handler that will be used to send SAX 2.0 events.
60     * @param singleDocument if <tt>true</tt> adapter will not produce
61     *        {@link ContentHandler#startDocument() startDocument()} and
62     *        {@link ContentHandler#endDocument() endDocument()} events.
63     */
64    public SAXClassAdapter(ContentHandler h, boolean singleDocument) {
65        super(h);
66        this.singleDocument = singleDocument;
67        if (!singleDocument) {
68            addDocumentStart();
69        }
70    }
71
72    public void visitSource(String source, String debug) {
73        if (source == null && debug == null) {
74            return;
75        }
76
77        AttributesImpl att = new AttributesImpl();
78        if (source != null)
79            att.addAttribute("", "file", "file", "", encode(source));
80        if (debug != null)
81            att.addAttribute("", "debug", "debug", "", encode(debug));
82
83        addElement("source", att);
84    }
85
86    public void visitOuterClass(String owner, String name, String desc) {
87        AttributesImpl att = new AttributesImpl();
88        att.addAttribute("", "owner", "owner", "", owner);
89        if (name != null)
90            att.addAttribute("", "name", "name", "", name);
91        if (desc != null)
92            att.addAttribute("", "desc", "desc", "", desc);
93
94        addElement("outerclass", att);
95    }
96
97    public final void visitAttribute(Attribute attr) {
98        // TODO Auto-generated SAXClassAdapter.visitAttribute
99    }
100
101    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
102        return new SAXAnnotationAdapter(getContentHandler(),
103                "annotation",
104                visible ? 1 : -1,
105                null,
106                desc);
107    }
108
109    public TypeAnnotationVisitor visitTypeAnnotation(
110        String desc, boolean visible, boolean inCode) {
111        throw new RuntimeException("Jaime did not implement yet");
112    }
113
114    public void visit(
115        int version,
116        int access,
117        String name,
118        String signature,
119        String superName,
120        String[] interfaces)
121    {
122        StringBuffer sb = new StringBuffer();
123        if ((access & Opcodes.ACC_PUBLIC) != 0)
124            sb.append("public ");
125        if ((access & Opcodes.ACC_PRIVATE) != 0)
126            sb.append("private ");
127        if ((access & Opcodes.ACC_PROTECTED) != 0)
128            sb.append("protected ");
129        if ((access & Opcodes.ACC_FINAL) != 0)
130            sb.append("final ");
131        if ((access & Opcodes.ACC_SUPER) != 0)
132            sb.append("super ");
133        if ((access & Opcodes.ACC_INTERFACE) != 0)
134            sb.append("interface ");
135        if ((access & Opcodes.ACC_ABSTRACT) != 0)
136            sb.append("abstract ");
137        if ((access & Opcodes.ACC_SYNTHETIC) != 0)
138            sb.append("synthetic ");
139        if ((access & Opcodes.ACC_ANNOTATION) != 0)
140            sb.append("annotation ");
141        if ((access & Opcodes.ACC_ENUM) != 0)
142            sb.append("enum ");
143        if ((access & Opcodes.ACC_DEPRECATED) != 0)
144            sb.append("deprecated ");
145
146        AttributesImpl att = new AttributesImpl();
147        att.addAttribute("", "access", "access", "", sb.toString());
148        if (name != null)
149            att.addAttribute("", "name", "name", "", name);
150        if (signature != null)
151            att.addAttribute("",
152                    "signature",
153                    "signature",
154                    "",
155                    encode(signature));
156        if (superName != null)
157            att.addAttribute("", "parent", "parent", "", superName);
158        att.addAttribute("",
159                "major",
160                "major",
161                "",
162                Integer.toString(version & 0xFFFF));
163        att.addAttribute("",
164                "minor",
165                "minor",
166                "",
167                Integer.toString(version >>> 16));
168        addStart("class", att);
169
170        addStart("interfaces", new AttributesImpl());
171        if (interfaces != null && interfaces.length > 0) {
172            for (int i = 0; i < interfaces.length; i++) {
173                AttributesImpl att2 = new AttributesImpl();
174                att2.addAttribute("", "name", "name", "", interfaces[i]);
175                addElement("interface", att2);
176            }
177        }
178        addEnd("interfaces");
179    }
180
181    public FieldVisitor visitField(
182        int access,
183        String name,
184        String desc,
185        String signature,
186        Object value)
187    {
188        StringBuffer sb = new StringBuffer();
189        if ((access & Opcodes.ACC_PUBLIC) != 0)
190            sb.append("public ");
191        if ((access & Opcodes.ACC_PRIVATE) != 0)
192            sb.append("private ");
193        if ((access & Opcodes.ACC_PROTECTED) != 0)
194            sb.append("protected ");
195        if ((access & Opcodes.ACC_STATIC) != 0)
196            sb.append("static ");
197        if ((access & Opcodes.ACC_FINAL) != 0)
198            sb.append("final ");
199        if ((access & Opcodes.ACC_VOLATILE) != 0)
200            sb.append("volatile ");
201        if ((access & Opcodes.ACC_TRANSIENT) != 0)
202            sb.append("transient ");
203        if ((access & Opcodes.ACC_SYNTHETIC) != 0)
204            sb.append("synthetic ");
205        if ((access & Opcodes.ACC_ENUM) != 0)
206            sb.append("enum ");
207        if ((access & Opcodes.ACC_DEPRECATED) != 0)
208            sb.append("deprecated ");
209
210        AttributesImpl att = new AttributesImpl();
211        att.addAttribute("", "access", "access", "", sb.toString());
212        att.addAttribute("", "name", "name", "", name);
213        att.addAttribute("", "desc", "desc", "", desc);
214        if (signature != null)
215            att.addAttribute("",
216                    "signature",
217                    "signature",
218                    "",
219                    encode(signature));
220        if (value != null) {
221            att.addAttribute("", "value", "value", "", encode(value.toString()));
222        }
223
224        return new SAXFieldAdapter(getContentHandler(), att);
225    }
226
227    public MethodVisitor visitMethod(
228        int access,
229        String name,
230        String desc,
231        String signature,
232        String[] exceptions)
233    {
234        StringBuffer sb = new StringBuffer();
235        if ((access & Opcodes.ACC_PUBLIC) != 0)
236            sb.append("public ");
237        if ((access & Opcodes.ACC_PRIVATE) != 0)
238            sb.append("private ");
239        if ((access & Opcodes.ACC_PROTECTED) != 0)
240            sb.append("protected ");
241        if ((access & Opcodes.ACC_STATIC) != 0)
242            sb.append("static ");
243        if ((access & Opcodes.ACC_FINAL) != 0)
244            sb.append("final ");
245        if ((access & Opcodes.ACC_SYNCHRONIZED) != 0)
246            sb.append("synchronized ");
247        if ((access & Opcodes.ACC_BRIDGE) != 0)
248            sb.append("bridge ");
249        if ((access & Opcodes.ACC_VARARGS) != 0)
250            sb.append("varargs ");
251        if ((access & Opcodes.ACC_NATIVE) != 0)
252            sb.append("native ");
253        if ((access & Opcodes.ACC_ABSTRACT) != 0)
254            sb.append("abstract ");
255        if ((access & Opcodes.ACC_STRICT) != 0)
256            sb.append("strict ");
257        if ((access & Opcodes.ACC_SYNTHETIC) != 0)
258            sb.append("synthetic ");
259        if ((access & Opcodes.ACC_DEPRECATED) != 0)
260            sb.append("deprecated ");
261
262        AttributesImpl att = new AttributesImpl();
263        att.addAttribute("", "access", "access", "", sb.toString());
264        att.addAttribute("", "name", "name", "", name);
265        att.addAttribute("", "desc", "desc", "", desc);
266        if (signature != null) {
267            att.addAttribute("", "signature", "signature", "", signature);
268        }
269        addStart("method", att);
270
271        addStart("exceptions", new AttributesImpl());
272        if (exceptions != null && exceptions.length > 0) {
273            for (int i = 0; i < exceptions.length; i++) {
274                AttributesImpl att2 = new AttributesImpl();
275                att2.addAttribute("", "name", "name", "", exceptions[i]);
276                addElement("exception", att2);
277            }
278        }
279        addEnd("exceptions");
280
281        return new SAXCodeAdapter(getContentHandler(), access);
282    }
283
284    public final void visitInnerClass(
285        String name,
286        String outerName,
287        String innerName,
288        int access)
289    {
290        StringBuffer sb = new StringBuffer();
291        if ((access & Opcodes.ACC_PUBLIC) != 0)
292            sb.append("public ");
293        if ((access & Opcodes.ACC_PRIVATE) != 0)
294            sb.append("private ");
295        if ((access & Opcodes.ACC_PROTECTED) != 0)
296            sb.append("protected ");
297        if ((access & Opcodes.ACC_STATIC) != 0)
298            sb.append("static ");
299        if ((access & Opcodes.ACC_FINAL) != 0)
300            sb.append("final ");
301        if ((access & Opcodes.ACC_SUPER) != 0)
302            sb.append("super ");
303        if ((access & Opcodes.ACC_INTERFACE) != 0)
304            sb.append("interface ");
305        if ((access & Opcodes.ACC_ABSTRACT) != 0)
306            sb.append("abstract ");
307        if ((access & Opcodes.ACC_SYNTHETIC) != 0)
308            sb.append("synthetic ");
309        if ((access & Opcodes.ACC_ANNOTATION) != 0)
310            sb.append("annotation ");
311        if ((access & Opcodes.ACC_ENUM) != 0)
312            sb.append("enum ");
313        if ((access & Opcodes.ACC_DEPRECATED) != 0)
314            sb.append("deprecated ");
315
316        AttributesImpl att = new AttributesImpl();
317        att.addAttribute("", "access", "access", "", sb.toString());
318        if (name != null)
319            att.addAttribute("", "name", "name", "", name);
320        if (outerName != null)
321            att.addAttribute("", "outerName", "outerName", "", outerName);
322        if (innerName != null)
323            att.addAttribute("", "innerName", "innerName", "", innerName);
324        addElement("innerclass", att);
325    }
326
327    public final void visitEnd() {
328        addEnd("class");
329        if (!singleDocument) {
330            addDocumentEnd();
331        }
332    }
333
334    static final String encode(String s) {
335        StringBuffer sb = new StringBuffer();
336        for (int i = 0; i < s.length(); i++) {
337            char c = s.charAt(i);
338            if (c == '\\') {
339                sb.append("\\\\");
340            } else if (c < 0x20 || c > 0x7f) {
341                sb.append("\\u");
342                if (c < 0x10) {
343                    sb.append("000");
344                } else if (c < 0x100) {
345                    sb.append("00");
346                } else if (c < 0x1000) {
347                    sb.append("0");
348                }
349                sb.append(Integer.toString(c, 16));
350            } else {
351                sb.append(c);
352            }
353        }
354        return sb.toString();
355    }
356
357}
358