/* Soot - a J*va Optimization Framework
* Copyright (C) 2000 Patrice Pominville and Feng Qian
*
* This library 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified by the Sable Research Group and others 1997-1999.
* See the 'credits' file distributed with Soot for the complete list of
* contributors. (Soot is distributed at http://www.sable.mcgill.ca/soot)
*/
package soot.tagkit;
import soot.options.*;
import java.util.*;
import soot.baf.*;
import soot.*;
/** A CodeAttribute object holds PC -> Tag pairs.
* It represents abstracted attributes of Code_attribute
* such as LineNumberTable, ArrayBoundsCheck.
*/
public class CodeAttribute extends JasminAttribute
{
protected List<Unit> mUnits;
protected List<Tag> mTags;
private byte[] value;
private String name = "CodeAtribute";
public CodeAttribute(){}
/** Creates an attribute object with the given name. */
public CodeAttribute(String name)
{
this.name = name;
}
/** Create an attribute object with the name and lists of unit-tag pairs. */
public CodeAttribute(String name, List<Unit> units, List<Tag> tags)
{
this.name = name;
this.mUnits = units;
this.mTags = tags;
}
/** Returns the name.*/
public String toString()
{
return name;
}
/** Returns the attribute name. */
public String getName()
{
return name;
}
/** Only used by SOOT to read in an existing attribute without interpret it.*/
public void setValue(byte[] v)
{
this.value = v;
}
/** Also only used as setValue(). */
public byte[] getValue() throws AttributeValueException
{
if (value == null)
throw new AttributeValueException();
else
return value;
}
/** Generates Jasmin Value String */
public String getJasminValue(Map instToLabel)
{
// some benchmarks fail because of the returned string larger than
// the possible buffer size.
StringBuffer buf = new StringBuffer();
if (mTags.size() != mUnits.size())
throw new RuntimeException("Sizes must match!");
Iterator<Tag> tagIt = mTags.iterator();
Iterator<Unit> unitIt = mUnits.iterator();
while (tagIt.hasNext())
{
Object unit = unitIt.next();
Object tag = tagIt.next();
buf.append("%"+instToLabel.get(unit) + "%"+
new String(Base64.encode(((Tag)tag).getValue())));
}
return buf.toString();
}
/** Returns a list of unit boxes that have tags attached. */
public List<UnitBox> getUnitBoxes()
{
List<UnitBox> unitBoxes = new ArrayList<UnitBox>(mUnits.size());
Iterator<Unit> it = mUnits.iterator();
while(it.hasNext()) {
unitBoxes.add(Baf.v().newInstBox(it.next()));
}
return unitBoxes;
}
public byte[] decode(String attr, Hashtable labelToPc)
{
if (Options.v().verbose())
G.v().out.println("[] JasminAttribute decode...");
List<byte[]> attributeHunks = new LinkedList<byte[]>();
int attributeSize = 0;
StringTokenizer st = new StringTokenizer(attr, "%");
boolean isLabel = false;
if(attr.startsWith("%"))
isLabel = true;
int tablesize = 0;
byte[] pcArray;
while(st.hasMoreTokens()) {
String token = st.nextToken();
if(isLabel) {
Integer pc = (Integer) labelToPc.get(token);
if(pc == null)
throw new RuntimeException("PC is null, the token is "+token);
int pcvalue = pc.intValue();
if(pcvalue > 65535)
throw new RuntimeException("PC great than 65535, the token is "+token+" : " +pcvalue);
pcArray = new byte[2];
pcArray[1] = (byte)(pcvalue&0x0FF);
pcArray[0] = (byte)((pcvalue>>8)&0x0FF);
attributeHunks.add(pcArray);
attributeSize += 2;
tablesize++;
} else {
byte[] hunk = Base64.decode(token.toCharArray());
attributeSize += hunk.length;
attributeHunks.add(hunk);
}
isLabel = !isLabel;
}
/* first two bytes indicate the length of attribute table. */
attributeSize += 2;
byte[] attributeValue = new byte[attributeSize];
{
attributeValue[0] = (byte)((tablesize>>8)&0x0FF);
attributeValue[1] = (byte)(tablesize&0x0FF);
}
int index=2;
Iterator<byte[]> it = attributeHunks.iterator();
while(it.hasNext()) {
byte[] hunk = it.next();
for (byte element : hunk) {
attributeValue[index++] = element;
}
}
if(index != (attributeSize))
throw new RuntimeException("Index does not euqal to attrubute size :"+index+" -- "+attributeSize);
if (Options.v().verbose())
G.v().out.println("[] Jasmin.decode finished...");
return attributeValue;
}
}