001    /*
002     * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
003     * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004     *
005     * This code is free software; you can redistribute it and/or modify it
006     * under the terms of the GNU General Public License version 2 only, as
007     * published by the Free Software Foundation.  Sun designates this
008     * particular file as subject to the "Classpath" exception as provided
009     * by Sun in the LICENSE file that accompanied this code.
010     *
011     * This code is distributed in the hope that it will be useful, but WITHOUT
012     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013     * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014     * version 2 for more details (a copy is included in the LICENSE file that
015     * accompanied this code).
016     *
017     * You should have received a copy of the GNU General Public License version
018     * 2 along with this work; if not, write to the Free Software Foundation,
019     * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020     *
021     * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022     * CA 95054 USA or visit www.sun.com if you need additional information or
023     * have any questions.
024     */
025    
026    package com.sun.tools.classfile;
027    
028    import com.sun.tools.classfile.ConstantPool.CONSTANT_Class_info;
029    import com.sun.tools.classfile.ConstantPool.CONSTANT_Double_info;
030    import com.sun.tools.classfile.ConstantPool.CONSTANT_Fieldref_info;
031    import com.sun.tools.classfile.ConstantPool.CONSTANT_Float_info;
032    import com.sun.tools.classfile.ConstantPool.CONSTANT_Integer_info;
033    import com.sun.tools.classfile.ConstantPool.CONSTANT_InterfaceMethodref_info;
034    import com.sun.tools.classfile.ConstantPool.CONSTANT_Long_info;
035    import com.sun.tools.classfile.ConstantPool.CONSTANT_Methodref_info;
036    import com.sun.tools.classfile.ConstantPool.CONSTANT_NameAndType_info;
037    import com.sun.tools.classfile.ConstantPool.CONSTANT_String_info;
038    import com.sun.tools.classfile.ConstantPool.CONSTANT_Utf8_info;
039    import com.sun.tools.classfile.ConstantPool.CPInfo;
040    import java.util.Map;
041    
042    /**
043     * Rewrites a class file using a map of translations.
044     *
045     *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
046     *  you write code that depends on this, you do so at your own risk.
047     *  This code and its internal interfaces are subject to change or
048     *  deletion without notice.</b>
049     */
050    public class ClassTranslator
051            implements ConstantPool.Visitor<ConstantPool.CPInfo,Map<Object,Object>> {
052        /**
053         * Create a new ClassFile from {@code cf}, such that for all entries
054         * {@code k&nbsp;-\&gt;&nbsp;v} in {@code translations},
055         * each occurrence of {@code k} in {@code cf} will be replaced by {@code v}.
056         * in
057         * @param cf the class file to be processed
058         * @param translations the set of translations to be applied
059         * @return a copy of {@code} with the values in {@code translations} substituted
060         */
061        public ClassFile translate(ClassFile cf, Map<Object,Object> translations) {
062            ClassFile cf2 = (ClassFile) translations.get(cf);
063            if (cf2 == null) {
064                ConstantPool constant_pool2 = translate(cf.constant_pool, translations);
065                Field[] fields2 = translate(cf.fields, cf.constant_pool, translations);
066                Method[] methods2 = translateMethods(cf.methods, cf.constant_pool, translations);
067                Attributes attributes2 = translateAttributes(cf.attributes, cf.constant_pool,
068                        translations);
069    
070                if (constant_pool2 == cf.constant_pool &&
071                        fields2 == cf.fields &&
072                        methods2 == cf.methods &&
073                        attributes2 == cf.attributes)
074                    cf2 = cf;
075                else
076                    cf2 = new ClassFile(
077                            cf.magic,
078                            cf.minor_version,
079                            cf.major_version,
080                            constant_pool2,
081                            cf.access_flags,
082                            cf.this_class,
083                            cf.super_class,
084                            cf.interfaces,
085                            fields2,
086                            methods2,
087                            attributes2);
088                translations.put(cf, cf2);
089            }
090            return cf2;
091        }
092    
093        ConstantPool translate(ConstantPool cp, Map<Object,Object> translations) {
094            ConstantPool cp2 = (ConstantPool) translations.get(cp);
095            if (cp2 == null) {
096                ConstantPool.CPInfo[] pool2 = new ConstantPool.CPInfo[cp.size()];
097                boolean eq = true;
098                for (int i = 0; i < cp.size(); i++) {
099                    ConstantPool.CPInfo cpInfo;
100                    try {
101                        cpInfo = cp.get(i);
102                    } catch (ConstantPool.InvalidIndex e) {
103                        throw new IllegalStateException(e);
104                    }
105                    ConstantPool.CPInfo cpInfo2 = translate(cpInfo, translations);
106                    eq &= (cpInfo == cpInfo2);
107                    pool2[i] = cpInfo2;
108                    if (cpInfo.getTag() != cpInfo2.getTag())
109                        throw new IllegalStateException();
110                    switch (cpInfo.getTag()) {
111                        case ConstantPool.CONSTANT_Double:
112                        case ConstantPool.CONSTANT_Long:
113                            i += 1;
114                    }
115                }
116    
117                if (eq)
118                    cp2 = cp;
119                else
120                    cp2 = new ConstantPool(pool2);
121    
122                translations.put(cp, cp2);
123            }
124            return cp2;
125        }
126    
127        ConstantPool.CPInfo translate(ConstantPool.CPInfo cpInfo, Map<Object,Object> translations) {
128            ConstantPool.CPInfo cpInfo2 = (ConstantPool.CPInfo) translations.get(cpInfo);
129            if (cpInfo2 == null) {
130                cpInfo2 = cpInfo.accept(this, translations);
131                translations.put(cpInfo, cpInfo2);
132            }
133            return cpInfo2;
134        }
135    
136        Field[] translate(Field[] fields, ConstantPool constant_pool, Map<Object,Object> translations) {
137            Field[] fields2 = (Field[]) translations.get(fields);
138            if (fields2 == null) {
139                fields2 = new Field[fields.length];
140                for (int i = 0; i < fields.length; i++)
141                    fields2[i] = translate(fields[i], constant_pool, translations);
142                if (equal(fields, fields2))
143                    fields2 = fields;
144                translations.put(fields, fields2);
145            }
146            return fields2;
147        }
148    
149        Field translate(Field field, ConstantPool constant_pool, Map<Object,Object> translations) {
150            Field field2 = (Field) translations.get(field);
151            if (field2 == null) {
152                Attributes attributes2 = translateAttributes(field.attributes, constant_pool,
153                        translations);
154    
155                if (attributes2 == field.attributes)
156                    field2 = field;
157                else
158                    field2 = new Field(
159                            field.access_flags,
160                            field.name_index,
161                            field.descriptor,
162                            attributes2);
163                translations.put(field, field2);
164            }
165            return field2;
166        }
167    
168        Method[] translateMethods(Method[] methods, ConstantPool constant_pool, Map<Object,Object> translations) {
169            Method[] methods2 = (Method[]) translations.get(methods);
170            if (methods2 == null) {
171                methods2 = new Method[methods.length];
172                for (int i = 0; i < methods.length; i++)
173                    methods2[i] = translate(methods[i], constant_pool, translations);
174                if (equal(methods, methods2))
175                    methods2 = methods;
176                translations.put(methods, methods2);
177            }
178            return methods2;
179        }
180    
181        Method translate(Method method, ConstantPool constant_pool, Map<Object,Object> translations) {
182            Method method2 = (Method) translations.get(method);
183            if (method2 == null) {
184                Attributes attributes2 = translateAttributes(method.attributes, constant_pool,
185                        translations);
186    
187                if (attributes2 == method.attributes)
188                    method2 = method;
189                else
190                    method2 = new Method(
191                            method.access_flags,
192                            method.name_index,
193                            method.descriptor,
194                            attributes2);
195                translations.put(method, method2);
196            }
197            return method2;
198        }
199    
200        Attributes translateAttributes(Attributes attributes,
201                ConstantPool constant_pool, Map<Object,Object> translations) {
202            Attributes attributes2 = (Attributes) translations.get(attributes);
203            if (attributes2 == null) {
204                Attribute[] attrArray2 = new Attribute[attributes.size()];
205                ConstantPool constant_pool2 = translate(constant_pool, translations);
206                boolean attrsEqual = true;
207                for (int i = 0; i < attributes.size(); i++) {
208                    Attribute attr = attributes.get(i);
209                    Attribute attr2 = translate(attr, translations);
210                    if (attr2 != attr)
211                        attrsEqual = false;
212                    attrArray2[i] = attr2;
213                }
214                if ((constant_pool2 == constant_pool) && attrsEqual)
215                    attributes2 = attributes;
216                else
217                    attributes2 = new Attributes(constant_pool2, attrArray2);
218                translations.put(attributes, attributes2);
219            }
220            return attributes2;
221        }
222    
223        Attribute translate(Attribute attribute, Map<Object,Object> translations) {
224            Attribute attribute2 = (Attribute) translations.get(attribute);
225            if (attribute2 == null) {
226                attribute2 = attribute; // don't support translation within attributes yet
227                                        // (what about Code attribute)
228                translations.put(attribute, attribute2);
229            }
230            return attribute2;
231        }
232    
233        private static <T> boolean equal(T[] a1, T[] a2) {
234            if (a1 == null || a2 == null)
235                return (a1 == a2);
236            if (a1.length != a2.length)
237                return false;
238            for (int i = 0; i < a1.length; i++) {
239                if (a1[i] != a2[i])
240                    return false;
241            }
242            return true;
243        }
244    
245        public CPInfo visitClass(CONSTANT_Class_info info, Map<Object, Object> translations) {
246            CONSTANT_Class_info info2 = (CONSTANT_Class_info) translations.get(info);
247            if (info2 == null) {
248                ConstantPool cp2 = translate(info.cp, translations);
249                if (cp2 == info.cp)
250                    info2 = info;
251                else
252                    info2 = new CONSTANT_Class_info(cp2, info.name_index);
253                translations.put(info, info2);
254            }
255            return info;
256        }
257    
258        public CPInfo visitDouble(CONSTANT_Double_info info, Map<Object, Object> translations) {
259            CONSTANT_Double_info info2 = (CONSTANT_Double_info) translations.get(info);
260            if (info2 == null) {
261                info2 = info;
262                translations.put(info, info2);
263            }
264            return info;
265        }
266    
267        public CPInfo visitFieldref(CONSTANT_Fieldref_info info, Map<Object, Object> translations) {
268            CONSTANT_Fieldref_info info2 = (CONSTANT_Fieldref_info) translations.get(info);
269            if (info2 == null) {
270                ConstantPool cp2 = translate(info.cp, translations);
271                if (cp2 == info.cp)
272                    info2 = info;
273                else
274                    info2 = new CONSTANT_Fieldref_info(cp2, info.class_index, info.name_and_type_index);
275                translations.put(info, info2);
276            }
277            return info;
278        }
279    
280        public CPInfo visitFloat(CONSTANT_Float_info info, Map<Object, Object> translations) {
281            CONSTANT_Float_info info2 = (CONSTANT_Float_info) translations.get(info);
282            if (info2 == null) {
283                info2 = info;
284                translations.put(info, info2);
285            }
286            return info;
287        }
288    
289        public CPInfo visitInteger(CONSTANT_Integer_info info, Map<Object, Object> translations) {
290            CONSTANT_Integer_info info2 = (CONSTANT_Integer_info) translations.get(info);
291            if (info2 == null) {
292                info2 = info;
293                translations.put(info, info2);
294            }
295            return info;
296        }
297    
298        public CPInfo visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, Map<Object, Object> translations) {
299            CONSTANT_InterfaceMethodref_info info2 = (CONSTANT_InterfaceMethodref_info) translations.get(info);
300            if (info2 == null) {
301                ConstantPool cp2 = translate(info.cp, translations);
302                if (cp2 == info.cp)
303                    info2 = info;
304                else
305                    info2 = new CONSTANT_InterfaceMethodref_info(cp2, info.class_index, info.name_and_type_index);
306                translations.put(info, info2);
307            }
308            return info;
309        }
310    
311        public CPInfo visitLong(CONSTANT_Long_info info, Map<Object, Object> translations) {
312            CONSTANT_Long_info info2 = (CONSTANT_Long_info) translations.get(info);
313            if (info2 == null) {
314                info2 = info;
315                translations.put(info, info2);
316            }
317            return info;
318        }
319    
320        public CPInfo visitNameAndType(CONSTANT_NameAndType_info info, Map<Object, Object> translations) {
321            CONSTANT_NameAndType_info info2 = (CONSTANT_NameAndType_info) translations.get(info);
322            if (info2 == null) {
323                ConstantPool cp2 = translate(info.cp, translations);
324                if (cp2 == info.cp)
325                    info2 = info;
326                else
327                    info2 = new CONSTANT_NameAndType_info(cp2, info.name_index, info.type_index);
328                translations.put(info, info2);
329            }
330            return info;
331        }
332    
333        public CPInfo visitMethodref(CONSTANT_Methodref_info info, Map<Object, Object> translations) {
334            CONSTANT_Methodref_info info2 = (CONSTANT_Methodref_info) translations.get(info);
335            if (info2 == null) {
336                ConstantPool cp2 = translate(info.cp, translations);
337                if (cp2 == info.cp)
338                    info2 = info;
339                else
340                    info2 = new CONSTANT_Methodref_info(cp2, info.class_index, info.name_and_type_index);
341                translations.put(info, info2);
342            }
343            return info;
344        }
345    
346        public CPInfo visitString(CONSTANT_String_info info, Map<Object, Object> translations) {
347            CONSTANT_String_info info2 = (CONSTANT_String_info) translations.get(info);
348            if (info2 == null) {
349                ConstantPool cp2 = translate(info.cp, translations);
350                if (cp2 == info.cp)
351                    info2 = info;
352                else
353                    info2 = new CONSTANT_String_info(cp2, info.string_index);
354                translations.put(info, info2);
355            }
356            return info;
357        }
358    
359        public CPInfo visitUtf8(CONSTANT_Utf8_info info, Map<Object, Object> translations) {
360            CONSTANT_Utf8_info info2 = (CONSTANT_Utf8_info) translations.get(info);
361            if (info2 == null) {
362                info2 = info;
363                translations.put(info, info2);
364            }
365            return info;
366        }
367    
368    }