/* SAAF: A static analyzer for APK files.
* Copyright (C) 2013 syssec.rub.de
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.rub.syssec.saaf.application;
import java.util.EnumSet;
import java.util.LinkedList;
import org.apache.log4j.Logger;
import de.rub.syssec.saaf.analysis.steps.obfuscation.Entropy;
import de.rub.syssec.saaf.misc.ByteUtils;
import de.rub.syssec.saaf.model.application.CodeLineInterface;
import de.rub.syssec.saaf.model.application.FieldInterface;
import de.rub.syssec.saaf.model.application.SyntaxException;
/**
* This class describes a field in SMALI code. It is able to parse its contents.
*
* @author Johannes Hoffmann <johannes.hoffmann@rub.de>
*
*/
public class Field implements FieldInterface {
private final EnumSet<Modifier> modifierSet = EnumSet.noneOf(Modifier.class);
private final CodeLineInterface cl;
private int arrayDimension = 0;
private String fieldName = null;
private boolean obfuscated;
private Entropy entropy;
private static final Logger LOGGER = Logger.getLogger(Field.class);
protected Field(CodeLineInterface cl) throws SyntaxException {
// parse the line and add it to the set
for (Modifier modifier : Modifier.values()) {
if (cl.contains(modifier.getBytePresentation())) {
// FIXME: public int privateBlah = 0; would yield public and private!
modifierSet.add(modifier);
}
}
this.cl = cl;
}
/* (non-Javadoc)
* @see de.rub.syssec.saaf.application.FieldInterface#isArray()
*/
@Override
public boolean isArray() {
if (arrayDimension > 0) return true;
else return false;
}
/* (non-Javadoc)
* @see de.rub.syssec.saaf.application.FieldInterface#getArrayDimension()
*/
@Override
public int getArrayDimension() {
return arrayDimension;
}
/* (non-Javadoc)
* @see de.rub.syssec.saaf.application.FieldInterface#hasModifier(de.rub.syssec.saaf.application.Field.Modifier)
*/
@Override
public boolean hasModifier(Modifier modifier) {
return modifierSet.contains(modifier);
}
/* (non-Javadoc)
* @see de.rub.syssec.saaf.application.FieldInterface#isStatic()
*/
@Override
public boolean isStatic() {
return hasModifier(Modifier.STATIC);
}
/* (non-Javadoc)
* @see de.rub.syssec.saaf.application.FieldInterface#isFinal()
*/
@Override
public boolean isFinal() {
return hasModifier(Modifier.FINAL);
}
/* (non-Javadoc)
* @see de.rub.syssec.saaf.application.FieldInterface#getAllModifiers()
*/
@Override
public EnumSet<Modifier> getAllModifiers() {
return modifierSet;
}
/* (non-Javadoc)
* @see de.rub.syssec.saaf.application.FieldInterface#getFieldName()
*/
@Override
public String getFieldName() {
if (fieldName == null) {
int colonIndex = ByteUtils.indexOf(cl.getLine(), ':');
int spaceBeforeColonPos = ByteUtils.indexOfReverse(cl.getLine(), ' ', colonIndex);
fieldName = new String(ByteUtils.subbytes(cl.getLine(), spaceBeforeColonPos+1, colonIndex));
}
return fieldName;
}
/**
* Parse all Fields from the given CodeLines.
*
* TODO: Catch exception to not abort whole parsing?
* @param codeLines
* @return
*/
public static LinkedList<FieldInterface> parseAllFields(LinkedList<CodeLineInterface> codeLines) {
LinkedList<FieldInterface> fieldList = new LinkedList<FieldInterface>();
for (CodeLineInterface codeLine : codeLines) {
if (codeLine.startsWith(FIELD)) {
try {
Field f = new Field(codeLine);
fieldList.add(f);
}
catch (SyntaxException e) {
LOGGER.error("Could not parse field ",e);
}
}
}
return fieldList;
}
/**
* Print the field and its description.
* TODO: Format to plain java syntax.
*/
public String toString() {
return cl.toString();
}
/* (non-Javadoc)
* @see de.rub.syssec.saaf.application.FieldInterface#getCodeLine()
*/
@Override
public CodeLineInterface getCodeLine() {
return cl;
}
@Override
public void setObfuscated(boolean b) {
this.obfuscated=b;
}
@Override
public boolean isObfuscated() {
return this.obfuscated;
}
@Override
public void setEntropy(Entropy entropy) {
this.entropy=entropy;
}
@Override
public Entropy getEntropy() {
return this.entropy;
}
}