/* * 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; import java.io.DataInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TreeMap; import mereflect.io.ClassReaderFactory; import andreflect.ApkClassContext; import andreflect.DexReader; import andreflect.DexReferenceCache; import andreflect.DexResource; public abstract class AbstractClassContext implements MEClassContext, Comparable<Object> { protected MEClassContext m_parent; protected List<MEClassContext> m_children = new ArrayList<MEClassContext>(); protected Map<String, MEClass> m_classCache = new TreeMap<String, MEClass>(); protected MEClassResource[] m_resourceCache = null; protected boolean m_isMidlet; @Override public MEClassContext getParentContext() { return m_parent; } @Override public void setParentContext(MEClassContext ctx) { m_parent = ctx; } @Override public synchronized MEClassContext[] getContexts() { return (m_children.toArray(new MEClassContext[m_children.size()])); } @Override public synchronized void addContext(MEClassContext ctx) { if (!m_children.contains(ctx)) { ctx.setParentContext(this); m_children.add(ctx); m_resourceCache = null; } } @Override public synchronized void removeContext(MEClassContext ctx) { if (m_children.contains(ctx)) { ctx.setParentContext(null); m_children.remove(ctx); m_resourceCache = null; } } @Override public synchronized MEClassResource[] getClassResources() throws IOException { if (m_resourceCache == null) { ArrayList<MEClassResource> rscs = new ArrayList<MEClassResource>(); addToList(rscs, getClassResourcesImpl()); MEClassContext[] ctxs = getContexts(); for (int i = 0; i < ctxs.length; i++) { addToList(rscs, ctxs[i].getClassResources()); } m_resourceCache = rscs.toArray(new MEClassResource[rscs.size()]); } return m_resourceCache; } public abstract MEClassResource[] getClassResourcesImpl() throws IOException; @Override public synchronized MEClassResource getClassResource(String name) throws IOException { MEClassResource[] rscs = getClassResources(); MEClassResource rsc = null; for (int i = 0; i < rscs.length; i++) { if (rscs[i].getClassName().equals(name)) { rsc = rscs[i]; break; } } return rsc; } @Override public String[] getClassnames() throws IOException { MEClassResource[] rscs = getClassResources(); String[] cnames = new String[rscs.length]; for (int i = 0; i < cnames.length; i++) { cnames[i] = rscs[i].getClassName(); } return cnames; } @Override public MEClass getMEClass(String classname) throws IOException, ClassNotFoundException { MEClass c = null; c = m_classCache.get(classname); if (c == null && getParentContext() != null) { try { c = getParentContext().getMEClass(classname); } catch (ClassNotFoundException cnfe) { c = null; } } if (c == null) { MEClassResource[] rscs = getClassResources(); for (int i = 0; i < rscs.length; i++) { if (rscs[i].getClassName().equals(classname)) { if (rscs[i] instanceof DexResource) { try { c = DexReader.readClassFile((DexResource) rscs[i], ((ApkClassContext) (rscs[i].getContext())).getDex().isOdex()); m_classCache.put(classname, c); c.setResource(rscs[i]); break; } catch (Exception e) { e.printStackTrace(); } } else { DataInputStream dis = null; try { dis = new DataInputStream(rscs[i].getInputStream()); c = ClassReaderFactory.getClassReader().readClassFile(dis); m_classCache.put(classname, c); c.setResource(rscs[i]); break; } finally { if (dis != null) { dis.close(); } } } } } } if (c == null) { throw new ClassNotFoundException(classname); } return c; } private void addToList(ArrayList<MEClassResource> list, MEClassResource[] rscs) { if (rscs != null) { for (int i = 0; i < rscs.length; i++) { if (!list.contains(rscs[i])) { list.add(rscs[i]); } } } } @Override public int compareTo(Object o) { if (o instanceof MEClassContext) { return getContextName().compareTo(((MEClassContext) o).getContextName()); } else { return getContextName().compareTo(o.toString()); } } @Override public boolean isMidlet() { return m_isMidlet; } @Override public DexReferenceCache getDexReferenceCache() { return null; } }