/* Copyright (c) 2002-2011 by XMLVM.org
*
* Project Info: http://www.xmlvm.org
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
package org.xmlvm.proc;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.Namespace;
import org.jdom.input.SAXBuilder;
import org.jdom.output.XMLOutputter;
import org.xmlvm.proc.out.OutputFile;
import org.xmlvm.util.comparators.XmlvmMethodComparator;
/**
* This class describes a XMLVM resource, that is e.g. produces by
* InputProcesses.
*
* TODO(Sascha): Some aspects in this class don't properly reflect the CLI input
* type. E.g., a CLI resource can have multiple types and therefore multiple
* super types.
*/
public class XmlvmResource
{
/**
*
*/
private static final String ATTRIBUTE_INTERFACE_TABLE_SIZE= "interfaceTableSize";
/**
*
*/
private static final String TAG_CLASS= "class";
/**
* Possible types for an XmlvmResource.
*/
public static enum Type
{
JVM, CLI, CLI_DFA, DEX, CONST_POOL
}
/**
* Possible tags for an XmlvmResource.
*/
public static enum Tag
{
SKELETON_ONLY;
}
/**
* Wrapper for a <code><dex:invoke-*></code> element.
*/
public class XmlvmInvokeInstruction
{
public Element invokeElement;
/**
* Wrapper for a <code><dex:invoke-*></code> element.
*
* @param invokeElement
* DOM element representing a
* <code><dex:invoke-*></code>.
*/
public XmlvmInvokeInstruction(Element invokeElement)
{
this.invokeElement= invokeElement;
}
public String toString()
{
return (new XMLOutputter()).outputString(invokeElement);
}
/**
* @return
*/
public String getClassType()
{
return invokeElement.getAttributeValue("class-type");
}
/**
* @return
*/
public String getMethodName()
{
return invokeElement.getAttributeValue("method");
}
/**
* @param vtableIndex
*/
public void setVtableIndex(int vtableIndex)
{
invokeElement.setAttribute("vtable-index", "" + vtableIndex);
}
/**
* @param type
*/
public void setClassType(String type)
{
invokeElement.setAttribute("class-type", type);
}
/**
* Returns a list of all parameter types (e.g. java.lang.String, ...)
*
* @return list of all parameter types
*/
public List<String> getParameterTypes()
{
Element signature= invokeElement.getChild("parameters", nsDEX);
@SuppressWarnings("unchecked")
List<Element> parameterList= signature.getChildren("parameter", nsDEX);
List<String> parameterTypes= new ArrayList<String>();
for (Element parameter : parameterList)
{
parameterTypes.add(parameter.getAttributeValue("type"));
}
return parameterTypes;
}
}
/**
* Wrapper for those XMLVM elements that have an associated string constant.
* In XMLVM these can only be either <code><dex:const-string></code>
* or a <code><vm:field></code> element with a constant string
* initializer.
*/
public class XmlvmConstantStringElement
{
private Element element;
/**
* Wrapper for a <code><dex:const-string*></code> or a
* <code><vm:field></code> element.
*
* @param element
* DOM element representing a
* <code><dex:const-string></code> or a
* <code><vm:field></code>.
*/
public XmlvmConstantStringElement(Element element)
{
this.element= element;
}
/**
* Returns the escaped version of the string that uses the \ooo octal
* notation for representing special characters.
*/
public String getEscapedStringConstant()
{
return element.getAttributeValue("value");
}
/**
* Returns the encoded version of the string. The encoded version
* represents the string as a comma-separated list of short values.
*/
public String getEncodedStringConstant()
{
return element.getAttributeValue("encoded-value");
}
/**
* Returns the length of the string.
*/
public int getLength()
{
return Integer.parseInt(element.getAttributeValue("length"));
}
/**
* Set the constant pool ID for this string.
*
* @param id
* Constant pool ID.
*/
public void setContantPoolID(int id)
{
element.setAttribute("id", "" + id);
}
}
public class XmlvmMemberReadWrite
{
public Element memberReadWriteElement;
/**
* Wrapper for a <code><dex:iget-*></code> or a
* <code><dex:iput-*></code> element.
*
* @param invokeElement
* DOM element representing a <code><dex:iget-*></code>
* or a <code><dex:iput-*></code>.
*/
public XmlvmMemberReadWrite(Element memberReadWriteElement)
{
this.memberReadWriteElement= memberReadWriteElement;
}
public String toString()
{
return (new XMLOutputter()).outputString(memberReadWriteElement);
}
/**
* @return
*/
public String getMemberName()
{
return this.memberReadWriteElement.getAttributeValue("member-name");
}
/**
* @param type
*/
public void setClassType(String type)
{
this.memberReadWriteElement.setAttribute("class-type", type);
}
/**
* @return
*/
public String getClassType()
{
return this.memberReadWriteElement.getAttributeValue("class-type");
}
}
/**
* Wrapper for a <code><vm:method></code> element.
*/
public class XmlvmMethod
{
public Element methodElement;
/**
* Wrapper for a <code><vm:method></code> element.
*
* @param invokeElement
* DOM element representing a <code><vm:method></code>.
*/
public XmlvmMethod(Element methodElement)
{
this.methodElement= methodElement;
}
public int hashCode()
{
return toString().hashCode();
}
public String toString()
{
return (new XMLOutputter()).outputString(methodElement);
}
public String getName()
{
return methodElement.getAttributeValue("name");
}
/**
* Retrieve all invoke instructions that are handled via a vtable (i.e.,
* <code><dex:invoke-virtual></code> and
* <code><dex:invoke-interface></code> instructions).
*
* @return All <code><dex:invoke-virtual></code> and
* <code><dex:invoke-interface></code> instructions of
* this method.
*/
public List<XmlvmInvokeInstruction> getVtableInvokeInstructions()
{
List<XmlvmInvokeInstruction> invokeInstructions= new ArrayList<XmlvmInvokeInstruction>();
searchForVtableInvokeInstructions(invokeInstructions, methodElement);
return invokeInstructions;
}
@SuppressWarnings("unchecked")
private void searchForVtableInvokeInstructions(List<XmlvmInvokeInstruction> invokeInstructions, Element element)
{
List<Element> children= element.getChildren("invoke-virtual", nsDEX);
for (Element instruction : children)
{
XmlvmInvokeInstruction invoke= new XmlvmInvokeInstruction(instruction);
invokeInstructions.add(invoke);
}
children= element.getChildren("invoke-virtual-range", nsDEX);
for (Element instruction : children)
{
XmlvmInvokeInstruction invoke= new XmlvmInvokeInstruction(instruction);
invokeInstructions.add(invoke);
}
children= element.getChildren();
for (Element node : children)
{
searchForVtableInvokeInstructions(invokeInstructions, node);
}
}
/**
* Determines if two Java methods can override each other. Two methods
* override each other, if their names as well as all their input
* parameter types are identical. Note that the return types need not be
* identical since Java allows covariant returns.
* <code>doesOverrideMethod()</code> does not check for subtype
* relationship of the return type. The return type is essentially
* ignored and therefore <code>doesOverrideMethod()</code> is
* commutative.
*
* @param method
* {@link #XmlvmResource} to be checked.
* @return true, if <code>method</code> overrides <code>this</code>.
*/
@SuppressWarnings("unchecked")
public boolean doesOverrideMethod(XmlvmMethod method)
{
return doesOverrideMethod(method.getName(), method.methodElement.getChild("signature", nsXMLVM).getChildren("parameter", nsXMLVM));
}
/**
* Determines if two Java methods can override each other. Two methods
* override each other, if their names as well as all their input
* parameter types are identical. Note that the return types need not be
* identical since Java allows covariant returns.
* <code>doesOverrideMethod()</code> does not check for subtype
* relationship of the return type. The return type is essentially
* ignored and therefore <code>doesOverrideMethod()</code> is
* commutative.
*
* @param method
* {@link #XmlvmInvokeVirtual} to be checked.
* @return true, if <code>method</code> overrides <code>this</code>.
*/
@SuppressWarnings("unchecked")
public boolean doesOverrideMethod(XmlvmInvokeInstruction instruction)
{
return doesOverrideMethod(instruction.getMethodName(), instruction.invokeElement.getChild("parameters", nsDEX).getChildren("parameter", nsDEX));
}
@SuppressWarnings("unchecked")
private boolean doesOverrideMethod(String methodName, List<Element> parameters)
{
if (!this.getName().equals(methodName))
{
return false;
}
Element mySignature= methodElement.getChild("signature", nsXMLVM);
List<Element> myParameters= mySignature.getChildren("parameter", nsXMLVM);
if (myParameters.size() != parameters.size())
{
return false;
}
for (int i= 0; i < myParameters.size(); i++)
{
String myParameterType= myParameters.get(i).getAttributeValue("type");
String otherParameterType= parameters.get(i).getAttributeValue("type");
if (!myParameterType.equals(otherParameterType))
{
return false;
}
}
return true;
}
/**
* Returns true if this method is static.
*/
public boolean isStatic()
{
String flag= methodElement.getAttributeValue("isStatic");
return flag != null && flag.equals("true");
}
/**
* Returns true if this method is private.
*/
public boolean isPrivate()
{
String flag= methodElement.getAttributeValue("isPrivate");
return flag != null && flag.equals("true");
}
/**
* Returns true if this method is protected.
*/
public boolean isProtected()
{
String flag= methodElement.getAttributeValue("isProtected");
return flag != null && flag.equals("true");
}
/**
* Returns true if this method is public.
*/
public boolean isPublic()
{
String flag= methodElement.getAttributeValue("isPublic");
return flag != null && flag.equals("true");
}
/**
* Returns true if this method is abstract.
*/
public boolean isAbstract()
{
String flag= methodElement.getAttributeValue("isAbstract");
return flag != null && flag.equals("true");
}
/**
* Returns true if this method is native.
*/
public boolean isNative()
{
String flag= methodElement.getAttributeValue("isNative");
return flag != null && flag.equals("true");
}
/**
* Returns true if this method is a constructor.
*/
public boolean isConstructor()
{
return methodElement.getAttributeValue("name").equals("<init>");
}
/**
* Returns true if this method is synthetic.
*/
public boolean isSynthetic()
{
String flag= methodElement.getAttributeValue("isSynthetic");
return flag != null && flag.equals("true");
}
/**
* Sets the @isSynthetic flag of the method.
*/
public void setSynthetic(boolean flag)
{
if (flag)
{
methodElement.setAttribute("isSynthetic", "true");
}
else
{
methodElement.removeAttribute("isSynthetic");
}
}
/**
* Returns whether this method is overriding another method the
* containing class inherited.
*
* This is used by the C# backend which needs to emit the special
* override keyword in the method signature in this case (see
* http://msdn.microsoft.com/en-us/library/ebca9ah3.aspx).
*
* It is not filled by other backends!
*/
public boolean isOverriding()
{
String flag= methodElement.getAttributeValue("isOverriding");
return flag != null && flag.equals("true");
}
/**
* Set if this method is overriding another method the containing class
* inherited.
*
* This is used by the C# backend which needs to emit the special
* override keyword in the method signature in this case (see
* http://msdn.microsoft.com/en-us/library/ebca9ah3.aspx)
*
* It is not filled by other backends!
*/
public void setOverriding(boolean overriding)
{
methodElement.setAttribute("isOverriding", Boolean.toString(overriding));
}
/**
* Set a vtable index for this method (XML attribute
* <code>vtableIndex</code>).
*/
public void setVtableIndex(int idx)
{
methodElement.setAttribute("vtableIndex", "" + idx);
}
/**
* Returns a list of all parameter types (e.g. java.lang.String, ...)
*
* @return list of all parameter types
*/
public List<String> getParameterTypes()
{
Element signature= methodElement.getChild("signature", nsXMLVM);
@SuppressWarnings("unchecked")
List<Element> parameterList= signature.getChildren("parameter", nsXMLVM);
List<String> parameterTypes= new ArrayList<String>();
for (Element parameter : parameterList)
{
parameterTypes.add(parameter.getAttributeValue("type"));
}
return parameterTypes;
}
/**
* @return the index in the interface table for this method, or null for
* none
*/
public Integer getInterfaceTableIndex()
{
Integer interfaceTableIndex= null;
String strVal= methodElement.getAttributeValue("itableIndex");
if (strVal != null)
{
try
{
interfaceTableIndex= Integer.parseInt(strVal);
}
catch (NumberFormatException e)
{
// do nothing
}
}
return interfaceTableIndex;
}
/**
* @param interfaceTableIndex
* the index of in the interface table for this method, or
* null for none
*/
public void setInterfaceTableIndex(Integer interfaceTableIndex)
{
methodElement.setAttribute("itableIndex", interfaceTableIndex == null ? "" : interfaceTableIndex.toString());
}
}
/**
* Add a copy of the given method to the XmlvmResource
*
* @param method
* method to add
* @return Copied method
*/
public XmlvmMethod addMethod(XmlvmMethod method)
{
Element clazz= xmlvmDocument.getRootElement().getChild(TAG_CLASS, nsXMLVM);
Element clone= (Element) method.methodElement.clone();
clazz.addContent(clone);
return new XmlvmMethod(clone);
}
/**
* Wrapper for a <code><vm:field></code> element.
*/
public class XmlvmField
{
public Element fieldElement;
/**
* Wrapper for a <code><vm:field></code> element.
*
* @param fieldElement
* DOM element representing a <code><vm:field></code>.
*/
public XmlvmField(Element fieldElement)
{
this.fieldElement= fieldElement;
}
/**
* Returns the name of the field.
*/
public String getName()
{
return fieldElement.getAttributeValue("name");
}
/**
* Returns the type of the field.
*/
public String getType()
{
return fieldElement.getAttributeValue("type");
}
/**
* Returns true if this field is private.
*/
public boolean isPrivate()
{
String flag= fieldElement.getAttributeValue("isPrivate");
return flag != null && flag.equals("true");
}
/**
* Returns true if this field is protected.
*/
public boolean isProtected()
{
String flag= fieldElement.getAttributeValue("isProtected");
return flag != null && flag.equals("true");
}
/**
* Returns true if this field is public.
*/
public boolean isPublic()
{
String flag= fieldElement.getAttributeValue("isPublic");
return flag != null && flag.equals("true");
}
/**
* Returns true if the field the <code>instruction</code> is accessing
* has the same name as this field.
*/
public boolean matchesName(XmlvmMemberReadWrite instruction)
{
return getName().equals(instruction.getMemberName());
}
/**
* Returns true if the given <code>field</code> has the same name and
* type as this field.
*/
public boolean matchesDeclaration(XmlvmField field)
{
return getName().equals(field.getName()) && getType().equals(field.getType());
}
}
/**
* @param search
*/
@SuppressWarnings("unchecked")
public void removeMethod(XmlvmMethod search)
{
List<Element> classes= xmlvmDocument.getRootElement().getChildren(TAG_CLASS, nsXMLVM);
for (Element clazz : classes)
{
if (clazz.removeContent(search.methodElement))
{
return;
}
}
}
/**
* vm:itable contains mappings between interface indices of implemented
* interfaces and the class vtable or directly methods of the class
*/
public class XmlvmItable
{
private Element itableElement;
public XmlvmItable(Element itableElement)
{
this.itableElement= itableElement;
}
/**
* Create a new mapping between a global interface method index and the
* vtable of a class
*
* @param itableIndex
* global interface method index
* @param vtableIndexClass
* Corresponding vtable index of an implementing method in a
* class.
*/
public void addVtableMapping(String ifaceName, XmlvmMethod ifaceMethod, int vtableIndex)
{
Element map= new Element("vtable-map", nsXMLVM);
map.setAttribute("ifaceName", ifaceName);
map.setAttribute("ifaceMethodName", ifaceMethod.getName());
Element signature= (Element) ifaceMethod.methodElement.getChild("signature", nsXMLVM).clone();
map.addContent(signature);
map.setAttribute("vtableIndex", "" + vtableIndex);
itableElement.addContent(map);
}
/**
* Create a new mapping between a global interface method index and a
* direct invoke
*
* @param itableIndex
* global interface method index
* @param classType
* class containing the method to be mapped
* @param methodName
* name of the method to be mapped
*/
public void addDirectMapping(String ifaceName, XmlvmMethod ifaceMethod, String classType)
{
Element map= new Element("direct-map", nsXMLVM);
map.setAttribute("ifaceName", ifaceName);
map.setAttribute("ifaceMethodName", ifaceMethod.getName());
Element signature= (Element) ifaceMethod.methodElement.getChild("signature", nsXMLVM).clone();
map.addContent(signature);
map.setAttribute("className", classType);
itableElement.addContent(map);
}
}
public static Namespace nsXMLVM= Namespace.getNamespace("vm", "http://xmlvm.org");
public static Namespace nsDEX= Namespace.getNamespace("dex", "http://xmlvm.org/dex");
public static Namespace nsJVM= Namespace.getNamespace("jvm", "http://xmlvm.org/jvm");
private final Type type;
private final Document xmlvmDocument;
private final Set<String> referencedTypes;
private final String name;
private final String superTypeName;
private final Map<Tag, String> tags= new HashMap<Tag, String>();
public XmlvmResource(Type type, Document xmlvmDocument)
{
this.type= type;
this.xmlvmDocument= xmlvmDocument;
if (type != Type.CONST_POOL)
{
this.referencedTypes= extractReferencedTypes(xmlvmDocument);
Element classElement= xmlvmDocument.getRootElement().getChild(TAG_CLASS, nsXMLVM);
this.name= classElement.getAttributeValue("name");
this.superTypeName= classElement.getAttributeValue("extends");
}
else
{
this.referencedTypes= null;
this.name= "ConstantPool";
this.superTypeName= null;
}
}
private static Set<String> extractReferencedTypes(Document xmlvmDocument)
{
Set<String> result= new HashSet<String>();
Element referencesElement= xmlvmDocument.getRootElement().getChild("references", nsXMLVM);
if (referencesElement == null)
{
return result;
}
@SuppressWarnings("unchecked")
List<Element> references= referencesElement.getChildren("reference", nsXMLVM);
for (Element reference : references)
{
result.add(reference.getAttributeValue("name"));
}
return result;
}
public String toString()
{
return getFullName();
}
/**
* Returns the XMLVM document of this resource.
*/
public Document getXmlvmDocument()
{
return xmlvmDocument;
}
/**
* Returns the type of this XMLVM resource.
*/
public Type getType()
{
return type;
}
/**
* Returns the name of this XMLVM resource.
*/
public String getName()
{
return name;
}
/**
* Returns the full name, which is the normal name prefixed by the package.
*/
public String getFullName()
{
String fullResourceName= getPackageName();
if (!fullResourceName.isEmpty())
{
fullResourceName+= ".";
}
fullResourceName+= getName();
return fullResourceName;
}
/**
* Checks if this class is abstract
*
* @return true if it's an abstract class otherwise false
*/
public boolean isAbstract()
{
Element clazz= xmlvmDocument.getRootElement().getChild(TAG_CLASS, nsXMLVM);
String flag= clazz.getAttributeValue("isAbstract");
return flag != null && flag.equals("true");
}
/**
* Returns the names of all types that are referenced in this resource.
*/
public Set<String> getReferencedTypes()
{
return referencedTypes;
}
/**
* Returns the name of the super class type.
*/
public String getSuperTypeName()
{
return superTypeName;
}
/**
* Returns the name of the package, this resource is in.
* <p>
* E.g. "java.lang"
*/
public String getPackageName()
{
if (type == Type.CONST_POOL)
{
return "org.xmlvm";
}
Element clazz= xmlvmDocument.getRootElement().getChild(TAG_CLASS, nsXMLVM);
return clazz.getAttributeValue("package");
}
/**
* Returns a comma-separated list of interfaces this resources implements.
*/
public String getInterfaces()
{
Element clazz= xmlvmDocument.getRootElement().getChild(TAG_CLASS, nsXMLVM);
return clazz.getAttributeValue("interfaces");
}
/**
* Returns all methods defined in this resource.
*/
public List<XmlvmMethod> getMethods()
{
List<XmlvmMethod> result= new ArrayList<XmlvmMethod>();
List<Element> methods= getMethodElements();
for (Element method : methods)
{
result.add(new XmlvmMethod(method));
}
return result;
}
/**
* Returns a sorted list of all methods defined in this resource.
*/
public List<XmlvmMethod> getMethodsSorted()
{
List<XmlvmMethod> result= getMethods();
Collections.sort(result, new XmlvmMethodComparator());
return result;
}
/**
* Returns all fields defined in this resource.
*/
@SuppressWarnings("unchecked")
public List<XmlvmField> getFields()
{
List<XmlvmField> result= new ArrayList<XmlvmField>();
List<Element> classes= xmlvmDocument.getRootElement().getChildren(TAG_CLASS, nsXMLVM);
for (Element clazz : classes)
{
List<Element> fields= clazz.getChildren("field", nsXMLVM);
for (Element field : fields)
{
result.add(new XmlvmField(field));
}
}
return result;
}
/**
* Returns whether this resource represents an interface.
*/
public boolean isInterface()
{
return Boolean.parseBoolean(xmlvmDocument.getRootElement().getChild(TAG_CLASS, nsXMLVM).getAttributeValue("isInterface"));
}
@SuppressWarnings("unchecked")
// JDOM's non-generic API.
private List<Element> getMethodElements()
{
List<Element> result= new ArrayList<Element>();
List<Element> classes= xmlvmDocument.getRootElement().getChildren(TAG_CLASS, nsXMLVM);
for (Element clazz : classes)
{
result.addAll(clazz.getChildren("method", nsXMLVM));
}
return result;
}
/**
* Set the XML attribute <code>vtableSize</code> that designates the number
* of vtable entries for this class.
*
* @param vtableSize
* Size of the vtable.
*/
@SuppressWarnings("unchecked")
// JDOM's non-generic API.
public void setVtableSize(int vtableSize)
{
List<Element> classes= xmlvmDocument.getRootElement().getChildren(TAG_CLASS, nsXMLVM);
if (classes.size() != 1)
{
System.err.println("XmlvmResource.setVtableSize(): cannot deal with multiple classes");
System.exit(-1);
}
classes.get(0).setAttribute("vtableSize", "" + vtableSize);
}
/**
* Creates an itable for this class.The created itable is essentially a
* mapping of methods defined in an interface to methods defined in the
* class. The XML markup of the vtable is as follows:
*
* <pre>
* <itable>
* <vtable-map itableIndex="..." vtableIndex="..."/>
* <vtable-map itableIndex="..." vtableIndex="..."/>
* ...
* <direct-map itableIndex="..." class-type="..." name="..."/>
* <direct-map itableIndex="..." class-type="..." name="..."/>
* ...
* </itable>
* </pre>
*
* @return A newly created itable.
*/
public XmlvmItable createItable()
{
Element itableElement= new Element("itable", nsXMLVM);
xmlvmDocument.getRootElement().getChild(TAG_CLASS, nsXMLVM).addContent(itableElement);
return new XmlvmItable(itableElement);
}
/**
* Collects a list of all instructions whose type may need to be adjusted
* for a specific set of classes that comprise the application being
* cross-compiled (see
* {@link org.xmlvm.plugins.c.COutputProcess#adjustTypes()}). Instructions
* that need to be considered are invoke-static, invoke-super, iput, iget,
* sput, and sget.
*
* @param invokeInstructions
* Will be filled with all invoke-static and invoke-super
* instructions upon return.
* @param readWriteInstructions
* Will be filled with all iput, iget, sput, and sget
* instructions upon return.
*/
@SuppressWarnings("unchecked")
public void collectInstructions(List<XmlvmInvokeInstruction> invokeInstructions, List<XmlvmMemberReadWrite> readWriteInstructions)
{
Element root= xmlvmDocument.getRootElement().getChild(TAG_CLASS, nsXMLVM);
Iterator<Object> iter= root.getDescendants();
while (iter.hasNext())
{
Object o= iter.next();
if (o instanceof Element)
{
Element elem= (Element) o;
String name= elem.getName();
if (name.startsWith("invoke-static") || name.startsWith("invoke-super"))
{
invokeInstructions.add(new XmlvmInvokeInstruction(elem));
}
if (name.startsWith("iput") || name.startsWith("iget") || name.startsWith("sput") || name.startsWith("sget"))
{
readWriteInstructions.add(new XmlvmMemberReadWrite(elem));
}
}
}
}
/**
* Collects a list of all dex:const-string instructions as well as vm:fields
* that have a string initializer.
*
* @param constStringInstructions
* Will be filled with all const-string instructions upon return.
*/
@SuppressWarnings("unchecked")
public void collectInstructions(List<XmlvmConstantStringElement> constStringInstructions)
{
Element root= xmlvmDocument.getRootElement().getChild(TAG_CLASS, nsXMLVM);
Iterator<Object> iter= root.getDescendants();
while (iter.hasNext())
{
Object o= iter.next();
if (o instanceof Element)
{
Element elem= (Element) o;
if (elem.getName().equals("const-string"))
{
constStringInstructions.add(new XmlvmConstantStringElement(elem));
}
if (elem.getName().equals("field") && elem.getAttributeValue("type").equals("java.lang.String") && elem.getAttributeValue("value") != null)
{
constStringInstructions.add(new XmlvmConstantStringElement(elem));
}
}
}
}
public static XmlvmResource fromFile(OutputFile file)
{
Document doc= null;
SAXBuilder builder= new SAXBuilder();
try
{
doc= builder.build(new ByteArrayInputStream(file.getDataAsBytes()));
}
catch (Exception e)
{
e.printStackTrace();
}
return new XmlvmResource(org.xmlvm.proc.XmlvmResource.Type.DEX, doc);
}
/**
* Creates a <vm:inmplementsInterface> in the vm:class which is used
* by xmlvm2c.xsl to initialize the implementedInterface array
*
* @param fullName
*/
public void createImplementsInterface(String fullName)
{
Element implementsInterfaceElement= new Element("implementsInterface", nsXMLVM);
implementsInterfaceElement.setAttribute("name", fullName);
xmlvmDocument.getRootElement().getChild(TAG_CLASS, nsXMLVM).addContent(implementsInterfaceElement);
}
/**
* Adds a public static <vm:field> element, corresponding to the given
* field of the given interface, implemented by the class represented by
* this resource.
*
* This method has no effect on resources which do not represent a
* class/interface (e.g. constant pool).
*
* This method is to be used by backends which do not support interface
* fields (as of now only C#).
*
* @param definingInterface
* the topmost interface where the given field is defined.
* @param field
* field which will be added to the class element of the
* xmlvmDocument
*/
public void addInterfaceField(String definingInterface, XmlvmField field)
{
Element classElement= xmlvmDocument.getRootElement().getChild("class", nsXMLVM);
if (classElement == null)
{
return;
}
Element interfaceFieldElement= new Element("field", nsXMLVM);
interfaceFieldElement.setAttribute("name", field.getName());
interfaceFieldElement.setAttribute("type", field.getType());
interfaceFieldElement.setAttribute("isPublic", "true");
interfaceFieldElement.setAttribute("isStatic", "true");
interfaceFieldElement.setAttribute("definingInterface", definingInterface);
classElement.addContent(interfaceFieldElement);
}
/**
* Sets a tag to a given value.
*
* @param tag
* The tag to set.
* @param tagValue
* The value of the tag.
*/
public void setTag(Tag tag, String tagValue)
{
tags.put(tag, tagValue);
}
/**
* Returns whether this resource contains the given tag.
*
* @param tag
* The tag to check.
*/
public boolean hasTag(Tag tag)
{
return tags.containsKey(tag);
}
/**
* Returns the value of the tag with the given tag.
*
* @param tag
* The tag to get.
*/
public String getTagValue(Tag tag)
{
return tags.get(tag);
}
/**
* @return the size of the interface table
*/
public Integer getInterfaceTableSize()
{
Element clazz= xmlvmDocument.getRootElement().getChild(TAG_CLASS, nsXMLVM);
String interfaceTableSize= clazz.getAttributeValue(ATTRIBUTE_INTERFACE_TABLE_SIZE);
return interfaceTableSize == null ? null : Integer.parseInt(interfaceTableSize);
}
/**
* @param interfaceTableSize
* the size of the interface table to set
*/
public void setInterfaceTableSize(Integer interfaceTableSize)
{
Element clazz= xmlvmDocument.getRootElement().getChild(TAG_CLASS, nsXMLVM);
clazz.setAttribute(ATTRIBUTE_INTERFACE_TABLE_SIZE, interfaceTableSize == null ? null : String.valueOf(interfaceTableSize));
}
}