/* * Copyright (C) 2012 Sony Mobile Communications AB * * This file is part of ApkAnalyser. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package mereflect.io; import java.io.IOException; import mereflect.MEClass; import mereflect.MEClassContext; import mereflect.Type; import mereflect.UnknownClass; import mereflect.primitives.AbstractPrimitive; import mereflect.primitives.MEArray; import mereflect.primitives.MEBoolean; import mereflect.primitives.MEByte; import mereflect.primitives.MEChar; import mereflect.primitives.MEDouble; import mereflect.primitives.MEFloat; import mereflect.primitives.MEInt; import mereflect.primitives.MELong; import mereflect.primitives.MEShort; import mereflect.primitives.MEVoid; /** * Simple helper class for parsing type descriptors. */ public class DescriptorParser { static MEClassContext superContext; private DescriptorParser() { } /** * When processing descriptors and types that are not found in specified class context, the supercontext will be searched in instead. * @TODO solve another way, this is superUgly * @param ctx */ public static void setSuperContext(MEClassContext ctx) { superContext = ctx; } public static void processType(Type t, StringBuffer s) { if (t.isArray()) { s.append(Type.CH_ARRAY); processType(((MEArray) t).getArrayType(), s); } else if (t.isPrimitive()) { s.append(((AbstractPrimitive) t).getDescriptorChar()); } else { s.append(Type.CH_CLASS_PRE); s.append(((MEClass) t).getRawName()); s.append(Type.CH_CLASS_POST); } } /** * Processes a type descriptor and returns a Type for the descriptor. * @param clazz any class of the context of where the descriptor is valid * @param descr The descriptor * @return the resolved type as a <code>Type</code> * @throws IOException, IllegalArgumentException */ public static Type processTypeDescriptor(MEClass clazz, StringBuffer descr) throws IOException { if (descr == null || descr.length() == 0) { return null; } Type t = null; char c = descr.charAt(0); descr.deleteCharAt(0); switch (c) { case Type.CH_ARRAY: t = new MEArray(processTypeDescriptor(clazz, descr)); break; case Type.CH_CLASS_PRE: int end = descr.indexOf(Character.toString(Type.CH_CLASS_POST)); String classname = descr.substring(0, end); classname = classname.replace('/', '.'); descr.delete(0, end + 1); try { t = clazz.getResource().getContext().getMEClass(classname); } catch (ClassNotFoundException cnfe) { try { if (superContext != null) { t = superContext.getMEClass(classname); } else { throw cnfe; } } catch (ClassNotFoundException cnfe2) { // TODO: could not find the class in apis either. // Workaround by specifying it as unknown, unsafe when doing ops on fields, but keep on running t = new UnknownClass(classname, clazz.getResource()); } } break; case Type.CH_BOOLEAN: t = new MEBoolean(); break; case Type.CH_BYTE: t = new MEByte(); break; case Type.CH_CHAR: t = new MEChar(); break; case Type.CH_DOUBLE: t = new MEDouble(); break; case Type.CH_FLOAT: t = new MEFloat(); break; case Type.CH_INT: t = new MEInt(); break; case Type.CH_LONG: t = new MELong(); break; case Type.CH_SHORT: t = new MEShort(); break; case Type.CH_VOID: t = new MEVoid(); break; default: throw new IllegalArgumentException("Unknown class type " + t); } return t; } }