--- /dev/null
+package org.bouncycastle.asn1;
+
+import java.io.*;
+import java.util.*;
+
+public class BERConstructedOctetString
+ extends DEROctetString
+{
+ /**
+ * convert a vector of octet strings into a single byte string
+ */
+ static private byte[] toBytes(
+ Vector octs)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ for (int i = 0; i != octs.size(); i++)
+ {
+ DEROctetString o = (DEROctetString)octs.elementAt(i);
+
+ try
+ {
+ bOut.write(o.getOctets());
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("exception converting octets " + e.toString());
+ }
+ }
+
+ return bOut.toByteArray();
+ }
+
+ private Vector octs;
+
+ /**
+ * @param string the octets making up the octet string.
+ */
+ public BERConstructedOctetString(
+ byte[] string)
+ {
+ super(string);
+ }
+
+ public BERConstructedOctetString(
+ Vector octs)
+ {
+ super(toBytes(octs));
+
+ this.octs = octs;
+ }
+
+ public BERConstructedOctetString(
+ DERObject obj)
+ {
+ super(obj);
+ }
+
+ public BERConstructedOctetString(
+ DEREncodable obj)
+ {
+ super(obj.getDERObject());
+ }
+
+ public byte[] getOctets()
+ {
+ return string;
+ }
+
+ public Vector getDEROctets()
+ {
+ if (octs == null)
+ {
+ octs = generateOcts();
+ }
+
+ return octs;
+ }
+
+ private Vector generateOcts()
+ {
+ int start = 0;
+ int end = 0;
+ Vector vec = new Vector();
+
+ while (end < string.length)
+ {
+ if ((end + 1) < string.length)
+ {
+ if (string[end] == 0 && string[end + 1] == 0)
+ {
+ byte[] nStr = new byte[end - start + 1];
+
+ for (int i = 0; i != nStr.length; i++)
+ {
+ nStr[i] = string[start + i];
+ }
+
+ vec.addElement(new DEROctetString(nStr));
+ start = end + 1;
+ }
+ }
+ end++;
+ }
+
+ byte[] nStr = new byte[end - start];
+ for (int i = 0; i != nStr.length; i++)
+ {
+ nStr[i] = string[start + i];
+ }
+
+ vec.addElement(new DEROctetString(nStr));
+
+ return vec;
+ }
+
+ public void encode(
+ DEROutputStream out)
+ throws IOException
+ {
+ if (out instanceof BEROutputStream)
+ {
+ out.write(CONSTRUCTED | OCTET_STRING);
+
+ out.write(0x80);
+
+ if (octs == null)
+ {
+ octs = generateOcts();
+ }
+
+ for (int i = 0; i != octs.size(); i++)
+ {
+ out.writeObject(octs.elementAt(i));
+ }
+
+ out.write(0x00);
+ out.write(0x00);
+ }
+ else
+ {
+ super.encode(out);
+ }
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1;
+
+import java.io.*;
+import java.util.*;
+
+public class BERConstructedSequence
+ extends DERConstructedSequence
+{
+ /*
+ * A note on the implementation:
+ * <p>
+ * As DER requires the constructed, definite-length model to
+ * be used for structured types, this varies slightly from the
+ * ASN.1 descriptions given. Rather than just outputing SEQUENCE,
+ * we also have to specify CONSTRUCTED, and the objects length.
+ */
+ void encode(
+ DEROutputStream out)
+ throws IOException
+ {
+ if (out instanceof BEROutputStream)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ BEROutputStream dOut = new BEROutputStream(bOut);
+ Enumeration e = getObjects();
+
+ while (e.hasMoreElements())
+ {
+ Object obj = e.nextElement();
+
+ dOut.writeObject(obj);
+ }
+
+ dOut.close();
+
+ byte[] bytes = bOut.toByteArray();
+
+ out.write(SEQUENCE | CONSTRUCTED);
+ out.write(0x80);
+ out.write(bytes);
+ out.write(0x00);
+ out.write(0x00);
+ }
+ else
+ {
+ super.encode(out);
+ }
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1;
+
+import java.math.BigInteger;
+import java.io.*;
+import java.util.*;
+
+public class BERInputStream
+ extends DERInputStream
+{
+ private DERObject END_OF_STREAM = new DERObject() {
+ void encode(
+ DEROutputStream out)
+ throws IOException
+ {
+ throw new IOException("Eeek!");
+ }
+
+ };
+ public BERInputStream(
+ InputStream is)
+ {
+ super(is);
+ }
+
+ /**
+ * read a string of bytes representing an indefinite length object.
+ */
+ private byte[] readIndefiniteLengthFully()
+ throws IOException
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ int b, b1;
+
+ b1 = read();
+
+ while ((b = read()) >= 0)
+ {
+ if (b1 == 0 && b == 0)
+ {
+ break;
+ }
+
+ bOut.write(b1);
+ b1 = b;
+ }
+
+ return bOut.toByteArray();
+ }
+
+ private BERConstructedOctetString buildConstructedOctetString(
+ DEROctetString o1,
+ DEROctetString o2)
+ throws IOException
+ {
+ Vector octs = new Vector();
+
+ if (o1 != null)
+ {
+ octs.addElement(o1);
+ octs.addElement(o2);
+ }
+
+ for (;;)
+ {
+ DERObject o = readObject();
+
+ if (o == END_OF_STREAM)
+ {
+ break;
+ }
+
+ octs.addElement(o);
+ }
+
+ return new BERConstructedOctetString(octs);
+ }
+
+ public DERObject readObject()
+ throws IOException
+ {
+ int tag = read();
+ if (tag == -1)
+ {
+ throw new EOFException();
+ }
+
+ int length = readLength();
+
+ if (length < 0) // indefinite length method
+ {
+ byte[] bytes;
+
+ switch (tag)
+ {
+ case NULL:
+ return null;
+ case SEQUENCE | CONSTRUCTED:
+ BERConstructedSequence seq = new BERConstructedSequence();
+
+ for (;;)
+ {
+ DERObject obj = readObject();
+
+ if (obj == END_OF_STREAM)
+ {
+ break;
+ }
+
+ seq.addObject(obj);
+ }
+ return seq;
+ case OCTET_STRING | CONSTRUCTED:
+ return buildConstructedOctetString(null, null);
+ default:
+ if ((tag & (TAGGED | CONSTRUCTED)) != 0)
+ {
+ // with tagged object tag number is bottom 4 bits
+ BERTaggedObject tagObj = new BERTaggedObject(tag & 0x0f, readObject());
+ DERObject o = readObject();
+
+ if (o == END_OF_STREAM)
+ {
+ return tagObj;
+ }
+ else if (o instanceof DEROctetString
+ && tagObj.getObject() instanceof DEROctetString)
+ {
+ //
+ // it's an implicit object - mark it as so...
+ //
+ tagObj = new BERTaggedObject(false, tag & 0x0f,
+ buildConstructedOctetString((DEROctetString)tagObj.getObject(), (DEROctetString)o));
+
+ return tagObj;
+ }
+
+ throw new IOException("truncated tagged object");
+ }
+
+ bytes = readIndefiniteLengthFully();
+
+ return buildObject(tag, bytes);
+ }
+ }
+ else
+ {
+ if (tag == 0 && length == 0) // end of contents marker.
+ {
+ return END_OF_STREAM;
+ }
+
+ byte[] bytes = new byte[length];
+
+ readFully(bytes);
+
+ return buildObject(tag, bytes);
+ }
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1;
+
+import java.io.*;
+
+public class BEROutputStream
+ extends DEROutputStream
+{
+ public BEROutputStream(
+ OutputStream os)
+ {
+ super(os);
+ }
+
+ public void writeObject(
+ Object obj)
+ throws IOException
+ {
+ if (obj == null)
+ {
+ writeNull();
+ }
+ else if (obj instanceof DERObject)
+ {
+ ((DERObject)obj).encode(this);
+ }
+ else if (obj instanceof DEREncodable)
+ {
+ ((DEREncodable)obj).getDERObject().encode(this);
+ }
+ else
+ {
+ throw new IOException("object not BEREncodable");
+ }
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * BER TaggedObject - in ASN.1 nottation this is any object proceeded by
+ * a [n] where n is some number - these are assume to follow the construction
+ * rules (as with sequences).
+ */
+public class BERTaggedObject
+ extends DERTaggedObject
+{
+ /**
+ * This creates an empty tagged object of tagNo (ie. zero length).
+ *
+ * @param tagNo the tag number for this object.
+ */
+ public BERTaggedObject(
+ int tagNo)
+ {
+ super(tagNo);
+ }
+
+ /**
+ * @param tagNo the tag number for this object.
+ * @param obj the tagged object.
+ */
+ public BERTaggedObject(
+ int tagNo,
+ DERObject obj)
+ {
+ super(tagNo, obj);
+ }
+
+ /**
+ * @param explicit true if an explicitly tagged object.
+ * @param tagNo the tag number for this object.
+ * @param obj the tagged object.
+ */
+ public BERTaggedObject(
+ boolean explicit,
+ int tagNo,
+ DERObject obj)
+ {
+ super(explicit, tagNo, obj);
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException
+ {
+ if (out instanceof BEROutputStream)
+ {
+ out.write(CONSTRUCTED | TAGGED | tagNo);
+ out.write(0x80);
+
+ if (!empty)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ BEROutputStream dOut = new BEROutputStream(bOut);
+
+ if (!explicit)
+ {
+ if (obj instanceof BERConstructedOctetString)
+ {
+ Vector octs = ((BERConstructedOctetString)obj).getDEROctets();
+
+ for (int i = 0; i != octs.size(); i++)
+ {
+ dOut.writeObject(octs.elementAt(i));
+ }
+ }
+ else
+ {
+ dOut.writeObject(obj); // hmmm...
+ }
+ }
+ else
+ {
+ dOut.writeObject(obj);
+ }
+
+ dOut.close();
+
+ out.write(bOut.toByteArray());
+ }
+
+ out.write(0x00);
+ out.write(0x00);
+ }
+ else
+ {
+ super.encode(out);
+ }
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1;
+
+import java.io.*;
+
+/**
+ * DER BMPString object.
+ */
+public class DERBMPString
+ extends DERObject
+ implements DERString
+{
+ String string;
+
+ /**
+ * basic constructor - byte encoded string.
+ */
+ public DERBMPString(
+ byte[] string)
+ {
+ try
+ {
+ this.string = new String(string, "UnicodeBig");
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ /**
+ * basic constructor
+ */
+ public DERBMPString(
+ String string)
+ {
+ this.string = string;
+ }
+
+ public String getString()
+ {
+ return string;
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException
+ {
+ char[] c = string.toCharArray();
+ byte[] b = new byte[c.length * 2];
+
+ for (int i = 0; i != c.length; i++)
+ {
+ b[2 * i] = (byte)((c[i] & 0xff00) >> 8);
+ b[2 * i + 1] = (byte)c[i];
+ }
+
+ out.writeEncoded(BMP_STRING, b);
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1;
+
+import java.io.*;
+
+public class DERBitString
+ extends DERObject
+{
+ protected byte[] data;
+ protected int padBits;
+
+ protected DERBitString(
+ byte data,
+ int padBits)
+ {
+ this.data = new byte[1];
+ this.data[0] = data;
+ this.padBits = padBits;
+ }
+
+ /**
+ * @param data the octets making up the bit string.
+ * @param padBits the number of extra bits at the end of the string.
+ */
+ public DERBitString(
+ byte[] data,
+ int padBits)
+ {
+ this.data = data;
+ this.padBits = padBits;
+ }
+
+ public DERBitString(
+ byte[] data)
+ {
+ this(data, 0);
+ }
+
+ public DERBitString(
+ DERObject obj)
+ {
+ try
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+
+ dOut.writeObject(obj);
+ dOut.close();
+
+ this.data = bOut.toByteArray();
+ this.padBits = 0;
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("Error processing object : " + e.toString());
+ }
+ }
+
+ public DERBitString(
+ DEREncodable obj)
+ {
+ this(obj.getDERObject());
+ }
+
+ public byte[] getBytes()
+ {
+ return data;
+ }
+
+ public int getPadBits()
+ {
+ return padBits;
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException
+ {
+ byte[] bytes = new byte[getBytes().length + 1];
+
+ bytes[0] = (byte)getPadBits();
+ System.arraycopy(getBytes(), 0, bytes, 1, bytes.length - 1);
+
+ out.writeEncoded(BIT_STRING, bytes);
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1;
+
+import java.io.*;
+
+public class DERBoolean
+ extends DERObject
+{
+ byte value;
+
+ public DERBoolean(
+ byte[] value)
+ {
+ this.value = value[0];
+ }
+
+ public DERBoolean(
+ boolean value)
+ {
+ this.value = (value) ? (byte)0xff : (byte)0;
+ }
+
+ public boolean isTrue()
+ {
+ return (value != 0);
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException
+ {
+ byte[] bytes = new byte[1];
+
+ bytes[0] = value;
+
+ out.writeEncoded(BOOLEAN, bytes);
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1;
+
+import java.io.*;
+import java.util.*;
+
+public class DERConstructedSequence
+ extends DERObject
+{
+ private Vector seq = new Vector();
+
+ public DERConstructedSequence()
+ {
+ }
+
+ public void addObject(
+ DEREncodable obj)
+ {
+ seq.addElement(obj);
+ }
+
+ public Enumeration getObjects()
+ {
+ return seq.elements();
+ }
+
+ /**
+ * return the object at the sequence postion indicated by index.
+ *
+ * @param the sequence number (starting at zero) of the object
+ * @return the object at the sequence postion indicated by index.
+ */
+ public Object getObjectAt(
+ int index)
+ {
+ return seq.elementAt(index);
+ }
+
+ /**
+ * return the number of objects in this sequence.
+ *
+ * @return the number of objects in this sequence.
+ */
+ public int getSize()
+ {
+ return seq.size();
+ }
+
+ /*
+ * A note on the implementation:
+ * <p>
+ * As DER requires the constructed, definite-length model to
+ * be used for structured types, this varies slightly from the
+ * ASN.1 descriptions given. Rather than just outputing SEQUENCE,
+ * we also have to specify CONSTRUCTED, and the objects length.
+ */
+ void encode(
+ DEROutputStream out)
+ throws IOException
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+ Enumeration e = getObjects();
+
+ while (e.hasMoreElements())
+ {
+ Object obj = e.nextElement();
+
+ dOut.writeObject(obj);
+ }
+
+ dOut.close();
+
+ byte[] bytes = bOut.toByteArray();
+
+ out.writeEncoded(SEQUENCE | CONSTRUCTED, bytes);
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1;
+
+import java.io.*;
+import java.util.*;
+
+public class DERConstructedSet
+ extends DERObject
+{
+ private Vector set = new Vector();
+
+ public DERConstructedSet()
+ {
+ }
+
+ public void addObject(
+ DEREncodable obj)
+ {
+ set.addElement(obj);
+ }
+
+ public Enumeration getObjects()
+ {
+ return set.elements();
+ }
+
+ /**
+ * return the object at the set postion indicated by index.
+ *
+ * @param the set number (starting at zero) of the object
+ * @return the object at the set postion indicated by index.
+ */
+ public Object getObjectAt(
+ int index)
+ {
+ return set.elementAt(index);
+ }
+
+ /**
+ * return the number of objects in this set.
+ *
+ * @return the number of objects in this set.
+ */
+ public int getSize()
+ {
+ return set.size();
+ }
+
+ /*
+ * A note on the implementation:
+ * <p>
+ * As DER requires the constructed, definite-length model to
+ * be used for structured types, this varies slightly from the
+ * ASN.1 descriptions given. Rather than just outputing SET,
+ * we also have to specify CONSTRUCTED, and the objects length.
+ */
+ void encode(
+ DEROutputStream out)
+ throws IOException
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+ Enumeration e = getObjects();
+
+ while (e.hasMoreElements())
+ {
+ Object obj = e.nextElement();
+
+ dOut.writeObject(obj);
+ }
+
+ dOut.close();
+
+ byte[] bytes = bOut.toByteArray();
+
+ out.writeEncoded(SET | CONSTRUCTED, bytes);
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1;
+
+public interface DEREncodable
+{
+ public DERObject getDERObject();
+}
--- /dev/null
+package org.bouncycastle.asn1;
+
+import java.io.*;
+
+/**
+ * DER IA5String object - this is an ascii string.
+ */
+public class DERIA5String
+ extends DERObject
+ implements DERString
+{
+ String string;
+
+ /**
+ * basic constructor - with bytes.
+ */
+ public DERIA5String(
+ byte[] string)
+ {
+ try
+ {
+ this.string = new String(string, "US-ASCII");
+ }
+ catch(UnsupportedEncodingException e)
+ {
+ throw new RuntimeException("PANIC: " + e);
+ }
+ }
+
+ /**
+ * basic constructor - with string.
+ */
+ public DERIA5String(
+ String string)
+ {
+ this.string = string;
+ }
+
+ public String getString()
+ {
+ return string;
+ }
+
+ public byte[] getOctets()
+ {
+ try
+ {
+ return string.getBytes("US-ASCII");
+ }
+ catch(UnsupportedEncodingException e)
+ {
+ throw new RuntimeException("PANIC: " + e);
+ }
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException
+ {
+ out.writeEncoded(IA5_STRING, this.getOctets());
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1;
+
+import java.math.BigInteger;
+import java.io.*;
+
+public class DERInputStream
+ extends FilterInputStream implements DERTags
+{
+ public DERInputStream(
+ InputStream is)
+ {
+ super(is);
+ }
+
+ protected int readLength()
+ throws IOException
+ {
+ int length = read();
+ if (length < 0)
+ {
+ throw new IOException("EOF found when length expected");
+ }
+
+ if (length == 0x80)
+ {
+ return -1; // indefinite-length encoding
+ }
+
+ if (length > 127)
+ {
+ int size = length & 0x7f;
+
+ length = 0;
+ for (int i = 0; i < size; i++)
+ {
+ int next = read();
+
+ if (next < 0)
+ {
+ throw new IOException("EOF found reading length");
+ }
+
+ length = (length << 8) + next;
+ }
+ }
+
+ return length;
+ }
+
+ protected void readFully(
+ byte[] bytes)
+ throws IOException
+ {
+ int left = bytes.length;
+
+ if (left == 0)
+ {
+ return;
+ }
+
+ while ((left -= read(bytes, bytes.length - left, left)) != 0)
+ {
+ ;
+ }
+ }
+
+ /**
+ * build an object given its tag and a byte stream to construct it
+ * from.
+ */
+ protected DERObject buildObject(
+ int tag,
+ byte[] bytes)
+ throws IOException
+ {
+ switch (tag)
+ {
+ case NULL:
+ return null;
+ case SEQUENCE | CONSTRUCTED:
+ ByteArrayInputStream bIn = new ByteArrayInputStream(bytes);
+ BERInputStream dIn = new BERInputStream(bIn);
+ DERConstructedSequence seq = new DERConstructedSequence();
+
+ try
+ {
+ for (;;)
+ {
+ DERObject obj = dIn.readObject();
+
+ seq.addObject(obj);
+ }
+ }
+ catch (EOFException ex)
+ {
+ return seq;
+ }
+ case SET | CONSTRUCTED:
+ bIn = new ByteArrayInputStream(bytes);
+ dIn = new BERInputStream(bIn);
+
+ DERSet set = new DERSet(dIn.readObject());
+
+ try
+ {
+ for (;;)
+ {
+ DERObject obj = dIn.readObject();
+
+ set.addObject(obj);
+ }
+ }
+ catch (EOFException ex)
+ {
+ return set;
+ }
+ case BOOLEAN:
+ return new DERBoolean(bytes);
+ case INTEGER:
+ return new DERInteger(bytes);
+ case OBJECT_IDENTIFIER:
+ int head = bytes[0] & 0xff;
+ StringBuffer objId = new StringBuffer();
+
+ objId.append(Integer.toString(head / 40));
+ objId.append('.');
+ objId.append(Integer.toString(head % 40));
+
+ int value = 0;
+
+ for (int i = 1; i != bytes.length; i++)
+ {
+ int b = bytes[i] & 0xff;
+
+ value = value * 128 + (b & 0x7f);
+ if ((b & 128) == 0) // end of number reached
+ {
+ objId.append('.');
+ objId.append(Integer.toString(value));
+ value = 0;
+ }
+ }
+
+ return new DERObjectIdentifier(objId.toString());
+ case BIT_STRING:
+ int padBits = bytes[0];
+ byte[] data = new byte[bytes.length - 1];
+
+ System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
+
+ return new DERBitString(data, padBits);
+ case PRINTABLE_STRING:
+ return new DERPrintableString(bytes);
+ case IA5_STRING:
+ return new DERIA5String(bytes);
+ case T61_STRING:
+ return new DERT61String(bytes);
+ case VISIBLE_STRING:
+ return new DERVisibleString(bytes);
+ case BMP_STRING:
+ return new DERBMPString(bytes);
+ case OCTET_STRING:
+ return new DEROctetString(bytes);
+ case UTC_TIME:
+ return new DERUTCTime(new String(bytes));
+ default:
+ //
+ // with tagged object tag number is bottom 4 bits
+ //
+ if ((tag & (TAGGED | CONSTRUCTED)) != 0)
+ {
+ if (bytes.length == 0) // empty tag!
+ {
+ return new DERTaggedObject(tag & 0x0f);
+ }
+
+ //
+ // simple type - implicit... return an octet string
+ //
+ if ((tag & CONSTRUCTED) == 0)
+ {
+ return new DERTaggedObject(false, tag & 0x0f, new DEROctetString(bytes));
+ }
+
+ bIn = new ByteArrayInputStream(bytes);
+ dIn = new BERInputStream(bIn);
+
+ DEREncodable dObj = dIn.readObject();
+
+ //
+ // explicitly tagged (probably!) - if it isn't we'd have to
+ // tell from the context
+ //
+ if (dIn.available() == 0)
+ {
+ return new DERTaggedObject(tag & 0x0f, dObj);
+ }
+
+ //
+ // another implicit object, we'll create a sequence...
+ //
+ seq = new DERConstructedSequence();
+
+ seq.addObject(dObj);
+
+ try
+ {
+ for (;;)
+ {
+ dObj = dIn.readObject();
+
+ seq.addObject(dObj);
+ }
+ }
+ catch (EOFException ex)
+ {
+ // ignore --
+ }
+
+ return new DERTaggedObject(false, tag & 0x0f, seq);
+ }
+
+ return new DERUnknownTag(tag, bytes);
+ }
+ }
+
+ public DERObject readObject()
+ throws IOException
+ {
+ int tag = read();
+ if (tag == -1)
+ {
+ throw new EOFException();
+ }
+
+ int length = readLength();
+ byte[] bytes = new byte[length];
+
+ readFully(bytes);
+
+ return buildObject(tag, bytes);
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1;
+
+import java.io.*;
+import java.math.BigInteger;
+
+public class DERInteger
+ extends DERObject
+{
+ byte[] bytes;
+
+ public DERInteger(
+ int value)
+ {
+ bytes = BigInteger.valueOf(value).toByteArray();
+ }
+
+ public DERInteger(
+ BigInteger value)
+ {
+ bytes = value.toByteArray();
+ }
+
+ public DERInteger(
+ byte[] bytes)
+ {
+ this.bytes = bytes;
+ }
+
+ public BigInteger getValue()
+ {
+ return new BigInteger(bytes);
+ }
+
+ /**
+ * in some cases positive values get crammed into a space,
+ * that's not quite big enough...
+ */
+ public BigInteger getPositiveValue()
+ {
+ return new BigInteger(1, bytes);
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException
+ {
+ out.writeEncoded(INTEGER, bytes);
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+public abstract class DERObject
+ implements DERTags, DEREncodable
+{
+ abstract void encode(DEROutputStream out)
+ throws IOException;
+
+ public DERObject getDERObject()
+ {
+ return this;
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1;
+
+import java.io.*;
+
+public class DERObjectIdentifier
+ extends DERObject
+{
+ String identifier;
+
+ public DERObjectIdentifier(
+ String identifier)
+ {
+ this.identifier = identifier;
+ }
+
+ public String getId()
+ {
+ return identifier;
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException
+ {
+ OIDTokenizer tok = new OIDTokenizer(identifier);
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+
+ // space for 5 7 bit numbers in an int
+ byte[] iBuf = new byte[5];
+
+ dOut.write(
+ Integer.parseInt(tok.nextToken()) * 40
+ + Integer.parseInt(tok.nextToken()));
+
+ while (tok.hasMoreTokens())
+ {
+ //
+ // translate into base 128
+ //
+ int value = Integer.parseInt(tok.nextToken());
+ int count = iBuf.length - 1;
+
+ iBuf[count--] = (byte)(value % 128);
+ value /= 128;
+
+ while (value != 0)
+ {
+ iBuf[count--] = (byte)((value % 128) | 0x80);
+ value /= 128;
+ }
+ dOut.write(iBuf, count + 1, iBuf.length - (count + 1));
+ }
+
+ dOut.close();
+
+ byte[] bytes = bOut.toByteArray();
+
+ out.writeEncoded(OBJECT_IDENTIFIER, bytes);
+ }
+
+ public int hashCode()
+ {
+ return identifier.hashCode();
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if ((o == null) || !(o instanceof DERObjectIdentifier))
+ {
+ return false;
+ }
+
+ return identifier.equals(((DERObjectIdentifier)o).identifier);
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1;
+
+import java.io.*;
+
+public class DEROctetString
+ extends DERObject
+{
+ byte[] string;
+
+ /**
+ * @param string the octets making up the octet string.
+ */
+ public DEROctetString(
+ byte[] string)
+ {
+ this.string = string;
+ }
+
+ public DEROctetString(
+ DERObject obj)
+ {
+ try
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+
+ dOut.writeObject(obj);
+ dOut.close();
+
+ this.string = bOut.toByteArray();
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("Error processing object : " + e.toString());
+ }
+ }
+
+ public DEROctetString(
+ DEREncodable obj)
+ {
+ this(obj.getDERObject());
+ }
+
+ public byte[] getOctets()
+ {
+ return string;
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException
+ {
+ out.writeEncoded(OCTET_STRING, string);
+ }
+
+ public int hashCode()
+ {
+ byte[] b = this.getOctets();
+ int value = 0;
+
+ for (int i = 0; i != b.length; i++)
+ {
+ value ^= (b[i] & 0xff) << (i % 4);
+ }
+
+ return value;
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (o == null || !(o instanceof DEROctetString))
+ {
+ return false;
+ }
+
+ DEROctetString other = (DEROctetString)o;
+
+ if (other.getOctets().length != this.getOctets().length)
+ {
+ return false;
+ }
+
+ byte[] b1 = other.getOctets();
+ byte[] b2 = this.getOctets();
+
+ for (int i = 0; i != b1.length; i++)
+ {
+ if (b1[i] != b2[i])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1;
+
+import java.io.*;
+
+public class DEROutputStream
+ extends FilterOutputStream implements DERTags
+{
+ public DEROutputStream(
+ OutputStream os)
+ {
+ super(os);
+ }
+
+ private void writeLength(
+ int length)
+ throws IOException
+ {
+ if (length > 127)
+ {
+ int size = 1;
+ int val = length;
+
+ while ((val >>>= 8) != 0)
+ {
+ size++;
+ }
+
+ write((byte)(size | 0x80));
+
+ for (int i = (size - 1) * 8; i >= 0; i -= 8)
+ {
+ write((byte)(length >> i));
+ }
+ }
+ else
+ {
+ write((byte)length);
+ }
+ }
+
+ void writeEncoded(
+ int tag,
+ byte[] bytes)
+ throws IOException
+ {
+ write(tag);
+ writeLength(bytes.length);
+ write(bytes);
+ }
+
+ protected void writeNull()
+ throws IOException
+ {
+ write(NULL);
+ write(0x00);
+ }
+
+ public void writeObject(
+ Object obj)
+ throws IOException
+ {
+ if (obj == null)
+ {
+ writeNull();
+ }
+ else if (obj instanceof DERObject)
+ {
+ ((DERObject)obj).encode(this);
+ }
+ else if (obj instanceof DEREncodable)
+ {
+ ((DEREncodable)obj).getDERObject().encode(this);
+ }
+ else
+ {
+ throw new IOException("object not DEREncodable");
+ }
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1;
+
+import java.io.*;
+
+/**
+ * DER PrintableString object.
+ */
+public class DERPrintableString
+ extends DERObject
+ implements DERString
+{
+ String string;
+
+ /**
+ * basic constructor - byte encoded string.
+ */
+ public DERPrintableString(
+ byte[] string)
+ {
+ try
+ {
+ this.string = new String(string, "US-ASCII");
+ }
+ catch(UnsupportedEncodingException e)
+ {
+ throw new RuntimeException("PANIC: " + e);
+ }
+ }
+
+ /**
+ * basic constructor
+ */
+ public DERPrintableString(
+ String string)
+ {
+ this.string = string;
+ }
+
+ public String getString()
+ {
+ return string;
+ }
+
+ public byte[] getOctets()
+ {
+ try
+ {
+ return string.getBytes("US-ASCII");
+ }
+ catch(UnsupportedEncodingException e)
+ {
+ throw new RuntimeException("PANIC: " + e);
+ }
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException
+ {
+ out.writeEncoded(PRINTABLE_STRING, this.getOctets());
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1;
+
+import java.io.*;
+
+/**
+ * DER Set with a single object.
+ */
+public class DERSet
+ extends DERConstructedSet
+{
+ /**
+ * @param sequence the sequence making up the set
+ */
+ public DERSet(
+ DEREncodable sequence)
+ {
+ this.addObject(sequence);
+ }
+
+ public DERObject getSequence()
+ {
+ return (DERObject)this.getObjectAt(0);
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1;
+
+/**
+ * basic interface for DER string objects.
+ */
+public interface DERString
+{
+ public String getString();
+}
--- /dev/null
+package org.bouncycastle.asn1;
+
+import java.io.*;
+
+/**
+ * DER T61String (also the teletex string)
+ */
+public class DERT61String
+ extends DERObject
+ implements DERString
+{
+ String string;
+
+ /**
+ * basic constructor - with bytes.
+ */
+ public DERT61String(
+ byte[] string)
+ {
+ this.string = new String(string);
+ }
+
+ /**
+ * basic constructor - with string.
+ */
+ public DERT61String(
+ String string)
+ {
+ this.string = string;
+ }
+
+ public String getString()
+ {
+ return string;
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException
+ {
+ out.writeEncoded(T61_STRING, string.getBytes());
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1;
+
+import java.io.*;
+
+/**
+ * DER TaggedObject - in ASN.1 nottation this is any object proceeded by
+ * a [n] where n is some number - these are assume to follow the construction
+ * rules (as with sequences).
+ */
+public class DERTaggedObject
+ extends DERObject
+{
+ int tagNo;
+ boolean empty = false;
+ boolean explicit = true;
+ DEREncodable obj = null;
+
+ /**
+ * This creates an empty tagged object of tagNo (ie. zero length).
+ *
+ * @param tagNo the tag number for this object.
+ */
+ public DERTaggedObject(
+ int tagNo)
+ {
+ this.explicit = true;
+ this.tagNo = tagNo;
+ this.empty = true;
+ }
+
+ /**
+ * @param tagNo the tag number for this object.
+ * @param obj the tagged object.
+ */
+ public DERTaggedObject(
+ int tagNo,
+ DEREncodable obj)
+ {
+ this.explicit = true;
+ this.tagNo = tagNo;
+ this.obj = obj;
+ }
+
+ /**
+ * @param explicit true if the object is explicitly tagged.
+ * @param tagNo the tag number for this object.
+ * @param obj the tagged object.
+ */
+ public DERTaggedObject(
+ boolean explicit,
+ int tagNo,
+ DEREncodable obj)
+ {
+ this.explicit = explicit;
+ this.tagNo = tagNo;
+ this.obj = obj;
+ }
+
+ public int getTagNo()
+ {
+ return tagNo;
+ }
+
+ public boolean isExplicit()
+ {
+ return explicit;
+ }
+
+ public boolean isEmpty()
+ {
+ return empty;
+ }
+
+ public DERObject getObject()
+ {
+ return obj.getDERObject();
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException
+ {
+ if (!empty)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+
+ dOut.writeObject(obj);
+ dOut.close();
+
+ byte[] bytes = bOut.toByteArray();
+
+ if (explicit)
+ {
+ out.writeEncoded(CONSTRUCTED | TAGGED | tagNo, bOut.toByteArray());
+ }
+ else
+ {
+ //
+ // need to mark constructed types...
+ //
+ if ((bytes[0] & CONSTRUCTED) != 0)
+ {
+ bytes[0] = (byte)(CONSTRUCTED | TAGGED | tagNo);
+ }
+ else
+ {
+ bytes[0] = (byte)(TAGGED | tagNo);
+ }
+
+ out.write(bytes);
+ }
+ }
+ else
+ {
+ out.writeEncoded(CONSTRUCTED | TAGGED | tagNo, new byte[0]);
+ }
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1;
+
+public interface DERTags
+{
+ public static final int BOOLEAN = 0x01;
+ public static final int INTEGER = 0x02;
+ public static final int BIT_STRING = 0x03;
+ public static final int OCTET_STRING = 0x04;
+ public static final int NULL = 0x05;
+ public static final int OBJECT_IDENTIFIER = 0x06;
+ public static final int EXTERNAL = 0x08;
+ public static final int SEQUENCE = 0x10;
+ public static final int SEQUENCE_OF = 0x10; // for completeness
+ public static final int SET = 0x11;
+ public static final int SET_OF = 0x11; // for completeness
+ public static final int CONSTRUCTED = 0x20;
+ public static final int TAGGED = 0x80;
+
+ public static final int NUMERIC_STRING = 0x12;
+ public static final int PRINTABLE_STRING = 0x13;
+ public static final int T61_STRING = 0x14;
+ public static final int VIDEOTEX_STRING = 0x15;
+ public static final int IA5_STRING = 0x16;
+ public static final int UTC_TIME = 0x17;
+ public static final int GENERALIZED_TIME = 0x18;
+ public static final int GRAPHIC_STRING = 0x19;
+ public static final int VISIBLE_STRING = 0x1a;
+ public static final int GENERAL_STRING = 0x1b;
+ public static final int BMP_STRING = 0x1e;
+}
--- /dev/null
+package org.bouncycastle.asn1;
+
+import java.io.*;
+import java.util.*;
+import java.io.*;
+
+/**
+ * UTC time object.
+ */
+public class DERUTCTime
+ extends DERObject
+{
+ String time;
+
+ /**
+ * The correct format for this is YYMMDDHHMMSSZ (it used to be that seconds were
+ * never encoded. When you're creating one of these objects from scratch, that's
+ * what you want to use, otherwise we'll try to deal with whatever gets read from
+ * the input stream... (this is why the input format is different from the getTime()
+ * method output).
+ * <p>
+ * You can generate a Java date string in the right format by using:
+ * <pre>
+ * dateF = new SimpleDateFormat("yyMMddHHmmss");
+ * tz = new SimpleTimeZone(0, "Z");
+ *
+ * dateF.setTimeZone(tz);
+ *
+ * utcTime = new DERUTCTime(dateF.format(new Date()) + "Z");
+ * </pre>
+ *
+ * @param time the time string.
+ */
+ public DERUTCTime(
+ String time)
+ {
+ this.time = time;
+ }
+
+ /**
+ * return the time - always in the form of
+ * YYMMDDhhmmssGMT(+hh:mm|-hh:mm).
+ * <p>
+ * Normally in a certificate we would expect "Z" rather than "GMT",
+ * however adding the "GMT" means we can just use:
+ * <pre>
+ * dateF = new SimpleDateFormat("yyMMddHHmmssz");
+ * </pre>
+ * To read in the time and get a date which is compatible with our local
+ * time zone.
+ */
+ public String getTime()
+ {
+ //
+ // standardise the format.
+ //
+ if (time.length() == 11)
+ {
+ return time.substring(0, 10) + "00GMT+00:00";
+ }
+ else if (time.length() == 13)
+ {
+ return time.substring(0, 12) + "GMT+00:00";
+ }
+ else if (time.length() == 17)
+ {
+ return time.substring(0, 12) + "GMT" + time.substring(12, 15) + ":" + time.substring(15, 17);
+ }
+
+ return time;
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException
+ {
+ out.writeEncoded(UTC_TIME, time.getBytes());
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1;
+
+import java.io.*;
+
+/**
+ * We insert one of these when we find a tag we don't recognise.
+ */
+public class DERUnknownTag
+ extends DERObject
+{
+ int tag;
+ byte[] data;
+
+ /**
+ * @param tag the tag value.
+ * @param data the octets making up the time.
+ */
+ public DERUnknownTag(
+ int tag,
+ byte[] data)
+ {
+ this.tag = tag;
+ this.data = data;
+ }
+
+ public int getTag()
+ {
+ return tag;
+ }
+
+ public byte[] getData()
+ {
+ return data;
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException
+ {
+ out.writeEncoded(tag, data);
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1;
+
+import java.io.*;
+
+/**
+ * DER VisibleString object.
+ */
+public class DERVisibleString
+ extends DERObject
+ implements DERString
+{
+ String string;
+
+ /**
+ * basic constructor - byte encoded string.
+ */
+ public DERVisibleString(
+ byte[] string)
+ {
+ try
+ {
+ this.string = new String(string, "US-ASCII");
+ }
+ catch(UnsupportedEncodingException e)
+ {
+ throw new RuntimeException("PANIC: " + e);
+ }
+ }
+
+ /**
+ * basic constructor
+ */
+ public DERVisibleString(
+ String string)
+ {
+ this.string = string;
+ }
+
+ public String getString()
+ {
+ return string;
+ }
+
+ public byte[] getOctets()
+ {
+ try
+ {
+ return string.getBytes("US-ASCII");
+ }
+ catch(UnsupportedEncodingException e)
+ {
+ throw new RuntimeException("PANIC: " + e);
+ }
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException
+ {
+ out.writeEncoded(VISIBLE_STRING, this.getOctets());
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1;
+
+/**
+ * class for breaking up an OID into it's component tokens, ala
+ * java.util.StringTokenizer. We need this class as some of the
+ * lightweight Java environment don't support classes like
+ * StringTokenizer.
+ */
+public class OIDTokenizer
+{
+ private String oid;
+ private int index;
+
+ public OIDTokenizer(
+ String oid)
+ {
+ this.oid = oid;
+ this.index = 0;
+ }
+
+ public boolean hasMoreTokens()
+ {
+ return (index != -1);
+ }
+
+ public String nextToken()
+ {
+ if (index == -1)
+ {
+ return null;
+ }
+
+ String token;
+ int end = oid.indexOf('.', index);
+
+ if (end == -1)
+ {
+ token = oid.substring(index);
+ index = -1;
+ return token;
+ }
+
+ token = oid.substring(index, end);
+
+ index = end + 1;
+ return token;
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1.pkcs;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+
+public interface PKCSObjectIdentifiers
+{
+ //
+ // pkcs-1 OBJECT IDENTIFIER ::= {
+ // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }
+ //
+ static final String pkcs_1 = "1.2.840.113549.1.1";
+ static final DERObjectIdentifier rsaEncryption = new DERObjectIdentifier(pkcs_1 + ".1");
+ static final DERObjectIdentifier md2WithRSAEncryption = new DERObjectIdentifier(pkcs_1 + ".2");
+ static final DERObjectIdentifier md4WithRSAEncryption = new DERObjectIdentifier(pkcs_1 + ".3");
+ static final DERObjectIdentifier md5WithRSAEncryption = new DERObjectIdentifier(pkcs_1 + ".4");
+ static final DERObjectIdentifier sha1WithRSAEncryption = new DERObjectIdentifier(pkcs_1 + ".5");
+ static final DERObjectIdentifier srsaOAEPEncryptionSET = new DERObjectIdentifier(pkcs_1 + ".6");
+
+ //
+ // pkcs-3 OBJECT IDENTIFIER ::= {
+ // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 3 }
+ //
+ static final String pkcs_3 = "1.2.840.113549.1.3";
+ static final DERObjectIdentifier dhKeyAgreement = new DERObjectIdentifier(pkcs_3 + ".1");
+
+ //
+ // pkcs-5 OBJECT IDENTIFIER ::= {
+ // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 5 }
+ //
+ static final String pkcs_5 = "1.2.840.113549.1.5";
+
+ static final DERObjectIdentifier id_PBES2 = new DERObjectIdentifier(pkcs_5 + ".13");
+
+ static final DERObjectIdentifier id_PBKDF2 = new DERObjectIdentifier(pkcs_5 + ".12");
+
+ //
+ // encryptionAlgorithm OBJECT IDENTIFIER ::= {
+ // iso(1) member-body(2) us(840) rsadsi(113549) 3 }
+ //
+ static final String encryptionAlgorithm = "1.2.840.113549.3";
+
+ static final DERObjectIdentifier des_EDE3_CBC = new DERObjectIdentifier(encryptionAlgorithm + ".7");
+ static final DERObjectIdentifier RC2_CBC = new DERObjectIdentifier(encryptionAlgorithm + ".2");
+
+ //
+ // object identifiers for digests
+ //
+
+ //
+ // md2 OBJECT IDENTIFIER ::=
+ // {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 2}
+ //
+ static final DERObjectIdentifier md2 = new DERObjectIdentifier("1.2.840.113549.2.2");
+
+ //
+ // md5 OBJECT IDENTIFIER ::=
+ // {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 5}
+ //
+ static final DERObjectIdentifier md5 = new DERObjectIdentifier("1.2.840.113549.2.5");
+
+ //
+ // pkcs-7 OBJECT IDENTIFIER ::= {
+ // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 7 }
+ //
+ static final String pkcs_7 = "1.2.840.113549.1.7";
+ static final DERObjectIdentifier data = new DERObjectIdentifier(pkcs_7 + ".1");
+ static final DERObjectIdentifier signedData = new DERObjectIdentifier(pkcs_7 + ".2");
+ static final DERObjectIdentifier envelopedData = new DERObjectIdentifier(pkcs_7 + ".3");
+ static final DERObjectIdentifier signedAndEnvelopedData = new DERObjectIdentifier(pkcs_7 + ".4");
+ static final DERObjectIdentifier digestedData = new DERObjectIdentifier(pkcs_7 + ".5");
+ static final DERObjectIdentifier encryptedData = new DERObjectIdentifier(pkcs_7 + ".6");
+
+ //
+ // pkcs-9 OBJECT IDENTIFIER ::= {
+ // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 }
+ //
+ static final String pkcs_9 = "1.2.840.113549.1.9";
+
+ static final DERObjectIdentifier pkcs_9_at_emailAddress = new DERObjectIdentifier(pkcs_9 + ".1");
+ static final DERObjectIdentifier pkcs_9_at_friendlyName = new DERObjectIdentifier(pkcs_9 + ".20");
+ static final DERObjectIdentifier pkcs_9_at_localKeyId = new DERObjectIdentifier(pkcs_9 + ".21");
+ static final DERObjectIdentifier x509certType = new DERObjectIdentifier(pkcs_9 + ".22.1");
+
+ //
+ // pkcs-12 OBJECT IDENTIFIER ::= {
+ // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 12 }
+ //
+ static final String pkcs_12 = "1.2.840.113549.1.12";
+ static final String bagtypes = pkcs_12 + ".10.1";
+
+ static final DERObjectIdentifier keyBag = new DERObjectIdentifier(bagtypes + ".1");
+ static final DERObjectIdentifier pkcs8ShroudedKeyBag = new DERObjectIdentifier(bagtypes + ".2");
+ static final DERObjectIdentifier certBag = new DERObjectIdentifier(bagtypes + ".3");
+ static final DERObjectIdentifier crlBag = new DERObjectIdentifier(bagtypes + ".4");
+ static final DERObjectIdentifier secretBag = new DERObjectIdentifier(bagtypes + ".5");
+ static final DERObjectIdentifier safeContentsBag = new DERObjectIdentifier(bagtypes + ".6");
+}
+
--- /dev/null
+package org.bouncycastle.asn1.x509;
+
+import java.io.*;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.*;
+
+public class AlgorithmIdentifier
+ implements DEREncodable
+{
+ private DERObjectIdentifier objectId;
+ private DERObject parameters;
+ private boolean parametersDefined = false;
+
+ public AlgorithmIdentifier(
+ DERObjectIdentifier objectId)
+ {
+ this.objectId = objectId;
+ }
+
+ public AlgorithmIdentifier(
+ DERObjectIdentifier objectId,
+ DERObject parameters)
+ {
+ parametersDefined = true;
+
+ this.objectId = objectId;
+ this.parameters = parameters;
+ }
+
+ public AlgorithmIdentifier(
+ DERConstructedSequence obj)
+ {
+ objectId = (DERObjectIdentifier)obj.getObjectAt(0);
+
+ if (obj.getSize() == 2)
+ {
+ parametersDefined = true;
+ parameters = (DERObject)obj.getObjectAt(1);
+ }
+ else
+ {
+ parameters = null;
+ }
+ }
+
+ public DERObjectIdentifier getObjectId()
+ {
+ return objectId;
+ }
+
+ public DERObject getParameters()
+ {
+ return parameters;
+ }
+
+ /**
+ * <pre>
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL }
+ * </pre>
+ */
+ public DERObject getDERObject()
+ {
+ DERConstructedSequence seq = new DERConstructedSequence();
+
+ seq.addObject(objectId);
+
+ if (parametersDefined)
+ {
+ seq.addObject(parameters);
+ }
+
+ return seq;
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if ((o == null) || !(o instanceof AlgorithmIdentifier))
+ {
+ return false;
+ }
+
+ AlgorithmIdentifier other = (AlgorithmIdentifier)o;
+
+ if (!this.getObjectId().equals(other.getObjectId()))
+ {
+ return false;
+ }
+
+ if (this.getParameters() == null && other.getParameters() == null)
+ {
+ return true;
+ }
+
+ if (this.getParameters() == null || other.getParameters() == null)
+ {
+ return false;
+ }
+
+ ByteArrayOutputStream b1Out = new ByteArrayOutputStream();
+ ByteArrayOutputStream b2Out = new ByteArrayOutputStream();
+ DEROutputStream d1Out = new DEROutputStream(b1Out);
+ DEROutputStream d2Out = new DEROutputStream(b2Out);
+
+ try
+ {
+ d1Out.writeObject(this.getParameters());
+ d2Out.writeObject(other.getParameters());
+
+ byte[] b1 = b1Out.toByteArray();
+ byte[] b2 = b2Out.toByteArray();
+
+ if (b1.length != b2.length)
+ {
+ return false;
+ }
+
+ for (int i = 0; i != b1.length; i++)
+ {
+ if (b1[i] != b2[i])
+ {
+ return false;
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+
+ return true;
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1.x509;
+
+import java.math.BigInteger;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.asn1.*;
+
+/**
+ * <pre>
+ * id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 35 }
+ *
+ * AuthorityKeyIdentifier ::= SEQUENCE {
+ * keyIdentifier [0] IMPLICIT KeyIdentifier OPTIONAL,
+ * authorityCertIssuer [1] IMPLICIT GeneralNames OPTIONAL,
+ * authorityCertSerialNumber [2] IMPLICIT CertificateSerialNumber OPTIONAL }
+ *
+ * KeyIdentifier ::= OCTET STRING
+ * </pre>
+ *
+ */
+public class AuthorityKeyIdentifier
+ implements DEREncodable
+{
+ DEROctetString keyidentifier=null;
+ GeneralNames certissuer=null;
+ DERInteger certserno=null;
+
+ public AuthorityKeyIdentifier(
+ DERConstructedSequence seq)
+ {
+ Enumeration e = seq.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ DERTaggedObject o = (DERTaggedObject)e.nextElement();
+
+ switch (o.getTagNo())
+ {
+ case 0:
+ this.keyidentifier= (DEROctetString)o.getObject();
+ break;
+
+ case 1:
+ if (o.getObject() instanceof DERConstructedSequence)
+ {
+ this.certissuer = new GeneralNames((DERConstructedSequence)o.getObject());
+ }
+ else
+ {
+ // as it's implicitly tagged we can loose the"sequence"
+ // if there is only one object.
+ //
+ DERConstructedSequence s = new DERConstructedSequence();
+
+ s.addObject(o.getObject());
+
+ this.certissuer = new GeneralNames(s);
+ }
+ break;
+ case 2:
+ //
+ // implicit tagging again...
+ //
+ DEROctetString oct = (DEROctetString)o.getObject();
+
+ this.certserno = new DERInteger(new BigInteger(oct.getOctets()));
+ break;
+ default:
+ throw new IllegalArgumentException("illegal tag");
+ }
+ }
+ }
+
+ /**
+ *
+ * Calulates the keyidentifier using a SHA1 hash over the BIT STRING
+ * from SubjectPublicKeyInfo as defined in RFC2459.
+ *
+ * Example of making a AuthorityKeyIdentifier:
+ * <pre>
+ * SubjectPublicKeyInfo apki = new SubjectPublicKeyInfo((DERConstructedSequence)new DERInputStream(
+ * new ByteArrayInputStream(publicKey.getEncoded())).readObject());
+ * AuthorityKeyIdentifier aki = new AuthorityKeyIdentifier(apki);
+ * </pre>
+ *
+ **/
+ public AuthorityKeyIdentifier(
+ SubjectPublicKeyInfo spki)
+ {
+ Digest digest = new SHA1Digest();
+ byte[] resBuf = new byte[digest.getDigestSize()];
+
+ DERBitString derpk = new DERBitString(spki.getPublicKey());
+ byte[] bytes = derpk.getBytes();
+ digest.update(bytes, 0, bytes.length);
+ digest.doFinal(resBuf, 0);
+ this.keyidentifier=new DEROctetString(resBuf);
+ }
+
+ /**
+ * create an AuthorityKeyIdentifier with the GeneralNames tag and
+ * the serial number provided as well.
+ */
+ public AuthorityKeyIdentifier(
+ SubjectPublicKeyInfo spki,
+ GeneralNames name,
+ BigInteger serialNumber)
+ {
+ Digest digest = new SHA1Digest();
+ byte[] resBuf = new byte[digest.getDigestSize()];
+
+ DERBitString derpk = new DERBitString(spki.getPublicKey());
+ byte[] bytes = derpk.getBytes();
+ digest.update(bytes, 0, bytes.length);
+ digest.doFinal(resBuf, 0);
+
+ this.keyidentifier = new DEROctetString(resBuf);
+ this.certissuer = name;
+ this.certserno = new DERInteger(serialNumber);
+ }
+
+ public byte[] getKeyIdentifier()
+ {
+ if (keyidentifier != null)
+ {
+ return keyidentifier.getOctets();
+ }
+
+ return null;
+ }
+
+ /**
+ * <pre>
+ * AuthorityKeyIdentifier ::= SEQUENCE {
+ * keyIdentifier [0] IMPLICIT KeyIdentifier OPTIONAL,
+ * authorityCertIssuer [1] IMPLICIT GeneralNames OPTIONAL,
+ * authorityCertSerialNumber [2] IMPLICIT CertificateSerialNumber OPTIONAL }
+ *
+ * KeyIdentifier ::= OCTET STRING
+ * </pre>
+ */
+ public DERObject getDERObject()
+ {
+ DERConstructedSequence seq = new DERConstructedSequence();
+
+ if (keyidentifier != null)
+ {
+ seq.addObject(new DERTaggedObject(false, 0, keyidentifier));
+ }
+
+ if (certissuer != null)
+ {
+ seq.addObject(new DERTaggedObject(false, 1, certissuer));
+ }
+
+ if (certserno != null)
+ {
+ seq.addObject(new DERTaggedObject(false, 2, certserno));
+ }
+
+
+ return seq;
+ }
+
+ public String toString()
+ {
+ return ("AuthorityKeyIdentifier: KeyID(" + this.keyidentifier.getOctets() + ")");
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1.x509;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.*;
+
+public class BasicConstraints
+ implements DEREncodable
+{
+ DERBoolean cA = new DERBoolean(false);
+ DERInteger pathLenConstraint = null;
+
+ public BasicConstraints(
+ DERConstructedSequence seq)
+ {
+ if (seq.getSize() != 0)
+ {
+ this.cA = (DERBoolean)seq.getObjectAt(0);
+ this.pathLenConstraint = (DERInteger)seq.getObjectAt(1);
+ }
+ }
+
+ public BasicConstraints(
+ boolean cA,
+ int pathLenConstraint)
+ {
+ this.cA = new DERBoolean(cA);
+ this.pathLenConstraint = new DERInteger(pathLenConstraint);
+ }
+
+ public BasicConstraints(
+ boolean cA)
+ {
+ this.cA = new DERBoolean(cA);
+ this.pathLenConstraint = null;
+ }
+
+ public boolean isCA()
+ {
+ return cA.isTrue();
+ }
+
+ public BigInteger getPathLenConstraint()
+ {
+ if (pathLenConstraint != null)
+ {
+ return pathLenConstraint.getValue();
+ }
+
+ return null;
+ }
+
+ /**
+ * <pre>
+ * BasicConstraints := SEQUENCE {
+ * cA BOOLEAN DEFAULT FALSE,
+ * pathLenConstraint INTEGER (0..MAX) OPTIONAL
+ * }
+ * </pre>
+ */
+ public DERObject getDERObject()
+ {
+ DERConstructedSequence seq = new DERConstructedSequence();
+
+ seq.addObject(cA);
+
+ if (pathLenConstraint != null)
+ {
+ seq.addObject(pathLenConstraint);
+ }
+
+ return seq;
+ }
+
+ public String toString()
+ {
+ return "BasicConstraints: isCa(" + this.isCA() + "), pathLenConstraint = " + pathLenConstraint.getValue();
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.*;
+
+public class CRLDistPoint
+ implements DEREncodable
+{
+ DERConstructedSequence seq = null;
+
+ public CRLDistPoint(
+ DistributionPoint[] points)
+ {
+ seq = new DERConstructedSequence();
+
+ for (int i = 0; i != points.length; i++)
+ {
+ seq.addObject(points[i]);
+ }
+ }
+
+ /**
+ * <pre>
+ * CRLDistPoint ::= SEQUENCE SIZE {1..MAX} OF DistributionPoint
+ * </pre>
+ */
+ public DERObject getDERObject()
+ {
+ return seq;
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1.x509;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.*;
+
+/**
+ * <pre>
+ * CRLNumber::= INTEGER(0..MAX)
+ * </pre>
+ */
+public class CRLNumber
+ extends DERInteger
+{
+
+ public CRLNumber(
+ BigInteger number)
+ {
+ super(number);
+ }
+
+ public BigInteger getCRLNumber()
+ {
+ return getPositiveValue();
+ }
+}
--- /dev/null
+
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.*;
+import org.bouncycastle.asn1.pkcs.*;
+
+/**
+ * PKIX RFC-2459
+ *
+ * The X.509 v2 CRL syntax is as follows. For signature calculation,
+ * the data that is to be signed is ASN.1 DER encoded.
+ *
+ * <pre>
+ * CertificateList ::= SEQUENCE {
+ * tbsCertList TBSCertList,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signatureValue BIT STRING }
+ * </pre>
+ */
+
+public class CertificateList
+ implements DEREncodable
+{
+ DERConstructedSequence seq;
+
+ TBSCertList tbsCertList;
+ AlgorithmIdentifier sigAlgId;
+ DERBitString sig;
+
+ public CertificateList(
+ DERConstructedSequence seq)
+ {
+ this.seq = seq;
+
+ if ( seq.getObjectAt(0) instanceof TBSCertList )
+ {
+ tbsCertList = (TBSCertList)seq.getObjectAt(0);
+ }
+ else
+ {
+ tbsCertList = new TBSCertList((DERConstructedSequence)seq.getObjectAt(0));
+ }
+
+ if ( seq.getObjectAt(1) instanceof AlgorithmIdentifier )
+ {
+ sigAlgId = (AlgorithmIdentifier)seq.getObjectAt(1);
+ }
+ else
+ {
+ sigAlgId = new AlgorithmIdentifier((DERConstructedSequence)seq.getObjectAt(1));
+ }
+
+ sig = (DERBitString)seq.getObjectAt(2);
+ }
+
+ public TBSCertList getTBSCertList()
+ {
+ return tbsCertList;
+ }
+
+ public TBSCertList.CRLEntry[] getRevokedCertificates()
+ {
+ return tbsCertList.getRevokedCertificates();
+ }
+
+ public AlgorithmIdentifier getSignatureAlgorithm()
+ {
+ return sigAlgId;
+ }
+
+ public DERBitString getSignature()
+ {
+ return sig;
+ }
+
+ public int getVersion()
+ {
+ return tbsCertList.getVersion();
+ }
+
+ public X509Name getIssuer()
+ {
+ return tbsCertList.getIssuer();
+ }
+
+ public DERUTCTime getThisUpdate()
+ {
+ return tbsCertList.getThisUpdate();
+ }
+
+ public DERUTCTime getNextUpdate()
+ {
+ return tbsCertList.getNextUpdate();
+ }
+
+ public DERObject getDERObject()
+ {
+ return seq;
+ }
+}
+
--- /dev/null
+package org.bouncycastle.asn1.x509;
+
+import java.math.*;
+import java.util.*;
+
+import org.bouncycastle.asn1.*;
+
+public class DSAParameter
+ implements DEREncodable
+{
+ DERInteger p, q, g;
+
+ public DSAParameter(
+ BigInteger p,
+ BigInteger q,
+ BigInteger g)
+ {
+ this.p = new DERInteger(p);
+ this.q = new DERInteger(q);
+ this.g = new DERInteger(g);
+ }
+
+ public DSAParameter(
+ DERConstructedSequence seq)
+ {
+ Enumeration e = seq.getObjects();
+
+ p = (DERInteger)e.nextElement();
+ q = (DERInteger)e.nextElement();
+ g = (DERInteger)e.nextElement();
+ }
+
+ public BigInteger getP()
+ {
+ return p.getPositiveValue();
+ }
+
+ public BigInteger getQ()
+ {
+ return q.getPositiveValue();
+ }
+
+ public BigInteger getG()
+ {
+ return g.getPositiveValue();
+ }
+
+ public DERObject getDERObject()
+ {
+ DERConstructedSequence seq = new DERConstructedSequence();
+
+ seq.addObject(p);
+ seq.addObject(q);
+ seq.addObject(g);
+
+ return seq;
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1.x509;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.*;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+
+/**
+ * <pre>
+ * DigestInfo::=SEQUENCE{
+ * digestAlgorithm AlgorithmIdentifier,
+ * digest OCTET STRING }
+ * </pre>
+ */
+public class DigestInfo
+ implements PKCSObjectIdentifiers, DEREncodable
+{
+ private byte[] digest;
+ private AlgorithmIdentifier algId;
+
+ public DigestInfo(
+ AlgorithmIdentifier algId,
+ byte[] digest)
+ {
+ this.digest = digest;
+ this.algId = algId;
+ }
+
+ public DigestInfo(
+ DERConstructedSequence seq)
+ {
+ Enumeration e = seq.getObjects();
+
+ algId = new AlgorithmIdentifier((DERConstructedSequence)e.nextElement());
+ digest = ((DEROctetString)e.nextElement()).getOctets();
+ }
+
+ public AlgorithmIdentifier getAlgorithmId()
+ {
+ return algId;
+ }
+
+ public byte[] getDigest()
+ {
+ return digest;
+ }
+
+ public DERObject getDERObject()
+ {
+ DERConstructedSequence seq = new DERConstructedSequence();
+
+ seq.addObject(algId);
+ seq.addObject(new DEROctetString(digest));
+
+ return seq;
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.*;
+
+public class DistributionPoint
+ implements DEREncodable
+{
+ DERConstructedSequence seq = null;
+
+ public DistributionPoint(
+ DistributionPointName distributionPoint,
+ ReasonFlags reasons,
+ GeneralNames cRLIssuer)
+ {
+ seq = new DERConstructedSequence();
+
+ if (distributionPoint != null)
+ {
+ seq.addObject(new DERTaggedObject(0, distributionPoint));
+ }
+
+ if (reasons != null)
+ {
+ seq.addObject(new DERTaggedObject(1, reasons));
+ }
+
+ if (cRLIssuer != null)
+ {
+ seq.addObject(new DERTaggedObject(2, cRLIssuer));
+ }
+ }
+
+ /**
+ * <pre>
+ * DistributionPoint ::= SEQUENCE {
+ * distributionPoint [0] DistributionPointName OPTIONAL,
+ * reasons [1] ReasonFlags OPTIONAL,
+ * cRLIssuer [2] GeneralNames OPTIONAL
+ * }
+ * </pre>
+ */
+ public DERObject getDERObject()
+ {
+ return seq;
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.*;
+
+public class DistributionPointName
+ implements DEREncodable
+{
+ DEREncodable name;
+ int type;
+
+ public static final int FULL_NAME = 0;
+ public static final int NAME_RELATIVE_TO_CRL_ISSUER = 1;
+
+ public DistributionPointName(
+ int type,
+ DEREncodable name)
+ {
+ this.type = type;
+ this.name = name;
+ }
+
+ /**
+ * <pre>
+ * DistributionPointName ::= CHOICE {
+ * fullName [0] GeneralNames,
+ * nameRelativeToCRLIssuer [1] RelativeDistinguishedName
+ * }
+ * </pre>
+ */
+ public DERObject getDERObject()
+ {
+ return new DERTaggedObject(false, type, name);
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.*;
+
+/**
+ * <pre>
+ * GeneralName ::= CHOICE {
+ * otherName [0] OtherName,
+ * rfc822Name [1] IA5String,
+ * dNSName [2] IA5String,
+ * x400Address [3] ORAddress,
+ * directoryName [4] Name,
+ * ediPartyName [5] EDIPartyName,
+ * uniformResourceIdentifier [6] IA5String,
+ * iPAddress [7] OCTET STRING,
+ * registeredID [8] OBJECT IDENTIFIER}
+ *
+ * OtherName ::= SEQUENCE {
+ * type-id OBJECT IDENTIFIER,
+ * value [0] EXPLICIT ANY DEFINED BY type-id }
+ *
+ * EDIPartyName ::= SEQUENCE {
+ * nameAssigner [0] DirectoryString OPTIONAL,
+ * partyName [1] DirectoryString }
+ * </pre>
+ */
+public class GeneralName
+ implements DEREncodable
+{
+ DEREncodable obj;
+ int tag;
+
+ public GeneralName(
+ X509Name directoryName)
+ {
+ this.obj = directoryName;
+ this.tag = 4;
+ }
+
+ /**
+ * When the subjectAltName extension contains an Internet mail address,
+ * the address MUST be included as an rfc822Name. The format of an
+ * rfc822Name is an "addr-spec" as defined in RFC 822 [RFC 822].
+ *
+ * When the subjectAltName extension contains a domain name service
+ * label, the domain name MUST be stored in the dNSName (an IA5String).
+ * The name MUST be in the "preferred name syntax," as specified by RFC
+ * 1034 [RFC 1034].
+ *
+ * When the subjectAltName extension contains a URI, the name MUST be
+ * stored in the uniformResourceIdentifier (an IA5String). The name MUST
+ * be a non-relative URL, and MUST follow the URL syntax and encoding
+ * rules specified in [RFC 1738]. The name must include both a scheme
+ * (e.g., "http" or "ftp") and a scheme-specific-part. The scheme-
+ * specific-part must include a fully qualified domain name or IP
+ * address as the host.
+ *
+ * When the subjectAltName extension contains a iPAddress, the address
+ * MUST be stored in the octet string in "network byte order," as
+ * specified in RFC 791 [RFC 791]. The least significant bit (LSB) of
+ * each octet is the LSB of the corresponding byte in the network
+ * address. For IP Version 4, as specified in RFC 791, the octet string
+ * MUST contain exactly four octets. For IP Version 6, as specified in
+ * RFC 1883, the octet string MUST contain exactly sixteen octets [RFC
+ * 1883].
+ */
+ public GeneralName(
+ DERObject name, int tag)
+ {
+ this.obj = name;
+ this.tag = tag;
+ }
+
+ public DERObject getDERObject()
+ {
+ return new DERTaggedObject(false, tag, obj);
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.*;
+
+public class GeneralNames
+ implements DEREncodable
+{
+ DERConstructedSequence seq;
+
+ public GeneralNames(
+ DERConstructedSequence seq)
+ {
+ this.seq = seq;
+ }
+
+ /**
+ * <pre>
+ * GeneralNames ::= SEQUENCE SIZE {1..MAX} OF GeneralName
+ * </pre>
+ */
+ public DERObject getDERObject()
+ {
+ return seq;
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.*;
+
+/**
+ * <pre>
+ * id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 }
+ *
+ * KeyUsage ::= BIT STRING {
+ * digitalSignature (0),
+ * nonRepudiation (1),
+ * keyEncipherment (2),
+ * dataEncipherment (3),
+ * keyAgreement (4),
+ * keyCertSign (5),
+ * cRLSign (6),
+ * encipherOnly (7),
+ * decipherOnly (8) }
+ * </pre>
+ */
+public class KeyUsage
+ extends DERBitString
+{
+ public static final int digitalSignature = (1 << 7);
+ public static final int nonRepudiation = (1 << 6);
+ public static final int keyEncipherment = (1 << 5);
+ public static final int dataEncipherment = (1 << 4);
+ public static final int keyAgreement = (1 << 3);
+ public static final int keyCertSign = (1 << 2);
+ public static final int cRLSign = (1 << 1);
+ public static final int encipherOnly = (1 << 0);
+ public static final int decipherOnly = (1 << 15);
+
+ static private byte[] getUsageBytes(
+ int usage)
+ {
+ byte[] usageBytes = new byte[2];
+
+ usageBytes[0] = (byte)(usage & 0xFF);
+ usageBytes[1] = (byte)((usage >> 8) & 0xFF);
+
+ return usageBytes;
+ }
+
+ /**
+ * Basic constructor.
+ *
+ * @param usage - the bitwise OR of the Key Usage flags giving the
+ * allowed uses for the key.
+ * e.g. (X509KeyUsage.keyEncipherment | X509KeyUsage.dataEncipherment)
+ */
+ public KeyUsage(
+ int usage)
+ {
+ super(getUsageBytes(usage), 7);
+ }
+
+ public KeyUsage(
+ DERBitString usage)
+ {
+ super(usage.getBytes(), usage.getPadBits());
+ }
+
+ public String toString()
+ {
+ return "KeyUsage: 0x" + Integer.toHexString(data[0] & 0xff);
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1.x509;
+
+import java.util.Enumeration;
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.*;
+
+public class RSAPublicKeyStructure
+ implements DEREncodable
+{
+ private BigInteger modulus;
+ private BigInteger publicExponent;
+
+ public RSAPublicKeyStructure(
+ BigInteger modulus,
+ BigInteger publicExponent)
+ {
+ this.modulus = modulus;
+ this.publicExponent = publicExponent;
+ }
+
+ public RSAPublicKeyStructure(
+ DERConstructedSequence seq)
+ {
+ Enumeration e = seq.getObjects();
+
+ modulus = ((DERInteger)e.nextElement()).getValue();
+ publicExponent = ((DERInteger)e.nextElement()).getValue();
+ }
+
+ public BigInteger getModulus()
+ {
+ return modulus;
+ }
+
+ public BigInteger getPublicExponent()
+ {
+ return publicExponent;
+ }
+
+ /**
+ * This outputs the key in PKCS1v2 format.
+ * <pre>
+ * RSAPublicKey ::= SEQUENCE {
+ * modulus INTEGER, -- n
+ * publicExponent INTEGER, -- e
+ * }
+ * </pre>
+ * <p>
+ */
+ public DERObject getDERObject()
+ {
+ DERConstructedSequence seq = new DERConstructedSequence();
+
+ seq.addObject(new DERInteger(getModulus()));
+ seq.addObject(new DERInteger(getPublicExponent()));
+
+ return seq;
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.*;
+
+public class ReasonFlags
+ extends DERBitString
+{
+ public static final int KEY_COMPROMISE = 1;
+ public static final int CA_COMPROMISE = (1 << 2);
+ public static final int AFFILIATION_CHANGED = (1 << 3);
+ public static final int SUPERSEDED = (1 << 4);
+ public static final int CESSATION_OF_OPERATION = (1 << 5);
+ public static final int CERTIFICATE_HOLD = (1 << 6);
+
+ /**
+ * <pre>
+ * ReasonFlags ::= BIT STRING {
+ * unused(0),
+ * keyCompromise(1),
+ * cACompromise(2),
+ * affiliationChanged(3),
+ * superseded(4),
+ * cessationOfOperation(5),
+ * certficateHold(6)
+ * }
+ * </pre>
+ */
+ public ReasonFlags(
+ int reasons)
+ {
+ super((byte)reasons, 1);
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.asn1.*;
+
+/**
+ * <pre>
+ * SubjectKeyIdentifier::= OCTET STRING
+ * </pre>
+ */
+public class SubjectKeyIdentifier
+ implements DEREncodable
+{
+ private byte[] keyidentifier;
+
+ public SubjectKeyIdentifier(
+ byte[] keyid)
+ {
+ this.keyidentifier=keyid;
+ }
+
+ public SubjectKeyIdentifier(
+ DEROctetString keyid)
+ {
+ this.keyidentifier=keyid.getOctets();
+
+ }
+
+ /**
+ *
+ * Calulates the keyidentifier using a SHA1 hash over the BIT STRING
+ * from SubjectPublicKeyInfo as defined in RFC2459.
+ *
+ **/
+ public SubjectKeyIdentifier(
+ SubjectPublicKeyInfo spki)
+ {
+ Digest digest = new SHA1Digest();
+ byte[] resBuf = new byte[digest.getDigestSize()];
+
+ DERBitString derpk = new DERBitString(spki.getPublicKey());
+ byte[] bytes = derpk.getBytes();
+ digest.update(bytes, 0, bytes.length);
+ digest.doFinal(resBuf, 0);
+ this.keyidentifier=resBuf;
+ }
+
+ public byte[] getKeyIdentifier()
+ {
+ return keyidentifier;
+ }
+
+ /**
+ * <pre>
+ * SubjectKeyIdentifier := OCTET STRING
+ * </pre>
+ */
+ public DERObject getDERObject()
+ {
+ DEROctetString oct = new DEROctetString(keyidentifier);
+ return oct;
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1.x509;
+
+import java.io.*;
+import java.util.Enumeration;
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.*;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+
+/**
+ * The object that contains the public key stored in a certficate.
+ * <p>
+ * The getEncoded() method in the public keys in the JCE produces a DER
+ * encoded one of these.
+ */
+public class SubjectPublicKeyInfo
+ implements DEREncodable
+{
+ private AlgorithmIdentifier algId;
+ private DERObject pubKey;
+
+ public SubjectPublicKeyInfo(
+ AlgorithmIdentifier algId,
+ DERObject publicKey)
+ {
+ this.pubKey = publicKey;
+ this.algId = algId;
+ }
+
+ public SubjectPublicKeyInfo(
+ DERConstructedSequence seq)
+ {
+ Enumeration e = seq.getObjects();
+
+ algId = new AlgorithmIdentifier((DERConstructedSequence)e.nextElement());
+
+ byte[] keyData = ((DERBitString)e.nextElement()).getBytes();
+
+ try
+ {
+ ByteArrayInputStream bIn = new ByteArrayInputStream(keyData);
+ DERInputStream dIn = new DERInputStream(bIn);
+
+ pubKey = (DERObject)dIn.readObject();
+ }
+ catch (IOException ex)
+ {
+ throw new IllegalArgumentException("error recovering public key");
+ }
+ }
+
+ public AlgorithmIdentifier getAlgorithmId()
+ {
+ return algId;
+ }
+
+ public DERObject getPublicKey()
+ {
+ return pubKey;
+ }
+
+ /**
+ * <pre>
+ * SubjectPublicKeyInfo ::= SEQUENCE {
+ * algorithm AlgorithmIdentifier,
+ * publicKey BIT STRING }
+ * </pre>
+ */
+ public DERObject getDERObject()
+ {
+ DERConstructedSequence seq = new DERConstructedSequence();
+
+ seq.addObject(algId);
+ seq.addObject(new DERBitString(pubKey));
+
+ return seq;
+ }
+}
--- /dev/null
+
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.*;
+import org.bouncycastle.asn1.pkcs.*;
+
+/**
+ * PKIX RFC-2459
+ *
+ * <pre>
+ * TBSCertList ::= SEQUENCE {
+ * version Version OPTIONAL,
+ * -- if present, shall be v2
+ * signature AlgorithmIdentifier,
+ * issuer Name,
+ * thisUpdate Time,
+ * nextUpdate Time OPTIONAL,
+ * revokedCertificates SEQUENCE OF SEQUENCE {
+ * userCertificate CertificateSerialNumber,
+ * revocationDate Time,
+ * crlEntryExtensions Extensions OPTIONAL
+ * -- if present, shall be v2
+ * } OPTIONAL,
+ * crlExtensions [0] EXPLICIT Extensions OPTIONAL
+ * -- if present, shall be v2
+ * }
+ * </pre>
+ */
+
+public class TBSCertList
+ implements DEREncodable
+{
+ public class CRLEntry
+ implements DEREncodable
+ {
+ DERConstructedSequence seq;
+
+ DERInteger userCertificate;
+ DERUTCTime revocationDate;
+ X509Extensions crlEntryExtensions;
+
+ public CRLEntry(
+ DERConstructedSequence seq)
+ {
+ this.seq = seq;
+
+ userCertificate = (DERInteger)seq.getObjectAt(0);
+ revocationDate = (DERUTCTime)seq.getObjectAt(1);
+ if ( seq.getSize() == 3 )
+ {
+ crlEntryExtensions = new X509Extensions((DERConstructedSequence)seq.getObjectAt(2));
+ }
+ }
+
+ public DERInteger getUserCertificate()
+ {
+ return userCertificate;
+ }
+
+ public DERUTCTime getRevocationDate()
+ {
+ return revocationDate;
+ }
+
+ public X509Extensions getExtensions()
+ {
+ return crlEntryExtensions;
+ }
+
+ public DERObject getDERObject()
+ {
+ return seq;
+ }
+ }
+
+ DERConstructedSequence seq;
+
+ DERInteger version;
+ AlgorithmIdentifier signature;
+ X509Name issuer;
+ DERUTCTime thisUpdate;
+ DERUTCTime nextUpdate;
+ CRLEntry[] revokedCertificates;
+ X509Extensions crlExtensions;
+
+ public TBSCertList(
+ DERConstructedSequence seq)
+ {
+ int seqPos = 0;
+
+ this.seq = seq;
+
+ if ( seq.getObjectAt(seqPos) instanceof DERInteger )
+ {
+ version = (DERInteger)seq.getObjectAt(seqPos++);
+ }
+ else
+ {
+ version = new DERInteger(0);
+ }
+
+ if ( seq.getObjectAt(seqPos) instanceof AlgorithmIdentifier )
+ {
+ signature = (AlgorithmIdentifier)seq.getObjectAt(seqPos++);
+ }
+ else
+ {
+ signature = new AlgorithmIdentifier((DERConstructedSequence)seq.getObjectAt(seqPos++));
+ }
+
+ if ( seq.getObjectAt(seqPos) instanceof X509Name )
+ {
+ issuer = (X509Name)seq.getObjectAt(seqPos++);
+ }
+ else
+ {
+ issuer = new X509Name((DERConstructedSequence)seq.getObjectAt(seqPos++));
+ }
+
+ thisUpdate = (DERUTCTime)seq.getObjectAt(seqPos++);
+
+ if ( seqPos < seq.getSize()
+ && seq.getObjectAt(seqPos) instanceof DERUTCTime )
+ {
+ nextUpdate = (DERUTCTime)seq.getObjectAt(seqPos++);
+ }
+
+ if ( seqPos < seq.getSize()
+ && !(seq.getObjectAt(seqPos) instanceof DERTaggedObject) )
+ {
+ DERConstructedSequence certs = (DERConstructedSequence)seq.getObjectAt(seqPos++);
+ revokedCertificates = new CRLEntry[certs.getSize()];
+
+ for ( int i = 0; i < revokedCertificates.length; i++ )
+ {
+ revokedCertificates[i] = new CRLEntry((DERConstructedSequence)certs.getObjectAt(i));
+ }
+ }
+
+ if ( seqPos < seq.getSize()
+ && seq.getObjectAt(seqPos) instanceof DERTaggedObject )
+ {
+ crlExtensions = new X509Extensions((DERConstructedSequence)((DERTaggedObject)seq.getObjectAt(seqPos++)).getObject());
+ }
+ }
+
+ public int getVersion()
+ {
+ return version.getValue().intValue() + 1;
+ }
+
+ public DERInteger getVersionNumber()
+ {
+ return version;
+ }
+
+ public AlgorithmIdentifier getSignature()
+ {
+ return signature;
+ }
+
+ public X509Name getIssuer()
+ {
+ return issuer;
+ }
+
+ public DERUTCTime getThisUpdate()
+ {
+ return thisUpdate;
+ }
+
+ public DERUTCTime getNextUpdate()
+ {
+ return nextUpdate;
+ }
+
+ public CRLEntry[] getRevokedCertificates()
+ {
+ return revokedCertificates;
+ }
+
+ public X509Extensions getExtensions()
+ {
+ return crlExtensions;
+ }
+
+ public DERObject getDERObject()
+ {
+ return seq;
+ }
+}
+
--- /dev/null
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.*;
+import org.bouncycastle.asn1.pkcs.*;
+
+/**
+ * <pre>
+ * TBSCertificate ::= SEQUENCE {
+ * version [ 0 ] Version DEFAULT v1(0),
+ * serialNumber CertificateSerialNumber,
+ * signature AlgorithmIdentifier,
+ * issuer Name,
+ * validity Validity,
+ * subject Name,
+ * subjectPublicKeyInfo SubjectPublicKeyInfo,
+ * issuerUniqueID [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL,
+ * subjectUniqueID [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL,
+ * extensions [ 3 ] Extensions OPTIONAL
+ * }
+ * </pre>
+ * <p>
+ * Note: issuerUniqueID and subjectUniqueID are both deprecated by the IETF. This class
+ * will parse them, but you really shouldn't be creating new ones.
+ */
+public class TBSCertificateStructure
+ implements DEREncodable, X509ObjectIdentifiers, PKCSObjectIdentifiers
+{
+ DERConstructedSequence seq;
+
+ DERInteger version;
+ DERInteger serialNumber;
+ AlgorithmIdentifier signature;
+ X509Name issuer;
+ DERUTCTime startDate, endDate;
+ X509Name subject;
+ SubjectPublicKeyInfo subjectPublicKeyInfo;
+ DERBitString issuerUniqueId;
+ DERBitString subjectUniqueId;
+ X509Extensions extensions;
+
+ public TBSCertificateStructure(
+ DERConstructedSequence seq)
+ {
+ int seqStart = 0;
+
+ this.seq = seq;
+
+ //
+ // some certficates don't include a version number - we assume v1
+ //
+ if (seq.getObjectAt(0) instanceof DERTaggedObject)
+ {
+ version = (DERInteger)((DERTaggedObject)seq.getObjectAt(0)).getObject();
+ }
+ else
+ {
+ seqStart = -1; // field 0 is missing!
+ version = new DERInteger(0);
+ }
+
+ serialNumber = (DERInteger)seq.getObjectAt(seqStart + 1);
+
+ if (seq.getObjectAt(seqStart + 2) instanceof AlgorithmIdentifier)
+ {
+ signature = (AlgorithmIdentifier)seq.getObjectAt(seqStart + 2);
+ }
+ else
+ {
+ signature = new AlgorithmIdentifier((DERConstructedSequence)seq.getObjectAt(seqStart + 2));
+ }
+
+ if (seq.getObjectAt(seqStart + 3) instanceof X509Name)
+ {
+ issuer = (X509Name)seq.getObjectAt(seqStart + 3);
+ }
+ else
+ {
+ issuer = new X509Name((DERConstructedSequence)seq.getObjectAt(seqStart + 3));
+ }
+
+ //
+ // before and after dates
+ //
+ DERConstructedSequence dates = (DERConstructedSequence)seq.getObjectAt(seqStart + 4);
+ startDate = (DERUTCTime)dates.getObjectAt(0);
+ endDate = (DERUTCTime)dates.getObjectAt(1);
+
+ if (seq.getObjectAt(seqStart + 5) instanceof X509Name)
+ {
+ subject = (X509Name)seq.getObjectAt(seqStart + 5);
+ }
+ else
+ {
+ subject = new X509Name((DERConstructedSequence)seq.getObjectAt(seqStart + 5));
+ }
+
+ //
+ // public key info.
+ //
+ if (seq.getObjectAt(seqStart + 6) instanceof SubjectPublicKeyInfo)
+ {
+ subjectPublicKeyInfo = (SubjectPublicKeyInfo)seq.getObjectAt(seqStart + 6);
+ }
+ else
+ {
+ subjectPublicKeyInfo = new SubjectPublicKeyInfo((DERConstructedSequence)seq.getObjectAt(seqStart + 6));
+ }
+
+ for (int extras = seq.getSize() - (seqStart + 6) - 1; extras > 0; extras--)
+ {
+ DERTaggedObject extra = (DERTaggedObject)seq.getObjectAt(seqStart + 6 + extras);
+
+ switch (extra.getTagNo())
+ {
+ case 1:
+ issuerUniqueId = (DERBitString)extra.getObject();
+ break;
+ case 2:
+ subjectUniqueId = (DERBitString)extra.getObject();
+ break;
+ case 3:
+ extensions = new X509Extensions((DERConstructedSequence)extra.getObject());
+ }
+ }
+ }
+
+ public int getVersion()
+ {
+ return version.getValue().intValue() + 1;
+ }
+
+ public DERInteger getVersionNumber()
+ {
+ return version;
+ }
+
+ public DERInteger getSerialNumber()
+ {
+ return serialNumber;
+ }
+
+ public AlgorithmIdentifier getSignature()
+ {
+ return signature;
+ }
+
+ public X509Name getIssuer()
+ {
+ return issuer;
+ }
+
+ public DERUTCTime getStartDate()
+ {
+ return startDate;
+ }
+
+ public DERUTCTime getEndDate()
+ {
+ return endDate;
+ }
+
+ public X509Name getSubject()
+ {
+ return subject;
+ }
+
+ public SubjectPublicKeyInfo getSubjectPublicKeyInfo()
+ {
+ return subjectPublicKeyInfo;
+ }
+
+ public DERBitString getIssuerUniqueId()
+ {
+ return issuerUniqueId;
+ }
+
+ public DERBitString getSubjectUniqueId()
+ {
+ return subjectUniqueId;
+ }
+
+ public X509Extensions getExtensions()
+ {
+ return extensions;
+ }
+
+ public DERObject getDERObject()
+ {
+ return seq;
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.*;
+import org.bouncycastle.asn1.pkcs.*;
+
+/**
+ * Generator for Version 1 TBSCertificateStructures.
+ * <pre>
+ * TBSCertificate ::= SEQUENCE {
+ * version [ 0 ] Version DEFAULT v1(0),
+ * serialNumber CertificateSerialNumber,
+ * signature AlgorithmIdentifier,
+ * issuer Name,
+ * validity Validity,
+ * subject Name,
+ * subjectPublicKeyInfo SubjectPublicKeyInfo,
+ * }
+ * </pre>
+ *
+ */
+public class V1TBSCertificateGenerator
+{
+ DERTaggedObject version = new DERTaggedObject(0, new DERInteger(0));
+
+ DERInteger serialNumber;
+ AlgorithmIdentifier signature;
+ X509Name issuer;
+ DERUTCTime startDate, endDate;
+ X509Name subject;
+ SubjectPublicKeyInfo subjectPublicKeyInfo;
+
+ public V1TBSCertificateGenerator()
+ {
+ }
+
+ public void setSerialNumber(
+ DERInteger serialNumber)
+ {
+ this.serialNumber = serialNumber;
+ }
+
+ public void setSignature(
+ AlgorithmIdentifier signature)
+ {
+ this.signature = signature;
+ }
+
+ public void setIssuer(
+ X509Name issuer)
+ {
+ this.issuer = issuer;
+ }
+
+ public void setStartDate(
+ DERUTCTime startDate)
+ {
+ this.startDate = startDate;
+ }
+
+ public void setEndDate(
+ DERUTCTime endDate)
+ {
+ this.endDate = endDate;
+ }
+
+ public void setSubject(
+ X509Name subject)
+ {
+ this.subject = subject;
+ }
+
+ public void setSubjectPublicKeyInfo(
+ SubjectPublicKeyInfo pubKeyInfo)
+ {
+ this.subjectPublicKeyInfo = pubKeyInfo;
+ }
+
+ public TBSCertificateStructure generateTBSCertificate()
+ {
+ if ((serialNumber == null) || (signature == null)
+ || (issuer == null) || (startDate == null) || (endDate == null)
+ || (subject == null) || (subjectPublicKeyInfo == null))
+ {
+ throw new IllegalStateException("not all mandatory fields set in V1 TBScertificate generator");
+ }
+
+ DERConstructedSequence seq = new DERConstructedSequence();
+
+ seq.addObject(version);
+ seq.addObject(serialNumber);
+ seq.addObject(signature);
+ seq.addObject(issuer);
+
+ //
+ // before and after dates
+ //
+ DERConstructedSequence validity = new DERConstructedSequence();
+
+ validity.addObject(startDate);
+ validity.addObject(endDate);
+
+ seq.addObject(validity);
+
+ seq.addObject(subject);
+
+ seq.addObject(subjectPublicKeyInfo);
+
+ return new TBSCertificateStructure(seq);
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1.x509;
+
+import java.util.Vector;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.*;
+
+/**
+ * Generator for Version 2 TBSCertList structures.
+ * <pre>
+ * TBSCertList ::= SEQUENCE {
+ * version Version OPTIONAL,
+ * -- if present, shall be v2
+ * signature AlgorithmIdentifier,
+ * issuer Name,
+ * thisUpdate Time,
+ * nextUpdate Time OPTIONAL,
+ * revokedCertificates SEQUENCE OF SEQUENCE {
+ * userCertificate CertificateSerialNumber,
+ * revocationDate Time,
+ * crlEntryExtensions Extensions OPTIONAL
+ * -- if present, shall be v2
+ * } OPTIONAL,
+ * crlExtensions [0] EXPLICIT Extensions OPTIONAL
+ * -- if present, shall be v2
+ * }
+ * </pre>
+ *
+ * <b>Note: This class may be subject to change</b>
+ */
+public class V2TBSCertListGenerator
+{
+ DERInteger version = new DERInteger(1);
+
+ AlgorithmIdentifier signature;
+ X509Name issuer;
+ DERUTCTime thisUpdate, nextUpdate=null;
+ X509Extensions extensions=null;
+ private Vector crlentries=null;
+
+ public V2TBSCertListGenerator()
+ {
+ }
+
+
+ public void setSignature(
+ AlgorithmIdentifier signature)
+ {
+ this.signature = signature;
+ }
+
+ public void setIssuer(
+ X509Name issuer)
+ {
+ this.issuer = issuer;
+ }
+
+ public void setThisUpdate(
+ DERUTCTime thisUpdate)
+ {
+ this.thisUpdate = thisUpdate;
+ }
+
+ public void setNextUpdate(
+ DERUTCTime nextUpdate)
+ {
+ this.nextUpdate = nextUpdate;
+ }
+
+
+ public void addCRLEntry(
+ DERConstructedSequence crlEntry)
+ {
+ if (crlentries == null)
+ crlentries = new Vector();
+ crlentries.addElement(crlEntry);
+ }
+
+ public void addCRLEntry(DERInteger userCertificate, DERUTCTime revocationDate, int reason)
+ {
+ DERConstructedSequence seq = new DERConstructedSequence();
+ seq.addObject(userCertificate);
+ seq.addObject(revocationDate);
+ if (reason != 0)
+ {
+ ReasonFlags rf = new ReasonFlags(reason);
+ DERConstructedSequence eseq = new DERConstructedSequence();
+ eseq.addObject(X509Extensions.ReasonCode);
+ eseq.addObject(rf);
+ X509Extensions ex = new X509Extensions(eseq);
+ seq.addObject(ex);
+ }
+ if (crlentries == null)
+ crlentries = new Vector();
+ crlentries.addElement(seq);
+ }
+
+ public void setExtensions(
+ X509Extensions extensions)
+ {
+ this.extensions = extensions;
+ }
+
+ public TBSCertList generateTBSCertList()
+ {
+ if ((signature == null) || (issuer == null) || (thisUpdate == null))
+ {
+ throw new IllegalStateException("Not all mandatory fields set in V2 TBSCertList generator.");
+ }
+
+ DERConstructedSequence seq = new DERConstructedSequence();
+
+ seq.addObject(version);
+ seq.addObject(signature);
+ seq.addObject(issuer);
+
+ seq.addObject(thisUpdate);
+ if (nextUpdate != null)
+ seq.addObject(nextUpdate);
+
+ // Add CRLEntries if they exist
+ if (crlentries != null) {
+ DERConstructedSequence certseq = new DERConstructedSequence();
+ Enumeration it = crlentries.elements();
+ while( it.hasMoreElements() ) {
+ certseq.addObject((DERConstructedSequence)it.nextElement());
+ }
+ seq.addObject(certseq);
+ }
+
+ if (extensions != null)
+ {
+ seq.addObject(new DERTaggedObject(0, extensions.getDERObject()));
+ }
+
+ return new TBSCertList(seq);
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.*;
+import org.bouncycastle.asn1.pkcs.*;
+
+/**
+ * Generator for Version 3 TBSCertificateStructures.
+ * <pre>
+ * TBSCertificate ::= SEQUENCE {
+ * version [ 0 ] Version DEFAULT v1(0),
+ * serialNumber CertificateSerialNumber,
+ * signature AlgorithmIdentifier,
+ * issuer Name,
+ * validity Validity,
+ * subject Name,
+ * subjectPublicKeyInfo SubjectPublicKeyInfo,
+ * issuerUniqueID [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL,
+ * subjectUniqueID [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL,
+ * extensions [ 3 ] Extensions OPTIONAL
+ * }
+ * </pre>
+ *
+ */
+public class V3TBSCertificateGenerator
+{
+ DERTaggedObject version = new DERTaggedObject(0, new DERInteger(2));
+
+ DERInteger serialNumber;
+ AlgorithmIdentifier signature;
+ X509Name issuer;
+ DERUTCTime startDate, endDate;
+ X509Name subject;
+ SubjectPublicKeyInfo subjectPublicKeyInfo;
+ X509Extensions extensions;
+
+ public V3TBSCertificateGenerator()
+ {
+ }
+
+ public void setSerialNumber(
+ DERInteger serialNumber)
+ {
+ this.serialNumber = serialNumber;
+ }
+
+ public void setSignature(
+ AlgorithmIdentifier signature)
+ {
+ this.signature = signature;
+ }
+
+ public void setIssuer(
+ X509Name issuer)
+ {
+ this.issuer = issuer;
+ }
+
+ public void setStartDate(
+ DERUTCTime startDate)
+ {
+ this.startDate = startDate;
+ }
+
+ public void setEndDate(
+ DERUTCTime endDate)
+ {
+ this.endDate = endDate;
+ }
+
+ public void setSubject(
+ X509Name subject)
+ {
+ this.subject = subject;
+ }
+
+ public void setSubjectPublicKeyInfo(
+ SubjectPublicKeyInfo pubKeyInfo)
+ {
+ this.subjectPublicKeyInfo = pubKeyInfo;
+ }
+
+ public void setExtensions(
+ X509Extensions extensions)
+ {
+ this.extensions = extensions;
+ }
+
+ public TBSCertificateStructure generateTBSCertificate()
+ {
+ if ((serialNumber == null) || (signature == null)
+ || (issuer == null) || (startDate == null) || (endDate == null)
+ || (subject == null) || (subjectPublicKeyInfo == null))
+ {
+ throw new IllegalStateException("not all mandatory fields set in V3 TBScertificate generator");
+ }
+
+ DERConstructedSequence seq = new DERConstructedSequence();
+
+ seq.addObject(version);
+ seq.addObject(serialNumber);
+ seq.addObject(signature);
+ seq.addObject(issuer);
+
+ //
+ // before and after dates
+ //
+ DERConstructedSequence validity = new DERConstructedSequence();
+
+ validity.addObject(startDate);
+ validity.addObject(endDate);
+
+ seq.addObject(validity);
+
+ seq.addObject(subject);
+
+ seq.addObject(subjectPublicKeyInfo);
+
+ if (extensions != null)
+ {
+ seq.addObject(new DERTaggedObject(3, extensions.getDERObject()));
+ }
+
+ return new TBSCertificateStructure(seq);
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.*;
+import org.bouncycastle.asn1.pkcs.*;
+
+/**
+ * an X509Certificate structure.
+ * <pre>
+ * Certificate ::= SEQUENCE {
+ * tbsCertificate TBSCertificate,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING
+ * }
+ * </pre>
+ */
+public class X509CertificateStructure
+ implements DEREncodable, X509ObjectIdentifiers, PKCSObjectIdentifiers
+{
+ DERConstructedSequence seq;
+ TBSCertificateStructure tbsCert;
+ AlgorithmIdentifier sigAlgId;
+ DERBitString sig;
+
+ public X509CertificateStructure(
+ DERConstructedSequence seq)
+ {
+ this.seq = seq;
+
+ //
+ // correct x509 certficate
+ //
+ if (seq.getSize() == 3)
+ {
+ if (seq.getObjectAt(0) instanceof TBSCertificateStructure)
+ {
+ tbsCert = (TBSCertificateStructure)seq.getObjectAt(0);
+ }
+ else
+ {
+ tbsCert = new TBSCertificateStructure((DERConstructedSequence)seq.getObjectAt(0));
+ }
+
+ if (seq.getObjectAt(1) instanceof AlgorithmIdentifier)
+ {
+ sigAlgId = (AlgorithmIdentifier)seq.getObjectAt(1);
+ }
+ else
+ {
+ sigAlgId = new AlgorithmIdentifier((DERConstructedSequence)seq.getObjectAt(1));
+ }
+
+ sig = (DERBitString)seq.getObjectAt(2);
+ }
+ }
+
+ public TBSCertificateStructure getTBSCertificate()
+ {
+ return tbsCert;
+ }
+
+ public int getVersion()
+ {
+ return tbsCert.getVersion();
+ }
+
+ public DERInteger getSerialNumber()
+ {
+ return tbsCert.getSerialNumber();
+ }
+
+ public X509Name getIssuer()
+ {
+ return tbsCert.getIssuer();
+ }
+
+ public DERUTCTime getStartDate()
+ {
+ return tbsCert.getStartDate();
+ }
+
+ public DERUTCTime getEndDate()
+ {
+ return tbsCert.getEndDate();
+ }
+
+ public X509Name getSubject()
+ {
+ return tbsCert.getSubject();
+ }
+
+ public SubjectPublicKeyInfo getSubjectPublicKeyInfo()
+ {
+ return tbsCert.getSubjectPublicKeyInfo();
+ }
+
+ public AlgorithmIdentifier getSignatureAlgorithm()
+ {
+ return sigAlgId;
+ }
+
+ public DERBitString getSignature()
+ {
+ return sig;
+ }
+
+ public DERObject getDERObject()
+ {
+ return seq;
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.*;
+
+/**
+ * an object for the elements in the X.509 V3 extension block.
+ */
+public class X509Extension
+{
+ boolean critical;
+ DEROctetString value;
+
+ public X509Extension(
+ DERBoolean critical,
+ DEROctetString value)
+ {
+ this.critical = critical.isTrue();
+ this.value = value;
+ }
+
+ public X509Extension(
+ boolean critical,
+ DEROctetString value)
+ {
+ this.critical = critical;
+ this.value = value;
+ }
+
+ public boolean isCritical()
+ {
+ return critical;
+ }
+
+ public DEROctetString getValue()
+ {
+ return value;
+ }
+
+ public int hashCode()
+ {
+ if (this.isCritical())
+ {
+ return this.getValue().hashCode();
+ }
+
+
+ return ~this.getValue().hashCode();
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (o == null || !(o instanceof X509Extension))
+ {
+ return false;
+ }
+
+ X509Extension other = (X509Extension)o;
+
+ return other.getValue().equals(this.getValue())
+ && (other.isCritical() == this.isCritical());
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1.x509;
+
+import java.io.*;
+import java.util.*;
+
+import org.bouncycastle.asn1.*;
+
+public class X509Extensions
+ implements DEREncodable
+{
+ /**
+ * Subject Key Identifier
+ */
+ public static final DERObjectIdentifier SubjectKeyIdentifier = new DERObjectIdentifier("2.5.29.14");
+
+ /**
+ * Key Usage
+ */
+ public static final DERObjectIdentifier KeyUsage = new DERObjectIdentifier("2.5.29.15");
+
+ /**
+ * Private Key Usage Period
+ */
+ public static final DERObjectIdentifier PrivateKeyUsagePeriod = new DERObjectIdentifier("2.5.29.16");
+
+ /**
+ * Subject Alternative Name
+ */
+ public static final DERObjectIdentifier SubjectAlternativeName = new DERObjectIdentifier("2.5.29.17");
+
+ /**
+ * Issuer Alternative Name
+ */
+ public static final DERObjectIdentifier IssuerAlternativeName = new DERObjectIdentifier("2.5.29.18");
+
+ /**
+ * Basic Constraints
+ */
+ public static final DERObjectIdentifier BasicConstraints = new DERObjectIdentifier("2.5.29.19");
+
+ /**
+ * CRL Number
+ */
+ public static final DERObjectIdentifier CRLNumber = new DERObjectIdentifier("2.5.29.20");
+
+ /**
+ * Reason code
+ */
+ public static final DERObjectIdentifier ReasonCode = new DERObjectIdentifier("2.5.29.21");
+
+ /**
+ * Hold Instruction Code
+ */
+ public static final DERObjectIdentifier InstructionCode = new DERObjectIdentifier("2.5.29.23");
+
+ /**
+ * Invalidity Date
+ */
+ public static final DERObjectIdentifier InvalidityDate = new DERObjectIdentifier("2.5.29.24");
+
+ /**
+ * Delta CRL indicator
+ */
+ public static final DERObjectIdentifier DeltaCRLIndicator = new DERObjectIdentifier("2.5.29.27");
+
+ /**
+ * Issuing Distribution Point
+ */
+ public static final DERObjectIdentifier IssuingDistributionPoint = new DERObjectIdentifier("2.5.29.28");
+
+ /**
+ * Certificate Issuer
+ */
+ public static final DERObjectIdentifier CertificateIssuer = new DERObjectIdentifier("2.5.29.29");
+
+ /**
+ * Name Constraints
+ */
+ public static final DERObjectIdentifier NameConstraints = new DERObjectIdentifier("2.5.29.30");
+
+ /**
+ * CRL Distribution Points
+ */
+ public static final DERObjectIdentifier CRLDistributionPoints = new DERObjectIdentifier("2.5.29.31");
+
+ /**
+ * Certificate Policies
+ */
+ public static final DERObjectIdentifier CertificatePolicies = new DERObjectIdentifier("2.5.29.32");
+
+ /**
+ * Policy Mappings
+ */
+ public static final DERObjectIdentifier PolicyMappings = new DERObjectIdentifier("2.5.29.33");
+
+ /**
+ * Authority Key Identifier
+ */
+ public static final DERObjectIdentifier AuthorityKeyIdentifier = new DERObjectIdentifier("2.5.29.35");
+
+ /**
+ * Policy Constraints
+ */
+ public static final DERObjectIdentifier PolicyConstraints = new DERObjectIdentifier("2.5.29.36");
+
+ private Hashtable extensions = new Hashtable();
+ private Vector ordering = new Vector();
+ private DERConstructedSequence seq;
+
+ /**
+ * Constructor from DERConstructedSequence.
+ *
+ * the extensions are a list of constructed sequences, either with (OID, OctetString) or (OID, Boolean, OctetString)
+ */
+ public X509Extensions(
+ DERConstructedSequence seq)
+ {
+ this.seq = seq;
+
+ Enumeration e = seq.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ DERConstructedSequence s = (DERConstructedSequence)e.nextElement();
+ Enumeration e1 = s.getObjects();
+
+ if (s.getSize() == 3)
+ {
+ extensions.put(s.getObjectAt(0), new X509Extension((DERBoolean)s.getObjectAt(1), (DEROctetString)s.getObjectAt(2)));
+ }
+ else
+ {
+ extensions.put(s.getObjectAt(0), new X509Extension(false, (DEROctetString)s.getObjectAt(1)));
+ }
+
+ ordering.addElement(s.getObjectAt(0));
+ }
+ }
+
+ /**
+ * constructor from a table of extensions.
+ * <p>
+ * it's is assumed the table contains OID/String pairs.
+ */
+ public X509Extensions(
+ Hashtable extensions)
+ {
+ this(null, extensions);
+ }
+
+ /**
+ * constructor from a table of extensions with ordering
+ * <p>
+ * it's is assumed the table contains OID/String pairs.
+ */
+ public X509Extensions(
+ Vector ordering,
+ Hashtable extensions)
+ {
+ this.seq = new DERConstructedSequence();
+
+ if (ordering == null)
+ {
+ Enumeration e = extensions.keys();
+
+ ordering = this.ordering;
+
+ while (e.hasMoreElements())
+ {
+ this.ordering.addElement(e.nextElement());
+ }
+ }
+
+ Enumeration e = ordering.elements();
+
+ while (e.hasMoreElements())
+ {
+ DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
+ X509Extension ext = (X509Extension)extensions.get(oid);
+ DERConstructedSequence s = new DERConstructedSequence();
+
+ s.addObject(oid);
+
+ if (ext.isCritical())
+ {
+ s.addObject(new DERBoolean(true));
+ }
+
+ s.addObject(ext.getValue());
+
+ seq.addObject(s);
+ }
+ }
+
+ /**
+ * return an Enumeration of the extension field's object ids.
+ */
+ public Enumeration oids()
+ {
+ return ordering.elements();
+ }
+
+ /**
+ * return the extension represented by the object identifier
+ * passed in.
+ *
+ * @return the extension if it's present, null otherwise.
+ */
+ public X509Extension getExtension(
+ DERObjectIdentifier oid)
+ {
+ return (X509Extension)extensions.get(oid);
+ }
+
+ public DERObject getDERObject()
+ {
+ return seq;
+ }
+
+ public int hashCode()
+ {
+ Enumeration e = extensions.keys();
+ int hashCode = 0;
+
+ while (e.hasMoreElements())
+ {
+ Object o = e.nextElement();
+
+ hashCode ^= o.hashCode();
+ hashCode ^= extensions.get(o).hashCode();
+ }
+
+ return hashCode;
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (o == null || !(o instanceof X509Extensions))
+ {
+ return false;
+ }
+
+ X509Extensions other = (X509Extensions)o;
+
+ Enumeration e1 = extensions.keys();
+ Enumeration e2 = other.extensions.keys();
+
+ while (e1.hasMoreElements() && e2.hasMoreElements())
+ {
+ Object o1 = e1.nextElement();
+ Object o2 = e2.nextElement();
+
+ if (!o1.equals(o2))
+ {
+ return false;
+ }
+ }
+
+ if (e1.hasMoreElements() || e2.hasMoreElements())
+ {
+ return false;
+ }
+
+ return true;
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1.x509;
+
+import java.io.*;
+import java.util.*;
+
+import org.bouncycastle.asn1.*;
+
+public class X509Name
+ implements DEREncodable
+{
+ /**
+ * country code - StringType(SIZE(2))
+ */
+ public static final DERObjectIdentifier C = new DERObjectIdentifier("2.5.4.6");
+
+ /**
+ * organization - StringType(SIZE(1..64))
+ */
+ public static final DERObjectIdentifier O = new DERObjectIdentifier("2.5.4.10");
+
+ /**
+ * organizational unit name - StringType(SIZE(1..64))
+ */
+ public static final DERObjectIdentifier OU = new DERObjectIdentifier("2.5.4.11");
+
+ /**
+ * common name - StringType(SIZE(1..64))
+ */
+ public static final DERObjectIdentifier CN = new DERObjectIdentifier("2.5.4.3");
+
+ /**
+ * device serial number name - StringType(SIZE(1..64))
+ */
+ public static final DERObjectIdentifier SN = new DERObjectIdentifier("2.5.4.5");
+
+ /**
+ * locality name - StringType(SIZE(1..64))
+ */
+ public static final DERObjectIdentifier L = new DERObjectIdentifier("2.5.4.7");
+
+ /**
+ * state, or province name - StringType(SIZE(1..64))
+ */
+ public static final DERObjectIdentifier ST = new DERObjectIdentifier("2.5.4.8");
+
+ /**
+ * email address (RSA PKCS#9 extension) - IA5String
+ * <p>
+ * note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here.
+ */
+ public static final DERObjectIdentifier EmailAddress = new DERObjectIdentifier("1.2.840.113549.1.9.1");
+
+ /**
+ * look up table translating OID values into their common symbols.
+ */
+ public static Hashtable OIDLookUp = new Hashtable();
+
+ /**
+ * look up table translating common symbols into their OIDS.
+ */
+ public static Hashtable SymbolLookUp = new Hashtable();
+
+ static
+ {
+ OIDLookUp.put(C, "C");
+ OIDLookUp.put(O, "O");
+ OIDLookUp.put(OU, "OU");
+ OIDLookUp.put(CN, "CN");
+ OIDLookUp.put(L, "L");
+ OIDLookUp.put(ST, "ST");
+ OIDLookUp.put(SN, "SN");
+ OIDLookUp.put(EmailAddress, "EmailAddress");
+
+ SymbolLookUp.put("C", C);
+ SymbolLookUp.put("O", O);
+ SymbolLookUp.put("OU", OU);
+ SymbolLookUp.put("CN", CN);
+ SymbolLookUp.put("L", L);
+ SymbolLookUp.put("ST", ST);
+ SymbolLookUp.put("SN", SN);
+ SymbolLookUp.put("EmailAddress", EmailAddress);
+ }
+
+ private Vector ordering = new Vector();
+ private Hashtable attributes = new Hashtable();
+ private DERConstructedSequence seq = null;
+
+ /**
+ * Constructor from DERConstructedSequence.
+ *
+ * the principal will be a list of constructed sets, each containing an (OID, String) pair.
+ */
+ public X509Name(
+ DERConstructedSequence seq)
+ {
+ this.seq = seq;
+
+ Enumeration e = seq.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ DERSet set = (DERSet)e.nextElement();
+ DERConstructedSequence s = (DERConstructedSequence)set.getSequence();
+
+ ordering.addElement(s.getObjectAt(0));
+ attributes.put(s.getObjectAt(0), ((DERString)s.getObjectAt(1)).getString());
+ }
+ }
+
+ /**
+ * constructor from a table of attributes.
+ * <p>
+ * it's is assumed the table contains OID/String pairs, and the contents
+ * of the table are copied into an internal table as part of the
+ * construction process.
+ * <p>
+ * <b>Note:</b> if the name you are trying to generate should be
+ * following a specific ordering, you should use the constructor
+ * with the ordering specified below.
+ */
+ public X509Name(
+ Hashtable attributes)
+ {
+ this(null, attributes);
+ }
+
+ /**
+ * constructor from a table of attributes with ordering.
+ * <p>
+ * it's is assumed the table contains OID/String pairs, and the contents
+ * of the table are copied into an internal table as part of the
+ * construction process. The ordering vector should contain the OIDs
+ * in the order they are meant to be encoded or printed in toString.
+ */
+ public X509Name(
+ Vector ordering,
+ Hashtable attributes)
+ {
+ if (ordering != null)
+ {
+ for (int i = 0; i != ordering.size(); i++)
+ {
+ this.ordering.addElement(ordering.elementAt(i));
+ }
+ }
+ else
+ {
+ Enumeration e = attributes.keys();
+
+ while (e.hasMoreElements())
+ {
+ this.ordering.addElement(e.nextElement());
+ }
+ }
+
+ for (int i = 0; i != this.ordering.size(); i++)
+ {
+ DERObjectIdentifier oid = (DERObjectIdentifier)this.ordering.elementAt(i);
+
+ if (OIDLookUp.get(oid) == null)
+ {
+ throw new IllegalArgumentException("Unknown object id - " + oid.getId() + " - passed to distinguished name");
+ }
+
+ if (attributes.get(oid) == null)
+ {
+ throw new IllegalArgumentException("No attribute for object id - " + oid.getId() + " - passed to distinguished name");
+ }
+
+ this.attributes.put(oid, attributes.get(oid)); // copy the hash table
+ }
+ }
+
+ /**
+ * takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+ * some such, converting it into an ordered set of name attributes.
+ */
+ public X509Name(
+ String dirName)
+ {
+ X509NameTokenizer nTok = new X509NameTokenizer(dirName);
+
+ while (nTok.hasMoreTokens())
+ {
+ String token = nTok.nextToken();
+ int index = token.indexOf('=');
+
+ if (index == -1)
+ {
+ throw new IllegalArgumentException("badly formated directory string");
+ }
+
+ String name = token.substring(0, index);
+ String value = token.substring(index + 1);
+
+ DERObjectIdentifier oid = (DERObjectIdentifier)SymbolLookUp.get(name);
+ if (oid == null)
+ {
+ throw new IllegalArgumentException("Unknown object id - " + oid.getId() + " - passed to distinguished name");
+ }
+
+ this.ordering.addElement(oid);
+ this.attributes.put(oid, value);
+ }
+ }
+
+ public DERObject getDERObject()
+ {
+ if (seq == null)
+ {
+ seq = new DERConstructedSequence();
+
+ for (int i = 0; i != ordering.size(); i++)
+ {
+ DERConstructedSequence s = new DERConstructedSequence();
+ DERObjectIdentifier oid = (DERObjectIdentifier)ordering.elementAt(i);
+
+ s.addObject(oid);
+ if (oid.equals(EmailAddress))
+ {
+ s.addObject(new DERIA5String((String)attributes.get(oid)));
+ }
+ else
+ {
+ s.addObject(new DERPrintableString((String)attributes.get(oid)));
+ }
+
+ seq.addObject(new DERSet(s));
+ }
+ }
+
+ return seq;
+ }
+
+ public int hashCode()
+ {
+ Enumeration e = attributes.keys();
+ int hashCode = 0;
+
+ while (e.hasMoreElements())
+ {
+ Object o = e.nextElement();
+
+ hashCode ^= o.hashCode();
+ hashCode ^= attributes.get(o).hashCode();
+ }
+
+ for (int i = 0; i != ordering.size(); i++)
+ {
+ hashCode ^= ordering.elementAt(i).hashCode();
+ }
+
+ return hashCode;
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (o == null || !(o instanceof X509Name))
+ {
+ return false;
+ }
+
+ X509Name other = (X509Name)o;
+
+ if (ordering.size() != other.ordering.size())
+ {
+ return false;
+ }
+
+ for (int i = 0; i != ordering.size(); i++)
+ {
+ if (!ordering.elementAt(i).equals(other.ordering.elementAt(i)))
+ {
+ return false;
+ }
+ }
+
+ Enumeration e1 = attributes.keys();
+ Enumeration e2 = other.attributes.keys();
+
+ while (e1.hasMoreElements() && e2.hasMoreElements())
+ {
+ Object o1 = e1.nextElement();
+ Object o2 = e2.nextElement();
+
+ if (!o1.equals(o2))
+ {
+ return false;
+ }
+ }
+
+ if (e1.hasMoreElements() || e2.hasMoreElements())
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ boolean first = true;
+
+ for (int i = 0; i != ordering.size(); i++)
+ {
+ Object oid = ordering.elementAt(i);
+ String sym = (String)OIDLookUp.get(oid);
+
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ buf.append(", ");
+ }
+
+ if (sym != null)
+ {
+ buf.append(sym);
+ buf.append("=");
+ buf.append((String)attributes.get(oid));
+ }
+ else
+ {
+ buf.append(((DERObjectIdentifier)oid).getId());
+ buf.append("=");
+ buf.append((String)attributes.get(oid));
+ }
+ }
+
+ return buf.toString();
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1.x509;
+
+/**
+ * class for breaking up an X509 Name into it's component tokens, ala
+ * java.util.StringTokenizer. We need this class as some of the
+ * lightweight Java environment don't support classes like
+ * StringTokenizer.
+ */
+public class X509NameTokenizer
+{
+ private String oid;
+ private int index;
+
+ public X509NameTokenizer(
+ String oid)
+ {
+ this.oid = oid;
+ this.index = 0;
+ }
+
+ public boolean hasMoreTokens()
+ {
+ return (index != -1);
+ }
+
+ public String nextToken()
+ {
+ if (index == -1)
+ {
+ return null;
+ }
+
+ String token;
+ int end = oid.indexOf(',', index);
+
+ if (end == -1)
+ {
+ token = oid.substring(index);
+ index = -1;
+ return token.trim();
+ }
+
+ token = oid.substring(index, end);
+
+ index = end + 1;
+ return token.trim();
+ }
+}
--- /dev/null
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+
+public interface X509ObjectIdentifiers
+{
+ //
+ // base id
+ //
+ static final String id = "2.5.4";
+
+ static final DERObjectIdentifier commonName = new DERObjectIdentifier(id + ".3");
+ static final DERObjectIdentifier countryName = new DERObjectIdentifier(id + ".6");
+ static final DERObjectIdentifier localityName = new DERObjectIdentifier(id + ".7");
+ static final DERObjectIdentifier stateOrProvinceName = new DERObjectIdentifier(id + ".8");
+ static final DERObjectIdentifier organization = new DERObjectIdentifier(id + ".10");
+ static final DERObjectIdentifier organizationalUnitName = new DERObjectIdentifier(id + ".11");
+
+ // id-SHA1 OBJECT IDENTIFIER ::=
+ // {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 } //
+ static final DERObjectIdentifier id_SHA1 = new DERObjectIdentifier("1.3.14.3.2.26");
+
+ //
+ // ripemd160 OBJECT IDENTIFIER ::=
+ // {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) hashAlgorithm(2) RIPEMD-160(1)}
+ //
+ static final DERObjectIdentifier ripemd160 = new DERObjectIdentifier("1.3.36.3.2.1");
+
+ //
+ // ripemd160WithRSAEncryption OBJECT IDENTIFIER ::=
+ // {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) signatureAlgorithm(3) rsaSignature(1) rsaSignatureWithripemd160(2) }
+ //
+ static final DERObjectIdentifier ripemd160WithRSAEncryption = new DERObjectIdentifier("1.3.36.3.3.1.2");
+
+
+ static final DERObjectIdentifier id_ea_rsa = new DERObjectIdentifier("2.5.8.1.1");
+}
+
--- /dev/null
+package org.bouncycastle.crypto;
+
+import java.math.BigInteger;
+
+/**
+ * base interface that a public/private key block cipher needs
+ * to conform to.
+ */
+public interface AsymmetricBlockCipher
+{
+ /**
+ * initialise the cipher.
+ *
+ * @param forEncryption if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param param the key and other data required by the cipher.
+ */
+ public void init(boolean forEncryption, CipherParameters param);
+
+ /**
+ * returns the largest size an input block can be.
+ *
+ * @return maximum size for an input block.
+ */
+ public int getInputBlockSize();
+
+ /**
+ * returns the maximum size of the block produced by this cipher.
+ *
+ * @return maximum size of the output block produced by the cipher.
+ */
+ public int getOutputBlockSize();
+
+ /**
+ * process the block of len bytes stored in in from offset inOff.
+ *
+ * @param in the input data
+ * @param inOff offset into the in array where the data starts
+ * @param len the length of the block to be processed.
+ * @return the resulting byte array of the encryption/decryption process.
+ * @exception InvalidCipherTextException data decrypts improperly.
+ * @exception DataLengthException the input data is too large for the cipher.
+ */
+ public byte[] processBlock(byte[] in, int inOff, int len)
+ throws InvalidCipherTextException;
+}
--- /dev/null
+package org.bouncycastle.crypto;
+
+/**
+ * a holding class for public/private parameter pairs.
+ */
+public class AsymmetricCipherKeyPair
+{
+ private CipherParameters publicParam;
+ private CipherParameters privateParam;
+
+ /**
+ * basic constructor.
+ *
+ * @param publicParam a public key parameters object.
+ * @param privateParam the corresponding private key parameters.
+ */
+ public AsymmetricCipherKeyPair(
+ CipherParameters publicParam,
+ CipherParameters privateParam)
+ {
+ this.publicParam = publicParam;
+ this.privateParam = privateParam;
+ }
+
+ /**
+ * return the public key parameters.
+ *
+ * @return the public key parameters.
+ */
+ public CipherParameters getPublic()
+ {
+ return publicParam;
+ }
+
+ /**
+ * return the private key parameters.
+ *
+ * @return the private key parameters.
+ */
+ public CipherParameters getPrivate()
+ {
+ return privateParam;
+ }
+}
--- /dev/null
+package org.bouncycastle.crypto;
+
+/**
+ * interface that a public/private key pair generator should conform to.
+ */
+public interface AsymmetricCipherKeyPairGenerator
+{
+ /**
+ * intialise the key pair generator.
+ *
+ * @param the parameters the key pair is to be initialised with.
+ */
+ public void init(KeyGenerationParameters param);
+
+ /**
+ * return an AsymmetricCipherKeyPair containing the generated keys.
+ *
+ * @return an AsymmetricCipherKeyPair containing the generated keys.
+ */
+ public AsymmetricCipherKeyPair generateKeyPair();
+}
+
--- /dev/null
+package org.bouncycastle.crypto;
+
+import java.lang.IllegalStateException;
+
+/**
+ * Block cipher engines are expected to conform to this interface.
+ */
+public interface BlockCipher
+{
+ /**
+ * Initialise the cipher.
+ *
+ * @param forEncryption if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param param the key and other data required by the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(boolean forEncryption, CipherParameters params)
+ throws IllegalArgumentException;
+
+ /**
+ * Return the name of the algorithm the cipher implements.
+ *
+ * @return the name of the algorithm the cipher implements.
+ */
+ public String getAlgorithmName();
+
+ /**
+ * Return the block size for this cipher (in bytes).
+ *
+ * @return the block size for this cipher in bytes.
+ */
+ public int getBlockSize();
+
+ /**
+ * Process one block of input from the array in and write it to
+ * the out array.
+ *
+ * @param in the array containing the input data.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the output data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ public int processBlock(byte[] in, int inOff, byte[] out, int outOff)
+ throws DataLengthException, IllegalStateException;
+
+ /**
+ * Reset the cipher. After resetting the cipher is in the same state
+ * as it was after the last init (if there was one).
+ */
+ public void reset();
+}
--- /dev/null
+package org.bouncycastle.crypto;
+
+import java.security.SecureRandom;
+
+/**
+ * The base class for symmetric, or secret, cipher key generators.
+ */
+public class CipherKeyGenerator
+{
+ protected SecureRandom random;
+ protected int strength;
+
+ /**
+ * initialise the key generator.
+ *
+ * @param param the parameters to be used for key generation
+ */
+ public void init(
+ KeyGenerationParameters param)
+ {
+ this.random = param.getRandom();
+ this.strength = (param.getStrength() + 7) / 8;
+ }
+
+ /**
+ * generate a secret key.
+ *
+ * @return a byte array containing the key value.
+ */
+ public byte[] generateKey()
+ {
+ byte[] key = new byte[strength];
+
+ random.nextBytes(key);
+
+ return key;
+ }
+}
--- /dev/null
+package org.bouncycastle.crypto;
+
+/**
+ * all parameter classes implement this.
+ */
+public interface CipherParameters
+{
+}
--- /dev/null
+package org.bouncycastle.crypto;
+
+/**
+ * the foundation class for the hard exceptions thrown by the crypto packages.
+ */
+public class CryptoException
+ extends Exception
+{
+ /**
+ * base constructor.
+ */
+ public CryptoException()
+ {
+ }
+
+ /**
+ * create a CryptoException with the given message.
+ *
+ * @param message the message to be carried with the exception.
+ */
+ public CryptoException(
+ String message)
+ {
+ super(message);
+ }
+}
--- /dev/null
+package org.bouncycastle.crypto;
+
+/**
+ * this exception is thrown if a buffer that is meant to have output
+ * copied into it turns out to be too short, or if we've been given
+ * insufficient input. In general this exception will get thrown rather
+ * than an ArrayOutOfBounds exception.
+ */
+public class DataLengthException
+ extends RuntimeCryptoException
+{
+ /**
+ * base constructor.
+ */
+ public DataLengthException()
+ {
+ }
+
+ /**
+ * create a DataLengthException with the given message.
+ *
+ * @param message the message to be carried with the exception.
+ */
+ public DataLengthException(
+ String message)
+ {
+ super(message);
+ }
+}
--- /dev/null
+package org.bouncycastle.crypto;
+
+/**
+ * interface that a message digest conforms to.
+ */
+public interface Digest
+{
+ /**
+ * return the algorithm name
+ *
+ * @return the algorithm name
+ */
+ public String getAlgorithmName();
+
+ /**
+ * return the size, in bytes, of the digest produced by this message digest.
+ *
+ * @return the size, in bytes, of the digest produced by this message digest.
+ */
+ public int getDigestSize();
+
+ /**
+ * update the message digest with a single byte.
+ *
+ * @param in the input byte to be entered.
+ */
+ public void update(byte in);
+
+ /**
+ * update the message digest with a block of bytes.
+ *
+ * @param in the byte array containing the data.
+ * @param inOff the offset into the byte array where the data starts.
+ * @param len the length of the data.
+ */
+ public void update(byte[] in, int inOff, int len);
+
+ /**
+ * close the digest, producing the final digest value. The doFinal
+ * call leaves the digest reset.
+ *
+ * @param out the array the digest is to be copied into.
+ * @param outOff the offset into the out array the digest is to start at.
+ */
+ public int doFinal(byte[] out, int outOff);
+
+ /**
+ * reset the digest back to it's initial state.
+ */
+ public void reset();
+}
--- /dev/null
+package org.bouncycastle.crypto;
+
+/**
+ * this exception is thrown whenever we find something we don't expect in a
+ * message.
+ */
+public class InvalidCipherTextException
+ extends CryptoException
+{
+ /**
+ * base constructor.
+ */
+ public InvalidCipherTextException()
+ {
+ }
+
+ /**
+ * create a InvalidCipherTextException with the given message.
+ *
+ * @param message the message to be carried with the exception.
+ */
+ public InvalidCipherTextException(
+ String message)
+ {
+ super(message);
+ }
+}
--- /dev/null
+package org.bouncycastle.crypto;
+
+import java.security.SecureRandom;
+
+/**
+ * The base class for parameters to key generators.
+ */
+public class KeyGenerationParameters
+{
+ private SecureRandom random;
+ private int strength;
+
+ /**
+ * initialise the generator with a source of randomness
+ * and a strength (in bits).
+ *
+ * @param random the random byte source.
+ * @param strength the size, in bits, of the keys we want to produce.
+ */
+ public KeyGenerationParameters(
+ SecureRandom random,
+ int strength)
+ {
+ this.random = random;
+ this.strength = strength;
+ }
+
+ /**
+ * return the random source associated with this
+ * generator.
+ *
+ * @return the generators random source.
+ */
+ public SecureRandom getRandom()
+ {
+ return random;
+ }
+
+ /**
+ * return the bit strength for keys produced by this generator,
+ *
+ * @return the strength of the keys this generator produces (in bits).
+ */
+ public int getStrength()
+ {
+ return strength;
+ }
+}
--- /dev/null
+package org.bouncycastle.crypto;
+
+/**
+ * the foundation class for the exceptions thrown by the crypto packages.
+ */
+public class RuntimeCryptoException
+ extends RuntimeException
+{
+ /**
+ * base constructor.
+ */
+ public RuntimeCryptoException()
+ {
+ }
+
+ /**
+ * create a RuntimeCryptoException with the given message.
+ *
+ * @param message the message to be carried with the exception.
+ */
+ public RuntimeCryptoException(
+ String message)
+ {
+ super(message);
+ }
+}
--- /dev/null
+package org.bouncycastle.crypto;
+
+/**
+ * a wrapper for block ciphers with a single byte block size, so that they
+ * can be treated like stream ciphers.
+ */
+public class StreamBlockCipher
+ implements StreamCipher
+{
+ private BlockCipher cipher;
+
+ private byte[] oneByte = new byte[1];
+
+ /**
+ * basic constructor.
+ *
+ * @param cipher the block cipher to be wrapped.
+ * @exception IllegalArgumentException if the cipher has a block size other than
+ * one.
+ */
+ public StreamBlockCipher(
+ BlockCipher cipher)
+ {
+ if (cipher.getBlockSize() != 1)
+ {
+ throw new IllegalArgumentException("block cipher block size != 1.");
+ }
+
+ this.cipher = cipher;
+ }
+
+ /**
+ * initialise the underlying cipher.
+ *
+ * @param forEncryption true if we are setting up for encryption, false otherwise.
+ * @param param the necessary parameters for the underlying cipher to be initialised.
+ */
+ public void init(
+ boolean forEncryption,
+ CipherParameters params)
+ {
+ cipher.init(forEncryption, params);
+ }
+
+ /**
+ * return the name of the algorithm we are wrapping.
+ *
+ * @return the name of the algorithm we are wrapping.
+ */
+ public String getAlgorithmName()
+ {
+ return cipher.getAlgorithmName();
+ }
+
+ /**
+ * encrypt/decrypt a single byte returning the result.
+ *
+ * @param in the byte to be processed.
+ * @return the result of processing the input byte.
+ */
+ public byte returnByte(
+ byte in)
+ {
+ oneByte[0] = in;
+
+ cipher.processBlock(oneByte, 0, oneByte, 0);
+
+ return oneByte[0];
+ }
+
+ /**
+ * process a block of bytes from in putting the result into out.
+ *
+ * @param in the input byte array.
+ * @param inOff the offset into the in array where the data to be processed starts.
+ * @param len the number of bytes to be processed.
+ * @param out the output buffer the processed bytes go into.
+ * @param outOff the offset into the output byte array the processed data stars at.
+ * @exception DataLengthException if the output buffer is too small.
+ */
+ public void processBytes(
+ byte[] in,
+ int inOff,
+ int len,
+ byte[] out,
+ int outOff)
+ throws DataLengthException
+ {
+ if (outOff + len > out.length)
+ {
+ throw new DataLengthException("output buffer too small in processBytes()");
+ }
+
+ for (int i = 0; i != len; i++)
+ {
+ cipher.processBlock(in, inOff + i, out, outOff + i);
+ }
+ }
+
+ /**
+ * reset the underlying cipher. This leaves it in the same state
+ * it was at after the last init (if there was one).
+ */
+ public void reset()
+ {
+ cipher.reset();
+ }
+}
--- /dev/null
+package org.bouncycastle.crypto;
+
+/**
+ * the interface stream ciphers conform to.
+ */
+public interface StreamCipher
+{
+ /**
+ * Initialise the cipher.
+ *
+ * @param forEncryption if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param param the key and other data required by the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(boolean forEncryption, CipherParameters params)
+ throws IllegalArgumentException;
+
+ /**
+ * Return the name of the algorithm the cipher implements.
+ *
+ * @return the name of the algorithm the cipher implements.
+ */
+ public String getAlgorithmName();
+
+ /**
+ * encrypt/decrypt a single byte returning the result.
+ *
+ * @param in the byte to be processed.
+ * @return the result of processing the input byte.
+ */
+ public byte returnByte(byte in);
+
+ /**
+ * process a block of bytes from in putting the result into out.
+ *
+ * @param in the input byte array.
+ * @param inOff the offset into the in array where the data to be processed starts.
+ * @param len the number of bytes to be processed.
+ * @param out the output buffer the processed bytes go into.
+ * @param outOff the offset into the output byte array the processed data stars at.
+ * @exception DataLengthException if the output buffer is too small.
+ */
+ public void processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
+ throws DataLengthException;
+
+ /**
+ * reset the cipher. This leaves it in the same state
+ * it was at after the last init (if there was one).
+ */
+ public void reset();
+}
--- /dev/null
+package org.bouncycastle.crypto.digests;
+
+import org.bouncycastle.crypto.Digest;
+
+/**
+ * base implementation of MD4 family style digest as outlined in
+ * "Handbook of Applied Cryptography", pages 344 - 347.
+ */
+public abstract class GeneralDigest
+ implements Digest
+{
+ private byte[] xBuf;
+ private int xBufOff;
+
+ private long byteCount;
+
+ /**
+ * Standard constructor
+ */
+ protected GeneralDigest()
+ {
+ xBuf = new byte[4];
+ xBufOff = 0;
+ }
+
+ /**
+ * Copy constructor. We are using copy constructors in place
+ * of the Object.clone() interface as this interface is not
+ * supported by J2ME.
+ */
+ protected GeneralDigest(GeneralDigest t)
+ {
+ xBuf = new byte[t.xBuf.length];
+ System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.length);
+
+ xBufOff = t.xBufOff;
+ byteCount = t.byteCount;
+ }
+
+ public void update(
+ byte in)
+ {
+ xBuf[xBufOff++] = in;
+
+ if (xBufOff == xBuf.length)
+ {
+ processWord(xBuf, 0);
+ xBufOff = 0;
+ }
+
+ byteCount++;
+ }
+
+ public void update(
+ byte[] in,
+ int inOff,
+ int len)
+ {
+ //
+ // fill the current word
+ //
+ while ((xBufOff != 0) && (len > 0))
+ {
+ update(in[inOff]);
+
+ inOff++;
+ len--;
+ }
+
+ //
+ // process whole words.
+ //
+ while (len > xBuf.length)
+ {
+ processWord(in, inOff);
+
+ inOff += xBuf.length;
+ len -= xBuf.length;
+ byteCount += xBuf.length;
+ }
+
+ //
+ // load in the remainder.
+ //
+ while (len > 0)
+ {
+ update(in[inOff]);
+
+ inOff++;
+ len--;
+ }
+ }
+
+ public void finish()
+ {
+ long bitLength = (byteCount << 3);
+
+ //
+ // add the pad bytes.
+ //
+ update((byte)128);
+
+ while (xBufOff != 0)
+ {
+ update((byte)0);
+ }
+
+ processLength(bitLength);
+
+ processBlock();
+ }
+
+ public void reset()
+ {
+ byteCount = 0;
+
+ xBufOff = 0;
+ for ( int i = 0; i < xBuf.length; i++ ) {
+ xBuf[i] = 0;
+ }
+ }
+
+ protected abstract void processWord(byte[] in, int inOff);
+
+ protected abstract void processLength(long bitLength);
+
+ protected abstract void processBlock();
+}
--- /dev/null
+package org.bouncycastle.crypto.digests;\r
+
+import org.bouncycastle.crypto.Digest;
+/**
+ * implementation of MD2
+ * as outlined in RFC1319 by B.Kaliski from RSA Laboratories April 1992
+ *
+ * @author Michael Lee
+ */
+public class MD2Digest\r
+ implements Digest\r
+{\r
+ private static final int DIGEST_LENGTH = 16;\r
+\r
+ /* X buffer */\r
+ private byte[] X = new byte[48];\r
+ private int xOff;
+\r /* M buffer */
+\r private byte[] M = new byte[16];\r
+ private int mOff;
+\r /* check sum */
+\r private byte[] C = new byte[16];
+ private int COff;
+
+ public MD2Digest()\r
+ {\r
+ reset();\r
+ }\r
+ public MD2Digest(MD2Digest t)\r
+ {
+ System.arraycopy(t.X, 0, X, 0, t.X.length);
+ xOff = t.xOff;
+ System.arraycopy(t.M, 0, M, 0, t.M.length);
+ mOff = t.mOff;
+ System.arraycopy(t.C, 0, C, 0, t.C.length);
+ COff = t.COff;
+ }
+ /**\r
+ * return the algorithm name
+ *
+ * @return the algorithm name
+ */
+ public String getAlgorithmName()
+ {
+ return "MD2";
+ }
+ /**
+ * return the size, in bytes, of the digest produced by this message digest.
+ *
+ * @return the size, in bytes, of the digest produced by this message digest.
+ */
+ public int getDigestSize()
+ {
+ return DIGEST_LENGTH;
+ }
+ /**
+ * close the digest, producing the final digest value. The doFinal
+ * call leaves the digest reset.
+ *
+ * @param out the array the digest is to be copied into.
+ * @param outOff the offset into the out array the digest is to start at.
+ */
+ public int doFinal(byte[] out, int outOff)
+ {
+ // add padding
+ byte paddingByte = (byte)(M.length-mOff);
+ for (int i=mOff;i<M.length;i++)
+ {
+ M[i] = paddingByte;
+ }
+ //do final check sum
+ processCheckSum(M);
+ // do final block process
+ processBlock(M);
+
+ processBlock(C);
+
+ System.arraycopy(X,xOff,out,outOff,16);
+
+ reset();
+
+ return DIGEST_LENGTH;
+ }
+ /**
+ * reset the digest back to it's initial state.
+ */
+ public void reset()\r
+ {\r
+ xOff = 0;\r
+ for (int i = 0; i != X.length; i++)
+ {
+ X[i] = 0;
+ }
+ mOff = 0;\r
+ for (int i = 0; i != M.length; i++)
+ {
+ M[i] = 0;
+ }
+ COff = 0;\r
+ for (int i = 0; i != C.length; i++)
+ {
+ C[i] = 0;
+ }
+ }\r
+ /**\r
+ * update the message digest with a single byte.
+ *
+ * @param in the input byte to be entered.
+ */
+ public void update(byte in)
+ {
+ M[mOff++] = in;
+
+ if (mOff == 16)
+ {
+ processCheckSum(M);
+ processBlock(M);
+ mOff = 0;
+ }
+ }
+
+ /**
+ * update the message digest with a block of bytes.
+ *
+ * @param in the byte array containing the data.
+ * @param inOff the offset into the byte array where the data starts.
+ * @param len the length of the data.
+ */
+ public void update(byte[] in, int inOff, int len)\r
+ {\r
+ //\r
+ // fill the current word
+ //
+ while ((mOff != 0) && (len > 0))
+ {
+ update(in[inOff]);
+ inOff++;
+ len--;
+ }
+
+ //
+ // process whole words.
+ //
+ while (len > 16)
+ {
+ System.arraycopy(in,inOff,M,0,16);
+ processCheckSum(M);
+ processBlock(M);
+ len -= 16;
+ inOff += 16;
+ }
+
+ //
+ // load in the remainder.
+ //
+ while (len > 0)
+ {
+ update(in[inOff]);
+ inOff++;
+ len--;
+ }\r
+ }\r
+ protected void processCheckSum(byte[] m)\r
+ {\r
+ int L = C[15];\r
+ for (int i=0;i<16;i++)\r
+ {\r
+ C[i] ^= S[(m[i] ^ L) & 0xff];\r
+ L = C[i];\r
+ }\r
+ }\r
+ protected void processBlock(byte[] m)\r
+ {
+ for (int i=0;i<16;i++)
+ {
+ X[i+16] = m[i];
+ X[i+32] = (byte)(m[i] ^ X[i]);
+ }
+ // encrypt block
+ int t = 0;
+
+ for (int j=0;j<18;j++)
+ {
+ for (int k=0;k<48;k++)
+ {
+ t = X[k] ^= S[t];
+ t = t & 0xff;
+ }
+ t = (t + j)%256;
+ }
+ }
+ // 256-byte random permutation constructed from the digits of PI
+ private static final byte[] S = {\r
+ (byte)41,(byte)46,(byte)67,(byte)201,(byte)162,(byte)216,(byte)124,\r
+ (byte)1,(byte)61,(byte)54,(byte)84,(byte)161,(byte)236,(byte)240,\r
+ (byte)6,(byte)19,(byte)98,(byte)167,(byte)5,(byte)243,(byte)192,\r
+ (byte)199,(byte)115,(byte)140,(byte)152,(byte)147,(byte)43,(byte)217,\r
+ (byte)188,(byte)76,(byte)130,(byte)202,(byte)30,(byte)155,(byte)87,\r
+ (byte)60,(byte)253,(byte)212,(byte)224,(byte)22,(byte)103,(byte)66,\r
+ (byte)111,(byte)24,(byte)138,(byte)23,(byte)229,(byte)18,(byte)190,\r
+ (byte)78,(byte)196,(byte)214,(byte)218,(byte)158,(byte)222,(byte)73,\r
+ (byte)160,(byte)251,(byte)245,(byte)142,(byte)187,(byte)47,(byte)238,\r
+ (byte)122,(byte)169,(byte)104,(byte)121,(byte)145,(byte)21,(byte)178,\r
+ (byte)7,(byte)63,(byte)148,(byte)194,(byte)16,(byte)137,(byte)11,\r
+ (byte)34,(byte)95,(byte)33,(byte)128,(byte)127,(byte)93,(byte)154,\r
+ (byte)90,(byte)144,(byte)50,(byte)39,(byte)53,(byte)62,(byte)204,\r
+ (byte)231,(byte)191,(byte)247,(byte)151,(byte)3,(byte)255,(byte)25,\r
+ (byte)48,(byte)179,(byte)72,(byte)165,(byte)181,(byte)209,(byte)215,\r
+ (byte)94,(byte)146,(byte)42,(byte)172,(byte)86,(byte)170,(byte)198,\r
+ (byte)79,(byte)184,(byte)56,(byte)210,(byte)150,(byte)164,(byte)125,\r
+ (byte)182,(byte)118,(byte)252,(byte)107,(byte)226,(byte)156,(byte)116,\r
+ (byte)4,(byte)241,(byte)69,(byte)157,(byte)112,(byte)89,(byte)100,\r
+ (byte)113,(byte)135,(byte)32,(byte)134,(byte)91,(byte)207,(byte)101,\r
+ (byte)230,(byte)45,(byte)168,(byte)2,(byte)27,(byte)96,(byte)37,\r
+ (byte)173,(byte)174,(byte)176,(byte)185,(byte)246,(byte)28,(byte)70,\r
+ (byte)97,(byte)105,(byte)52,(byte)64,(byte)126,(byte)15,(byte)85,\r
+ (byte)71,(byte)163,(byte)35,(byte)221,(byte)81,(byte)175,(byte)58,\r
+ (byte)195,(byte)92,(byte)249,(byte)206,(byte)186,(byte)197,(byte)234,\r
+ (byte)38,(byte)44,(byte)83,(byte)13,(byte)110,(byte)133,(byte)40,\r
+ (byte)132, 9,(byte)211,(byte)223,(byte)205,(byte)244,(byte)65,\r
+ (byte)129,(byte)77,(byte)82,(byte)106,(byte)220,(byte)55,(byte)200,\r
+ (byte)108,(byte)193,(byte)171,(byte)250,(byte)36,(byte)225,(byte)123,\r
+ (byte)8,(byte)12,(byte)189,(byte)177,(byte)74,(byte)120,(byte)136,\r
+ (byte)149,(byte)139,(byte)227,(byte)99,(byte)232,(byte)109,(byte)233,\r
+ (byte)203,(byte)213,(byte)254,(byte)59,(byte)0,(byte)29,(byte)57,\r
+ (byte)242,(byte)239,(byte)183,(byte)14,(byte)102,(byte)88,(byte)208,\r
+ (byte)228,(byte)166,(byte)119,(byte)114,(byte)248,(byte)235,(byte)117,\r
+ (byte)75,(byte)10,(byte)49,(byte)68,(byte)80,(byte)180,(byte)143,\r
+ (byte)237,(byte)31,(byte)26,(byte)219,(byte)153,(byte)141,(byte)51,\r
+ (byte)159,(byte)17,(byte)131,(byte)20\r
+ };\r
+}\r
--- /dev/null
+package org.bouncycastle.crypto.digests;
+
+import org.bouncycastle.crypto.Digest;
+
+/**
+ * implementation of MD5 as outlined in "Handbook of Applied Cryptography", pages 346 - 347.
+ */
+public class MD5Digest
+ extends GeneralDigest
+{
+ private static final int DIGEST_LENGTH = 16;
+
+ private int H1, H2, H3, H4; // IV's
+
+ private int[] X = new int[16];
+ private int xOff;
+
+ /**
+ * Standard constructor
+ */
+ public MD5Digest()
+ {
+ reset();
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public MD5Digest(MD5Digest t)
+ {
+ super(t);
+
+ H1 = t.H1;
+ H2 = t.H2;
+ H3 = t.H3;
+ H4 = t.H4;
+
+ System.arraycopy(t.X, 0, X, 0, t.X.length);
+ xOff = t.xOff;
+ }
+
+ public String getAlgorithmName()
+ {
+ return "MD5";
+ }
+
+ public int getDigestSize()
+ {
+ return DIGEST_LENGTH;
+ }
+
+ protected void processWord(
+ byte[] in,
+ int inOff)
+ {
+ X[xOff++] = (in[inOff] & 0xff) | ((in[inOff + 1] & 0xff) << 8)
+ | ((in[inOff + 2] & 0xff) << 16) | ((in[inOff + 3] & 0xff) << 24);
+
+ if (xOff == 16)
+ {
+ processBlock();
+ }
+ }
+
+ protected void processLength(
+ long bitLength)
+ {
+ if (xOff > 14)
+ {
+ processBlock();
+ }
+
+ X[14] = (int)(bitLength & 0xffffffff);
+ X[15] = (int)(bitLength >>> 32);
+ }
+
+ private void unpackWord(
+ int word,
+ byte[] out,
+ int outOff)
+ {
+ out[outOff] = (byte)word;
+ out[outOff + 1] = (byte)(word >>> 8);
+ out[outOff + 2] = (byte)(word >>> 16);
+ out[outOff + 3] = (byte)(word >>> 24);
+ }
+
+ public int doFinal(
+ byte[] out,
+ int outOff)
+ {
+ finish();
+
+ unpackWord(H1, out, outOff);
+ unpackWord(H2, out, outOff + 4);
+ unpackWord(H3, out, outOff + 8);
+ unpackWord(H4, out, outOff + 12);
+
+ reset();
+
+ return DIGEST_LENGTH;
+ }
+
+ /**
+ * reset the chaining variables to the IV values.
+ */
+ public void reset()
+ {
+ super.reset();
+
+ H1 = 0x67452301;
+ H2 = 0xefcdab89;
+ H3 = 0x98badcfe;
+ H4 = 0x10325476;
+
+ xOff = 0;
+
+ for (int i = 0; i != X.length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+
+ //
+ // round 1 left rotates
+ //
+ private static final int S11 = 7;
+ private static final int S12 = 12;
+ private static final int S13 = 17;
+ private static final int S14 = 22;
+
+ //
+ // round 2 left rotates
+ //
+ private static final int S21 = 5;
+ private static final int S22 = 9;
+ private static final int S23 = 14;
+ private static final int S24 = 20;
+
+ //
+ // round 3 left rotates
+ //
+ private static final int S31 = 4;
+ private static final int S32 = 11;
+ private static final int S33 = 16;
+ private static final int S34 = 23;
+
+ //
+ // round 4 left rotates
+ //
+ private static final int S41 = 6;
+ private static final int S42 = 10;
+ private static final int S43 = 15;
+ private static final int S44 = 21;
+
+ /*
+ * rotate int x left n bits.
+ */
+ private int rotateLeft(
+ int x,
+ int n)
+ {
+ return (x << n) | (x >>> (32 - n));
+ }
+
+ /*
+ * F, G, H and I are the basic MD5 functions.
+ */
+ private int F(
+ int u,
+ int v,
+ int w)
+ {
+ return (u & v) | (~u & w);
+ }
+
+ private int G(
+ int u,
+ int v,
+ int w)
+ {
+ return (u & w) | (v & ~w);
+ }
+
+ private int H(
+ int u,
+ int v,
+ int w)
+ {
+ return u ^ v ^ w;
+ }
+
+ private int K(
+ int u,
+ int v,
+ int w)
+ {
+ return v ^ (u | ~w);
+ }
+
+ protected void processBlock()
+ {
+ int a = H1;
+ int b = H2;
+ int c = H3;
+ int d = H4;
+
+ //
+ // Round 1 - F cycle, 16 times.
+ //
+ a = rotateLeft((a + F(b, c, d) + X[ 0] + 0xd76aa478), S11) + b;
+ d = rotateLeft((d + F(a, b, c) + X[ 1] + 0xe8c7b756), S12) + a;
+ c = rotateLeft((c + F(d, a, b) + X[ 2] + 0x242070db), S13) + d;
+ b = rotateLeft((b + F(c, d, a) + X[ 3] + 0xc1bdceee), S14) + c;
+ a = rotateLeft((a + F(b, c, d) + X[ 4] + 0xf57c0faf), S11) + b;
+ d = rotateLeft((d + F(a, b, c) + X[ 5] + 0x4787c62a), S12) + a;
+ c = rotateLeft((c + F(d, a, b) + X[ 6] + 0xa8304613), S13) + d;
+ b = rotateLeft((b + F(c, d, a) + X[ 7] + 0xfd469501), S14) + c;
+ a = rotateLeft((a + F(b, c, d) + X[ 8] + 0x698098d8), S11) + b;
+ d = rotateLeft((d + F(a, b, c) + X[ 9] + 0x8b44f7af), S12) + a;
+ c = rotateLeft((c + F(d, a, b) + X[10] + 0xffff5bb1), S13) + d;
+ b = rotateLeft((b + F(c, d, a) + X[11] + 0x895cd7be), S14) + c;
+ a = rotateLeft((a + F(b, c, d) + X[12] + 0x6b901122), S11) + b;
+ d = rotateLeft((d + F(a, b, c) + X[13] + 0xfd987193), S12) + a;
+ c = rotateLeft((c + F(d, a, b) + X[14] + 0xa679438e), S13) + d;
+ b = rotateLeft((b + F(c, d, a) + X[15] + 0x49b40821), S14) + c;
+
+ //
+ // Round 2 - G cycle, 16 times.
+ //
+ a = rotateLeft((a + G(b, c, d) + X[ 1] + 0xf61e2562), S21) + b;
+ d = rotateLeft((d + G(a, b, c) + X[ 6] + 0xc040b340), S22) + a;
+ c = rotateLeft((c + G(d, a, b) + X[11] + 0x265e5a51), S23) + d;
+ b = rotateLeft((b + G(c, d, a) + X[ 0] + 0xe9b6c7aa), S24) + c;
+ a = rotateLeft((a + G(b, c, d) + X[ 5] + 0xd62f105d), S21) + b;
+ d = rotateLeft((d + G(a, b, c) + X[10] + 0x02441453), S22) + a;
+ c = rotateLeft((c + G(d, a, b) + X[15] + 0xd8a1e681), S23) + d;
+ b = rotateLeft((b + G(c, d, a) + X[ 4] + 0xe7d3fbc8), S24) + c;
+ a = rotateLeft((a + G(b, c, d) + X[ 9] + 0x21e1cde6), S21) + b;
+ d = rotateLeft((d + G(a, b, c) + X[14] + 0xc33707d6), S22) + a;
+ c = rotateLeft((c + G(d, a, b) + X[ 3] + 0xf4d50d87), S23) + d;
+ b = rotateLeft((b + G(c, d, a) + X[ 8] + 0x455a14ed), S24) + c;
+ a = rotateLeft((a + G(b, c, d) + X[13] + 0xa9e3e905), S21) + b;
+ d = rotateLeft((d + G(a, b, c) + X[ 2] + 0xfcefa3f8), S22) + a;
+ c = rotateLeft((c + G(d, a, b) + X[ 7] + 0x676f02d9), S23) + d;
+ b = rotateLeft((b + G(c, d, a) + X[12] + 0x8d2a4c8a), S24) + c;
+
+ //
+ // Round 3 - H cycle, 16 times.
+ //
+ a = rotateLeft((a + H(b, c, d) + X[ 5] + 0xfffa3942), S31) + b;
+ d = rotateLeft((d + H(a, b, c) + X[ 8] + 0x8771f681), S32) + a;
+ c = rotateLeft((c + H(d, a, b) + X[11] + 0x6d9d6122), S33) + d;
+ b = rotateLeft((b + H(c, d, a) + X[14] + 0xfde5380c), S34) + c;
+ a = rotateLeft((a + H(b, c, d) + X[ 1] + 0xa4beea44), S31) + b;
+ d = rotateLeft((d + H(a, b, c) + X[ 4] + 0x4bdecfa9), S32) + a;
+ c = rotateLeft((c + H(d, a, b) + X[ 7] + 0xf6bb4b60), S33) + d;
+ b = rotateLeft((b + H(c, d, a) + X[10] + 0xbebfbc70), S34) + c;
+ a = rotateLeft((a + H(b, c, d) + X[13] + 0x289b7ec6), S31) + b;
+ d = rotateLeft((d + H(a, b, c) + X[ 0] + 0xeaa127fa), S32) + a;
+ c = rotateLeft((c + H(d, a, b) + X[ 3] + 0xd4ef3085), S33) + d;
+ b = rotateLeft((b + H(c, d, a) + X[ 6] + 0x04881d05), S34) + c;
+ a = rotateLeft((a + H(b, c, d) + X[ 9] + 0xd9d4d039), S31) + b;
+ d = rotateLeft((d + H(a, b, c) + X[12] + 0xe6db99e5), S32) + a;
+ c = rotateLeft((c + H(d, a, b) + X[15] + 0x1fa27cf8), S33) + d;
+ b = rotateLeft((b + H(c, d, a) + X[ 2] + 0xc4ac5665), S34) + c;
+
+ //
+ // Round 4 - K cycle, 16 times.
+ //
+ a = rotateLeft((a + K(b, c, d) + X[ 0] + 0xf4292244), S41) + b;
+ d = rotateLeft((d + K(a, b, c) + X[ 7] + 0x432aff97), S42) + a;
+ c = rotateLeft((c + K(d, a, b) + X[14] + 0xab9423a7), S43) + d;
+ b = rotateLeft((b + K(c, d, a) + X[ 5] + 0xfc93a039), S44) + c;
+ a = rotateLeft((a + K(b, c, d) + X[12] + 0x655b59c3), S41) + b;
+ d = rotateLeft((d + K(a, b, c) + X[ 3] + 0x8f0ccc92), S42) + a;
+ c = rotateLeft((c + K(d, a, b) + X[10] + 0xffeff47d), S43) + d;
+ b = rotateLeft((b + K(c, d, a) + X[ 1] + 0x85845dd1), S44) + c;
+ a = rotateLeft((a + K(b, c, d) + X[ 8] + 0x6fa87e4f), S41) + b;
+ d = rotateLeft((d + K(a, b, c) + X[15] + 0xfe2ce6e0), S42) + a;
+ c = rotateLeft((c + K(d, a, b) + X[ 6] + 0xa3014314), S43) + d;
+ b = rotateLeft((b + K(c, d, a) + X[13] + 0x4e0811a1), S44) + c;
+ a = rotateLeft((a + K(b, c, d) + X[ 4] + 0xf7537e82), S41) + b;
+ d = rotateLeft((d + K(a, b, c) + X[11] + 0xbd3af235), S42) + a;
+ c = rotateLeft((c + K(d, a, b) + X[ 2] + 0x2ad7d2bb), S43) + d;
+ b = rotateLeft((b + K(c, d, a) + X[ 9] + 0xeb86d391), S44) + c;
+
+ H1 += a;
+ H2 += b;
+ H3 += c;
+ H4 += d;
+
+ //
+ // reset the offset and clean out the word buffer.
+ //
+ xOff = 0;
+ for (int i = 0; i != X.length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+}
--- /dev/null
+package org.bouncycastle.crypto.digests;
+
+import org.bouncycastle.crypto.Digest;
+
+/**
+ * implementation of SHA-1 as outlined in "Handbook of Applied Cryptography", pages 346 - 349.
+ *
+ * It is interesting to ponder why the, apart from the extra IV, the other difference here from MD5
+ * is the "endienness" of the word processing!
+ */
+public class SHA1Digest
+ extends GeneralDigest
+{
+ private static final int DIGEST_LENGTH = 20;
+
+ private int H1, H2, H3, H4, H5;
+
+ private int[] X = new int[80];
+ private int xOff;
+
+ /**
+ * Standard constructor
+ */
+ public SHA1Digest()
+ {
+ reset();
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public SHA1Digest(SHA1Digest t)
+ {
+ super(t);
+
+ H1 = t.H1;
+ H2 = t.H2;
+ H3 = t.H3;
+ H4 = t.H4;
+ H5 = t.H5;
+
+ System.arraycopy(t.X, 0, X, 0, t.X.length);
+ xOff = t.xOff;
+ }
+
+ public String getAlgorithmName()
+ {
+ return "SHA-1";
+ }
+
+ public int getDigestSize()
+ {
+ return DIGEST_LENGTH;
+ }
+
+ protected void processWord(
+ byte[] in,
+ int inOff)
+ {
+ X[xOff++] = ((in[inOff] & 0xff) << 24) | ((in[inOff + 1] & 0xff) << 16)
+ | ((in[inOff + 2] & 0xff) << 8) | ((in[inOff + 3] & 0xff));
+
+ if (xOff == 16)
+ {
+ processBlock();
+ }
+ }
+
+ private void unpackWord(
+ int word,
+ byte[] out,
+ int outOff)
+ {
+ out[outOff] = (byte)(word >>> 24);
+ out[outOff + 1] = (byte)(word >>> 16);
+ out[outOff + 2] = (byte)(word >>> 8);
+ out[outOff + 3] = (byte)word;
+ }
+
+ protected void processLength(
+ long bitLength)
+ {
+ if (xOff > 14)
+ {
+ processBlock();
+ }
+
+ X[14] = (int)(bitLength >>> 32);
+ X[15] = (int)(bitLength & 0xffffffff);
+ }
+
+ public int doFinal(
+ byte[] out,
+ int outOff)
+ {
+ finish();
+
+ unpackWord(H1, out, outOff);
+ unpackWord(H2, out, outOff + 4);
+ unpackWord(H3, out, outOff + 8);
+ unpackWord(H4, out, outOff + 12);
+ unpackWord(H5, out, outOff + 16);
+
+ reset();
+
+ return DIGEST_LENGTH;
+ }
+
+ /**
+ * reset the chaining variables
+ */
+ public void reset()
+ {
+ super.reset();
+
+ H1 = 0x67452301;
+ H2 = 0xefcdab89;
+ H3 = 0x98badcfe;
+ H4 = 0x10325476;
+ H5 = 0xc3d2e1f0;
+
+ xOff = 0;
+ for (int i = 0; i != X.length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+
+ //
+ // Additive constants
+ //
+ private static final int Y1 = 0x5a827999;
+ private static final int Y2 = 0x6ed9eba1;
+ private static final int Y3 = 0x8f1bbcdc;
+ private static final int Y4 = 0xca62c1d6;
+
+ private int f(
+ int u,
+ int v,
+ int w)
+ {
+ return ((u & v) | ((~u) & w));
+ }
+
+ private int h(
+ int u,
+ int v,
+ int w)
+ {
+ return (u ^ v ^ w);
+ }
+
+ private int g(
+ int u,
+ int v,
+ int w)
+ {
+ return ((u & v) | (u & w) | (v & w));
+ }
+
+ private int rotateLeft(
+ int x,
+ int n)
+ {
+ return (x << n) | (x >>> (32 - n));
+ }
+
+ protected void processBlock()
+ {
+ //
+ // expand 16 word block into 80 word block.
+ //
+ for (int i = 16; i <= 79; i++)
+ {
+ X[i] = rotateLeft((X[i - 3] ^ X[i - 8] ^ X[i - 14] ^ X[i - 16]), 1);
+ }
+
+ //
+ // set up working variables.
+ //
+ int A = H1;
+ int B = H2;
+ int C = H3;
+ int D = H4;
+ int E = H5;
+
+ //
+ // round 1
+ //
+ for (int j = 0; j <= 19; j++)
+ {
+ int t = rotateLeft(A, 5) + f(B, C, D) + E + X[j] + Y1;
+
+ E = D;
+ D = C;
+ C = rotateLeft(B, 30);
+ B = A;
+ A = t;
+ }
+
+ //
+ // round 2
+ //
+ for (int j = 20; j <= 39; j++)
+ {
+ int t = rotateLeft(A, 5) + h(B, C, D) + E + X[j] + Y2;
+
+ E = D;
+ D = C;
+ C = rotateLeft(B, 30);
+ B = A;
+ A = t;
+ }
+
+ //
+ // round 3
+ //
+ for (int j = 40; j <= 59; j++)
+ {
+ int t = rotateLeft(A, 5) + g(B, C, D) + E + X[j] + Y3;
+
+ E = D;
+ D = C;
+ C = rotateLeft(B, 30);
+ B = A;
+ A = t;
+ }
+
+ //
+ // round 4
+ //
+ for (int j = 60; j <= 79; j++)
+ {
+ int t = rotateLeft(A, 5) + h(B, C, D) + E + X[j] + Y4;
+
+ E = D;
+ D = C;
+ C = rotateLeft(B, 30);
+ B = A;
+ A = t;
+ }
+
+ H1 += A;
+ H2 += B;
+ H3 += C;
+ H4 += D;
+ H5 += E;
+
+ //
+ // reset the offset and clean out the word buffer.
+ //
+ xOff = 0;
+ for (int i = 0; i != X.length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+}
--- /dev/null
+package org.bouncycastle.crypto.encodings;
+
+import java.math.BigInteger;
+import java.util.Random;
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.AsymmetricBlockCipher;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+
+/**
+ * this does your basic PKCS 1 v1.5 padding - whether or not you should be using this
+ * depends on your application - see PKCS1 Version 2 for details.
+ */
+public class PKCS1Encoding
+ implements AsymmetricBlockCipher
+{
+ private static int HEADER_LENGTH = 10;
+
+ // HACK
+ //private SecureRandom random;
+ private Random random = new Random();
+
+ private AsymmetricBlockCipher engine;
+ private boolean forEncryption;
+ private boolean forPrivateKey;
+
+ public PKCS1Encoding(
+ AsymmetricBlockCipher cipher)
+ {
+ this.engine = cipher;
+ }
+
+ public AsymmetricBlockCipher getUnderlyingCipher()
+ {
+ return engine;
+ }
+
+ public void init(
+ boolean forEncryption,
+ CipherParameters param)
+ {
+ AsymmetricKeyParameter kParam;
+ if (param instanceof ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
+
+ // HACK
+ //this.random = rParam.getRandom();
+ kParam = (AsymmetricKeyParameter)rParam.getParameters();
+ }
+ else
+ {
+ // HACK
+ //this.random = new SecureRandom();
+ kParam = (AsymmetricKeyParameter)param;
+ }
+
+ engine.init(forEncryption, kParam);
+
+ this.forPrivateKey = kParam.isPrivate();
+ this.forEncryption = forEncryption;
+ }
+
+ public int getInputBlockSize()
+ {
+ int baseBlockSize = engine.getInputBlockSize();
+
+ if (forEncryption)
+ {
+ return baseBlockSize - HEADER_LENGTH;
+ }
+ else
+ {
+ return baseBlockSize;
+ }
+ }
+
+ public int getOutputBlockSize()
+ {
+ int baseBlockSize = engine.getOutputBlockSize();
+
+ if (forEncryption)
+ {
+ return baseBlockSize;
+ }
+ else
+ {
+ return baseBlockSize - HEADER_LENGTH;
+ }
+ }
+
+ public byte[] processBlock(
+ byte[] in,
+ int inOff,
+ int inLen)
+ throws InvalidCipherTextException
+ {
+ if (forEncryption)
+ {
+ return encodeBlock(in, inOff, inLen);
+ }
+ else
+ {
+ return decodeBlock(in, inOff, inLen);
+ }
+ }
+
+ private byte[] encodeBlock(
+ byte[] in,
+ int inOff,
+ int inLen)
+ throws InvalidCipherTextException
+ {
+ byte[] block = new byte[engine.getInputBlockSize()];
+
+ if (forPrivateKey)
+ {
+ block[0] = 0x01; // type code 1
+
+ for (int i = 1; i != block.length - inLen - 1; i++)
+ {
+ block[i] = (byte)0xFF;
+ }
+ }
+ else
+ {
+ random.nextBytes(block); // random fill
+
+ block[0] = 0x02; // type code 2
+
+ //
+ // a zero byte marks the end of the padding, so all
+ // the pad bytes must be non-zero.
+ //
+ for (int i = 1; i != block.length - inLen - 1; i++)
+ {
+ while (block[i] == 0)
+ {
+ block[i] = (byte)random.nextInt();
+ }
+ }
+ }
+
+ block[block.length - inLen - 1] = 0x00; // mark the end of the padding
+ System.arraycopy(in, inOff, block, block.length - inLen, inLen);
+
+ return engine.processBlock(block, 0, block.length);
+ }
+
+ /**
+ * @exception InvalidCipherTextException if the decrypted block is not in PKCS1 format.
+ */
+ private byte[] decodeBlock(
+ byte[] in,
+ int inOff,
+ int inLen)
+ throws InvalidCipherTextException
+ {
+ byte[] block = engine.processBlock(in, inOff, inLen);
+ if (block.length < getOutputBlockSize())
+ {
+ throw new InvalidCipherTextException("block truncated");
+ }
+
+ if (block[0] != 1 && block[0] != 2)
+ {
+ throw new InvalidCipherTextException("unknown block type");
+ }
+
+ //
+ // find and extract the message block.
+ //
+ int start;
+
+ for (start = 1; start != block.length; start++)
+ {
+ if (block[start] == 0)
+ {
+ break;
+ }
+ }
+
+ start++; // data should start at the next byte
+
+ if (start >= block.length || start < HEADER_LENGTH)
+ {
+ throw new InvalidCipherTextException("no data in block");
+ }
+
+ byte[] result = new byte[block.length - start];
+
+ System.arraycopy(block, start, result, 0, result.length);
+
+ return result;
+ }
+}
--- /dev/null
+package org.bouncycastle.crypto.engines;\r
+\r
+import org.bouncycastle.crypto.StreamCipher;\r
+import org.bouncycastle.crypto.CipherParameters;\r
+import org.bouncycastle.crypto.DataLengthException;\r
+import org.bouncycastle.crypto.params.KeyParameter;\r
+\r
+public class RC4Engine implements StreamCipher\r
+{\r
+ private final static int STATE_LENGTH = 256;\r
+\r
+ /*\r
+ * variables to hold the state of the RC4 engine\r
+ * during encryption and decryption\r
+ */\r
+\r
+ private byte[] engineState = null;\r
+ private int x = 0;\r
+ private int y = 0;\r
+ private byte[] workingKey = null;\r
+\r
+ /**\r
+ * initialise a RC4 cipher.\r
+ *\r
+ * @param forEncryption whether or not we are for encryption.\r
+ * @param params the parameters required to set up the cipher.\r
+ * @exception IllegalArgumentException if the params argument is\r
+ * inappropriate.\r
+ */\r
+ public void init(\r
+ boolean forEncryption, \r
+ CipherParameters params\r
+ )\r
+ {\r
+ if (params instanceof KeyParameter)\r
+ {\r
+ /* \r
+ * RC4 encryption and decryption is completely\r
+ * symmetrical, so the 'forEncryption' is \r
+ * irrelevant.\r
+ */\r
+ workingKey = ((KeyParameter)params).getKey();\r
+ setKey(workingKey);\r
+\r
+ return;\r
+ }\r
+\r
+ throw new IllegalArgumentException("invalid parameter passed to RC4 init - " + params.getClass().getName());\r
+ }\r
+\r
+ public String getAlgorithmName()\r
+ {\r
+ return "RC4";\r
+ }\r
+\r
+ public byte returnByte(byte in)\r
+ {\r
+ x = (x + 1) & 0xff;\r
+ y = (engineState[x] + y) & 0xff;\r
+\r
+ // swap\r
+ byte tmp = engineState[x];\r
+ engineState[x] = engineState[y];\r
+ engineState[y] = tmp;\r
+\r
+ // xor\r
+ return (byte)(in ^ engineState[(engineState[x] + engineState[y]) & 0xff]);\r
+ }\r
+\r
+ public void processBytes(\r
+ byte[] in, \r
+ int inOff, \r
+ int len, \r
+ byte[] out, \r
+ int outOff\r
+ )\r
+ {\r
+ if ((inOff + len) > in.length)\r
+ {\r
+ throw new DataLengthException("input buffer too short");\r
+ }\r
+\r
+ if ((outOff + len) > out.length)\r
+ {\r
+ throw new DataLengthException("output buffer too short");\r
+ }\r
+\r
+ for (int i = 0; i < len ; i++)\r
+ {\r
+ x = (x + 1) & 0xff;\r
+ y = (engineState[x] + y) & 0xff;\r
+\r
+ // swap\r
+ byte tmp = engineState[x];\r
+ engineState[x] = engineState[y];\r
+ engineState[y] = tmp;\r
+\r
+ // xor\r
+ out[i+outOff] = (byte)(in[i + inOff]\r
+ ^ engineState[(engineState[x] + engineState[y]) & 0xff]);\r
+ }\r
+ }\r
+\r
+ public void reset()\r
+ {\r
+ setKey(workingKey);\r
+ }\r
+\r
+ // Private implementation\r
+\r
+ private void setKey(byte[] keyBytes)\r
+ {\r
+ workingKey = keyBytes;\r
+\r
+ // System.out.println("the key length is ; "+ workingKey.length);\r
+\r
+ x = 0;\r
+ y = 0;\r
+\r
+ if (engineState == null)\r
+ {\r
+ engineState = new byte[STATE_LENGTH];\r
+ }\r
+\r
+ // reset the state of the engine\r
+ for (int i=0; i < STATE_LENGTH; i++)\r
+ {\r
+ engineState[i] = (byte)i;\r
+ }\r
+ \r
+ int i1 = 0;\r
+ int i2 = 0;\r
+\r
+ for (int i=0; i < STATE_LENGTH; i++)\r
+ {\r
+ i2 = ((keyBytes[i1] & 0xff) + engineState[i] + i2) & 0xff;\r
+ // do the byte-swap inline\r
+ byte tmp = engineState[i];\r
+ engineState[i] = engineState[i2];\r
+ engineState[i2] = tmp;\r
+ i1 = (i1+1) % keyBytes.length; \r
+ }\r
+ }\r
+}\r
--- /dev/null
+package org.bouncycastle.crypto.engines;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.AsymmetricBlockCipher;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+
+/**
+ * this does your basic RSA algorithm.
+ */
+public class RSAEngine
+ implements AsymmetricBlockCipher
+{
+ private RSAKeyParameters key;
+ private boolean forEncryption;
+
+ /**
+ * initialise the RSA engine.
+ *
+ * @param forEncryption treu if we are encrypting, false otherwise.
+ * @param param the necessary RSA key parameters.
+ */
+ public void init(
+ boolean forEncryption,
+ CipherParameters param)
+ {
+ this.key = (RSAKeyParameters)param;
+ this.forEncryption = forEncryption;
+ }
+
+ /**
+ * Return the maximum size for an input block to this engine.
+ * For RSA this is always one byte less than the key size on
+ * encryption, and the same length as the key size on decryption.
+ *
+ * @return maximum size for an input block.
+ */
+ public int getInputBlockSize()
+ {
+ int bitSize = key.getModulus().bitLength();
+
+ if (forEncryption)
+ {
+ if ((bitSize % 8) == 0)
+ {
+ return bitSize / 8 - 1;
+ }
+
+ return bitSize / 8;
+ }
+ else
+ {
+ return (bitSize + 7) / 8;
+ }
+ }
+
+ /**
+ * Return the maximum size for an output block to this engine.
+ * For RSA this is always one byte less than the key size on
+ * decryption, and the same length as the key size on encryption.
+ *
+ * @return maximum size for an input block.
+ */
+ public int getOutputBlockSize()
+ {
+ int bitSize = key.getModulus().bitLength();
+
+ if (forEncryption)
+ {
+ return ((bitSize - 1) + 7) / 8;
+ }
+ else
+ {
+ return (bitSize - 7) / 8;
+ }
+ }
+
+ /**
+ * Process a single block using the basic RSA algorithm.
+ *
+ * @param in the input array.
+ * @param inOff the offset into the input buffer where the data starts.
+ * @param inLen the length of the data to be processed.
+ * @return the result of the RSA process.
+ * @exception DataLengthException the input block is too large.
+ */
+ public byte[] processBlock(
+ byte[] in,
+ int inOff,
+ int inLen)
+ {
+ if (inLen > (getInputBlockSize() + 1))
+ {
+ throw new DataLengthException("input too large for RSA cipher.\n");
+ }
+ else if (inLen == (getInputBlockSize() + 1) && (in[inOff] & 0x80) != 0)
+ {
+ throw new DataLengthException("input too large for RSA cipher.\n");
+ }
+
+ byte[] block;
+
+ if (inOff != 0 || inLen != in.length)
+ {
+ block = new byte[inLen];
+
+ System.arraycopy(in, inOff, block, 0, inLen);
+ }
+ else
+ {
+ block = in;
+ }
+
+ BigInteger input = new BigInteger(1, block);
+ byte[] output;
+
+ if (key instanceof RSAPrivateCrtKeyParameters)
+ {
+ //
+ // we have the extra factors, use the Chinese Remainder Theorem - the author
+ // wishes to express his thanks to Dirk Bonekaemper at rtsffm.com for
+ // advice regarding the expression of this.
+ //
+ RSAPrivateCrtKeyParameters crtKey = (RSAPrivateCrtKeyParameters)key;
+
+ BigInteger d = crtKey.getExponent();
+ BigInteger p = crtKey.getP();
+ BigInteger q = crtKey.getQ();
+ BigInteger dP = crtKey.getDP();
+ BigInteger dQ = crtKey.getDQ();
+ BigInteger qInv = crtKey.getQInv();
+
+ BigInteger mP, mQ, h, m;
+
+ // mP = ((input mod p) ^ dP)) mod p
+ mP = (input.remainder(p)).modPow(dP, p);
+
+ // mQ = ((input mod q) ^ dQ)) mod q
+ mQ = (input.remainder(q)).modPow(dQ, q);
+
+ // h = qInv * (mP - mQ) mod p
+ h = mP.subtract(mQ);
+ h = h.multiply(qInv);
+ h = h.mod(p); // mod (in Java) returns the positive residual
+
+ // m = h * q + mQ
+ m = h.multiply(q);
+ m = m.add(mQ);
+
+ output = m.toByteArray();
+ }
+ else
+ {
+ output = input.modPow(
+ key.getExponent(), key.getModulus()).toByteArray();
+ }
+
+ if (forEncryption)
+ {
+ if (output[0] == 0 && output.length > getOutputBlockSize()) // have ended up with an extra zero byte, copy down.
+ {
+ byte[] tmp = new byte[output.length - 1];
+
+ System.arraycopy(output, 1, tmp, 0, tmp.length);
+
+ return tmp;
+ }
+
+ if (output.length < getOutputBlockSize()) // have ended up with less bytes than normal, lengthen
+ {
+ byte[] tmp = new byte[getOutputBlockSize()];
+
+ System.arraycopy(output, 0, tmp, tmp.length - output.length, output.length);
+
+ return tmp;
+ }
+ }
+ else
+ {
+ if (output[0] == 0) // have ended up with an extra zero byte, copy down.
+ {
+ byte[] tmp = new byte[output.length - 1];
+
+ System.arraycopy(output, 1, tmp, 0, tmp.length);
+
+ return tmp;
+ }
+ }
+ return output;
+ }
+}
--- /dev/null
+package org.bouncycastle.crypto.params;
+
+import org.bouncycastle.crypto.CipherParameters;
+
+public class AsymmetricKeyParameter
+ implements CipherParameters
+{
+ boolean privateKey;
+
+ public AsymmetricKeyParameter(
+ boolean privateKey)
+ {
+ this.privateKey = privateKey;
+ }
+
+ public boolean isPrivate()
+ {
+ return privateKey;
+ }
+}
--- /dev/null
+package org.bouncycastle.crypto.params;
+
+import org.bouncycastle.crypto.CipherParameters;
+
+public class KeyParameter
+ implements CipherParameters
+{
+ private byte[] key;
+
+ public KeyParameter(
+ byte[] key)
+ {
+ this(key, 0, key.length);
+ }
+
+ public KeyParameter(
+ byte[] key,
+ int keyOff,
+ int keyLen)
+ {
+ this.key = new byte[keyLen];
+
+ System.arraycopy(key, keyOff, this.key, 0, keyLen);
+ }
+
+ public byte[] getKey()
+ {
+ return key;
+ }
+}
--- /dev/null
+package org.bouncycastle.crypto.params;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.CipherParameters;
+
+public class ParametersWithRandom
+ implements CipherParameters
+{
+ private SecureRandom random;
+ private CipherParameters parameters;
+
+ public ParametersWithRandom(
+ CipherParameters parameters,
+ SecureRandom random)
+ {
+ this.random = random;
+ this.parameters = parameters;
+ }
+
+ public ParametersWithRandom(
+ CipherParameters parameters)
+ {
+ this.random = null;
+ this.parameters = parameters;
+ }
+
+ public SecureRandom getRandom()
+ {
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+ return random;
+ }
+
+ public CipherParameters getParameters()
+ {
+ return parameters;
+ }
+}
--- /dev/null
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.CipherParameters;
+
+public class RSAKeyParameters
+ extends AsymmetricKeyParameter
+{
+ private BigInteger modulus;
+ private BigInteger exponent;
+
+ public RSAKeyParameters(
+ boolean isPrivate,
+ BigInteger modulus,
+ BigInteger exponent)
+ {
+ super(isPrivate);
+
+ this.modulus = modulus;
+ this.exponent = exponent;
+ }
+
+ public BigInteger getModulus()
+ {
+ return modulus;
+ }
+
+ public BigInteger getExponent()
+ {
+ return exponent;
+ }
+}
--- /dev/null
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+public class RSAPrivateCrtKeyParameters
+ extends RSAKeyParameters
+{
+ private BigInteger e;
+ private BigInteger p;
+ private BigInteger q;
+ private BigInteger dP;
+ private BigInteger dQ;
+ private BigInteger qInv;
+
+ /**
+ *
+ */
+ public RSAPrivateCrtKeyParameters(
+ BigInteger modulus,
+ BigInteger publicExponent,
+ BigInteger privateExponent,
+ BigInteger p,
+ BigInteger q,
+ BigInteger dP,
+ BigInteger dQ,
+ BigInteger qInv)
+ {
+ super(true, modulus, privateExponent);
+
+ this.e = publicExponent;
+ this.p = p;
+ this.q = q;
+ this.dP = dP;
+ this.dQ = dQ;
+ this.qInv = qInv;
+ }
+
+ public BigInteger getPublicExponent()
+ {
+ return e;
+ }
+
+ public BigInteger getP()
+ {
+ return p;
+ }
+
+ public BigInteger getQ()
+ {
+ return q;
+ }
+
+ public BigInteger getDP()
+ {
+ return dP;
+ }
+
+ public BigInteger getDQ()
+ {
+ return dQ;
+ }
+
+ public BigInteger getQInv()
+ {
+ return qInv;
+ }
+}
--- /dev/null
+package org.bouncycastle.util.encoders;
+
+public class Base64
+{
+ private static byte[] encodingTable =
+ {
+ (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
+ (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
+ (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
+ (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
+ (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
+ (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
+ (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
+ (byte)'v',
+ (byte)'w', (byte)'x', (byte)'y', (byte)'z',
+ (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6',
+ (byte)'7', (byte)'8', (byte)'9',
+ (byte)'+', (byte)'/'
+ };
+
+ /**
+ * encode the input data producong a base 64 encoded byte array.
+ *
+ * @return a byte array containing the base 64 encoded data.
+ */
+ public static byte[] encode(
+ byte[] data)
+ {
+ byte[] bytes;
+
+ if ((data.length % 3) == 0)
+ {
+ bytes = new byte[4 * data.length / 3];
+ }
+ else
+ {
+ bytes = new byte[4 * ((data.length / 3) + 1)];
+ }
+
+ for (int i = 0, j = 0;
+ i < ((data.length / 3) * 3); i += 3, j += 4)
+ {
+ int b1, b2, b3, b4;
+ int d1, d2, d3;
+
+ d1 = data[i] & 0xff;
+ d2 = data[i + 1] & 0xff;
+ d3 = data[i + 2] & 0xff;
+
+ b1 = (d1 >>> 2) & 0x3f;
+ b2 = ((d1 << 4) | (d2 >>> 4)) & 0x3f;
+ b3 = ((d2 << 2) | (d3 >>> 6)) & 0x3f;
+ b4 = d3 & 0x3f;
+
+ bytes[j] = encodingTable[b1];
+ bytes[j + 1] = encodingTable[b2];
+ bytes[j + 2] = encodingTable[b3];
+ bytes[j + 3] = encodingTable[b4];
+ }
+
+ /*
+ * process the tail end.
+ */
+ int b1, b2, b3;
+ int d1, d2;
+
+ switch (data.length % 3)
+ {
+ case 0: /* nothing left to do */
+ break;
+ case 1:
+ d1 = data[data.length - 1] & 0xff;
+ b1 = (d1 >>> 2) & 0x3f;
+ b2 = (d1 << 4) & 0x3f;
+
+ bytes[bytes.length - 4] = encodingTable[b1];
+ bytes[bytes.length - 3] = encodingTable[b2];
+ bytes[bytes.length - 2] = (byte)'=';
+ bytes[bytes.length - 1] = (byte)'=';
+ break;
+ case 2:
+ d1 = data[data.length - 2] & 0xff;
+ d2 = data[data.length - 1] & 0xff;
+
+ b1 = (d1 >>> 2) & 0x3f;
+ b2 = ((d1 << 4) | (d2 >>> 4)) & 0x3f;
+ b3 = (d2 << 2) & 0x3f;
+
+ bytes[bytes.length - 4] = encodingTable[b1];
+ bytes[bytes.length - 3] = encodingTable[b2];
+ bytes[bytes.length - 2] = encodingTable[b3];
+ bytes[bytes.length - 1] = (byte)'=';
+ break;
+ }
+
+ return bytes;
+ }
+
+ /*
+ * set up the decoding table.
+ */
+ private static byte[] decodingTable;
+
+ static
+ {
+ decodingTable = new byte[128];
+
+ for (int i = 'A'; i <= 'Z'; i++)
+ {
+ decodingTable[i] = (byte)(i - 'A');
+ }
+
+ for (int i = 'a'; i <= 'z'; i++)
+ {
+ decodingTable[i] = (byte)(i - 'a' + 26);
+ }
+
+ for (int i = '0'; i <= '9'; i++)
+ {
+ decodingTable[i] = (byte)(i - '0' + 52);
+ }
+
+ decodingTable['+'] = 62;
+ decodingTable['/'] = 63;
+ }
+
+ /**
+ * decode the base 64 encoded input data.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] decode(
+ byte[] data)
+ {
+ byte[] bytes;
+ byte b1, b2, b3, b4;
+
+ if (data[data.length - 2] == '=')
+ {
+ bytes = new byte[(((data.length / 4) - 1) * 3) + 1];
+ }
+ else if (data[data.length - 1] == '=')
+ {
+ bytes = new byte[(((data.length / 4) - 1) * 3) + 2];
+ }
+ else
+ {
+ bytes = new byte[((data.length / 4) * 3)];
+ }
+
+ for (int i = 0, j = 0; i < data.length - 4; i += 4, j += 3)
+ {
+ b1 = decodingTable[data[i]];
+ b2 = decodingTable[data[i + 1]];
+ b3 = decodingTable[data[i + 2]];
+ b4 = decodingTable[data[i + 3]];
+
+ bytes[j] = (byte)((b1 << 2) | (b2 >> 4));
+ bytes[j + 1] = (byte)((b2 << 4) | (b3 >> 2));
+ bytes[j + 2] = (byte)((b3 << 6) | b4);
+ }
+
+ if (data[data.length - 2] == '=')
+ {
+ b1 = decodingTable[data[data.length - 4]];
+ b2 = decodingTable[data[data.length - 3]];
+
+ bytes[bytes.length - 1] = (byte)((b1 << 2) | (b2 >> 4));
+ }
+ else if (data[data.length - 1] == '=')
+ {
+ b1 = decodingTable[data[data.length - 4]];
+ b2 = decodingTable[data[data.length - 3]];
+ b3 = decodingTable[data[data.length - 2]];
+
+ bytes[bytes.length - 2] = (byte)((b1 << 2) | (b2 >> 4));
+ bytes[bytes.length - 1] = (byte)((b2 << 4) | (b3 >> 2));
+ }
+ else
+ {
+ b1 = decodingTable[data[data.length - 4]];
+ b2 = decodingTable[data[data.length - 3]];
+ b3 = decodingTable[data[data.length - 2]];
+ b4 = decodingTable[data[data.length - 1]];
+
+ bytes[bytes.length - 3] = (byte)((b1 << 2) | (b2 >> 4));
+ bytes[bytes.length - 2] = (byte)((b2 << 4) | (b3 >> 2));
+ bytes[bytes.length - 1] = (byte)((b3 << 6) | b4);
+ }
+
+ return bytes;
+ }
+
+ /**
+ * decode the base 64 encoded String data.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] decode(
+ String data)
+ {
+ byte[] bytes;
+ byte b1, b2, b3, b4;
+
+ if (data.charAt(data.length() - 2) == '=')
+ {
+ bytes = new byte[(((data.length() / 4) - 1) * 3) + 1];
+ }
+ else if (data.charAt(data.length() - 1) == '=')
+ {
+ bytes = new byte[(((data.length() / 4) - 1) * 3) + 2];
+ }
+ else
+ {
+ bytes = new byte[((data.length() / 4) * 3)];
+ }
+
+ for (int i = 0, j = 0; i < data.length() - 4; i += 4, j += 3)
+ {
+ b1 = decodingTable[data.charAt(i)];
+ b2 = decodingTable[data.charAt(i + 1)];
+ b3 = decodingTable[data.charAt(i + 2)];
+ b4 = decodingTable[data.charAt(i + 3)];
+
+ bytes[j] = (byte)((b1 << 2) | (b2 >> 4));
+ bytes[j + 1] = (byte)((b2 << 4) | (b3 >> 2));
+ bytes[j + 2] = (byte)((b3 << 6) | b4);
+ }
+
+ if (data.charAt(data.length() - 2) == '=')
+ {
+ b1 = decodingTable[data.charAt(data.length() - 4)];
+ b2 = decodingTable[data.charAt(data.length() - 3)];
+
+ bytes[bytes.length - 1] = (byte)((b1 << 2) | (b2 >> 4));
+ }
+ else if (data.charAt(data.length() - 1) == '=')
+ {
+ b1 = decodingTable[data.charAt(data.length() - 4)];
+ b2 = decodingTable[data.charAt(data.length() - 3)];
+ b3 = decodingTable[data.charAt(data.length() - 2)];
+
+ bytes[bytes.length - 2] = (byte)((b1 << 2) | (b2 >> 4));
+ bytes[bytes.length - 1] = (byte)((b2 << 4) | (b3 >> 2));
+ }
+ else
+ {
+ b1 = decodingTable[data.charAt(data.length() - 4)];
+ b2 = decodingTable[data.charAt(data.length() - 3)];
+ b3 = decodingTable[data.charAt(data.length() - 2)];
+ b4 = decodingTable[data.charAt(data.length() - 1)];
+
+ bytes[bytes.length - 3] = (byte)((b1 << 2) | (b2 >> 4));
+ bytes[bytes.length - 2] = (byte)((b2 << 4) | (b3 >> 2));
+ bytes[bytes.length - 1] = (byte)((b3 << 6) | b4);
+ }
+
+ return bytes;
+ }
+}
--- /dev/null
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-\r
+ *\r
+ * The contents of this file are subject to the Netscape Public\r
+ * License Version 1.1 (the "License"); you may not use this file\r
+ * except in compliance with the License. You may obtain a copy of\r
+ * the License at http://www.mozilla.org/NPL/\r
+ *\r
+ * Software distributed under the License is distributed on an "AS\r
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr\r
+ * implied. See the License for the specific language governing\r
+ * rights and limitations under the License.\r
+ *\r
+ * The Original Code is Rhino code, released\r
+ * May 6, 1999.\r
+ *\r
+ * The Initial Developer of the Original Code is Netscape\r
+ * Communications Corporation. Portions created by Netscape are\r
+ * Copyright (C) 1997-1999 Netscape Communications Corporation. All\r
+ * Rights Reserved.\r
+ *\r
+ * Contributor(s): \r
+ * Norris Boyd\r
+ *\r
+ * Alternatively, the contents of this file may be used under the\r
+ * terms of the GNU Public License (the "GPL"), in which case the\r
+ * provisions of the GPL are applicable instead of those above.\r
+ * If you wish to allow use of your version of this file only\r
+ * under the terms of the GPL and not to allow others to use your\r
+ * version of this file under the NPL, indicate your decision by\r
+ * deleting the provisions above and replace them with the notice\r
+ * and other provisions required by the GPL. If you do not delete\r
+ * the provisions above, a recipient may use your version of this\r
+ * file under either the NPL or the GPL.\r
+ */\r
+\r
+package org.mozilla.javascript;\r
+\r
+/**\r
+ * This class implements the "arguments" object.\r
+ *\r
+ * See ECMA 10.1.8\r
+ *\r
+ * @see org.mozilla.javascript.NativeCall\r
+ * @author Norris Boyd\r
+ */\r
+class Arguments extends ScriptableObject {\r
+\r
+ public Arguments(NativeCall activation) {\r
+ this.activation = activation;\r
+\r
+ Scriptable parent = activation.getParentScope();\r
+ setParentScope(parent);\r
+ setPrototype(ScriptableObject.getObjectPrototype(parent));\r
+\r
+ args = activation.getOriginalArguments();\r
+ int length = args.length;\r
+ Object callee = activation.funObj;\r
+\r
+ defineProperty("length", new Integer(length),\r
+ ScriptableObject.DONTENUM);\r
+ defineProperty("callee", callee, ScriptableObject.DONTENUM);\r
+\r
+ hasCaller = (activation.funObj.version <= Context.VERSION_1_3 &&\r
+ activation.funObj.version != Context.VERSION_DEFAULT);\r
+ }\r
+\r
+ public String getClassName() {\r
+ return "Arguments";\r
+ }\r
+\r
+ public boolean has(String name, Scriptable start) {\r
+ return (hasCaller && name.equals("caller")) || super.has(name, start);\r
+ }\r
+\r
+ public boolean has(int index, Scriptable start) {\r
+ Object[] args = activation.getOriginalArguments();\r
+ return (0 <= index && index < args.length) || super.has(index, start);\r
+ }\r
+\r
+ public Object get(String name, Scriptable start) {\r
+ if (hasCaller && name.equals("caller")) {\r
+ NativeCall caller = activation.caller;\r
+ if (caller == null || caller.originalArgs == null) return null;\r
+ return caller.get("arguments", caller);\r
+\r
+ } else if (name.equals("cascade")) {\r
+ return org.xwt.Trap.cascadeFunction;\r
+\r
+ } else if (name.equals("trapee")) {\r
+ return org.xwt.Trap.currentTrapee();\r
+ }\r
+\r
+ return super.get(name, start);\r
+ }\r
+\r
+ public Object get(int index, Scriptable start) {\r
+ if (0 <= index && index < args.length) {\r
+ NativeFunction f = activation.funObj;\r
+ if (index < f.argCount)\r
+ return activation.get(f.argNames[index], activation);\r
+ return args[index];\r
+ }\r
+ return super.get(index, start);\r
+ }\r
+\r
+ public void put(String name, Scriptable start, Object value) {\r
+ if (name.equals("caller")) {\r
+ // Set "hasCaller" to false so that we won't look up a \r
+ // computed value.\r
+ hasCaller = false;\r
+ }\r
+ super.put(name, start, value);\r
+ }\r
+\r
+ public void put(int index, Scriptable start, Object value) {\r
+ if (0 <= index && index < args.length) {\r
+ NativeFunction f = activation.funObj;\r
+ if (index < f.argCount)\r
+ activation.put(f.argNames[index], activation, value);\r
+ else\r
+ args[index] = value;\r
+ return;\r
+ }\r
+ super.put(index, start, value);\r
+ }\r
+\r
+ public void delete(String name) {\r
+ if (name.equals("caller"))\r
+ hasCaller = false;\r
+ super.delete(name);\r
+ }\r
+\r
+ public void delete(int index) {\r
+ if (0 <= index && index < args.length) {\r
+ NativeFunction f = activation.funObj;\r
+ if (index < f.argCount)\r
+ activation.delete(f.argNames[index]);\r
+ else\r
+ args[index] = Undefined.instance;\r
+ }\r
+ }\r
+\r
+ private NativeCall activation;\r
+ private Object[] args;\r
+ private boolean hasCaller;\r
+}\r
--- /dev/null
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-\r
+ *\r
+ * The contents of this file are subject to the Netscape Public\r
+ * License Version 1.1 (the "License"); you may not use this file\r
+ * except in compliance with the License. You may obtain a copy of\r
+ * the License at http://www.mozilla.org/NPL/\r
+ *\r
+ * Software distributed under the License is distributed on an "AS\r
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr\r
+ * implied. See the License for the specific language governing\r
+ * rights and limitations under the License.\r
+ *\r
+ * The Original Code is Rhino code, released\r
+ * May 6, 1999.\r
+ *\r
+ * The Initial Developer of the Original Code is Netscape\r
+ * Communications Corporation. Portions created by Netscape are\r
+ * Copyright (C) 1997-1999 Netscape Communications Corporation. All\r
+ * Rights Reserved.\r
+ *\r
+ * Contributor(s): \r
+ * Norris Boyd\r
+ * Igor Bukanov\r
+ * Roger Lawrence\r
+ * Mike McCabe\r
+ *\r
+ * Alternatively, the contents of this file may be used under the\r
+ * terms of the GNU Public License (the "GPL"), in which case the\r
+ * provisions of the GPL are applicable instead of those above.\r
+ * If you wish to allow use of your version of this file only\r
+ * under the terms of the GPL and not to allow others to use your\r
+ * version of this file under the NPL, indicate your decision by\r
+ * deleting the provisions above and replace them with the notice\r
+ * and other provisions required by the GPL. If you do not delete\r
+ * the provisions above, a recipient may use your version of this\r
+ * file under either the NPL or the GPL.\r
+ */\r
+\r
+package org.mozilla.javascript;\r
+\r
+/**\r
+ * The base class for Function objects\r
+ * See ECMA 15.3.\r
+ * @author Norris Boyd\r
+ */\r
+public class BaseFunction extends IdScriptable implements Function {\r
+\r
+ static void init(Context cx, Scriptable scope, boolean sealed) {\r
+ BaseFunction obj = new BaseFunction();\r
+ obj.prototypeFlag = true;\r
+ obj.functionName = "";\r
+ obj.prototypePropertyAttrs = DONTENUM | READONLY | PERMANENT;\r
+ obj.addAsPrototype(MAX_PROTOTYPE_ID, cx, scope, sealed);\r
+ }\r
+ \r
+ protected void fillConstructorProperties\r
+ (Context cx, IdFunction ctor, boolean sealed)\r
+ {\r
+ // Fix up bootstrapping problem: getPrototype of the IdFunction \r
+ // can not return Function.prototype because Function object is not\r
+ // yet defined.\r
+ ctor.setPrototype(this);\r
+ }\r
+\r
+ public String getClassName() {\r
+ return "Function";\r
+ }\r
+\r
+ /**\r
+ * Implements the instanceof operator for JavaScript Function objects.\r
+ * <p>\r
+ * <code>\r
+ * foo = new Foo();<br>\r
+ * foo instanceof Foo; // true<br>\r
+ * </code>\r
+ *\r
+ * @param instance The value that appeared on the LHS of the instanceof\r
+ * operator\r
+ * @return true if the "prototype" property of "this" appears in\r
+ * value's prototype chain\r
+ *\r
+ */\r
+ public boolean hasInstance(Scriptable instance) {\r
+ Object protoProp = ScriptableObject.getProperty(this, "prototype");\r
+ if (protoProp instanceof Scriptable && protoProp != Undefined.instance)\r
+ {\r
+ return ScriptRuntime.jsDelegatesTo(instance, (Scriptable)protoProp);\r
+ }\r
+ throw NativeGlobal.typeError1\r
+ ("msg.instanceof.bad.prototype", functionName, instance);\r
+ }\r
+\r
+ protected int getIdDefaultAttributes(int id) {\r
+ switch (id) {\r
+ case Id_length:\r
+ case Id_arity:\r
+ case Id_name:\r
+ return DONTENUM | READONLY | PERMANENT;\r
+ case Id_prototype:\r
+ return prototypePropertyAttrs;\r
+ case Id_arguments:\r
+ return EMPTY;\r
+ }\r
+ return super.getIdDefaultAttributes(id);\r
+ }\r
+ \r
+ protected boolean hasIdValue(int id) {\r
+ if (id == Id_prototype) {\r
+ return prototypeProperty != NOT_FOUND;\r
+ }\r
+ else if (id == Id_arguments) {\r
+ // Should after delete Function.arguments its activation still\r
+ // be available during Function call? \r
+ // This code assumes it should not: after default set/deleteIdValue\r
+ // hasIdValue/getIdValue would not be called again\r
+ // To handle the opposite case, set/deleteIdValue should be \r
+ // overwritten as well\r
+ return null != getActivation(Context.getContext());\r
+ }\r
+ return super.hasIdValue(id);\r
+ }\r
+ \r
+ protected Object getIdValue(int id) {\r
+ switch (id) {\r
+ case Id_length: return wrap_int(getLength());\r
+ case Id_arity: return wrap_int(getArity());\r
+ case Id_name: return getFunctionName();\r
+ case Id_prototype: return getPrototypeProperty();\r
+ case Id_arguments: return getArguments();\r
+ }\r
+ return super.getIdValue(id);\r
+ }\r
+ \r
+ protected void setIdValue(int id, Object value) {\r
+ if (id == Id_prototype) {\r
+ prototypeProperty = (value != null) ? value : NULL_TAG;\r
+ return;\r
+ }\r
+ super.setIdValue(id, value);\r
+ }\r
+\r
+ protected void deleteIdValue(int id) {\r
+ if (id == Id_prototype) {\r
+ prototypeProperty = NOT_FOUND;\r
+ return;\r
+ }\r
+ super.deleteIdValue(id);\r
+ }\r
+\r
+ public int methodArity(int methodId) {\r
+ if (prototypeFlag) {\r
+ switch (methodId) {\r
+ case Id_constructor:\r
+ case Id_toString:\r
+ case Id_apply:\r
+ case Id_call:\r
+ return 1;\r
+ }\r
+ }\r
+ return super.methodArity(methodId);\r
+ }\r
+\r
+ public Object execMethod(int methodId, IdFunction f, Context cx,\r
+ Scriptable scope, Scriptable thisObj, \r
+ Object[] args)\r
+ throws JavaScriptException\r
+ {\r
+ if (prototypeFlag) {\r
+ switch (methodId) {\r
+ case Id_constructor:\r
+ return jsConstructor(cx, scope, args);\r
+\r
+ case Id_toString:\r
+ return jsFunction_toString(cx, thisObj, args);\r
+\r
+ case Id_apply:\r
+ return jsFunction_apply(cx, scope, thisObj, args);\r
+\r
+ case Id_call:\r
+ return jsFunction_call(cx, scope, thisObj, args);\r
+ }\r
+ }\r
+ return super.execMethod(methodId, f, cx, scope, thisObj, args);\r
+ }\r
+\r
+ /**\r
+ * Make value as DontEnum, DontDelete, ReadOnly\r
+ * prototype property of this Function object \r
+ */\r
+ public void setImmunePrototypeProperty(Object value) {\r
+ prototypeProperty = (value != null) ? value : NULL_TAG;\r
+ prototypePropertyAttrs = DONTENUM | READONLY | PERMANENT;\r
+ }\r
+\r
+ protected Scriptable getClassPrototype() {\r
+ Object protoVal = getPrototypeProperty();\r
+ if (protoVal == null \r
+ || !(protoVal instanceof Scriptable)\r
+ || (protoVal == Undefined.instance))\r
+ protoVal = getClassPrototype(this, "Object");\r
+ return (Scriptable) protoVal;\r
+ }\r
+\r
+ /**\r
+ * Should be overridden.\r
+ */\r
+ public Object call(Context cx, Scriptable scope, Scriptable thisObj,\r
+ Object[] args)\r
+ throws JavaScriptException\r
+ {\r
+ return Undefined.instance;\r
+ }\r
+\r
+ public Scriptable construct(Context cx, Scriptable scope, Object[] args)\r
+ throws JavaScriptException\r
+ {\r
+ Scriptable newInstance = new NativeObject();\r
+\r
+ newInstance.setPrototype(getClassPrototype());\r
+ newInstance.setParentScope(getParentScope());\r
+\r
+ Object val = call(cx, scope, newInstance, args);\r
+ if (val instanceof Scriptable && val != Undefined.instance) {\r
+ return (Scriptable) val;\r
+ }\r
+ return newInstance;\r
+ }\r
+\r
+ /**\r
+ * Decompile the source information associated with this js\r
+ * function/script back into a string.\r
+ *\r
+ * @param cx Current context\r
+ *\r
+ * @param indent How much to indent the decompiled result\r
+ *\r
+ * @param justbody Whether the decompilation should omit the\r
+ * function header and trailing brace.\r
+ */\r
+\r
+ public String decompile(Context cx, int indent, boolean justbody) {\r
+ StringBuffer sb = new StringBuffer();\r
+ if (!justbody) {\r
+ sb.append("function ");\r
+ sb.append(getFunctionName());\r
+ sb.append("() {\n\t");\r
+ }\r
+ sb.append("[native code, arity=");\r
+ sb.append(getArity());\r
+ sb.append("]\n");\r
+ if (!justbody) {\r
+ sb.append("}\n");\r
+ }\r
+ return sb.toString();\r
+ }\r
+\r
+ public int getArity() { return 0; }\r
+\r
+ public int getLength() { return 0; }\r
+\r
+ public String getFunctionName() {\r
+ if (functionName == null)\r
+ return "";\r
+ if (functionName.equals("anonymous")) {\r
+ Context cx = Context.getCurrentContext();\r
+ if (cx != null && cx.getLanguageVersion() == Context.VERSION_1_2)\r
+ return "";\r
+ }\r
+ return functionName;\r
+ }\r
+\r
+ private Object getPrototypeProperty() {\r
+ Object result = prototypeProperty;\r
+ if (result == null) { \r
+ synchronized (this) {\r
+ result = prototypeProperty;\r
+ if (result == null) {\r
+ setupDefaultPrototype();\r
+ result = prototypeProperty;\r
+ }\r
+ }\r
+ }\r
+ else if (result == NULL_TAG) { result = null; }\r
+ return result;\r
+ }\r
+\r
+ private void setupDefaultPrototype() {\r
+ NativeObject obj = new NativeObject();\r
+ final int attr = ScriptableObject.DONTENUM |\r
+ ScriptableObject.READONLY |\r
+ ScriptableObject.PERMANENT;\r
+ obj.defineProperty("constructor", this, attr);\r
+ // put the prototype property into the object now, then in the\r
+ // wacky case of a user defining a function Object(), we don't\r
+ // get an infinite loop trying to find the prototype.\r
+ prototypeProperty = obj;\r
+ Scriptable proto = getObjectPrototype(this); \r
+ if (proto != obj) {\r
+ // not the one we just made, it must remain grounded\r
+ obj.setPrototype(proto);\r
+ }\r
+ }\r
+\r
+ private Object getArguments() {\r
+ // <Function name>.arguments is deprecated, so we use a slow\r
+ // way of getting it that doesn't add to the invocation cost.\r
+ // TODO: add warning, error based on version\r
+ NativeCall activation = getActivation(Context.getContext());\r
+ return activation == null \r
+ ? null \r
+ : activation.get("arguments", activation);\r
+ }\r
+ \r
+ NativeCall getActivation(Context cx) {\r
+ NativeCall activation = cx.currentActivation;\r
+ while (activation != null) {\r
+ if (activation.getFunctionObject() == this) \r
+ return activation;\r
+ activation = activation.caller;\r
+ }\r
+ return null;\r
+ }\r
+ \r
+ private static Object jsConstructor(Context cx, Scriptable scope, \r
+ Object[] args)\r
+ {\r
+ int arglen = args.length;\r
+ StringBuffer funArgs = new StringBuffer();\r
+\r
+ /* Collect the arguments into a string. */\r
+\r
+ int i;\r
+ for (i = 0; i < arglen - 1; i++) {\r
+ if (i > 0)\r
+ funArgs.append(',');\r
+ funArgs.append(ScriptRuntime.toString(args[i]));\r
+ }\r
+ String funBody = arglen == 0 ? "" : ScriptRuntime.toString(args[i]);\r
+\r
+ String source = "function (" + funArgs.toString() + ") {" +\r
+ funBody + "}";\r
+ int[] linep = { 0 };\r
+ String filename = Context.getSourcePositionFromStack(linep);\r
+ if (filename == null) {\r
+ filename = "<eval'ed string>";\r
+ linep[0] = 1;\r
+ }\r
+ Object securityDomain = cx.getSecurityDomainForStackDepth(4);\r
+ Scriptable global = ScriptableObject.getTopLevelScope(scope);\r
+ \r
+ // Compile the function with opt level of -1 to force interpreter\r
+ // mode.\r
+ int oldOptLevel = cx.getOptimizationLevel();\r
+ cx.setOptimizationLevel(-1);\r
+ NativeFunction fn;\r
+ try {\r
+ fn = (NativeFunction) cx.compileFunction(global, source,\r
+ filename, linep[0], \r
+ securityDomain);\r
+ }\r
+ finally { cx.setOptimizationLevel(oldOptLevel); }\r
+\r
+ fn.functionName = "anonymous";\r
+ fn.setPrototype(getFunctionPrototype(global));\r
+ fn.setParentScope(global);\r
+\r
+ return fn;\r
+ }\r
+\r
+ private static Object jsFunction_toString(Context cx, Scriptable thisObj,\r
+ Object[] args)\r
+ {\r
+ int indent = ScriptRuntime.toInt32(args, 0);\r
+ Object val = thisObj.getDefaultValue(ScriptRuntime.FunctionClass);\r
+ if (val instanceof BaseFunction) {\r
+ return ((BaseFunction)val).decompile(cx, indent, false);\r
+ }\r
+ throw NativeGlobal.typeError1("msg.incompat.call", "toString", thisObj);\r
+ }\r
+\r
+ /**\r
+ * Function.prototype.apply\r
+ *\r
+ * A proposed ECMA extension for round 2.\r
+ */\r
+ private static Object jsFunction_apply(Context cx, Scriptable scope,\r
+ Scriptable thisObj, Object[] args)\r
+ throws JavaScriptException\r
+ {\r
+ if (args.length != 2)\r
+ return jsFunction_call(cx, scope, thisObj, args);\r
+ Object val = thisObj.getDefaultValue(ScriptRuntime.FunctionClass);\r
+ Scriptable newThis = args[0] == null\r
+ ? ScriptableObject.getTopLevelScope(thisObj)\r
+ : ScriptRuntime.toObject(scope, args[0]);\r
+ Object[] newArgs;\r
+ if (args.length > 1) {\r
+ if ((args[1] instanceof NativeArray) \r
+ || (args[1] instanceof Arguments))\r
+ newArgs = cx.getElements((Scriptable) args[1]);\r
+ else\r
+ throw NativeGlobal.typeError0("msg.arg.isnt.array", thisObj); \r
+ }\r
+ else\r
+ newArgs = ScriptRuntime.emptyArgs;\r
+ return ScriptRuntime.call(cx, val, newThis, newArgs, newThis);\r
+ }\r
+\r
+ /**\r
+ * Function.prototype.call\r
+ *\r
+ * A proposed ECMA extension for round 2.\r
+ */\r
+ private static Object jsFunction_call(Context cx, Scriptable scope,\r
+ Scriptable thisObj, Object[] args)\r
+ throws JavaScriptException\r
+ {\r
+ Object val = thisObj.getDefaultValue(ScriptRuntime.FunctionClass);\r
+ if (args.length == 0) {\r
+ Scriptable s = ScriptRuntime.toObject(scope, val);\r
+ Scriptable topScope = s.getParentScope();\r
+ return ScriptRuntime.call(cx, val, \r
+ topScope, ScriptRuntime.emptyArgs, \r
+ topScope);\r
+ } else {\r
+ Scriptable newThis = args[0] == null\r
+ ? ScriptableObject.getTopLevelScope(thisObj)\r
+ : ScriptRuntime.toObject(scope, args[0]);\r
+\r
+ Object[] newArgs = new Object[args.length - 1];\r
+ System.arraycopy(args, 1, newArgs, 0, newArgs.length);\r
+ return ScriptRuntime.call(cx, val, newThis, newArgs, newThis);\r
+ }\r
+ }\r
+\r
+ protected int maxInstanceId() { return MAX_INSTANCE_ID; }\r
+\r
+ protected String getIdName(int id) {\r
+ switch (id) {\r
+ case Id_length: return "length";\r
+ case Id_arity: return "arity";\r
+ case Id_name: return "name";\r
+ case Id_prototype: return "prototype";\r
+ case Id_arguments: return "arguments";\r
+ }\r
+ \r
+ if (prototypeFlag) {\r
+ switch (id) {\r
+ case Id_constructor: return "constructor";\r
+ case Id_toString: return "toString";\r
+ case Id_apply: return "apply";\r
+ case Id_call: return "call";\r
+ }\r
+ }\r
+ return null;\r
+ }\r
+\r
+// #string_id_map#\r
+\r
+ private static final int\r
+ Id_length = 1,\r
+ Id_arity = 2,\r
+ Id_name = 3,\r
+ Id_prototype = 4,\r
+ Id_arguments = 5,\r
+ \r
+ MAX_INSTANCE_ID = 5;\r
+\r
+ protected int mapNameToId(String s) {\r
+ int id;\r
+// #generated# Last update: 2001-05-20 00:12:12 GMT+02:00\r
+ L0: { id = 0; String X = null; int c;\r
+ L: switch (s.length()) {\r
+ case 4: X="name";id=Id_name; break L;\r
+ case 5: X="arity";id=Id_arity; break L;\r
+ case 6: X="length";id=Id_length; break L;\r
+ case 9: c=s.charAt(0);\r
+ if (c=='a') { X="arguments";id=Id_arguments; }\r
+ else if (c=='p') { X="prototype";id=Id_prototype; }\r
+ break L;\r
+ }\r
+ if (X!=null && X!=s && !X.equals(s)) id = 0;\r
+ }\r
+// #/generated#\r
+// #/string_id_map#\r
+\r
+ if (id != 0 || !prototypeFlag) { return id; }\r
+\r
+// #string_id_map#\r
+// #generated# Last update: 2001-05-20 00:12:12 GMT+02:00\r
+ L0: { id = 0; String X = null;\r
+ L: switch (s.length()) {\r
+ case 4: X="call";id=Id_call; break L;\r
+ case 5: X="apply";id=Id_apply; break L;\r
+ case 8: X="toString";id=Id_toString; break L;\r
+ case 11: X="constructor";id=Id_constructor; break L;\r
+ }\r
+ if (X!=null && X!=s && !X.equals(s)) id = 0;\r
+ }\r
+// #/generated#\r
+ return id;\r
+ }\r
+\r
+ private static final int\r
+ Id_constructor = MAX_INSTANCE_ID + 1,\r
+ Id_toString = MAX_INSTANCE_ID + 2,\r
+ Id_apply = MAX_INSTANCE_ID + 3,\r
+ Id_call = MAX_INSTANCE_ID + 4,\r
+ \r
+ MAX_PROTOTYPE_ID = MAX_INSTANCE_ID + 4;\r
+\r
+// #/string_id_map#\r
+ \r
+ protected String functionName;\r
+\r
+ private Object prototypeProperty; \r
+ private int prototypePropertyAttrs = DONTENUM;\r
+\r
+ private boolean prototypeFlag;\r
+}\r
+\r
--- /dev/null
+\r
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-\r
+ *\r
+ * The contents of this file are subject to the Netscape Public\r
+ * License Version 1.1 (the "License"); you may not use this file\r
+ * except in compliance with the License. You may obtain a copy of\r
+ * the License at http://www.mozilla.org/NPL/\r
+ *\r
+ * Software distributed under the License is distributed on an "AS\r
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr\r
+ * implied. See the License for the specific language governing\r
+ * rights and limitations under the License.\r
+ *\r
+ * The Original Code is Rhino code, released\r
+ * May 6, 1999.\r
+ *\r
+ * The Initial Developer of the Original Code is Netscape\r
+ * Communications Corporation. Portions created by Netscape are\r
+ * Copyright (C) 1997-1999 Netscape Communications Corporation. All\r
+ * Rights Reserved.\r
+ *\r
+ * Contributor(s): \r
+ * Waldemar Horwat\r
+ *\r
+ * Alternatively, the contents of this file may be used under the\r
+ * terms of the GNU Public License (the "GPL"), in which case the\r
+ * provisions of the GPL are applicable instead of those above.\r
+ * If you wish to allow use of your version of this file only\r
+ * under the terms of the GPL and not to allow others to use your\r
+ * version of this file under the NPL, indicate your decision by\r
+ * deleting the provisions above and replace them with the notice\r
+ * and other provisions required by the GPL. If you do not delete\r
+ * the provisions above, a recipient may use your version of this\r
+ * file under either the NPL or the GPL.\r
+ */\r
+package org.mozilla.javascript;\r
+\r
+final class BinaryDigitReader {\r
+ int lgBase; // Logarithm of base of number\r
+ int digit; // Current digit value in radix given by base\r
+ int digitPos; // Bit position of last bit extracted from digit\r
+ String digits; // String containing the digits\r
+ int start; // Index of the first remaining digit\r
+ int end; // Index past the last remaining digit\r
+\r
+ BinaryDigitReader(int base, String digits, int start, int end) {\r
+ lgBase = 0;\r
+ while (base != 1) {\r
+ lgBase++;\r
+ base >>= 1;\r
+ }\r
+ digitPos = 0;\r
+ this.digits = digits;\r
+ this.start = start;\r
+ this.end = end;\r
+ }\r
+\r
+ /* Return the next binary digit from the number or -1 if done */\r
+ int getNextBinaryDigit()\r
+ {\r
+ if (digitPos == 0) {\r
+ if (start == end)\r
+ return -1;\r
+ \r
+ char c = digits.charAt(start++);\r
+ if ('0' <= c && c <= '9')\r
+ digit = c - '0';\r
+ else if ('a' <= c && c <= 'z')\r
+ digit = c - 'a' + 10;\r
+ else digit = c - 'A' + 10;\r
+ digitPos = lgBase;\r
+ }\r
+ return digit >> --digitPos & 1;\r
+ }\r
+}\r
--- /dev/null
+\r
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-\r
+ *\r
+ * The contents of this file are subject to the Netscape Public\r
+ * License Version 1.1 (the "License"); you may not use this file\r
+ * except in compliance with the License. You may obtain a copy of\r
+ * the License at http://www.mozilla.org/NPL/\r
+ *\r
+ * Software distributed under the License is distributed on an "AS\r
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr\r
+ * implied. See the License for the specific language governing\r
+ * rights and limitations under the License.\r
+ *\r
+ * The Original Code is Rhino code, released\r
+ * May 6, 1999.\r
+ *\r
+ * The Initial Developer of the Original Code is Netscape\r
+ * Communications Corporation. Portions created by Netscape are\r
+ * Copyright (C) 1997-1999 Netscape Communications Corporation. All\r
+ * Rights Reserved.\r
+ *\r
+ * Contributor(s): \r
+ *\r
+ * Alternatively, the contents of this file may be used under the\r
+ * terms of the GNU Public License (the "GPL"), in which case the\r
+ * provisions of the GPL are applicable instead of those above.\r
+ * If you wish to allow use of your version of this file only\r
+ * under the terms of the GPL and not to allow others to use your\r
+ * version of this file under the NPL, indicate your decision by\r
+ * deleting the provisions above and replace them with the notice\r
+ * and other provisions required by the GPL. If you do not delete\r
+ * the provisions above, a recipient may use your version of this\r
+ * file under either the NPL or the GPL.\r
+ */\r
+// API class\r
+\r
+package org.mozilla.javascript;\r
+\r
+/**\r
+ * Thrown if errors are detected while attempting to define a host object\r
+ * from a Java class.\r
+ */\r
+public class ClassDefinitionException extends Exception {\r
+\r
+ public ClassDefinitionException(String detail) {\r
+ super(detail);\r
+ }\r
+}\r
--- /dev/null
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-\r
+ *\r
+ * The contents of this file are subject to the Netscape Public\r
+ * License Version 1.1 (the "License"); you may not use this file\r
+ * except in compliance with the License. You may obtain a copy of\r
+ * the License at http://www.mozilla.org/NPL/\r
+ *\r
+ * Software distributed under the License is distributed on an "AS\r
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr\r
+ * implied. See the License for the specific language governing\r
+ * rights and limitations under the License.\r
+ *\r
+ * The Original Code is Rhino code, released\r
+ * May 6, 1999.\r
+ *\r
+ * The Initial Developer of the Original Code is Netscape\r
+ * Communications Corporation. Portions created by Netscape are\r
+ * Copyright (C) 1997-1999 Netscape Communications Corporation. All\r
+ * Rights Reserved.\r
+ *\r
+ * Contributor(s):\r
+ * Norris Boyd\r
+ * Roger Lawrence\r
+ * Andi Vajda\r
+ *\r
+ * Alternatively, the contents of this file may be used under the\r
+ * terms of the GNU Public License (the "GPL"), in which case the\r
+ * provisions of the GPL are applicable instead of those above.\r
+ * If you wish to allow use of your version of this file only\r
+ * under the terms of the GPL and not to allow others to use your\r
+ * version of this file under the NPL, indicate your decision by\r
+ * deleting the provisions above and replace them with the notice\r
+ * and other provisions required by the GPL. If you do not delete\r
+ * the provisions above, a recipient may use your version of this\r
+ * file under either the NPL or the GPL.\r
+ */\r
+\r
+package org.mozilla.javascript;\r
+\r
+public interface ClassNameHelper {\r
+\r
+ public String getTargetClassFileName();\r
+\r
+ public void setTargetClassFileName(String classFileName);\r
+\r
+ public String getTargetPackage();\r
+\r
+ public void setTargetPackage(String targetPackage);\r
+\r
+ public String getTargetClassFileName(String className);\r
+ \r
+ public String getGeneratingDirectory();\r
+ \r
+ public void setTargetExtends(Class extendsClass);\r
+ \r
+ public void setTargetImplements(Class[] implementsClasses);\r
+\r
+ public ClassOutput getClassOutput();\r
+\r
+ public void setClassOutput(ClassOutput classOutput);\r
+ \r
+ public void reset();\r
+}\r
--- /dev/null
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-\r
+ *\r
+ * The contents of this file are subject to the Netscape Public\r
+ * License Version 1.1 (the "License"); you may not use this file\r
+ * except in compliance with the License. You may obtain a copy of\r
+ * the License at http://www.mozilla.org/NPL/\r
+ *\r
+ * Software distributed under the License is distributed on an "AS\r
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr\r
+ * implied. See the License for the specific language governing\r
+ * rights and limitations under the License.\r
+ *\r
+ * The Original Code is Rhino code, released\r
+ * May 6, 1999.\r
+ *\r
+ * The Initial Developer of the Original Code is Netscape\r
+ * Communications Corporation. Portions created by Netscape are\r
+ * Copyright (C) 1997-2000 Netscape Communications Corporation. All\r
+ * Rights Reserved.\r
+ *\r
+ * Contributor(s): \r
+ * Andi Vajda\r
+ *\r
+ * Alternatively, the contents of this file may be used under the\r
+ * terms of the GNU Public License (the "GPL"), in which case the\r
+ * provisions of the GPL are applicable instead of those above.\r
+ * If you wish to allow use of your version of this file only\r
+ * under the terms of the GPL and not to allow others to use your\r
+ * version of this file under the NPL, indicate your decision by\r
+ * deleting the provisions above and replace them with the notice\r
+ * and other provisions required by the GPL. If you do not delete\r
+ * the provisions above, a recipient may use your version of this\r
+ * file under either the NPL or the GPL.\r
+ */\r
+package org.mozilla.javascript;\r
+\r
+// API class\r
+\r
+import java.io.*;\r
+\r
+/**\r
+ * This interface is implemented by classes interested in the bytecode\r
+ * generated by the rhino compiler for script objects.\r
+ *\r
+ * @see Context\r
+ * @author Andi Vajda\r
+ */\r
+public interface ClassOutput {\r \r
+ /**\r
+ * @param className the name of the class for which bytecode is ready.\r
+ * @param isTopLevel if true, represents the top-level script being compiled\r
+ * @return a stream into which to write bytecode.\r
+ * @since 1.5 Release 2\r
+ */\r
+ public OutputStream getOutputStream(String className, boolean isTopLevel)\r
+ throws IOException;\r
+}\r
--- /dev/null
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-\r
+ *\r
+ * The contents of this file are subject to the Netscape Public\r
+ * License Version 1.1 (the "License"); you may not use this file\r
+ * except in compliance with the License. You may obtain a copy of\r
+ * the License at http://www.mozilla.org/NPL/\r
+ *\r
+ * Software distributed under the License is distributed on an "AS\r
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or\r
+ * implied. See the License for the specific language governing\r
+ * rights and limitations under the License.\r
+ *\r
+ * The Original Code is Rhino code, released\r
+ * May 6, 1999.\r
+ *\r
+ * The Initial Developer of the Original Code is Netscape\r
+ * Communications Corporation. Portions created by Netscape are\r
+ * Copyright (C) 1997-2000 Netscape Communications Corporation. All\r
+ * Rights Reserved.\r
+ *\r
+ * Contributor(s):\r
+ *\r
+ * Patrick Beard\r
+ * Norris Boyd\r
+ * Igor Bukanov\r
+ * Brendan Eich\r
+ * Roger Lawrence\r
+ * Mike McCabe\r
+ * Ian D. Stewart\r
+ * Andi Vajda\r
+ * Andrew Wason\r
+ *\r
+ * Alternatively, the contents of this file may be used under the\r
+ * terms of the GNU Public License (the "GPL"), in which case the\r
+ * provisions of the GPL are applicable instead of those above.\r
+ * If you wish to allow use of your version of this file only\r
+ * under the terms of the GPL and not to allow others to use your\r
+ * version of this file under the NPL, indicate your decision by\r
+ * deleting the provisions above and replace them with the notice\r
+ * and other provisions required by the GPL. If you do not delete\r
+ * the provisions above, a recipient may use your version of this\r
+ * file under either the NPL or the GPL.\r
+ */\r
+\r
+// API class\r
+\r
+package org.mozilla.javascript;\r
+\r
+import java.beans.*;\r
+import java.io.*;\r
+import java.util.Vector;\r
+import java.util.Enumeration;\r
+import java.util.Hashtable;\r
+import java.util.Locale;\r
+import java.util.ResourceBundle;\r
+import java.util.ListResourceBundle;\r
+import java.text.MessageFormat;\r
+import java.lang.reflect.*;\r
+import org.mozilla.javascript.debug.*;\r
+\r
+/**\r
+ * This class represents the runtime context of an executing script.\r
+ *\r
+ * Before executing a script, an instance of Context must be created\r
+ * and associated with the thread that will be executing the script.\r
+ * The Context will be used to store information about the executing\r
+ * of the script such as the call stack. Contexts are associated with\r
+ * the current thread using the <a href="#enter()">enter()</a> method.<p>\r
+ *\r
+ * The behavior of the execution engine may be altered through methods\r
+ * such as <a href="#setLanguageVersion>setLanguageVersion</a> and\r
+ * <a href="#setErrorReporter>setErrorReporter</a>.<p>\r
+ *\r
+ * Different forms of script execution are supported. Scripts may be\r
+ * evaluated from the source directly, or first compiled and then later\r
+ * executed. Interactive execution is also supported.<p>\r
+ *\r
+ * Some aspects of script execution, such as type conversions and\r
+ * object creation, may be accessed directly through methods of\r
+ * Context.\r
+ *\r
+ * @see Scriptable\r
+ * @author Norris Boyd\r
+ * @author Brendan Eich\r
+ */\r
+\r
+public class Context {\r
+ public static final String languageVersionProperty = "language version";\r
+ public static final String errorReporterProperty = "error reporter";\r
+ \r
+ /**\r
+ * Create a new Context.\r
+ *\r
+ * Note that the Context must be associated with a thread before\r
+ * it can be used to execute a script.\r
+ *\r
+ * @see org.mozilla.javascript.Context#enter\r
+ */\r
+ public Context() {\r
+ init();\r
+ }\r
+ \r
+ /**\r
+ * Create a new context with the associated security support.\r
+ * \r
+ * @param securitySupport an encapsulation of the functionality \r
+ * needed to support security for scripts.\r
+ * @see org.mozilla.javascript.SecuritySupport\r
+ */\r
+ public Context(SecuritySupport securitySupport) {\r
+ this.securitySupport = securitySupport;\r
+ init();\r
+ }\r
+ \r
+ private void init() {\r
+ setLanguageVersion(VERSION_DEFAULT);\r
+ optimizationLevel = codegenClass != null ? 0 : -1;\r
+ Object[] array = contextListeners;\r
+ if (array != null) {\r
+ for (int i = array.length; i-- != 0;) {\r
+ ((ContextListener)array[i]).contextCreated(this);\r
+ }\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * Get a context associated with the current thread, creating\r
+ * one if need be.\r
+ *\r
+ * The Context stores the execution state of the JavaScript\r
+ * engine, so it is required that the context be entered\r
+ * before execution may begin. Once a thread has entered\r
+ * a Context, then getCurrentContext() may be called to find\r
+ * the context that is associated with the current thread.\r
+ * <p>\r
+ * Calling <code>enter()</code> will\r
+ * return either the Context currently associated with the\r
+ * thread, or will create a new context and associate it \r
+ * with the current thread. Each call to <code>enter()</code>\r
+ * must have a matching call to <code>exit()</code>. For example,\r
+ * <pre>\r
+ * Context cx = Context.enter();\r
+ * ...\r
+ * cx.evaluateString(...);\r
+ * Context.exit();\r
+ * </pre>\r
+ * @return a Context associated with the current thread\r
+ * @see org.mozilla.javascript.Context#getCurrentContext\r
+ * @see org.mozilla.javascript.Context#exit\r
+ */\r
+ public static Context enter() {\r
+ return enter(null);\r
+ }\r
+ \r
+ /**\r
+ * Get a Context associated with the current thread, using\r
+ * the given Context if need be.\r
+ * <p>\r
+ * The same as <code>enter()</code> except that <code>cx</code>\r
+ * is associated with the current thread and returned if \r
+ * the current thread has no associated context and <code>cx</code>\r
+ * is not associated with any other thread.\r
+ * @param cx a Context to associate with the thread if possible\r
+ * @return a Context associated with the current thread\r
+ */\r
+ public static Context enter(Context cx) {\r
+ // There's some duplication of code in this method to avoid\r
+ // unnecessary synchronizations.\r
+ Thread t = Thread.currentThread();\r
+ Context current = (Context) threadContexts.get(t);\r
+ if (current != null) {\r
+ synchronized (current) {\r
+ current.enterCount++;\r
+ }\r
+ }\r
+ else if (cx != null) {\r
+ synchronized (cx) {\r
+ if (cx.currentThread == null) {\r
+ cx.currentThread = t;\r
+ threadContexts.put(t, cx);\r
+ cx.enterCount++;\r
+ }\r
+ }\r
+ current = cx;\r
+ }\r
+ else {\r
+ current = new Context();\r
+ current.currentThread = t;\r
+ threadContexts.put(t, current);\r
+ current.enterCount = 1;\r
+ }\r
+ Object[] array = contextListeners;\r
+ if (array != null) {\r
+ for (int i = array.length; i-- != 0;) {\r
+ ((ContextListener)array[i]).contextEntered(current);\r
+ }\r
+ }\r
+ return current;\r
+ }\r
+ \r
+ /**\r
+ * Exit a block of code requiring a Context.\r
+ *\r
+ * Calling <code>exit()</code> will remove the association between\r
+ * the current thread and a Context if the prior call to \r
+ * <code>enter()</code> on this thread newly associated a Context \r
+ * with this thread.\r
+ * Once the current thread no longer has an associated Context,\r
+ * it cannot be used to execute JavaScript until it is again associated\r
+ * with a Context.\r
+ *\r
+ * @see org.mozilla.javascript.Context#enter\r
+ */\r
+ public static void exit() {\r
+ Context cx = getCurrentContext();\r
+ boolean released = false;\r
+ if (cx != null) {\r
+ synchronized (cx) {\r
+ if (--cx.enterCount == 0) {\r
+ threadContexts.remove(cx.currentThread);\r
+ cx.currentThread = null;\r
+ released = true;\r
+ }\r
+ }\r
+ Object[] array = contextListeners;\r
+ if (array != null) {\r
+ for (int i = array.length; i-- != 0;) {\r
+ ContextListener l = (ContextListener)array[i];\r
+ l.contextExited(cx);\r
+ if (released) { l.contextReleased(cx); }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Get the current Context.\r
+ *\r
+ * The current Context is per-thread; this method looks up\r
+ * the Context associated with the current thread. <p>\r
+ *\r
+ * @return the Context associated with the current thread, or\r
+ * null if no context is associated with the current \r
+ * thread.\r
+ * @see org.mozilla.javascript.Context#enter\r
+ * @see org.mozilla.javascript.Context#exit\r
+ */\r
+ public static Context getCurrentContext() {\r
+ Thread t = Thread.currentThread();\r
+ return (Context) threadContexts.get(t);\r
+ }\r
+ \r
+ public static Context getContextForThread(Thread t) {\r
+ Context ret = (Context) threadContexts.get(t);\r
+ return ret == null ? Context.enter() : ret;\r
+ }\r
+ \r
+ /**\r
+ * Language versions\r
+ *\r
+ * All integral values are reserved for future version numbers.\r
+ */\r
+\r
+ /**\r
+ * The unknown version.\r
+ */\r
+ public static final int VERSION_UNKNOWN = -1;\r
+\r
+ /**\r
+ * The default version.\r
+ */\r
+ public static final int VERSION_DEFAULT = 0;\r
+\r
+ /**\r
+ * JavaScript 1.0\r
+ */\r
+ public static final int VERSION_1_0 = 100;\r
+\r
+ /**\r
+ * JavaScript 1.1\r
+ */\r
+ public static final int VERSION_1_1 = 110;\r
+\r
+ /**\r
+ * JavaScript 1.2\r
+ */\r
+ public static final int VERSION_1_2 = 120;\r
+\r
+ /**\r
+ * JavaScript 1.3\r
+ */\r
+ public static final int VERSION_1_3 = 130;\r
+\r
+ /**\r
+ * JavaScript 1.4\r
+ */\r
+ public static final int VERSION_1_4 = 140;\r
+\r
+ /**\r
+ * JavaScript 1.5\r
+ */\r
+ public static final int VERSION_1_5 = 150;\r
+\r
+ /**\r
+ * Get the current language version.\r
+ * <p>\r
+ * The language version number affects JavaScript semantics as detailed\r
+ * in the overview documentation.\r
+ *\r
+ * @return an integer that is one of VERSION_1_0, VERSION_1_1, etc.\r
+ */\r
+ public int getLanguageVersion() {\r
+ return version;\r
+ }\r
+\r
+ /**\r
+ * Set the language version.\r
+ *\r
+ * <p>\r
+ * Setting the language version will affect functions and scripts compiled\r
+ * subsequently. See the overview documentation for version-specific\r
+ * behavior.\r
+ *\r
+ * @param version the version as specified by VERSION_1_0, VERSION_1_1, etc.\r
+ */\r
+ public void setLanguageVersion(int version) {\r
+ Object[] array = listeners;\r
+ if (array != null && version != this.version) {\r
+ firePropertyChangeImpl(array, languageVersionProperty,\r
+ new Integer(this.version), \r
+ new Integer(version));\r
+ }\r
+ this.version = version;\r
+ }\r
+\r
+ /**\r
+ * Get the implementation version.\r
+ *\r
+ * <p>\r
+ * The implementation version is of the form \r
+ * <pre>\r
+ * "<i>name langVer</i> <code>release</code> <i>relNum date</i>"\r
+ * </pre>\r
+ * where <i>name</i> is the name of the product, <i>langVer</i> is \r
+ * the language version, <i>relNum</i> is the release number, and \r
+ * <i>date</i> is the release date for that specific \r
+ * release in the form "yyyy mm dd". \r
+ *\r
+ * @return a string that encodes the product, language version, release \r
+ * number, and date.\r
+ */\r
+ public String getImplementationVersion() {\r
+ return "Rhino 1.5 release 2 2001 07 27";\r
+ }\r
+\r
+ /**\r
+ * Get the current error reporter.\r
+ *\r
+ * @see org.mozilla.javascript.ErrorReporter\r
+ */\r
+ public ErrorReporter getErrorReporter() {\r
+ if (errorReporter == null) {\r
+ errorReporter = new DefaultErrorReporter();\r
+ }\r
+ return errorReporter;\r
+ }\r
+\r
+ /**\r
+ * Change the current error reporter.\r
+ *\r
+ * @return the previous error reporter\r
+ * @see org.mozilla.javascript.ErrorReporter\r
+ */\r
+ public ErrorReporter setErrorReporter(ErrorReporter reporter) {\r
+ ErrorReporter result = errorReporter;\r
+ Object[] array = listeners;\r
+ if (array != null && errorReporter != reporter) {\r
+ firePropertyChangeImpl(array, errorReporterProperty,\r
+ errorReporter, reporter);\r
+ }\r
+ errorReporter = reporter;\r
+ return result;\r
+ }\r
+\r
+ /**\r
+ * Get the current locale. Returns the default locale if none has\r
+ * been set.\r
+ *\r
+ * @see java.util.Locale\r
+ */\r
+\r
+ public Locale getLocale() {\r
+ if (locale == null)\r
+ locale = Locale.getDefault();\r
+ return locale;\r
+ }\r
+\r
+ /**\r
+ * Set the current locale.\r
+ *\r
+ * @see java.util.Locale\r
+ */\r
+ public Locale setLocale(Locale loc) {\r
+ Locale result = locale;\r
+ locale = loc;\r
+ return result;\r
+ }\r
+ \r
+ /**\r
+ * Register an object to receive notifications when a bound property\r
+ * has changed\r
+ * @see java.beans.PropertyChangeEvent\r
+ * @see #removePropertyChangeListener(java.beans.PropertyChangeListener)\r
+ * @param listener the listener\r
+ */\r
+ public void addPropertyChangeListener(PropertyChangeListener listener) {\r
+ synchronized (this) {\r
+ listeners = ListenerArray.add(listeners, listener);\r
+ } \r
+ }\r
+ \r
+ /**\r
+ * Remove an object from the list of objects registered to receive \r
+ * notification of changes to a bounded property\r
+ * @see java.beans.PropertyChangeEvent\r
+ * @see #addPropertyChangeListener(java.beans.PropertyChangeListener)\r
+ * @param listener the listener\r
+ */\r
+ public void removePropertyChangeListener(PropertyChangeListener listener) {\r
+ synchronized (this) {\r
+ listeners = ListenerArray.remove(listeners, listener);\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * Notify any registered listeners that a bounded property has changed\r
+ * @see #addPropertyChangeListener(java.beans.PropertyChangeListener)\r
+ * @see #removePropertyChangeListener(java.beans.PropertyChangeListener)\r
+ * @see java.beans.PropertyChangeListener\r
+ * @see java.beans.PropertyChangeEvent\r
+ * @param property the bound property\r
+ * @param oldValue the old value\r
+ * @param newVale the new value\r
+ */\r
+ void firePropertyChange(String property, Object oldValue,\r
+ Object newValue)\r
+ {\r
+ Object[] array = listeners;\r
+ if (array != null) {\r
+ firePropertyChangeImpl(array, property, oldValue, newValue);\r
+ }\r
+ }\r
+\r
+ private void firePropertyChangeImpl(Object[] array, String property,\r
+ Object oldValue, Object newValue)\r
+ {\r
+ for (int i = array.length; i-- != 0;) {\r
+ Object obj = array[i];\r
+ if (obj instanceof PropertyChangeListener) {\r
+ PropertyChangeListener l = (PropertyChangeListener)obj;\r
+ l.propertyChange(new PropertyChangeEvent(\r
+ this, property, oldValue, newValue));\r
+ }\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * Report a warning using the error reporter for the current thread.\r
+ *\r
+ * @param message the warning message to report\r
+ * @param sourceName a string describing the source, such as a filename\r
+ * @param lineno the starting line number\r
+ * @param lineSource the text of the line (may be null)\r
+ * @param lineOffset the offset into lineSource where problem was detected\r
+ * @see org.mozilla.javascript.ErrorReporter\r
+ */\r
+ public static void reportWarning(String message, String sourceName,\r
+ int lineno, String lineSource,\r
+ int lineOffset)\r
+ {\r
+ Context cx = Context.getContext();\r
+ cx.getErrorReporter().warning(message, sourceName, lineno,\r
+ lineSource, lineOffset);\r
+ }\r
+\r
+ /**\r
+ * Report a warning using the error reporter for the current thread.\r
+ *\r
+ * @param message the warning message to report\r
+ * @see org.mozilla.javascript.ErrorReporter\r
+ */\r
+ public static void reportWarning(String message) {\r
+ int[] linep = { 0 };\r
+ String filename = getSourcePositionFromStack(linep);\r
+ Context.reportWarning(message, filename, linep[0], null, 0);\r
+ }\r
+\r
+ /**\r
+ * Report an error using the error reporter for the current thread.\r
+ *\r
+ * @param message the error message to report\r
+ * @param sourceName a string describing the source, such as a filename\r
+ * @param lineno the starting line number\r
+ * @param lineSource the text of the line (may be null)\r
+ * @param lineOffset the offset into lineSource where problem was detected\r
+ * @see org.mozilla.javascript.ErrorReporter\r
+ */\r
+ public static void reportError(String message, String sourceName,\r
+ int lineno, String lineSource,\r
+ int lineOffset)\r
+ {\r
+ Context cx = getCurrentContext();\r
+ if (cx != null) {\r
+ cx.errorCount++;\r
+ cx.getErrorReporter().error(message, sourceName, lineno,\r
+ lineSource, lineOffset);\r
+ } else {\r
+ throw new EvaluatorException(message);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Report an error using the error reporter for the current thread.\r
+ *\r
+ * @param message the error message to report\r
+ * @see org.mozilla.javascript.ErrorReporter\r
+ */\r
+ public static void reportError(String message) {\r
+ int[] linep = { 0 };\r
+ String filename = getSourcePositionFromStack(linep);\r
+ Context.reportError(message, filename, linep[0], null, 0);\r
+ }\r
+\r
+ /**\r
+ * Report a runtime error using the error reporter for the current thread.\r
+ *\r
+ * @param message the error message to report\r
+ * @param sourceName a string describing the source, such as a filename\r
+ * @param lineno the starting line number\r
+ * @param lineSource the text of the line (may be null)\r
+ * @param lineOffset the offset into lineSource where problem was detected\r
+ * @return a runtime exception that will be thrown to terminate the\r
+ * execution of the script\r
+ * @see org.mozilla.javascript.ErrorReporter\r
+ */\r
+ public static EvaluatorException reportRuntimeError(String message,\r
+ String sourceName,\r
+ int lineno,\r
+ String lineSource,\r
+ int lineOffset)\r
+ {\r
+ Context cx = getCurrentContext();\r
+ if (cx != null) {\r
+ cx.errorCount++;\r
+ return cx.getErrorReporter().\r
+ runtimeError(message, sourceName, lineno,\r
+ lineSource, lineOffset);\r
+ } else {\r
+ throw new EvaluatorException(message);\r
+ }\r
+ }\r
+\r
+ static EvaluatorException reportRuntimeError0(String messageId) {\r
+ return reportRuntimeError(getMessage0(messageId));\r
+ }\r
+\r
+ static EvaluatorException reportRuntimeError1\r
+ (String messageId, Object arg1) \r
+ {\r
+ return reportRuntimeError(getMessage1(messageId, arg1));\r
+ }\r
+\r
+ static EvaluatorException reportRuntimeError2\r
+ (String messageId, Object arg1, Object arg2) \r
+ {\r
+ return reportRuntimeError(getMessage2(messageId, arg1, arg2));\r
+ }\r
+\r
+ static EvaluatorException reportRuntimeError3\r
+ (String messageId, Object arg1, Object arg2, Object arg3) \r
+ {\r
+ return reportRuntimeError(getMessage3(messageId, arg1, arg2, arg3));\r
+ }\r
+\r
+ /**\r
+ * Report a runtime error using the error reporter for the current thread.\r
+ *\r
+ * @param message the error message to report\r
+ * @see org.mozilla.javascript.ErrorReporter\r
+ */\r
+ public static EvaluatorException reportRuntimeError(String message) {\r
+ int[] linep = { 0 };\r
+ String filename = getSourcePositionFromStack(linep);\r
+ return Context.reportRuntimeError(message, filename, linep[0], null, 0);\r
+ }\r
+\r
+ /**\r
+ * Initialize the standard objects.\r
+ *\r
+ * Creates instances of the standard objects and their constructors\r
+ * (Object, String, Number, Date, etc.), setting up 'scope' to act\r
+ * as a global object as in ECMA 15.1.<p>\r
+ *\r
+ * This method must be called to initialize a scope before scripts\r
+ * can be evaluated in that scope.\r
+ *\r
+ * @param scope the scope to initialize, or null, in which case a new\r
+ * object will be created to serve as the scope\r
+ * @return the initialized scope\r
+ */\r
+ public Scriptable initStandardObjects(ScriptableObject scope) {\r
+ return initStandardObjects(scope, false);\r
+ }\r
+ \r
+ /**\r
+ * Initialize the standard objects.\r
+ *\r
+ * Creates instances of the standard objects and their constructors\r
+ * (Object, String, Number, Date, etc.), setting up 'scope' to act\r
+ * as a global object as in ECMA 15.1.<p>\r
+ *\r
+ * This method must be called to initialize a scope before scripts\r
+ * can be evaluated in that scope.<p>\r
+ * \r
+ * This form of the method also allows for creating "sealed" standard\r
+ * objects. An object that is sealed cannot have properties added or\r
+ * removed. This is useful to create a "superglobal" that can be shared \r
+ * among several top-level objects. Note that sealing is not allowed in\r
+ * the current ECMA/ISO language specification, but is likely for\r
+ * the next version.\r
+ *\r
+ * @param scope the scope to initialize, or null, in which case a new\r
+ * object will be created to serve as the scope\r
+ * @param sealed whether or not to create sealed standard objects that\r
+ * cannot be modified. \r
+ * @return the initialized scope\r
+ * @since 1.4R3\r
+ */\r
+ public ScriptableObject initStandardObjects(ScriptableObject scope,\r
+ boolean sealed)\r
+ {\r
+ if (scope == null)\r
+ scope = new NativeObject();\r
+\r
+ BaseFunction.init(this, scope, sealed);\r
+ NativeObject.init(this, scope, sealed);\r
+\r
+ Scriptable objectProto = ScriptableObject.getObjectPrototype(scope);\r
+\r
+ // Function.prototype.__proto__ should be Object.prototype\r
+ Scriptable functionProto = ScriptableObject.getFunctionPrototype(scope);\r
+ functionProto.setPrototype(objectProto);\r
+\r
+ // Set the prototype of the object passed in if need be\r
+ if (scope.getPrototype() == null)\r
+ scope.setPrototype(objectProto);\r
+\r
+ // must precede NativeGlobal since it's needed therein\r
+ NativeError.init(this, scope, sealed);\r
+ NativeGlobal.init(this, scope, sealed);\r
+\r
+ NativeArray.init(this, scope, sealed);\r
+ NativeString.init(this, scope, sealed);\r
+ NativeBoolean.init(this, scope, sealed);\r
+ NativeNumber.init(this, scope, sealed);\r
+ NativeDate.init(this, scope, sealed);\r
+ NativeMath.init(this, scope, sealed);\r
+\r
+ NativeWith.init(this, scope, sealed);\r
+ NativeCall.init(this, scope, sealed);\r
+ NativeScript.init(this, scope, sealed);\r
+\r
+ new LazilyLoadedCtor(scope, \r
+ "RegExp",\r
+ "org.mozilla.javascript.regexp.NativeRegExp",\r
+ sealed);\r
+\r
+ // This creates the Packages and java package roots.\r
+ new LazilyLoadedCtor(scope, \r
+ "Packages",\r
+ "org.mozilla.javascript.NativeJavaPackage",\r
+ sealed);\r
+ new LazilyLoadedCtor(scope, \r
+ "java", \r
+ "org.mozilla.javascript.NativeJavaPackage",\r
+ sealed);\r
+ new LazilyLoadedCtor(scope, \r
+ "getClass",\r
+ "org.mozilla.javascript.NativeJavaPackage",\r
+ sealed);\r
+ \r
+ // Define the JavaAdapter class, allowing it to be overridden.\r
+ String adapterClass = "org.mozilla.javascript.JavaAdapter";\r
+ String adapterProperty = "JavaAdapter";\r
+ try {\r
+ adapterClass = System.getProperty(adapterClass, adapterClass);\r
+ adapterProperty = System.getProperty\r
+ ("org.mozilla.javascript.JavaAdapterClassName",\r
+ adapterProperty);\r
+ }\r
+ catch (SecurityException e) {\r
+ // We may not be allowed to get system properties. Just\r
+ // use the default adapter in that case.\r
+ }\r
+\r
+ new LazilyLoadedCtor(scope, adapterProperty, adapterClass, sealed);\r
+\r
+ return scope;\r
+ }\r
+ \r
+ /**\r
+ * Get the singleton object that represents the JavaScript Undefined value.\r
+ */\r
+ public static Object getUndefinedValue() {\r
+ return Undefined.instance;\r
+ }\r
+ \r
+ /**\r
+ * Evaluate a JavaScript source string.\r
+ *\r
+ * The provided source name and line number are used for error messages\r
+ * and for producing debug information.\r
+ *\r
+ * @param scope the scope to execute in\r
+ * @param source the JavaScript source\r
+ * @param sourceName a string describing the source, such as a filename\r
+ * @param lineno the starting line number\r
+ * @param securityDomain an arbitrary object that specifies security \r
+ * information about the origin or owner of the script. For \r
+ * implementations that don't care about security, this value \r
+ * may be null.\r
+ * @return the result of evaluating the string\r
+ * @exception JavaScriptException if an uncaught JavaScript exception\r
+ * occurred while evaluating the source string\r
+ * @see org.mozilla.javascript.SecuritySupport\r
+ */\r
+ public Object evaluateString(Scriptable scope, String source,\r
+ String sourceName, int lineno,\r
+ Object securityDomain)\r
+ throws JavaScriptException\r
+ {\r
+ try {\r
+ Reader in = new StringReader(source);\r
+ return evaluateReader(scope, in, sourceName, lineno, \r
+ securityDomain);\r
+ }\r
+ catch (IOException ioe) {\r
+ // Should never occur because we just made the reader from a String\r
+ throw new RuntimeException();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Evaluate a reader as JavaScript source.\r
+ *\r
+ * All characters of the reader are consumed.\r
+ *\r
+ * @param scope the scope to execute in\r
+ * @param in the Reader to get JavaScript source from\r
+ * @param sourceName a string describing the source, such as a filename\r
+ * @param lineno the starting line number\r
+ * @param securityDomain an arbitrary object that specifies security \r
+ * information about the origin or owner of the script. For \r
+ * implementations that don't care about security, this value \r
+ * may be null.\r
+ * @return the result of evaluating the source\r
+ *\r
+ * @exception IOException if an IOException was generated by the Reader\r
+ * @exception JavaScriptException if an uncaught JavaScript exception\r
+ * occurred while evaluating the Reader\r
+ */\r
+ public Object evaluateReader(Scriptable scope, Reader in,\r
+ String sourceName, int lineno,\r
+ Object securityDomain)\r
+ throws IOException, JavaScriptException\r
+ {\r
+ Script script = compileReader(scope, in, sourceName, lineno, \r
+ securityDomain);\r
+ if (script != null)\r
+ return script.exec(this, scope);\r
+ else\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * Check whether a string is ready to be compiled.\r
+ * <p>\r
+ * stringIsCompilableUnit is intended to support interactive compilation of\r
+ * javascript. If compiling the string would result in an error\r
+ * that might be fixed by appending more source, this method\r
+ * returns false. In every other case, it returns true.\r
+ * <p>\r
+ * Interactive shells may accumulate source lines, using this\r
+ * method after each new line is appended to check whether the\r
+ * statement being entered is complete.\r
+ *\r
+ * @param source the source buffer to check\r
+ * @return whether the source is ready for compilation\r
+ * @since 1.4 Release 2\r
+ */\r
+ synchronized public boolean stringIsCompilableUnit(String source)\r
+ {\r
+ Reader in = new StringReader(source);\r
+ // no source name or source text manager, because we're just\r
+ // going to throw away the result.\r
+ TokenStream ts = new TokenStream(in, null, null, 1);\r
+\r
+ // Temporarily set error reporter to always be the exception-throwing\r
+ // DefaultErrorReporter. (This is why the method is synchronized...)\r
+ ErrorReporter currentReporter = \r
+ setErrorReporter(new DefaultErrorReporter());\r
+\r
+ boolean errorseen = false;\r
+ try {\r
+ IRFactory irf = new IRFactory(ts, null);\r
+ Parser p = new Parser(irf);\r
+ p.parse(ts);\r
+ } catch (IOException ioe) {\r
+ errorseen = true;\r
+ } catch (EvaluatorException ee) {\r
+ errorseen = true;\r
+ } finally {\r
+ // Restore the old error reporter.\r
+ setErrorReporter(currentReporter);\r
+ }\r
+ // Return false only if an error occurred as a result of reading past\r
+ // the end of the file, i.e. if the source could be fixed by\r
+ // appending more source.\r
+ if (errorseen && ts.eof())\r
+ return false;\r
+ else \r
+ return true;\r
+ }\r
+\r
+ /**\r
+ * Compiles the source in the given reader.\r
+ * <p>\r
+ * Returns a script that may later be executed.\r
+ * Will consume all the source in the reader.\r
+ *\r
+ * @param scope if nonnull, will be the scope in which the script object\r
+ * is created. The script object will be a valid JavaScript object\r
+ * as if it were created using the JavaScript1.3 Script constructor\r
+ * @param in the input reader\r
+ * @param sourceName a string describing the source, such as a filename\r
+ * @param lineno the starting line number for reporting errors\r
+ * @param securityDomain an arbitrary object that specifies security \r
+ * information about the origin or owner of the script. For \r
+ * implementations that don't care about security, this value \r
+ * may be null.\r
+ * @return a script that may later be executed\r
+ * @see org.mozilla.javascript.Script#exec\r
+ * @exception IOException if an IOException was generated by the Reader\r
+ */\r
+ public Script compileReader(Scriptable scope, Reader in, String sourceName,\r
+ int lineno, Object securityDomain)\r
+ throws IOException\r
+ {\r
+ return (Script) compile(scope, in, sourceName, lineno, securityDomain, \r
+ false);\r
+ }\r
+\r
+\r
+ /**\r
+ * Compile a JavaScript function.\r
+ * <p>\r
+ * The function source must be a function definition as defined by\r
+ * ECMA (e.g., "function f(a) { return a; }"). \r
+ *\r
+ * @param scope the scope to compile relative to\r
+ * @param source the function definition source\r
+ * @param sourceName a string describing the source, such as a filename\r
+ * @param lineno the starting line number\r
+ * @param securityDomain an arbitrary object that specifies security \r
+ * information about the origin or owner of the script. For \r
+ * implementations that don't care about security, this value \r
+ * may be null.\r
+ * @return a Function that may later be called\r
+ * @see org.mozilla.javascript.Function\r
+ */\r
+ public Function compileFunction(Scriptable scope, String source,\r
+ String sourceName, int lineno,\r
+ Object securityDomain)\r
+ {\r
+ Reader in = new StringReader(source);\r
+ try {\r
+ return (Function) compile(scope, in, sourceName, lineno, \r
+ securityDomain, true);\r
+ }\r
+ catch (IOException ioe) {\r
+ // Should never happen because we just made the reader\r
+ // from a String\r
+ throw new RuntimeException();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Decompile the script.\r
+ * <p>\r
+ * The canonical source of the script is returned.\r
+ *\r
+ * @param script the script to decompile\r
+ * @param scope the scope under which to decompile\r
+ * @param indent the number of spaces to indent the result\r
+ * @return a string representing the script source\r
+ */\r
+ public String decompileScript(Script script, Scriptable scope,\r
+ int indent)\r
+ {\r
+ NativeScript ns = (NativeScript) script;\r
+ ns.initScript(scope);\r
+ return ns.decompile(this, indent, false);\r
+ }\r
+\r
+ /**\r
+ * Decompile a JavaScript Function.\r
+ * <p>\r
+ * Decompiles a previously compiled JavaScript function object to\r
+ * canonical source.\r
+ * <p>\r
+ * Returns function body of '[native code]' if no decompilation\r
+ * information is available.\r
+ *\r
+ * @param fun the JavaScript function to decompile\r
+ * @param indent the number of spaces to indent the result\r
+ * @return a string representing the function source\r
+ */\r
+ public String decompileFunction(Function fun, int indent) {\r
+ if (fun instanceof BaseFunction)\r
+ return ((BaseFunction)fun).decompile(this, indent, false);\r
+ else\r
+ return "function " + fun.getClassName() +\r
+ "() {\n\t[native code]\n}\n";\r
+ }\r
+\r
+ /**\r
+ * Decompile the body of a JavaScript Function.\r
+ * <p>\r
+ * Decompiles the body a previously compiled JavaScript Function\r
+ * object to canonical source, omitting the function header and\r
+ * trailing brace.\r
+ *\r
+ * Returns '[native code]' if no decompilation information is available.\r
+ *\r
+ * @param fun the JavaScript function to decompile\r
+ * @param indent the number of spaces to indent the result\r
+ * @return a string representing the function body source.\r
+ */\r
+ public String decompileFunctionBody(Function fun, int indent) {\r
+ if (fun instanceof BaseFunction)\r
+ return ((BaseFunction)fun).decompile(this, indent, true);\r
+ else\r
+ // not sure what the right response here is. JSRef currently\r
+ // dumps core.\r
+ return "[native code]\n";\r
+ }\r
+\r
+ /**\r
+ * Create a new JavaScript object.\r
+ *\r
+ * Equivalent to evaluating "new Object()".\r
+ * @param scope the scope to search for the constructor and to evaluate\r
+ * against\r
+ * @return the new object\r
+ * @exception PropertyException if "Object" cannot be found in\r
+ * the scope\r
+ * @exception NotAFunctionException if the "Object" found in the scope\r
+ * is not a function\r
+ * @exception JavaScriptException if an uncaught JavaScript exception\r
+ * occurred while creating the object\r
+ */\r
+ public Scriptable newObject(Scriptable scope)\r
+ throws PropertyException,\r
+ NotAFunctionException,\r
+ JavaScriptException\r
+ {\r
+ return newObject(scope, "Object", null);\r
+ }\r
+\r
+ /**\r
+ * Create a new JavaScript object by executing the named constructor.\r
+ *\r
+ * The call <code>newObject(scope, "Foo")</code> is equivalent to\r
+ * evaluating "new Foo()".\r
+ *\r
+ * @param scope the scope to search for the constructor and to evaluate against\r
+ * @param constructorName the name of the constructor to call\r
+ * @return the new object\r
+ * @exception PropertyException if a property with the constructor\r
+ * name cannot be found in the scope\r
+ * @exception NotAFunctionException if the property found in the scope\r
+ * is not a function\r
+ * @exception JavaScriptException if an uncaught JavaScript exception\r
+ * occurred while creating the object\r
+ */\r
+ public Scriptable newObject(Scriptable scope, String constructorName)\r
+ throws PropertyException,\r
+ NotAFunctionException,\r
+ JavaScriptException\r
+ {\r
+ return newObject(scope, constructorName, null);\r
+ }\r
+\r
+ /**\r
+ * Creates a new JavaScript object by executing the named constructor.\r
+ *\r
+ * Searches <code>scope</code> for the named constructor, calls it with\r
+ * the given arguments, and returns the result.<p>\r
+ *\r
+ * The code\r
+ * <pre>\r
+ * Object[] args = { "a", "b" };\r
+ * newObject(scope, "Foo", args)</pre>\r
+ * is equivalent to evaluating "new Foo('a', 'b')", assuming that the Foo\r
+ * constructor has been defined in <code>scope</code>.\r
+ *\r
+ * @param scope The scope to search for the constructor and to evaluate\r
+ * against\r
+ * @param constructorName the name of the constructor to call\r
+ * @param args the array of arguments for the constructor\r
+ * @return the new object\r
+ * @exception PropertyException if a property with the constructor\r
+ * name cannot be found in the scope\r
+ * @exception NotAFunctionException if the property found in the scope\r
+ * is not a function\r
+ * @exception JavaScriptException if an uncaught JavaScript exception\r
+ * occurs while creating the object\r
+ */\r
+ public Scriptable newObject(Scriptable scope, String constructorName,\r
+ Object[] args)\r
+ throws PropertyException,\r
+ NotAFunctionException,\r
+ JavaScriptException\r
+ {\r
+ Object ctorVal = ScriptRuntime.getTopLevelProp(scope, constructorName);\r
+ if (ctorVal == Scriptable.NOT_FOUND) {\r
+ String message = getMessage1("msg.ctor.not.found", constructorName);\r
+ throw new PropertyException(message);\r
+ }\r
+ if (!(ctorVal instanceof Function)) {\r
+ String message = getMessage1("msg.not.ctor", constructorName);\r
+ throw new NotAFunctionException(message);\r
+ }\r
+ Function ctor = (Function) ctorVal;\r
+ return ctor.construct(this, ctor.getParentScope(),\r
+ (args == null) ? ScriptRuntime.emptyArgs : args);\r
+ }\r
+\r
+ /**\r
+ * Create an array with a specified initial length.\r
+ * <p>\r
+ * @param scope the scope to create the object in\r
+ * @param length the initial length (JavaScript arrays may have\r
+ * additional properties added dynamically).\r
+ * @return the new array object\r
+ */\r
+ public Scriptable newArray(Scriptable scope, int length) {\r
+ Scriptable result = new NativeArray(length);\r
+ newArrayHelper(scope, result);\r
+ return result;\r
+ }\r
+\r
+ /**\r
+ * Create an array with a set of initial elements.\r
+ * <p>\r
+ * @param scope the scope to create the object in\r
+ * @param elements the initial elements. Each object in this array\r
+ * must be an acceptable JavaScript type.\r
+ * @return the new array object\r
+ */\r
+ public Scriptable newArray(Scriptable scope, Object[] elements) {\r
+ Scriptable result = new NativeArray(elements);\r
+ newArrayHelper(scope, result);\r
+ return result;\r
+ }\r
+ \r
+ /**\r
+ * Get the elements of a JavaScript array.\r
+ * <p>\r
+ * If the object defines a length property, a Java array with that\r
+ * length is created and initialized with the values obtained by\r
+ * calling get() on object for each value of i in [0,length-1]. If\r
+ * there is not a defined value for a property the Undefined value\r
+ * is used to initialize the corresponding element in the array. The\r
+ * Java array is then returned.\r
+ * If the object doesn't define a length property, null is returned.\r
+ * @param object the JavaScript array or array-like object\r
+ * @return a Java array of objects\r
+ * @since 1.4 release 2\r
+ */\r
+ public Object[] getElements(Scriptable object) {\r
+ double doubleLen = NativeArray.getLengthProperty(object);\r
+ if (doubleLen != doubleLen)\r
+ return null;\r
+ int len = (int) doubleLen;\r
+ Object[] result = new Object[len];\r
+ for (int i=0; i < len; i++) {\r
+ Object elem = object.get(i, object);\r
+ result[i] = elem == Scriptable.NOT_FOUND ? Undefined.instance \r
+ : elem;\r
+ }\r
+ return result;\r
+ }\r
+\r
+ /**\r
+ * Convert the value to a JavaScript boolean value.\r
+ * <p>\r
+ * See ECMA 9.2.\r
+ *\r
+ * @param value a JavaScript value\r
+ * @return the corresponding boolean value converted using\r
+ * the ECMA rules\r
+ */\r
+ public static boolean toBoolean(Object value) {\r
+ return ScriptRuntime.toBoolean(value);\r
+ }\r
+\r
+ /**\r
+ * Convert the value to a JavaScript Number value.\r
+ * <p>\r
+ * Returns a Java double for the JavaScript Number.\r
+ * <p>\r
+ * See ECMA 9.3.\r
+ *\r
+ * @param value a JavaScript value\r
+ * @return the corresponding double value converted using\r
+ * the ECMA rules\r
+ */\r
+ public static double toNumber(Object value) {\r
+ return ScriptRuntime.toNumber(value);\r
+ }\r
+\r
+ /**\r
+ * Convert the value to a JavaScript String value.\r
+ * <p>\r
+ * See ECMA 9.8.\r
+ * <p>\r
+ * @param value a JavaScript value\r
+ * @return the corresponding String value converted using\r
+ * the ECMA rules\r
+ */\r
+ public static String toString(Object value) {\r
+ return ScriptRuntime.toString(value);\r
+ }\r
+\r
+ /**\r
+ * Convert the value to an JavaScript object value.\r
+ * <p>\r
+ * Note that a scope must be provided to look up the constructors\r
+ * for Number, Boolean, and String.\r
+ * <p>\r
+ * See ECMA 9.9.\r
+ * <p>\r
+ * Additionally, arbitrary Java objects and classes will be\r
+ * wrapped in a Scriptable object with its Java fields and methods\r
+ * reflected as JavaScript properties of the object.\r
+ *\r
+ * @param value any Java object\r
+ * @param scope global scope containing constructors for Number,\r
+ * Boolean, and String\r
+ * @return new JavaScript object\r
+ */\r
+ public static Scriptable toObject(Object value, Scriptable scope) {\r
+ return ScriptRuntime.toObject(scope, value, null);\r
+ }\r
+ \r
+ /**\r
+ * Convert the value to an JavaScript object value.\r
+ * <p>\r
+ * Note that a scope must be provided to look up the constructors\r
+ * for Number, Boolean, and String.\r
+ * <p>\r
+ * See ECMA 9.9.\r
+ * <p>\r
+ * Additionally, arbitrary Java objects and classes will be\r
+ * wrapped in a Scriptable object with its Java fields and methods\r
+ * reflected as JavaScript properties of the object. If the \r
+ * "staticType" parameter is provided, it will be used as the static\r
+ * type of the Java value to create.\r
+ *\r
+ * @param value any Java object\r
+ * @param scope global scope containing constructors for Number,\r
+ * Boolean, and String\r
+ * @param staticType the static type of the Java value to create\r
+ * @return new JavaScript object\r
+ */\r
+ public static Scriptable toObject(Object value, Scriptable scope, \r
+ Class staticType) {\r
+ if (value == null && staticType != null)\r
+ return null;\r
+ return ScriptRuntime.toObject(scope, value, staticType);\r
+ }\r
+\r
+ /**\r
+ * Tell whether debug information is being generated.\r
+ * @since 1.3\r
+ */\r
+ public boolean isGeneratingDebug() {\r
+ return generatingDebug;\r
+ }\r
+\r
+ /**\r
+ * Specify whether or not debug information should be generated.\r
+ * <p>\r
+ * Setting the generation of debug information on will set the\r
+ * optimization level to zero.\r
+ * @since 1.3\r
+ */\r
+ public void setGeneratingDebug(boolean generatingDebug) {\r
+ generatingDebugChanged = true;\r
+ if (generatingDebug)\r
+ setOptimizationLevel(0);\r
+ this.generatingDebug = generatingDebug;\r
+ }\r
+\r
+ /**\r
+ * Tell whether source information is being generated.\r
+ * @since 1.3\r
+ */\r
+ public boolean isGeneratingSource() {\r
+ return generatingSource;\r
+ }\r
+\r
+ /**\r
+ * Specify whether or not source information should be generated.\r
+ * <p>\r
+ * Without source information, evaluating the "toString" method\r
+ * on JavaScript functions produces only "[native code]" for\r
+ * the body of the function.\r
+ * Note that code generated without source is not fully ECMA\r
+ * conformant.\r
+ * @since 1.3\r
+ */\r
+ public void setGeneratingSource(boolean generatingSource) {\r
+ this.generatingSource = generatingSource;\r
+ }\r
+\r
+ /**\r
+ * Get the current optimization level.\r
+ * <p>\r
+ * The optimization level is expressed as an integer between -1 and\r
+ * 9.\r
+ * @since 1.3\r
+ *\r
+ */\r
+ public int getOptimizationLevel() {\r
+ return optimizationLevel;\r
+ }\r
+\r
+ /**\r
+ * Set the current optimization level.\r
+ * <p>\r
+ * The optimization level is expected to be an integer between -1 and\r
+ * 9. Any negative values will be interpreted as -1, and any values\r
+ * greater than 9 will be interpreted as 9.\r
+ * An optimization level of -1 indicates that interpretive mode will\r
+ * always be used. Levels 0 through 9 indicate that class files may \r
+ * be generated. Higher optimization levels trade off compile time\r
+ * performance for runtime performance.\r
+ * The optimizer level can't be set greater than -1 if the optimizer\r
+ * package doesn't exist at run time.\r
+ * @param optimizationLevel an integer indicating the level of\r
+ * optimization to perform\r
+ * @since 1.3\r
+ *\r
+ */\r
+ public void setOptimizationLevel(int optimizationLevel) {\r
+ if (optimizationLevel < 0) {\r
+ optimizationLevel = -1;\r
+ } else if (optimizationLevel > 9) {\r
+ optimizationLevel = 9;\r
+ }\r
+ if (codegenClass == null)\r
+ optimizationLevel = -1;\r
+ this.optimizationLevel = optimizationLevel;\r
+ }\r
+\r
+ /**\r
+ * Get the current target class file name.\r
+ * <p>\r
+ * If nonnull, requests to compile source will result in one or\r
+ * more class files being generated.\r
+ * @since 1.3\r
+ */\r
+ public String getTargetClassFileName() {\r
+ return nameHelper == null\r
+ ? null \r
+ : nameHelper.getTargetClassFileName();\r
+ }\r
+\r
+ /**\r
+ * Set the current target class file name.\r
+ * <p>\r
+ * If nonnull, requests to compile source will result in one or\r
+ * more class files being generated. If null, classes will only\r
+ * be generated in memory.\r
+ *\r
+ * @since 1.3\r
+ */\r
+ public void setTargetClassFileName(String classFileName) {\r
+ if (nameHelper != null)\r
+ nameHelper.setTargetClassFileName(classFileName);\r
+ }\r
+\r
+ /**\r
+ * Get the current package to generate classes into.\r
+ *\r
+ * @since 1.3\r
+ */\r
+ public String getTargetPackage() {\r
+ return (nameHelper == null) ? null : nameHelper.getTargetPackage();\r
+ }\r
+\r
+ /**\r
+ * Set the package to generate classes into.\r
+ *\r
+ * @since 1.3\r
+ */\r
+ public void setTargetPackage(String targetPackage) {\r
+ if (nameHelper != null)\r
+ nameHelper.setTargetPackage(targetPackage);\r
+ }\r
+\r
+ /**\r
+ * Get the current interface to write class bytes into.\r
+ *\r
+ * @see ClassOutput\r
+ * @since 1.5 Release 2\r
+ */\r
+ public ClassOutput getClassOutput() {\r
+ return nameHelper == null ? null : nameHelper.getClassOutput();\r
+ }\r
+\r
+ /**\r
+ * Set the interface to write class bytes into.\r
+ * Unless setTargetClassFileName() has been called classOutput will be\r
+ * used each time the javascript compiler has generated the bytecode for a\r
+ * script class.\r
+ *\r
+ * @see ClassOutput\r
+ * @since 1.5 Release 2\r
+ */\r
+ public void setClassOutput(ClassOutput classOutput) {\r
+ if (nameHelper != null)\r
+ nameHelper.setClassOutput(classOutput);\r
+ }\r
+ \r
+ /**\r
+ * Add a Context listener.\r
+ */\r
+ public static void addContextListener(ContextListener listener) {\r
+ synchronized (staticDataLock) {\r
+ contextListeners = ListenerArray.add(contextListeners, listener);\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * Remove a Context listener.\r
+ * @param listener the listener to remove.\r
+ */\r
+ public static void removeContextListener(ContextListener listener) {\r
+ synchronized (staticDataLock) {\r
+ contextListeners = ListenerArray.remove(contextListeners, listener);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Set the security support for this context. \r
+ * <p> SecuritySupport may only be set if it is currently null.\r
+ * Otherwise a SecurityException is thrown.\r
+ * @param supportObj a SecuritySupport object\r
+ * @throws SecurityException if there is already a SecuritySupport\r
+ * object for this Context\r
+ */\r
+ public synchronized void setSecuritySupport(SecuritySupport supportObj) {\r
+ if (securitySupport != null) {\r
+ throw new SecurityException("Cannot overwrite existing " +\r
+ "SecuritySupport object");\r
+ }\r
+ securitySupport = supportObj;\r
+ }\r
+ \r
+ /**\r
+ * Return true if a security domain is required on calls to\r
+ * compile and evaluate scripts.\r
+ *\r
+ * @since 1.4 Release 2\r
+ */\r
+ public static boolean isSecurityDomainRequired() { \r
+ return requireSecurityDomain;\r
+ }\r
+ \r
+ /**\r
+ * Returns the security context associated with the innermost\r
+ * script or function being executed by the interpreter.\r
+ * @since 1.4 release 2\r
+ */\r
+ public Object getInterpreterSecurityDomain() {\r
+ return interpreterSecurityDomain;\r
+ }\r
+ \r
+ /**\r
+ * Returns true if the class parameter is a class in the \r
+ * interpreter. Typically used by embeddings that get a class\r
+ * context to check security. These embeddings must know \r
+ * whether to get the security context associated with the\r
+ * interpreter or not.\r
+ * \r
+ * @param cl a class to test whether or not it is an interpreter\r
+ * class\r
+ * @return true if cl is an interpreter class\r
+ * @since 1.4 release 2\r
+ */\r
+ public boolean isInterpreterClass(Class cl) {\r
+ return cl == Interpreter.class;\r
+ }\r
+ \r
+ /**\r
+ * Set the class that the generated target will extend.\r
+ * \r
+ * @param extendsClass the class it extends\r
+ */\r
+ public void setTargetExtends(Class extendsClass) {\r
+ if (nameHelper != null) {\r
+ nameHelper.setTargetExtends(extendsClass);\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * Set the interfaces that the generated target will implement.\r
+ * \r
+ * @param implementsClasses an array of Class objects, one for each\r
+ * interface the target will extend\r
+ */\r
+ public void setTargetImplements(Class[] implementsClasses) {\r
+ if (nameHelper != null) {\r
+ nameHelper.setTargetImplements(implementsClasses);\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * Get a value corresponding to a key.\r
+ * <p>\r
+ * Since the Context is associated with a thread it can be \r
+ * used to maintain values that can be later retrieved using \r
+ * the current thread. \r
+ * <p>\r
+ * Note that the values are maintained with the Context, so\r
+ * if the Context is disassociated from the thread the values\r
+ * cannot be retreived. Also, if private data is to be maintained\r
+ * in this manner the key should be a java.lang.Object \r
+ * whose reference is not divulged to untrusted code.\r
+ * @param key the key used to lookup the value\r
+ * @return a value previously stored using putThreadLocal.\r
+ */\r
+ public Object getThreadLocal(Object key) {\r
+ if (hashtable == null)\r
+ return null;\r
+ return hashtable.get(key);\r
+ }\r
+\r
+ /**\r
+ * Put a value that can later be retrieved using a given key.\r
+ * <p>\r
+ * @param key the key used to index the value\r
+ * @param value the value to save\r
+ */\r
+ public void putThreadLocal(Object key, Object value) {\r
+ if (hashtable == null)\r
+ hashtable = new Hashtable();\r
+ hashtable.put(key, value);\r
+ }\r
+ \r
+ /**\r
+ * Remove values from thread-local storage.\r
+ * @param key the key for the entry to remove.\r
+ * @since 1.5 release 2\r
+ */\r
+ public void removeThreadLocal(Object key) {\r
+ if (hashtable == null)\r
+ return;\r
+ hashtable.remove(key);\r
+ } \r
+ \r
+ /**\r
+ * Return whether functions are compiled by this context using\r
+ * dynamic scope.\r
+ * <p>\r
+ * If functions are compiled with dynamic scope, then they execute\r
+ * in the scope of their caller, rather than in their parent scope.\r
+ * This is useful for sharing functions across multiple scopes.\r
+ * @since 1.5 Release 1\r
+ */\r
+ public boolean hasCompileFunctionsWithDynamicScope() {\r
+ return compileFunctionsWithDynamicScopeFlag;\r
+ }\r
+ \r
+ /**\r
+ * Set whether functions compiled by this context should use\r
+ * dynamic scope.\r
+ * <p>\r
+ * @param flag if true, compile functions with dynamic scope\r
+ * @since 1.5 Release 1\r
+ */\r
+ public void setCompileFunctionsWithDynamicScope(boolean flag) {\r
+ compileFunctionsWithDynamicScopeFlag = flag;\r
+ }\r
+ \r
+ /**\r
+ * Set whether to cache some values statically.\r
+ * <p>\r
+ * By default, the engine will cache some values statically \r
+ * (reflected Java classes, for instance). This can speed\r
+ * execution dramatically, but increases the memory footprint.\r
+ * Also, with caching enabled, references may be held to \r
+ * objects past the lifetime of any real usage. \r
+ * <p>\r
+ * If caching is enabled and this method is called with a \r
+ * <code>false</code> argument, the caches will be emptied.\r
+ * So one strategy could be to clear the caches at times\r
+ * appropriate to the application.\r
+ * <p>\r
+ * Caching is enabled by default.\r
+ * \r
+ * @param cachingEnabled if true, caching is enabled\r
+ * @since 1.5 Release 1 \r
+ */\r
+ public static void setCachingEnabled(boolean cachingEnabled) {\r
+ if (isCachingEnabled && !cachingEnabled) {\r
+ // Caching is being turned off. Empty caches.\r
+ JavaMembers.classTable = new Hashtable();\r
+ nameHelper.reset();\r
+ }\r
+ isCachingEnabled = cachingEnabled;\r
+ FunctionObject.setCachingEnabled(cachingEnabled);\r
+ }\r
+ \r
+ /**\r
+ * Set a WrapHandler for this Context.\r
+ * <p>\r
+ * The WrapHandler allows custom object wrapping behavior for \r
+ * Java object manipulated with JavaScript.\r
+ * @see org.mozilla.javascript.WrapHandler\r
+ * @since 1.5 Release 2 \r
+ */\r
+ public void setWrapHandler(WrapHandler wrapHandler) {\r
+ this.wrapHandler = wrapHandler;\r
+ }\r
+ \r
+ /**\r
+ * Return the current WrapHandler, or null if none is defined.\r
+ * @see org.mozilla.javascript.WrapHandler\r
+ * @since 1.5 Release 2 \r
+ */\r
+ public WrapHandler getWrapHandler() {\r
+ return wrapHandler;\r
+ }\r
+ \r
+ public DebuggableEngine getDebuggableEngine() {\r
+ if (debuggableEngine == null)\r
+ debuggableEngine = new DebuggableEngineImpl(this);\r
+ return debuggableEngine;\r
+ }\r
+ \r
+ \r
+ /**\r
+ * if hasFeature(FEATURE_NON_ECMA_GET_YEAR) returns true,\r
+ * Date.prototype.getYear subtructs 1900 only if 1900 <= date < 2000\r
+ * in deviation with Ecma B.2.4\r
+ */\r
+ public static final int FEATURE_NON_ECMA_GET_YEAR = 1;\r
+ \r
+ /**\r
+ * Controls certain aspects of script semantics. \r
+ * Should be overwritten to alter default behavior.\r
+ * @param featureIndex feature index to check\r
+ * @return true if the <code>featureIndex</code> feature is turned on\r
+ * @see #FEATURE_NON_ECMA_GET_YEAR\r
+ */\r
+ public boolean hasFeature(int featureIndex) {\r
+ if (featureIndex == FEATURE_NON_ECMA_GET_YEAR) {\r
+ /*\r
+ * During the great date rewrite of 1.3, we tried to track the\r
+ * evolving ECMA standard, which then had a definition of\r
+ * getYear which always subtracted 1900. Which we\r
+ * implemented, not realizing that it was incompatible with\r
+ * the old behavior... now, rather than thrash the behavior\r
+ * yet again, we've decided to leave it with the - 1900\r
+ * behavior and point people to the getFullYear method. But\r
+ * we try to protect existing scripts that have specified a\r
+ * version...\r
+ */\r
+ return (version == Context.VERSION_1_0 \r
+ || version == Context.VERSION_1_1\r
+ || version == Context.VERSION_1_2);\r
+ }\r
+ throw new RuntimeException("Bad feature index: " + featureIndex);\r
+ }\r
+\r
+ /**\r
+ * Get/Set threshold of executed instructions counter that triggers call to\r
+ * <code>observeInstructionCount()</code>.\r
+ * When the threshold is zero, instruction counting is disabled, \r
+ * otherwise each time the run-time executes at least the threshold value\r
+ * of script instructions, <code>observeInstructionCount()</code> will \r
+ * be called.\r
+ */\r
+ public int getInstructionObserverThreshold() {\r
+ return instructionThreshold;\r
+ }\r
+ \r
+ public void setInstructionObserverThreshold(int threshold) {\r
+ instructionThreshold = threshold;\r
+ }\r
+ \r
+ /** \r
+ * Allow application to monitor counter of executed script instructions\r
+ * in Context subclasses.\r
+ * Run-time calls this when instruction counting is enabled and the counter\r
+ * reaches limit set by <code>setInstructionObserverThreshold()</code>.\r
+ * The method is useful to observe long running scripts and if necessary\r
+ * to terminate them.\r
+ * @param instructionCount amount of script instruction executed since \r
+ * last call to <code>observeInstructionCount</code> \r
+ * @throws Error to terminate the script\r
+ */\r
+ protected void observeInstructionCount(int instructionCount) {}\r
+ \r
+ /********** end of API **********/\r
+ \r
+ void pushFrame(DebugFrame frame) {\r
+ if (frameStack == null)\r
+ frameStack = new java.util.Stack();\r
+ frameStack.push(frame);\r
+ }\r
+ \r
+ void popFrame() {\r
+ frameStack.pop();\r
+ }\r
+ \r
+\r
+\r
+ static String getMessage0(String messageId) {\r
+ return getMessage(messageId, null);\r
+ }\r
+\r
+ static String getMessage1(String messageId, Object arg1) {\r
+ Object[] arguments = {arg1};\r
+ return getMessage(messageId, arguments);\r
+ }\r
+\r
+ static String getMessage2(String messageId, Object arg1, Object arg2) {\r
+ Object[] arguments = {arg1, arg2};\r
+ return getMessage(messageId, arguments);\r
+ }\r
+\r
+ static String getMessage3\r
+ (String messageId, Object arg1, Object arg2, Object arg3) {\r
+ Object[] arguments = {arg1, arg2, arg3};\r
+ return getMessage(messageId, arguments);\r
+ }\r
+ /**\r
+ * Internal method that reports an error for missing calls to\r
+ * enter().\r
+ */\r
+ static Context getContext() {\r
+ Thread t = Thread.currentThread();\r
+ Context cx = (Context) threadContexts.get(t);\r
+ if (cx == null) {\r
+ throw new RuntimeException(\r
+ "No Context associated with current Thread");\r
+ }\r
+ return cx;\r
+ }\r
+\r
+ /** GCJ doesn't have an easy way to bundle up .properties files, so we do this */\r
+ static class HardCodedResourceBundle extends ListResourceBundle {\r
+ public Object[][] getContents() { return contents; }\r
+ static final Object[][] contents = {\r
+ { "msg.dup.parms", "Duplicate parameter name \"{0}\"." },\r
+ { "msg.ctor.not.found", "Constructor for \"{0}\" not found." },\r
+ { "msg.not.ctor", "\"{0}\" is not a constructor." },\r
+ { "msg.varargs.ctor", "Method or constructor \"{0}\" must be static with the signature \"(Context cx, Object[] args, Function ctorObj, boolean inNewExpr)\" to define a variable arguments constructor." },\r
+ { "msg.varargs.fun", "Method \"{0}\" must be static with the signature \"(Context cx, Scriptable thisObj, Object[] args, Function funObj)\" to define a variable arguments function." },\r
+ { "msg.incompat.call", "Method \"{0}\" called on incompatible object." },\r
+ { "msg.bad.parms", "Bad method parameters for \"{0}\"." },\r
+ { "msg.no.overload", "Method \"{0}\" occurs multiple times in class \"{1}\"." },\r
+ { "msg.method.not.found", "Method \"{0}\" not found in \"{1}\"." },\r
+ { "msg.bad.for.in.lhs", "Invalid left-hand side of for..in loop." },\r
+ { "msg.bad.lhs.assign", "Invalid assignment left-hand side." },\r
+ { "msg.mult.index", "Only one variable allowed in for..in loop." },\r
+ { "msg.cant.convert", "Can''t convert to type \"{0}\"." },\r
+ { "msg.cant.call.indirect", "Function \"{0}\" must be called directly, and not by way of a function of another name." },\r
+ { "msg.eval.nonstring", "Calling eval() with anything other than a primitive string value will simply return the value. Is this what you intended?" },\r
+ { "msg.only.from.new", "\"{0}\" may only be invoked from a \"new\" expression." },\r
+ { "msg.deprec.ctor", "The \"{0}\" constructor is deprecated." },\r
+ { "msg.no.function.ref.found.in", "no source found in {1} to decompile function reference {0}" },\r
+ { "msg.no.function.ref.found", "no source found to decompile function reference {0}" },\r
+ { "msg.arg.isnt.array", "second argument to Function.prototype.apply must be an array" },\r
+ { "msg.bad.esc.mask", "invalid string escape mask" },\r
+ { "msg.cant.instantiate", "error instantiating ({0}): class {1} is interface or abstract" },\r
+ { "msg.bad.ctor.sig", "Found constructor with wrong signature: {0} calling {1} with signature {2}" },\r
+ { "msg.not.java.obj", "Expected argument to getClass() to be a Java object." },\r
+ { "msg.no.java.ctor", "Java constructor for \"{0}\" with arguments \"{1}\" not found." },\r
+ { "msg.method.ambiguous", "The choice of Java method {0}.{1} matching JavaScript argument types ({2}) is ambiguous; candidate methods are: {3}" },\r
+ { "msg.constructor.ambiguous", "The choice of Java constructor {0} matching JavaScript argument types ({1}) is ambiguous; candidate constructors are: {2}" },\r
+ { "msg.conversion.not.allowed", "Cannot convert {0} to {1}" },\r
+ { "msg.bad.quant", "Invalid quantifier {0}" },\r
+ { "msg.overlarge.max", "Overly large maximum {0}" },\r
+ { "msg.zero.quant", "Zero quantifier {0}" },\r
+ { "msg.max.lt.min", "Maximum {0} less than minimum" },\r
+ { "msg.unterm.quant", "Unterminated quantifier {0}" },\r
+ { "msg.unterm.paren", "Unterminated parenthetical {0}" },\r
+ { "msg.unterm.class", "Unterminated character class {0}" },\r
+ { "msg.bad.range", "Invalid range in character class." },\r
+ { "msg.trail.backslash", "Trailing \\ in regular expression." },\r
+ { "msg.no.regexp", "Regular expressions are not available." },\r
+ { "msg.bad.backref", "back-reference exceeds number of capturing parentheses." },\r
+ { "msg.dup.label", "Duplicate label {0}." },\r
+ { "msg.undef.label", "Undefined label {0}." },\r
+ { "msg.bad.break", "Unlabelled break must be inside loop or switch." },\r
+ { "msg.continue.outside", "continue must be inside loop." },\r
+ { "msg.continue.nonloop", "Can only continue to labeled iteration statement." },\r
+ { "msg.fn.redecl", "Function \"{0}\" redeclared; prior definition will be ignored." },\r
+ { "msg.no.paren.parms", "missing ( before function parameters" },\r
+ { "msg.no.parm", "missing formal parameter" },\r
+ { "msg.no.paren.after.parms", "missing ) after formal parameters" },\r
+ { "msg.no.brace.body", "missing '{' before function body" },\r
+ { "msg.no.brace.after.body", "missing } after function body" },\r
+ { "msg.no.paren.cond", "missing ( before condition" },\r
+ { "msg.no.paren.after.cond", "missing ) after condition" },\r
+ { "msg.no.semi.stmt", "missing ; before statement" },\r
+ { "msg.no.name.after.dot", "missing name after . operator" },\r
+ { "msg.no.bracket.index", "missing ] in index expression" },\r
+ { "msg.no.paren.switch", "missing ( before switch expression" },\r
+ { "msg.no.paren.after.switch", "missing ) after switch expression" },\r
+ { "msg.no.brace.switch", "missing '{' before switch body" },\r
+ { "msg.bad.switch", "invalid switch statement" },\r
+ { "msg.no.colon.case", "missing : after case expression" },\r
+ { "msg.no.while.do", "missing while after do-loop body" },\r
+ { "msg.no.paren.for", "missing ( after for" },\r
+ { "msg.no.semi.for", "missing ; after for-loop initializer" },\r
+ { "msg.no.semi.for.cond", "missing ; after for-loop condition" },\r
+ { "msg.no.paren.for.ctrl", "missing ) after for-loop control" },\r
+ { "msg.no.paren.with", "missing ( before with-statement object" },\r
+ { "msg.no.paren.after.with", "missing ) after with-statement object" },\r
+ { "msg.bad.return", "invalid return" },\r
+ { "msg.no.brace.block", "missing } in compound statement" },\r
+ { "msg.bad.label", "invalid label" },\r
+ { "msg.bad.var", "missing variable name" },\r
+ { "msg.bad.var.init", "invalid variable initialization" },\r
+ { "msg.no.colon.cond", "missing : in conditional expression" },\r
+ { "msg.no.paren.arg", "missing ) after argument list" },\r
+ { "msg.no.bracket.arg", "missing ] after element list" },\r
+ { "msg.bad.prop", "invalid property id" },\r
+ { "msg.no.colon.prop", "missing : after property id" },\r
+ { "msg.no.brace.prop", "missing } after property list" },\r
+ { "msg.no.paren", "missing ) in parenthetical" },\r
+ { "msg.reserved.id", "identifier is a reserved word" },\r
+ { "msg.no.paren.catch", "missing ( before catch-block condition" },\r
+ { "msg.bad.catchcond", "invalid catch block condition" },\r
+ { "msg.catch.unreachable", "any catch clauses following an unqualified catch are unreachable" },\r
+ { "msg.no.brace.catchblock", "missing '{' before catch-block body" },\r
+ { "msg.try.no.catchfinally", "''try'' without ''catch'' or ''finally''" },\r
+ { "msg.syntax", "syntax error" },\r
+ { "msg.assn.create", "Assignment to undefined \"{0}\" will create a new variable. Add a variable statement at the top level scope to remove this warning." },\r
+ { "msg.prop.not.found", "Property not found." },\r
+ { "msg.invalid.type", "Invalid JavaScript value of type {0}" },\r
+ { "msg.primitive.expected", "Primitive type expected (had {0} instead)" },\r
+ { "msg.null.to.object", "Cannot convert null to an object." },\r
+ { "msg.undef.to.object", "Cannot convert undefined to an object." },\r
+ { "msg.cyclic.value", "Cyclic {0} value not allowed." },\r
+ { "msg.is.not.defined", "\"{0}\" is not defined." },\r
+ { "msg.isnt.function", "{0} is not a function." },\r
+ { "msg.bad.default.value", "Object''s getDefaultValue() method returned an object." },\r
+ { "msg.instanceof.not.object", " Can''t use instanceof on a non-object." },\r
+ { "msg.instanceof.bad.prototype", " ''prototype'' property of {0} is not an object." },\r
+ { "msg.bad.radix", " illegal radix {0}." },\r
+ { "msg.default.value", "Cannot find default value for object." },\r
+ { "msg.zero.arg.ctor", "Cannot load class \"{0}\" which has no zero-parameter constructor." },\r
+ { "msg.multiple.ctors", "Cannot have more than one constructor method, but found both {0} and {1}." },\r
+ { "msg.ctor.multiple.parms", "Can''t define constructor or class {0} since more than one constructor has multiple parameters." },\r
+ { "msg.extend.scriptable", "{0} must extend ScriptableObject in order to define property {1}." },\r
+ { "msg.bad.getter.parms", "In order to define a property, getter {0} must have zero parameters or a single ScriptableObject parameter." },\r
+ { "msg.obj.getter.parms", "Expected static or delegated getter {0} to take a ScriptableObject parameter." },\r
+ { "msg.getter.static", "Getter and setter must both be static or neither be static." },\r
+ { "msg.setter2.parms", "Two-parameter setter must take a ScriptableObject as its first parameter." },\r
+ { "msg.setter1.parms", "Expected single parameter setter for {0}" },\r
+ { "msg.setter2.expected", "Expected static or delegated setter {0} to take two parameters." },\r
+ { "msg.setter.parms", "Expected either one or two parameters for setter." },\r
+ { "msg.add.sealed", "Cannot add a property to a sealed object." },\r
+ { "msg.remove.sealed", "Cannot remove a property from a sealed object." },\r
+ { "msg.token.replaces.pushback", "ungot token {0} replaces pushback token {1}" },\r
+ { "msg.missing.exponent", "missing exponent" },\r
+ { "msg.caught.nfe", "number format error: {0}" },\r
+ { "msg.unterminated.string.lit", "unterminated string literal" },\r
+ { "msg.oct.esc.too.large", "octal escape too large" },\r
+ { "msg.nested.comment", "nested comment" },\r
+ { "msg.unterminated.comment", "unterminated comment" },\r
+ { "msg.unterminated.re.lit", "unterminated regular expression literal" },\r
+ { "msg.invalid.re.flag", "invalid flag after regular expression" },\r
+ { "msg.no.re.input.for", "no input for {0}" },\r
+ { "msg.illegal.character", "illegal character" },\r
+ { "msg.invalid.escape", "invalid Unicode escape sequence" },\r
+ { "msg.bad.octal.literal", "illegal octal literal digit {0}; interpreting it as a decimal digit" },\r
+ { "msg.undefined", "The undefined value has no properties." },\r
+ { "msg.java.internal.field.type", "Internal error: type conversion of {0} to assign to {1} on {2} failed." },\r
+ { "msg.java.conversion.implicit_method", "Can''t find converter method \"{0}\" on class {1}." },\r
+ { "msg.java.method.assign", "Java method \"{0}\" cannot be assigned to." },\r
+ { "msg.java.internal.private", "Internal error: attempt to access private/protected field \"{0}\"." },\r
+ { "msg.java.no_such_method", "Can''t find method {0}." },\r
+ { "msg.script.is.not.constructor", "Script objects are not constructors." },\r
+ { "msg.nonjava.method", "Java method \"{0}\" was invoked with a ''this'' value that was not a Java object." },\r
+ { "msg.java.member.not.found", "Java class \"{0}\" has no public instance field or method named \"{1}\"." },\r
+ { "msg.pkg.int", "Java package names may not be numbers." },\r
+ { "msg.ambig.import", "Ambiguous import: \"{0}\" and and \"{1}\"." },\r
+ { "msg.not.pkg", "Function importPackage must be called with a package; had \"{0}\" instead." },\r
+ { "msg.not.class", "Function importClass must be called with a class; had \"{0}\" instead." },\r
+ { "msg.prop.defined", "Cannot import \"{0}\" since a property by that name is already defined." },\r
+ { "msg.arraylength.bad", "Inappropriate array length." },\r
+ { "msg.bad.uri", "Malformed URI sequence." },\r
+ { "msg.bad.precision", "Precision {0} out of range." }\r
+ };\r
+ }\r
+\r
+ static final ResourceBundle myresources = new HardCodedResourceBundle();\r
+\r
+ /* OPT there's a noticable delay for the first error! Maybe it'd\r
+ * make sense to use a ListResourceBundle instead of a properties\r
+ * file to avoid (synchronized) text parsing.\r
+ */\r
+ static String getMessage(String messageId, Object[] arguments) {\r
+ Context cx = getCurrentContext();\r
+ Locale locale = cx != null ? cx.getLocale() : Locale.getDefault();\r
+\r
+ // ResourceBundle does cacheing.\r
+ ResourceBundle rb = myresources;\r
+\r
+ String formatString;\r
+ try {\r
+ formatString = rb.getString(messageId);\r
+ } catch (java.util.MissingResourceException mre) {\r
+ throw new RuntimeException\r
+ ("no message resource found for message property "+ messageId);\r
+ }\r
+\r
+ /*\r
+ * It's OK to format the string, even if 'arguments' is null;\r
+ * we need to format it anyway, to make double ''s collapse to\r
+ * single 's.\r
+ */\r
+ // TODO: MessageFormat is not available on pJava\r
+ MessageFormat formatter = new MessageFormat(formatString);\r
+ return formatter.format(arguments);\r
+ }\r
+\r
+ // debug flags\r
+ static final boolean printTrees = false;\r
+ \r
+ /**\r
+ * Compile a script.\r
+ *\r
+ * Reads script source from the reader and compiles it, returning\r
+ * a class for either the script or the function depending on the\r
+ * value of <code>returnFunction</code>.\r
+ *\r
+ * @param scope the scope to compile relative to\r
+ * @param in the Reader to read source from\r
+ * @param sourceName the name of the origin of the source (usually\r
+ * a file or URL)\r
+ * @param lineno the line number of the start of the source\r
+ * @param securityDomain an arbitrary object that specifies security \r
+ * information about the origin or owner of the script. For \r
+ * implementations that don't care about security, this value \r
+ * may be null.\r
+ * @param returnFunction if true, will expect the source to contain\r
+ * a function; return value is assumed to\r
+ * then be a org.mozilla.javascript.Function\r
+ * @return a class for the script or function\r
+ * @see org.mozilla.javascript.Context#compileReader\r
+ */\r
+ private Object compile(Scriptable scope, Reader in, String sourceName, \r
+ int lineno, Object securityDomain, \r
+ boolean returnFunction)\r
+ throws IOException\r
+ {\r
+ if (debugger != null && in != null) {\r
+ in = new DebugReader(in);\r
+ }\r
+ TokenStream ts = new TokenStream(in, scope, sourceName, lineno);\r
+ return compile(scope, ts, securityDomain, in, returnFunction);\r
+ }\r
+\r
+ private static Class codegenClass = null;\r
+ private static ClassNameHelper nameHelper = null;\r
+ static {\r
+ /*\r
+ try {\r
+ codegenClass = Class.forName(\r
+ "org.mozilla.javascript.optimizer.Codegen");\r
+ Class nameHelperClass = Class.forName(\r
+ "org.mozilla.javascript.optimizer.OptClassNameHelper");\r
+ nameHelper = (ClassNameHelper)nameHelperClass.newInstance();\r
+ } catch (ClassNotFoundException x) {\r
+ // ...must be running lite, that's ok\r
+ codegenClass = null;\r
+ } catch (IllegalAccessException x) {\r
+ codegenClass = null;\r
+ } catch (InstantiationException x) {\r
+ codegenClass = null;\r
+ }\r
+ */\r
+ }\r
+ \r
+ private Interpreter getCompiler() {\r
+ if (codegenClass != null) {\r
+ try {\r
+ return (Interpreter) codegenClass.newInstance();\r
+ }\r
+ catch (SecurityException x) { \r
+ }\r
+ catch (IllegalArgumentException x) {\r
+ }\r
+ catch (InstantiationException x) {\r
+ }\r
+ catch (IllegalAccessException x) {\r
+ }\r
+ // fall through\r
+ }\r
+ return new Interpreter();\r
+ }\r
+ \r
+ private Object compile(Scriptable scope, TokenStream ts, \r
+ Object securityDomain, Reader in,\r
+ boolean returnFunction)\r
+ throws IOException\r
+ {\r
+ Interpreter compiler = optimizationLevel == -1 \r
+ ? new Interpreter()\r
+ : getCompiler();\r
+ \r
+ errorCount = 0;\r
+ IRFactory irf = compiler.createIRFactory(ts, nameHelper, scope);\r
+ Parser p = new Parser(irf);\r
+ Node tree = (Node) p.parse(ts);\r
+ if (tree == null) \r
+ return null;\r
+\r
+ tree = compiler.transform(tree, ts, scope);\r
+\r
+ if (printTrees)\r
+ System.out.println(tree.toStringTree());\r
+ \r
+ if (returnFunction) {\r
+ Node first = tree.getFirstChild();\r
+ if (first == null)\r
+ return null;\r
+ tree = (Node) first.getProp(Node.FUNCTION_PROP);\r
+ if (tree == null)\r
+ return null;\r
+ }\r
+ \r
+ if (in instanceof DebugReader) {\r
+ DebugReader dr = (DebugReader) in;\r
+ tree.putProp(Node.DEBUGSOURCE_PROP, dr.getSaved());\r
+ }\r
+\r
+ Object result = compiler.compile(this, scope, tree, securityDomain,\r
+ securitySupport, nameHelper);\r
+\r
+ return errorCount == 0 ? result : null;\r
+ }\r
+\r
+ static String getSourcePositionFromStack(int[] linep) {\r
+ Context cx = getCurrentContext();\r
+ if (cx == null)\r
+ return null;\r
+ if (cx.interpreterLine > 0 && cx.interpreterSourceFile != null) {\r
+ linep[0] = cx.interpreterLine;\r
+ return cx.interpreterSourceFile;\r
+ }\r
+ /**\r
+ * A bit of a hack, but the only way to get filename and line\r
+ * number from an enclosing frame.\r
+ */\r
+ CharArrayWriter writer = new CharArrayWriter();\r
+ RuntimeException re = new RuntimeException();\r
+ re.printStackTrace(new PrintWriter(writer));\r
+ String s = writer.toString();\r
+ int open = -1;\r
+ int close = -1;\r
+ int colon = -1;\r
+ for (int i=0; i < s.length(); i++) {\r
+ char c = s.charAt(i);\r
+ if (c == ':')\r
+ colon = i;\r
+ else if (c == '(')\r
+ open = i;\r
+ else if (c == ')')\r
+ close = i;\r
+ else if (c == '\n' && open != -1 && close != -1 && colon != -1 && \r
+ open < colon && colon < close) \r
+ {\r
+ String fileStr = s.substring(open + 1, colon);\r
+ if (fileStr.endsWith(".js")) {\r
+ String lineStr = s.substring(colon + 1, close);\r
+ try {\r
+ linep[0] = Integer.parseInt(lineStr);\r
+ return fileStr;\r
+ }\r
+ catch (NumberFormatException e) {\r
+ // fall through\r
+ }\r
+ }\r
+ open = close = colon = -1;\r
+ }\r
+ }\r
+\r
+ return null;\r
+ }\r
+\r
+ RegExpProxy getRegExpProxy() {\r
+ if (regExpProxy == null) {\r
+ try {\r
+ Class c = Class.forName(\r
+ "org.mozilla.javascript.regexp.RegExpImpl");\r
+ regExpProxy = (RegExpProxy) c.newInstance();\r
+ return regExpProxy;\r
+ } catch (ClassNotFoundException e) {\r
+ } catch (InstantiationException e) {\r
+ } catch (IllegalAccessException e) {\r
+ }\r
+ }\r
+ return regExpProxy;\r
+ }\r
+\r
+ private void newArrayHelper(Scriptable scope, Scriptable array) {\r
+ array.setParentScope(scope);\r
+ Object ctor = ScriptRuntime.getTopLevelProp(scope, "Array");\r
+ if (ctor != null && ctor instanceof Scriptable) {\r
+ Scriptable s = (Scriptable) ctor;\r
+ array.setPrototype((Scriptable) s.get("prototype", s));\r
+ }\r
+ }\r
+ \r
+ final boolean isVersionECMA1() {\r
+ return version == VERSION_DEFAULT || version >= VERSION_1_3;\r
+ }\r
+\r
+ /**\r
+ * Get the security context from the given class.\r
+ * <p>\r
+ * When some form of security check needs to be done, the class context\r
+ * must retrieved from the security manager to determine what class is\r
+ * requesting some form of privileged access. \r
+ * @since 1.4 release 2\r
+ */\r
+ Object getSecurityDomainFromClass(Class cl) {\r
+ if (cl == Interpreter.class)\r
+ return interpreterSecurityDomain;\r
+ return securitySupport.getSecurityDomain(cl);\r
+ }\r
+ \r
+ SecuritySupport getSecuritySupport() {\r
+ return securitySupport;\r
+ }\r
+ \r
+ Object getSecurityDomainForStackDepth(int depth) {\r
+ Object result = null;\r
+ if (securitySupport != null) {\r
+ Class[] classes = securitySupport.getClassContext();\r
+ if (classes != null) {\r
+ if (depth != -1) {\r
+ int depth1 = depth + 1;\r
+ result = getSecurityDomainFromClass(classes[depth1]);\r
+ } else {\r
+ for (int i=1; i < classes.length; i++) {\r
+ result = getSecurityDomainFromClass(classes[i]);\r
+ if (result != null)\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ if (result != null)\r
+ return result;\r
+ if (requireSecurityDomain) \r
+ checkSecurityDomainRequired();\r
+ return null;\r
+ }\r
+\r
+ private static boolean requireSecurityDomain = false;\r
+ private static boolean resourceMissing = false;\r
+\r
+ final static String securityResourceName = "org.mozilla.javascript.resources.Security";\r
+ \r
+ final public static void checkSecurityDomainRequired() { }\r
+\r
+ public boolean isGeneratingDebugChanged() {\r
+ return generatingDebugChanged;\r
+ }\r
+ \r
+\r
+ /**\r
+ * Add a name to the list of names forcing the creation of real\r
+ * activation objects for functions.\r
+ *\r
+ * @param name the name of the object to add to the list\r
+ */\r
+ public void addActivationName(String name) {\r
+ if (activationNames == null) \r
+ activationNames = new Hashtable(5);\r
+ activationNames.put(name, name);\r
+ }\r
+\r
+ /**\r
+ * Check whether the name is in the list of names of objects\r
+ * forcing the creation of activation objects.\r
+ *\r
+ * @param name the name of the object to test\r
+ *\r
+ * @return true if an function activation object is needed.\r
+ */\r
+ public boolean isActivationNeeded(String name) {\r
+ if ("arguments".equals(name))\r
+ return true;\r
+ return activationNames != null && activationNames.containsKey(name);\r
+ }\r
+\r
+ /**\r
+ * Remove a name from the list of names forcing the creation of real\r
+ * activation objects for functions.\r
+ *\r
+ * @param name the name of the object to remove from the list\r
+ */\r
+ public void removeActivationName(String name) {\r
+ if (activationNames != null)\r
+ activationNames.remove(name);\r
+ }\r
+\r
+\r
+ static final boolean useJSObject = false;\r
+\r
+ /** \r
+ * The activation of the currently executing function or script. \r
+ */\r
+ NativeCall currentActivation;\r
+\r
+ // for Objects, Arrays to tag themselves as being printed out,\r
+ // so they don't print themselves out recursively.\r
+ Hashtable iterating;\r
+ \r
+ Object interpreterSecurityDomain;\r
+\r
+ int version;\r
+ int errorCount;\r
+ static boolean isCachingEnabled = true;\r
+ \r
+ private SecuritySupport securitySupport;\r
+ private ErrorReporter errorReporter;\r
+ private Thread currentThread;\r
+ private static Hashtable threadContexts = new Hashtable(11);\r
+ private RegExpProxy regExpProxy;\r
+ private Locale locale;\r
+ private boolean generatingDebug;\r
+ private boolean generatingDebugChanged;\r
+ private boolean generatingSource=true;\r
+ private boolean compileFunctionsWithDynamicScopeFlag;\r
+ private int optimizationLevel;\r
+ WrapHandler wrapHandler;\r
+ Debugger debugger;\r
+ DebuggableEngine debuggableEngine;\r
+ boolean inLineStepMode;\r
+ java.util.Stack frameStack; \r
+ private int enterCount;\r
+ private Object[] listeners;\r
+ private Hashtable hashtable;\r
+\r
+ /**\r
+ * This is the list of names of objects forcing the creation of\r
+ * function activation records.\r
+ */\r
+ private Hashtable activationNames;\r
+\r
+ // Private lock for static fields to avoid a possibility of denial\r
+ // of service via synchronized (Context.class) { while (true) {} }\r
+ private static final Object staticDataLock = new Object();\r
+ private static Object[] contextListeners;\r
+ public Function currentFunction;\r
+ Vector arrayCache = new Vector(10);\r
+\r
+ // For the interpreter to indicate line/source for error reports.\r
+ public int interpreterLine;\r
+ public String interpreterSourceFile;\r
+\r
+ public int stackDepth = 0;\r
+\r
+ // For instruction counting (interpreter only)\r
+ int instructionCount;\r
+ int instructionThreshold;\r
+}\r
--- /dev/null
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-\r
+ *\r
+ * The contents of this file are subject to the Netscape Public\r
+ * License Version 1.1 (the "License"); you may not use this file\r
+ * except in compliance with the License. You may obtain a copy of\r
+ * the License at http://www.mozilla.org/NPL/\r
+ *\r
+ * Software distributed under the License is distributed on an "AS\r
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr\r
+ * implied. See the License for the specific language governing\r
+ * rights and limitations under the License.\r
+ *\r
+ * The Original Code is Rhino code, released\r
+ * May 6, 1999.\r
+ *\r
+ * The Initial Developer of the Original Code is Netscape\r
+ * Communications Corporation. Portions created by Netscape are\r
+ * Copyright (C) 1997-2000 Netscape Communications Corporation. All\r
+ * Rights Reserved.\r
+ *\r
+ * Contributor(s): \r
+ * Norris Boyd\r
+ *\r
+ * Alternatively, the contents of this file may be used under the\r
+ * terms of the GNU Public License (the "GPL"), in which case the\r
+ * provisions of the GPL are applicable instead of those above.\r
+ * If you wish to allow use of your version of this file only\r
+ * under the terms of the GPL and not to allow others to use your\r
+ * version of this file under the NPL, indicate your decision by\r
+ * deleting the provisions above and replace them with the notice\r
+ * and other provisions required by the GPL. If you do not delete\r
+ * the provisions above, a recipient may use your version of this\r
+ * file under either the NPL or the GPL.\r
+ */\r
+\r
+// API class\r
+\r
+package org.mozilla.javascript;\r
+\r
+/**\r
+ * Embeddings that wish to \r
+ * @see org.mozilla.javascript.Context#addContextListener\r
+ */\r
+public interface ContextListener {\r
+\r
+ public void contextCreated(Context cx);\r
+ \r
+ public void contextEntered(Context cx);\r
+ \r
+ public void contextExited(Context cx);\r
+ \r
+ public void contextReleased(Context cx);\r
+}\r
--- /dev/null
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-\r
+ *\r
+ * The contents of this file are subject to the Netscape Public\r
+ * License Version 1.1 (the "License"); you may not use this file\r
+ * except in compliance with the License. You may obtain a copy of\r
+ * the License at http://www.mozilla.org/NPL/\r
+ *\r
+ * Software distributed under the License is distributed on an "AS\r
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr\r
+ * implied. See the License for the specific language governing\r
+ * rights and limitations under the License.\r
+ *\r
+ * The Original Code is Rhino code, released\r
+ * May 6, 1999.\r
+ *\r
+ * The Initial Developer of the Original Code is Netscape\r
+ * Communications Corporation. Portions created by Netscape are\r
+ * Copyright (C) 1997-1999 Netscape Communications Corporation. All\r
+ * Rights Reserved.\r
+ *\r
+ * Contributor(s):\r
+ * Waldemar Horwat\r
+ * Roger Lawrence\r
+ *\r
+ * Alternatively, the contents of this file may be used under the\r
+ * terms of the GNU Public License (the "GPL"), in which case the\r
+ * provisions of the GPL are applicable instead of those above.\r
+ * If you wish to allow use of your version of this file only\r
+ * under the terms of the GPL and not to allow others to use your\r
+ * version of this file under the NPL, indicate your decision by\r
+ * deleting the provisions above and replace them with the notice\r
+ * and other provisions required by the GPL. If you do not delete\r
+ * the provisions above, a recipient may use your version of this\r
+ * file under either the NPL or the GPL.\r
+ */\r
+\r
+package org.mozilla.javascript;\r
+\r
+import java.math.BigInteger;\r
+\r
+class DToA {\r
+\r
+\r
+/* "-0.0000...(1073 zeros after decimal point)...0001\0" is the longest string that we could produce,\r
+ * which occurs when printing -5e-324 in binary. We could compute a better estimate of the size of\r
+ * the output string and malloc fewer bytes depending on d and base, but why bother? */\r
+\r
+ static final int DTOBASESTR_BUFFER_SIZE = 1078;\r
+\r
+ static char BASEDIGIT(int digit) {\r
+ return (char)((digit >= 10) ? 'a' - 10 + digit : '0' + digit);\r
+ }\r
+ \r
+ static final int\r
+ DTOSTR_STANDARD = 0, /* Either fixed or exponential format; round-trip */\r
+ DTOSTR_STANDARD_EXPONENTIAL = 1, /* Always exponential format; round-trip */\r
+ DTOSTR_FIXED = 2, /* Round to <precision> digits after the decimal point; exponential if number is large */\r
+ DTOSTR_EXPONENTIAL = 3, /* Always exponential format; <precision> significant digits */\r
+ DTOSTR_PRECISION = 4; /* Either fixed or exponential format; <precision> significant digits */\r
+ \r
+\r
+ static final int Frac_mask = 0xfffff;\r
+ static final int Exp_shift = 20;\r
+ static final int Exp_msk1 = 0x100000;\r
+ static final int Bias = 1023;\r
+ static final int P = 53;\r
+\r
+ static final int Exp_shift1 = 20;\r
+ static final int Exp_mask = 0x7ff00000;\r
+ static final int Bndry_mask = 0xfffff;\r
+ static final int Log2P = 1;\r
+\r
+ static final int Sign_bit = 0x80000000;\r
+ static final int Exp_11 = 0x3ff00000;\r
+ static final int Ten_pmax = 22;\r
+ static final int Quick_max = 14;\r
+ static final int Bletch = 0x10;\r
+ static final int Frac_mask1 = 0xfffff;\r
+ static final int Int_max = 14;\r
+ static final int n_bigtens = 5;\r
+\r
+ \r
+ static final double tens[] = {\r
+ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,\r
+ 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,\r
+ 1e20, 1e21, 1e22\r
+ };\r
+ \r
+ static final double bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };\r
+\r
+ static int lo0bits(int y)\r
+ {\r
+ int k;\r
+ int x = y;\r
+\r
+ if ((x & 7) != 0) {\r
+ if ((x & 1) != 0)\r
+ return 0;\r
+ if ((x & 2) != 0) {\r
+ return 1;\r
+ }\r
+ return 2;\r
+ }\r
+ k = 0;\r
+ if ((x & 0xffff) == 0) {\r
+ k = 16;\r
+ x >>>= 16;\r
+ }\r
+ if ((x & 0xff) == 0) {\r
+ k += 8;\r
+ x >>>= 8;\r
+ }\r
+ if ((x & 0xf) == 0) {\r
+ k += 4;\r
+ x >>>= 4;\r
+ }\r
+ if ((x & 0x3) == 0) {\r
+ k += 2;\r
+ x >>>= 2;\r
+ }\r
+ if ((x & 1) == 0) {\r
+ k++;\r
+ x >>>= 1;\r
+ if ((x & 1) == 0)\r
+ return 32;\r
+ }\r
+ return k;\r
+ }\r
+\r
+ /* Return the number (0 through 32) of most significant zero bits in x. */\r
+ static int hi0bits(int x)\r
+ {\r
+ int k = 0;\r
+\r
+ if ((x & 0xffff0000) == 0) {\r
+ k = 16;\r
+ x <<= 16;\r
+ }\r
+ if ((x & 0xff000000) == 0) {\r
+ k += 8;\r
+ x <<= 8;\r
+ }\r
+ if ((x & 0xf0000000) == 0) {\r
+ k += 4;\r
+ x <<= 4;\r
+ }\r
+ if ((x & 0xc0000000) == 0) {\r
+ k += 2;\r
+ x <<= 2;\r
+ }\r
+ if ((x & 0x80000000) == 0) {\r
+ k++;\r
+ if ((x & 0x40000000) == 0)\r
+ return 32;\r
+ }\r
+ return k;\r
+ }\r
+\r
+ static void stuffBits(byte bits[], int offset, int val)\r
+ {\r
+ bits[offset] = (byte)(val >> 24);\r
+ bits[offset + 1] = (byte)(val >> 16);\r
+ bits[offset + 2] = (byte)(val >> 8);\r
+ bits[offset + 3] = (byte)(val);\r
+ }\r
+\r
+ /* Convert d into the form b*2^e, where b is an odd integer. b is the returned\r
+ * Bigint and e is the returned binary exponent. Return the number of significant\r
+ * bits in b in bits. d must be finite and nonzero. */\r
+ static BigInteger d2b(double d, int[] e, int[] bits)\r
+ {\r
+ byte dbl_bits[];\r
+ int i, k, y, z, de;\r
+ long dBits = Double.doubleToLongBits(d);\r
+ int d0 = (int)(dBits >>> 32);\r
+ int d1 = (int)(dBits);\r
+\r
+ z = d0 & Frac_mask;\r
+ d0 &= 0x7fffffff; /* clear sign bit, which we ignore */\r
+\r
+ if ((de = (int)(d0 >>> Exp_shift)) != 0)\r
+ z |= Exp_msk1;\r
+\r
+ if ((y = d1) != 0) {\r
+ dbl_bits = new byte[8];\r
+ k = lo0bits(y);\r
+ y >>>= k;\r
+ if (k != 0) {\r
+ stuffBits(dbl_bits, 4, y | z << (32 - k));\r
+ z >>= k;\r
+ }\r
+ else\r
+ stuffBits(dbl_bits, 4, y);\r
+ stuffBits(dbl_bits, 0, z);\r
+ i = (z != 0) ? 2 : 1;\r
+ }\r
+ else {\r
+ // JS_ASSERT(z);\r
+ dbl_bits = new byte[4];\r
+ k = lo0bits(z);\r
+ z >>>= k;\r
+ stuffBits(dbl_bits, 0, z);\r
+ k += 32;\r
+ i = 1;\r
+ }\r
+ if (de != 0) {\r
+ e[0] = de - Bias - (P-1) + k;\r
+ bits[0] = P - k;\r
+ }\r
+ else {\r
+ e[0] = de - Bias - (P-1) + 1 + k;\r
+ bits[0] = 32*i - hi0bits(z);\r
+ }\r
+ return new BigInteger(dbl_bits);\r
+ }\r
+\r
+ public static String JS_dtobasestr(int base, double d)\r
+ {\r
+ char[] buffer; /* The output string */\r
+ int p; /* index to current position in the buffer */\r
+ int pInt; /* index to the beginning of the integer part of the string */\r
+\r
+ int q;\r
+ int digit;\r
+ double di; /* d truncated to an integer */\r
+ double df; /* The fractional part of d */\r
+\r
+// JS_ASSERT(base >= 2 && base <= 36);\r
+\r
+ buffer = new char[DTOBASESTR_BUFFER_SIZE];\r
+\r
+ p = 0;\r
+ if (d < 0.0) {\r
+ buffer[p++] = '-';\r
+ d = -d;\r
+ }\r
+\r
+ /* Check for Infinity and NaN */\r
+ if (Double.isNaN(d))\r
+ return "NaN";\r
+ else\r
+ if (Double.isInfinite(d))\r
+ return "Infinity";\r
+\r
+ /* Output the integer part of d with the digits in reverse order. */\r
+ pInt = p;\r
+ di = (int)d;\r
+ BigInteger b = BigInteger.valueOf((int)di);\r
+ String intDigits = b.toString(base);\r
+ intDigits.getChars(0, intDigits.length(), buffer, p);\r
+ p += intDigits.length();\r
+\r
+ df = d - di;\r
+ if (df != 0.0) {\r
+ /* We have a fraction. */\r
+ buffer[p++] = '.';\r
+\r
+ long dBits = Double.doubleToLongBits(d);\r
+ int word0 = (int)(dBits >> 32);\r
+ int word1 = (int)(dBits);\r
+\r
+ int[] e = new int[1];\r
+ int[] bbits = new int[1];\r
+ \r
+ b = d2b(df, e, bbits);\r
+// JS_ASSERT(e < 0);\r
+ /* At this point df = b * 2^e. e must be less than zero because 0 < df < 1. */\r
+\r
+ int s2 = -(word0 >>> Exp_shift1 & Exp_mask >> Exp_shift1);\r
+ if (s2 == 0)\r
+ s2 = -1;\r
+ s2 += Bias + P;\r
+ /* 1/2^s2 = (nextDouble(d) - d)/2 */\r
+// JS_ASSERT(-s2 < e);\r
+ BigInteger mlo = BigInteger.valueOf(1);\r
+ BigInteger mhi = mlo;\r
+ if ((word1 == 0) && ((word0 & Bndry_mask) == 0)\r
+ && ((word0 & (Exp_mask & Exp_mask << 1)) != 0)) {\r
+ /* The special case. Here we want to be within a quarter of the last input\r
+ significant digit instead of one half of it when the output string's value is less than d. */\r
+ s2 += Log2P;\r
+ mhi = BigInteger.valueOf(1<<Log2P);\r
+ }\r
+\r
+ b = b.shiftLeft(e[0] + s2);\r
+ BigInteger s = BigInteger.valueOf(1);\r
+ s = s.shiftLeft(s2);\r
+ /* At this point we have the following:\r
+ * s = 2^s2;\r
+ * 1 > df = b/2^s2 > 0;\r
+ * (d - prevDouble(d))/2 = mlo/2^s2;\r
+ * (nextDouble(d) - d)/2 = mhi/2^s2. */\r
+ BigInteger bigBase = BigInteger.valueOf(base);\r
+\r
+ boolean done = false;\r
+ do {\r
+ b = b.multiply(bigBase);\r
+ BigInteger[] divResult = b.divideAndRemainder(s);\r
+ b = divResult[1];\r
+ digit = (char)(divResult[0].intValue());\r
+ if (mlo == mhi)\r
+ mlo = mhi = mlo.multiply(bigBase);\r
+ else {\r
+ mlo = mlo.multiply(bigBase);\r
+ mhi = mhi.multiply(bigBase);\r
+ }\r
+\r
+ /* Do we yet have the shortest string that will round to d? */\r
+ int j = b.compareTo(mlo);\r
+ /* j is b/2^s2 compared with mlo/2^s2. */\r
+ BigInteger delta = s.subtract(mhi);\r
+ int j1 = (delta.signum() <= 0) ? 1 : b.compareTo(delta);\r
+ /* j1 is b/2^s2 compared with 1 - mhi/2^s2. */\r
+ if (j1 == 0 && ((word1 & 1) == 0)) {\r
+ if (j > 0)\r
+ digit++;\r
+ done = true;\r
+ } else\r
+ if (j < 0 || (j == 0 && ((word1 & 1) == 0))) {\r
+ if (j1 > 0) {\r
+ /* Either dig or dig+1 would work here as the least significant digit.\r
+ Use whichever would produce an output value closer to d. */\r
+ b = b.shiftLeft(1);\r
+ j1 = b.compareTo(s);\r
+ if (j1 > 0) /* The even test (|| (j1 == 0 && (digit & 1))) is not here because it messes up odd base output\r
+ * such as 3.5 in base 3. */\r
+ digit++;\r
+ }\r
+ done = true;\r
+ } else if (j1 > 0) {\r
+ digit++;\r
+ done = true;\r
+ }\r
+// JS_ASSERT(digit < (uint32)base);\r
+ buffer[p++] = BASEDIGIT(digit);\r
+ } while (!done);\r
+ }\r
+\r
+ return new String(buffer, 0, p);\r
+ }\r
+\r
+ /* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.\r
+ *\r
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by\r
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 92-101].\r
+ *\r
+ * Modifications:\r
+ * 1. Rather than iterating, we use a simple numeric overestimate\r
+ * to determine k = floor(log10(d)). We scale relevant\r
+ * quantities using O(log2(k)) rather than O(k) multiplications.\r
+ * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't\r
+ * try to generate digits strictly left to right. Instead, we\r
+ * compute with fewer bits and propagate the carry if necessary\r
+ * when rounding the final digit up. This is often faster.\r
+ * 3. Under the assumption that input will be rounded nearest,\r
+ * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.\r
+ * That is, we allow equality in stopping tests when the\r
+ * round-nearest rule will give the same floating-point value\r
+ * as would satisfaction of the stopping test with strict\r
+ * inequality.\r
+ * 4. We remove common factors of powers of 2 from relevant\r
+ * quantities.\r
+ * 5. When converting floating-point integers less than 1e16,\r
+ * we use floating-point arithmetic rather than resorting\r
+ * to multiple-precision integers.\r
+ * 6. When asked to produce fewer than 15 digits, we first try\r
+ * to get by with floating-point arithmetic; we resort to\r
+ * multiple-precision integer arithmetic only if we cannot\r
+ * guarantee that the floating-point calculation has given\r
+ * the correctly rounded result. For k requested digits and\r
+ * "uniformly" distributed input, the probability is\r
+ * something like 10^(k-15) that we must resort to the Long\r
+ * calculation.\r
+ */\r
+\r
+ static int word0(double d)\r
+ {\r
+ long dBits = Double.doubleToLongBits(d);\r
+ return (int)(dBits >> 32);\r
+ }\r
+ \r
+ static double setWord0(double d, int i)\r
+ {\r
+ long dBits = Double.doubleToLongBits(d);\r
+ dBits = ((long)i << 32) | (dBits & 0x0FFFFFFFFL);\r
+ return Double.longBitsToDouble(dBits);\r
+ }\r
+ \r
+ static int word1(double d)\r
+ {\r
+ long dBits = Double.doubleToLongBits(d);\r
+ return (int)(dBits);\r
+ }\r
+ \r
+ /* Return b * 5^k. k must be nonnegative. */\r
+ // XXXX the C version built a cache of these\r
+ static BigInteger pow5mult(BigInteger b, int k)\r
+ {\r
+ return b.multiply(BigInteger.valueOf(5).pow(k));\r
+ }\r
+ \r
+ static boolean roundOff(StringBuffer buf)\r
+ {\r
+ char lastCh;\r
+ while ((lastCh = buf.charAt(buf.length() - 1)) == '9') {\r
+ buf.setLength(buf.length() - 1);\r
+ if (buf.length() == 0) {\r
+ return true;\r
+ }\r
+ }\r
+ buf.append((char)(lastCh + 1));\r
+ return false;\r
+ }\r
+ \r
+ /* Always emits at least one digit. */\r
+ /* If biasUp is set, then rounding in modes 2 and 3 will round away from zero\r
+ * when the number is exactly halfway between two representable values. For example, \r
+ * rounding 2.5 to zero digits after the decimal point will return 3 and not 2.\r
+ * 2.49 will still round to 2, and 2.51 will still round to 3. */\r
+ /* bufsize should be at least 20 for modes 0 and 1. For the other modes,\r
+ * bufsize should be two greater than the maximum number of output characters expected. */\r
+ static int\r
+ JS_dtoa(double d, int mode, boolean biasUp, int ndigits,\r
+ boolean[] sign, StringBuffer buf)\r
+ {\r
+ /* Arguments ndigits, decpt, sign are similar to those\r
+ of ecvt and fcvt; trailing zeros are suppressed from\r
+ the returned string. If not null, *rve is set to point\r
+ to the end of the return value. If d is +-Infinity or NaN,\r
+ then *decpt is set to 9999.\r
+\r
+ mode:\r
+ 0 ==> shortest string that yields d when read in\r
+ and rounded to nearest.\r
+ 1 ==> like 0, but with Steele & White stopping rule;\r
+ e.g. with IEEE P754 arithmetic , mode 0 gives\r
+ 1e23 whereas mode 1 gives 9.999999999999999e22.\r
+ 2 ==> max(1,ndigits) significant digits. This gives a\r
+ return value similar to that of ecvt, except\r
+ that trailing zeros are suppressed.\r
+ 3 ==> through ndigits past the decimal point. This\r
+ gives a return value similar to that from fcvt,\r
+ except that trailing zeros are suppressed, and\r
+ ndigits can be negative.\r
+ 4-9 should give the same return values as 2-3, i.e.,\r
+ 4 <= mode <= 9 ==> same return as mode\r
+ 2 + (mode & 1). These modes are mainly for\r
+ debugging; often they run slower but sometimes\r
+ faster than modes 2-3.\r
+ 4,5,8,9 ==> left-to-right digit generation.\r
+ 6-9 ==> don't try fast floating-point estimate\r
+ (if applicable).\r
+\r
+ Values of mode other than 0-9 are treated as mode 0.\r
+\r
+ Sufficient space is allocated to the return value\r
+ to hold the suppressed trailing zeros.\r
+ */\r
+\r
+ int b2, b5, i, ieps, ilim, ilim0, ilim1,\r
+ j, j1, k, k0, m2, m5, s2, s5;\r
+ char dig;\r
+ long L;\r
+ long x;\r
+ BigInteger b, b1, delta, mlo, mhi, S;\r
+ int[] be = new int[1];\r
+ int[] bbits = new int[1];\r
+ double d2, ds, eps;\r
+ boolean spec_case, denorm, k_check, try_quick, leftright;\r
+\r
+ if ((word0(d) & Sign_bit) != 0) {\r
+ /* set sign for everything, including 0's and NaNs */\r
+ sign[0] = true;\r
+ // word0(d) &= ~Sign_bit; /* clear sign bit */\r
+ d = setWord0(d, word0(d) & ~Sign_bit);\r
+ }\r
+ else\r
+ sign[0] = false;\r
+\r
+ if ((word0(d) & Exp_mask) == Exp_mask) {\r
+ /* Infinity or NaN */\r
+ buf.append(((word1(d) == 0) && ((word0(d) & Frac_mask) == 0)) ? "Infinity" : "NaN");\r
+ return 9999;\r
+ }\r
+ if (d == 0) {\r
+// no_digits:\r
+ buf.setLength(0);\r
+ buf.append('0'); /* copy "0" to buffer */\r
+ return 1;\r
+ }\r
+ \r
+ b = d2b(d, be, bbits);\r
+ if ((i = (int)(word0(d) >>> Exp_shift1 & (Exp_mask>>Exp_shift1))) != 0) {\r
+ d2 = setWord0(d, (word0(d) & Frac_mask1) | Exp_11);\r
+ /* log(x) ~=~ log(1.5) + (x-1.5)/1.5\r
+ * log10(x) = log(x) / log(10)\r
+ * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))\r
+ * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2)\r
+ *\r
+ * This suggests computing an approximation k to log10(d) by\r
+ *\r
+ * k = (i - Bias)*0.301029995663981\r
+ * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );\r
+ *\r
+ * We want k to be too large rather than too small.\r
+ * The error in the first-order Taylor series approximation\r
+ * is in our favor, so we just round up the constant enough\r
+ * to compensate for any error in the multiplication of\r
+ * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,\r
+ * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,\r
+ * adding 1e-13 to the constant term more than suffices.\r
+ * Hence we adjust the constant term to 0.1760912590558.\r
+ * (We could get a more accurate k by invoking log10,\r
+ * but this is probably not worthwhile.)\r
+ */\r
+ i -= Bias;\r
+ denorm = false;\r
+ }\r
+ else {\r
+ /* d is denormalized */\r
+ i = bbits[0] + be[0] + (Bias + (P-1) - 1);\r
+ x = (i > 32) ? word0(d) << (64 - i) | word1(d) >>> (i - 32) : word1(d) << (32 - i);\r
+// d2 = x;\r
+// word0(d2) -= 31*Exp_msk1; /* adjust exponent */\r
+ d2 = setWord0(x, word0(x) - 31*Exp_msk1);\r
+ i -= (Bias + (P-1) - 1) + 1;\r
+ denorm = true;\r
+ }\r
+ /* At this point d = f*2^i, where 1 <= f < 2. d2 is an approximation of f. */\r
+ ds = (d2-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;\r
+ k = (int)ds;\r
+ if (ds < 0.0 && ds != k)\r
+ k--; /* want k = floor(ds) */\r
+ k_check = true;\r
+ if (k >= 0 && k <= Ten_pmax) {\r
+ if (d < tens[k])\r
+ k--;\r
+ k_check = false;\r
+ }\r
+ /* At this point floor(log10(d)) <= k <= floor(log10(d))+1.\r
+ If k_check is zero, we're guaranteed that k = floor(log10(d)). */\r
+ j = bbits[0] - i - 1;\r
+ /* At this point d = b/2^j, where b is an odd integer. */\r
+ if (j >= 0) {\r
+ b2 = 0;\r
+ s2 = j;\r
+ }\r
+ else {\r
+ b2 = -j;\r
+ s2 = 0;\r
+ }\r
+ if (k >= 0) {\r
+ b5 = 0;\r
+ s5 = k;\r
+ s2 += k;\r
+ }\r
+ else {\r
+ b2 -= k;\r
+ b5 = -k;\r
+ s5 = 0;\r
+ }\r
+ /* At this point d/10^k = (b * 2^b2 * 5^b5) / (2^s2 * 5^s5), where b is an odd integer,\r
+ b2 >= 0, b5 >= 0, s2 >= 0, and s5 >= 0. */\r
+ if (mode < 0 || mode > 9)\r
+ mode = 0;\r
+ try_quick = true;\r
+ if (mode > 5) {\r
+ mode -= 4;\r
+ try_quick = false;\r
+ }\r
+ leftright = true;\r
+ ilim = ilim1 = 0;\r
+ switch(mode) {\r
+ case 0:\r
+ case 1:\r
+ ilim = ilim1 = -1;\r
+ i = 18;\r
+ ndigits = 0;\r
+ break;\r
+ case 2:\r
+ leftright = false;\r
+ /* no break */\r
+ case 4:\r
+ if (ndigits <= 0)\r
+ ndigits = 1;\r
+ ilim = ilim1 = i = ndigits;\r
+ break;\r
+ case 3:\r
+ leftright = false;\r
+ /* no break */\r
+ case 5:\r
+ i = ndigits + k + 1;\r
+ ilim = i;\r
+ ilim1 = i - 1;\r
+ if (i <= 0)\r
+ i = 1;\r
+ }\r
+ /* ilim is the maximum number of significant digits we want, based on k and ndigits. */\r
+ /* ilim1 is the maximum number of significant digits we want, based on k and ndigits,\r
+ when it turns out that k was computed too high by one. */\r
+\r
+ boolean fast_failed = false;\r
+ if (ilim >= 0 && ilim <= Quick_max && try_quick) {\r
+\r
+ /* Try to get by with floating-point arithmetic. */\r
+\r
+ i = 0;\r
+ d2 = d;\r
+ k0 = k;\r
+ ilim0 = ilim;\r
+ ieps = 2; /* conservative */\r
+ /* Divide d by 10^k, keeping track of the roundoff error and avoiding overflows. */\r
+ if (k > 0) {\r
+ ds = tens[k&0xf];\r
+ j = k >> 4;\r
+ if ((j & Bletch) != 0) {\r
+ /* prevent overflows */\r
+ j &= Bletch - 1;\r
+ d /= bigtens[n_bigtens-1];\r
+ ieps++;\r
+ }\r
+ for(; (j != 0); j >>= 1, i++)\r
+ if ((j & 1) != 0) {\r
+ ieps++;\r
+ ds *= bigtens[i];\r
+ }\r
+ d /= ds;\r
+ }\r
+ else if ((j1 = -k) != 0) {\r
+ d *= tens[j1 & 0xf];\r
+ for(j = j1 >> 4; (j != 0); j >>= 1, i++)\r
+ if ((j & 1) != 0) {\r
+ ieps++;\r
+ d *= bigtens[i];\r
+ }\r
+ }\r
+ /* Check that k was computed correctly. */\r
+ if (k_check && d < 1.0 && ilim > 0) {\r
+ if (ilim1 <= 0)\r
+ fast_failed = true;\r
+ else {\r
+ ilim = ilim1;\r
+ k--;\r
+ d *= 10.;\r
+ ieps++;\r
+ }\r
+ }\r
+ /* eps bounds the cumulative error. */\r
+// eps = ieps*d + 7.0;\r
+// word0(eps) -= (P-1)*Exp_msk1;\r
+ eps = ieps*d + 7.0;\r
+ eps = setWord0(eps, word0(eps) - (P-1)*Exp_msk1);\r
+ if (ilim == 0) {\r
+ S = mhi = null;\r
+ d -= 5.0;\r
+ if (d > eps) {\r
+ buf.append('1');\r
+ k++;\r
+ return k + 1;\r
+ }\r
+ if (d < -eps) {\r
+ buf.setLength(0);\r
+ buf.append('0'); /* copy "0" to buffer */\r
+ return 1;\r
+ }\r
+ fast_failed = true;\r
+ }\r
+ if (!fast_failed) {\r
+ fast_failed = true;\r
+ if (leftright) {\r
+ /* Use Steele & White method of only\r
+ * generating digits needed.\r
+ */\r
+ eps = 0.5/tens[ilim-1] - eps;\r
+ for(i = 0;;) {\r
+ L = (long)d;\r
+ d -= L;\r
+ buf.append((char)('0' + L));\r
+ if (d < eps) {\r
+ return k + 1;\r
+ }\r
+ if (1.0 - d < eps) {\r
+// goto bump_up;\r
+ char lastCh;\r
+ while (true) {\r
+ lastCh = buf.charAt(buf.length() - 1);\r
+ buf.setLength(buf.length() - 1);\r
+ if (lastCh != '9') break;\r
+ if (buf.length() == 0) {\r
+ k++;\r
+ lastCh = '0';\r
+ break;\r
+ }\r
+ } \r
+ buf.append((char)(lastCh + 1));\r
+ return k + 1;\r
+ }\r
+ if (++i >= ilim)\r
+ break;\r
+ eps *= 10.0;\r
+ d *= 10.0;\r
+ }\r
+ }\r
+ else {\r
+ /* Generate ilim digits, then fix them up. */\r
+ eps *= tens[ilim-1];\r
+ for(i = 1;; i++, d *= 10.0) {\r
+ L = (long)d;\r
+ d -= L;\r
+ buf.append((char)('0' + L));\r
+ if (i == ilim) {\r
+ if (d > 0.5 + eps) {\r
+// goto bump_up;\r
+ char lastCh;\r
+ while (true) {\r
+ lastCh = buf.charAt(buf.length() - 1);\r
+ buf.setLength(buf.length() - 1);\r
+ if (lastCh != '9') break;\r
+ if (buf.length() == 0) {\r
+ k++;\r
+ lastCh = '0';\r
+ break;\r
+ }\r
+ } \r
+ buf.append((char)(lastCh + 1));\r
+ return k + 1;\r
+ }\r
+ else\r
+ if (d < 0.5 - eps) {\r
+ while (buf.charAt(buf.length() - 1) == '0')\r
+ buf.setLength(buf.length() - 1);\r
+// while(*--s == '0') ;\r
+// s++;\r
+ return k + 1;\r
+ }\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ if (fast_failed) {\r
+ buf.setLength(0);\r
+ d = d2;\r
+ k = k0;\r
+ ilim = ilim0;\r
+ }\r
+ }\r
+\r
+ /* Do we have a "small" integer? */\r
+\r
+ if (be[0] >= 0 && k <= Int_max) {\r
+ /* Yes. */\r
+ ds = tens[k];\r
+ if (ndigits < 0 && ilim <= 0) {\r
+ S = mhi = null;\r
+ if (ilim < 0 || d < 5*ds || (!biasUp && d == 5*ds)) {\r
+ buf.setLength(0);\r
+ buf.append('0'); /* copy "0" to buffer */\r
+ return 1;\r
+ }\r
+ buf.append('1');\r
+ k++;\r
+ return k + 1;\r
+ }\r
+ for(i = 1;; i++) {\r
+ L = (long) (d / ds);\r
+ d -= L*ds;\r
+ buf.append((char)('0' + L));\r
+ if (i == ilim) {\r
+ d += d;\r
+ if ((d > ds) || (d == ds && (((L & 1) != 0) || biasUp))) {\r
+// bump_up:\r
+// while(*--s == '9')\r
+// if (s == buf) {\r
+// k++;\r
+// *s = '0';\r
+// break;\r
+// }\r
+// ++*s++;\r
+ char lastCh;\r
+ while (true) {\r
+ lastCh = buf.charAt(buf.length() - 1);\r
+ buf.setLength(buf.length() - 1);\r
+ if (lastCh != '9') break;\r
+ if (buf.length() == 0) {\r
+ k++;\r
+ lastCh = '0';\r
+ break;\r
+ }\r
+ } \r
+ buf.append((char)(lastCh + 1));\r
+ }\r
+ break;\r
+ }\r
+ d *= 10.0;\r
+ if (d == 0)\r
+ break;\r
+ }\r
+ return k + 1;\r
+ }\r
+\r
+ m2 = b2;\r
+ m5 = b5;\r
+ mhi = mlo = null;\r
+ if (leftright) {\r
+ if (mode < 2) {\r
+ i = (denorm) ? be[0] + (Bias + (P-1) - 1 + 1) : 1 + P - bbits[0];\r
+ /* i is 1 plus the number of trailing zero bits in d's significand. Thus,\r
+ (2^m2 * 5^m5) / (2^(s2+i) * 5^s5) = (1/2 lsb of d)/10^k. */\r
+ }\r
+ else {\r
+ j = ilim - 1;\r
+ if (m5 >= j)\r
+ m5 -= j;\r
+ else {\r
+ s5 += j -= m5;\r
+ b5 += j;\r
+ m5 = 0;\r
+ }\r
+ if ((i = ilim) < 0) {\r
+ m2 -= i;\r
+ i = 0;\r
+ }\r
+ /* (2^m2 * 5^m5) / (2^(s2+i) * 5^s5) = (1/2 * 10^(1-ilim))/10^k. */\r
+ }\r
+ b2 += i;\r
+ s2 += i;\r
+ mhi = BigInteger.valueOf(1);\r
+ /* (mhi * 2^m2 * 5^m5) / (2^s2 * 5^s5) = one-half of last printed (when mode >= 2) or\r
+ input (when mode < 2) significant digit, divided by 10^k. */\r
+ }\r
+ /* We still have d/10^k = (b * 2^b2 * 5^b5) / (2^s2 * 5^s5). Reduce common factors in\r
+ b2, m2, and s2 without changing the equalities. */\r
+ if (m2 > 0 && s2 > 0) {\r
+ i = (m2 < s2) ? m2 : s2;\r
+ b2 -= i;\r
+ m2 -= i;\r
+ s2 -= i;\r
+ }\r
+\r
+ /* Fold b5 into b and m5 into mhi. */\r
+ if (b5 > 0) {\r
+ if (leftright) {\r
+ if (m5 > 0) {\r
+ mhi = pow5mult(mhi, m5);\r
+ b1 = mhi.multiply(b);\r
+ b = b1;\r
+ }\r
+ if ((j = b5 - m5) != 0)\r
+ b = pow5mult(b, j);\r
+ }\r
+ else\r
+ b = pow5mult(b, b5);\r
+ }\r
+ /* Now we have d/10^k = (b * 2^b2) / (2^s2 * 5^s5) and\r
+ (mhi * 2^m2) / (2^s2 * 5^s5) = one-half of last printed or input significant digit, divided by 10^k. */\r
+\r
+ S = BigInteger.valueOf(1);\r
+ if (s5 > 0)\r
+ S = pow5mult(S, s5);\r
+ /* Now we have d/10^k = (b * 2^b2) / (S * 2^s2) and\r
+ (mhi * 2^m2) / (S * 2^s2) = one-half of last printed or input significant digit, divided by 10^k. */\r
+\r
+ /* Check for special case that d is a normalized power of 2. */\r
+ spec_case = false;\r
+ if (mode < 2) {\r
+ if ( (word1(d) == 0) && ((word0(d) & Bndry_mask) == 0)\r
+ && ((word0(d) & (Exp_mask & Exp_mask << 1)) != 0)\r
+ ) {\r
+ /* The special case. Here we want to be within a quarter of the last input\r
+ significant digit instead of one half of it when the decimal output string's value is less than d. */\r
+ b2 += Log2P;\r
+ s2 += Log2P;\r
+ spec_case = true;\r
+ }\r
+ }\r
+\r
+ /* Arrange for convenient computation of quotients:\r
+ * shift left if necessary so divisor has 4 leading 0 bits.\r
+ *\r
+ * Perhaps we should just compute leading 28 bits of S once\r
+ * and for all and pass them and a shift to quorem, so it\r
+ * can do shifts and ors to compute the numerator for q.\r
+ */\r
+ byte [] S_bytes = S.toByteArray();\r
+ int S_hiWord = 0;\r
+ for (int idx = 0; idx < 4; idx++) {\r
+ S_hiWord = (S_hiWord << 8);\r
+ if (idx < S_bytes.length)\r
+ S_hiWord |= (S_bytes[idx] & 0xFF);\r
+ } \r
+ if ((i = (((s5 != 0) ? 32 - hi0bits(S_hiWord) : 1) + s2) & 0x1f) != 0)\r
+ i = 32 - i;\r
+ /* i is the number of leading zero bits in the most significant word of S*2^s2. */\r
+ if (i > 4) {\r
+ i -= 4;\r
+ b2 += i;\r
+ m2 += i;\r
+ s2 += i;\r
+ }\r
+ else if (i < 4) {\r
+ i += 28;\r
+ b2 += i;\r
+ m2 += i;\r
+ s2 += i;\r
+ }\r
+ /* Now S*2^s2 has exactly four leading zero bits in its most significant word. */\r
+ if (b2 > 0)\r
+ b = b.shiftLeft(b2);\r
+ if (s2 > 0)\r
+ S = S.shiftLeft(s2);\r
+ /* Now we have d/10^k = b/S and\r
+ (mhi * 2^m2) / S = maximum acceptable error, divided by 10^k. */\r
+ if (k_check) {\r
+ if (b.compareTo(S) < 0) {\r
+ k--;\r
+ b = b.multiply(BigInteger.valueOf(10)); /* we botched the k estimate */\r
+ if (leftright)\r
+ mhi = mhi.multiply(BigInteger.valueOf(10));\r
+ ilim = ilim1;\r
+ }\r
+ }\r
+ /* At this point 1 <= d/10^k = b/S < 10. */\r
+\r
+ if (ilim <= 0 && mode > 2) {\r
+ /* We're doing fixed-mode output and d is less than the minimum nonzero output in this mode.\r
+ Output either zero or the minimum nonzero output depending on which is closer to d. */\r
+ if ((ilim < 0 )\r
+ || ((i = b.compareTo(S = S.multiply(BigInteger.valueOf(5)))) < 0)\r
+ || ((i == 0 && !biasUp))) {\r
+ /* Always emit at least one digit. If the number appears to be zero\r
+ using the current mode, then emit one '0' digit and set decpt to 1. */\r
+ /*no_digits:\r
+ k = -1 - ndigits;\r
+ goto ret; */\r
+ buf.setLength(0);\r
+ buf.append('0'); /* copy "0" to buffer */\r
+ return 1;\r
+// goto no_digits;\r
+ }\r
+// one_digit:\r
+ buf.append('1');\r
+ k++;\r
+ return k + 1;\r
+ }\r
+ if (leftright) {\r
+ if (m2 > 0)\r
+ mhi = mhi.shiftLeft(m2);\r
+\r
+ /* Compute mlo -- check for special case\r
+ * that d is a normalized power of 2.\r
+ */\r
+\r
+ mlo = mhi;\r
+ if (spec_case) {\r
+ mhi = mlo;\r
+ mhi = mhi.shiftLeft(Log2P);\r
+ }\r
+ /* mlo/S = maximum acceptable error, divided by 10^k, if the output is less than d. */\r
+ /* mhi/S = maximum acceptable error, divided by 10^k, if the output is greater than d. */\r
+\r
+ for(i = 1;;i++) { \r
+ BigInteger[] divResult = b.divideAndRemainder(S);\r
+ b = divResult[1]; \r
+ dig = (char)(divResult[0].intValue() + '0');\r
+ /* Do we yet have the shortest decimal string\r
+ * that will round to d?\r
+ */\r
+ j = b.compareTo(mlo);\r
+ /* j is b/S compared with mlo/S. */\r
+ delta = S.subtract(mhi);\r
+ j1 = (delta.signum() <= 0) ? 1 : b.compareTo(delta);\r
+ /* j1 is b/S compared with 1 - mhi/S. */\r
+ if ((j1 == 0) && (mode == 0) && ((word1(d) & 1) == 0)) {\r
+ if (dig == '9') {\r
+ buf.append('9');\r
+ if (roundOff(buf)) {\r
+ k++;\r
+ buf.append('1');\r
+ }\r
+ return k + 1;\r
+// goto round_9_up;\r
+ }\r
+ if (j > 0)\r
+ dig++;\r
+ buf.append(dig);\r
+ return k + 1;\r
+ }\r
+ if ((j < 0) \r
+ || ((j == 0) \r
+ && (mode == 0)\r
+ && ((word1(d) & 1) == 0)\r
+ )) {\r
+ if (j1 > 0) {\r
+ /* Either dig or dig+1 would work here as the least significant decimal digit.\r
+ Use whichever would produce a decimal value closer to d. */\r
+ b = b.shiftLeft(1);\r
+ j1 = b.compareTo(S);\r
+ if (((j1 > 0) || (j1 == 0 && (((dig & 1) == 1) || biasUp)))\r
+ && (dig++ == '9')) {\r
+ buf.append('9');\r
+ if (roundOff(buf)) {\r
+ k++;\r
+ buf.append('1');\r
+ }\r
+ return k + 1;\r
+// goto round_9_up;\r
+ }\r
+ }\r
+ buf.append(dig);\r
+ return k + 1;\r
+ }\r
+ if (j1 > 0) {\r
+ if (dig == '9') { /* possible if i == 1 */\r
+// round_9_up:\r
+// *s++ = '9';\r
+// goto roundoff;\r
+ buf.append('9');\r
+ if (roundOff(buf)) {\r
+ k++;\r
+ buf.append('1');\r
+ } \r
+ return k + 1;\r
+ }\r
+ buf.append((char)(dig + 1));\r
+ return k + 1;\r
+ }\r
+ buf.append(dig);\r
+ if (i == ilim)\r
+ break;\r
+ b = b.multiply(BigInteger.valueOf(10));\r
+ if (mlo == mhi)\r
+ mlo = mhi = mhi.multiply(BigInteger.valueOf(10));\r
+ else {\r
+ mlo = mlo.multiply(BigInteger.valueOf(10));\r
+ mhi = mhi.multiply(BigInteger.valueOf(10));\r
+ }\r
+ }\r
+ }\r
+ else\r
+ for(i = 1;; i++) {\r
+// (char)(dig = quorem(b,S) + '0');\r
+ BigInteger[] divResult = b.divideAndRemainder(S);\r
+ b = divResult[1]; \r
+ dig = (char)(divResult[0].intValue() + '0');\r
+ buf.append(dig);\r
+ if (i >= ilim)\r
+ break;\r
+ b = b.multiply(BigInteger.valueOf(10));\r
+ }\r
+\r
+ /* Round off last digit */\r
+\r
+ b = b.shiftLeft(1);\r
+ j = b.compareTo(S);\r
+ if ((j > 0) || (j == 0 && (((dig & 1) == 1) || biasUp))) {\r
+// roundoff:\r
+// while(*--s == '9')\r
+// if (s == buf) {\r
+// k++;\r
+// *s++ = '1';\r
+// goto ret;\r
+// }\r
+// ++*s++;\r
+ if (roundOff(buf)) {\r
+ k++;\r
+ buf.append('1');\r
+ return k + 1;\r
+ } \r
+ }\r
+ else {\r
+ /* Strip trailing zeros */\r
+ while (buf.charAt(buf.length() - 1) == '0')\r
+ buf.setLength(buf.length() - 1);\r
+// while(*--s == '0') ;\r
+// s++;\r
+ }\r
+// ret:\r
+// Bfree(S);\r
+// if (mhi) {\r
+// if (mlo && mlo != mhi)\r
+// Bfree(mlo);\r
+// Bfree(mhi);\r
+// }\r
+// ret1:\r
+// Bfree(b);\r
+// JS_ASSERT(s < buf + bufsize);\r
+ return k + 1;\r
+ }\r
+\r
+ /* Mapping of JSDToStrMode -> JS_dtoa mode */\r
+ private static final int dtoaModes[] = {\r
+ 0, /* DTOSTR_STANDARD */\r
+ 0, /* DTOSTR_STANDARD_EXPONENTIAL, */\r
+ 3, /* DTOSTR_FIXED, */\r
+ 2, /* DTOSTR_EXPONENTIAL, */\r
+ 2}; /* DTOSTR_PRECISION */\r
+\r
+ static void\r
+ JS_dtostr(StringBuffer buffer, int mode, int precision, double d)\r
+ {\r
+ int decPt; /* Position of decimal point relative to first digit returned by JS_dtoa */\r
+ boolean[] sign = new boolean[1]; /* true if the sign bit was set in d */\r
+ int nDigits; /* Number of significand digits returned by JS_dtoa */\r
+\r
+// JS_ASSERT(bufferSize >= (size_t)(mode <= DTOSTR_STANDARD_EXPONENTIAL ? DTOSTR_STANDARD_BUFFER_SIZE :\r
+// DTOSTR_VARIABLE_BUFFER_SIZE(precision)));\r
+\r
+ if (mode == DTOSTR_FIXED && (d >= 1e21 || d <= -1e21))\r
+ mode = DTOSTR_STANDARD; /* Change mode here rather than below because the buffer may not be large enough to hold a large integer. */\r
+\r
+ decPt = JS_dtoa(d, dtoaModes[mode], mode >= DTOSTR_FIXED, precision, sign, buffer);\r
+ nDigits = buffer.length();\r
+\r
+ /* If Infinity, -Infinity, or NaN, return the string regardless of the mode. */\r
+ if (decPt != 9999) {\r
+ boolean exponentialNotation = false;\r
+ int minNDigits = 0; /* Minimum number of significand digits required by mode and precision */\r
+ int p;\r
+ int q;\r
+\r
+ switch (mode) {\r
+ case DTOSTR_STANDARD:\r
+ if (decPt < -5 || decPt > 21)\r
+ exponentialNotation = true;\r
+ else\r
+ minNDigits = decPt;\r
+ break;\r
+\r
+ case DTOSTR_FIXED:\r
+ if (precision >= 0)\r
+ minNDigits = decPt + precision;\r
+ else\r
+ minNDigits = decPt;\r
+ break;\r
+\r
+ case DTOSTR_EXPONENTIAL:\r
+// JS_ASSERT(precision > 0);\r
+ minNDigits = precision;\r
+ /* Fall through */\r
+ case DTOSTR_STANDARD_EXPONENTIAL:\r
+ exponentialNotation = true;\r
+ break;\r
+\r
+ case DTOSTR_PRECISION:\r
+// JS_ASSERT(precision > 0);\r
+ minNDigits = precision;\r
+ if (decPt < -5 || decPt > precision)\r
+ exponentialNotation = true;\r
+ break;\r
+ }\r
+\r
+ /* If the number has fewer than minNDigits, pad it with zeros at the end */\r
+ if (nDigits < minNDigits) {\r
+ p = minNDigits;\r
+ nDigits = minNDigits;\r
+ do {\r
+ buffer.append('0');\r
+ } while (buffer.length() != p);\r
+ }\r
+ \r
+ if (exponentialNotation) {\r
+ /* Insert a decimal point if more than one significand digit */\r
+ if (nDigits != 1) {\r
+ buffer.insert(1, '.');\r
+ }\r
+ buffer.append('e');\r
+ if ((decPt - 1) >= 0)\r
+ buffer.append('+');\r
+ buffer.append(decPt - 1);\r
+// JS_snprintf(numEnd, bufferSize - (numEnd - buffer), "e%+d", decPt-1);\r
+ } else if (decPt != nDigits) {\r
+ /* Some kind of a fraction in fixed notation */\r
+// JS_ASSERT(decPt <= nDigits);\r
+ if (decPt > 0) {\r
+ /* dd...dd . dd...dd */\r
+ buffer.insert(decPt, '.');\r
+ } else {\r
+ /* 0 . 00...00dd...dd */\r
+ for (int i = 0; i < 1 - decPt; i++)\r
+ buffer.insert(0, '0');\r
+ buffer.insert(1, '.');\r
+ }\r
+ }\r
+ }\r
+\r
+ /* If negative and neither -0.0 nor NaN, output a leading '-'. */\r
+ if (sign[0] &&\r
+ !(word0(d) == Sign_bit && word1(d) == 0) &&\r
+ !((word0(d) & Exp_mask) == Exp_mask &&\r
+ ((word1(d) != 0) || ((word0(d) & Frac_mask) != 0)))) {\r
+ buffer.insert(0, '-');\r
+ }\r
+ }\r
+\r
+}\r
+\r
--- /dev/null
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-\r
+ *\r
+ * The contents of this file are subject to the Netscape Public\r
+ * License Version 1.1 (the "License"); you may not use this file\r
+ * except in compliance with the License. You may obtain a copy of\r
+ * the License at http://www.mozilla.org/NPL/\r
+ *\r
+ * Software distributed under the License is distributed on an "AS\r
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr\r
+ * implied. See the License for the specific language governing\r
+ * rights and limitations under the License.\r
+ *\r
+ * The Original Code is Rhino code, released\r
+ * May 6, 1999.\r
+ *\r
+ * The Initial Developer of the Original Code is Netscape\r
+ * Communications Corporation. Portions created by Netscape are\r
+ * Copyright (C) 1997-2000 Netscape Communications Corporation. All\r
+ * Rights Reserved.\r
+ *\r
+ * Contributor(s): \r
+ * Norris Boyd\r
+ *\r
+ * Alternatively, the contents of this file may be used under the\r
+ * terms of the GNU Public License (the "GPL"), in which case the\r
+ * provisions of the GPL are applicable instead of those above.\r
+ * If you wish to allow use of your version of this file only\r
+ * under the terms of the GPL and not to allow others to use your\r
+ * version of this file under the NPL, indicate your decision by\r
+ * deleting the provisions above and replace them with the notice\r
+ * and other provisions required by the GPL. If you do not delete\r
+ * the provisions above, a recipient may use your version of this\r
+ * file under either the NPL or the GPL.\r
+ */\r
+\r
+// API class\r
+\r
+package org.mozilla.javascript;\r
+\r
+import org.mozilla.javascript.debug.*;\r
+\r
+public class DebuggableEngineImpl implements DebuggableEngine {\r
+ \r
+ public DebuggableEngineImpl(Context cx) {\r
+ this.cx = cx;\r
+ }\r
+\r
+ /**\r
+ * Set whether the engine should break when it encounters\r
+ * the next line.\r
+ * <p>\r
+ * The engine will call the attached debugger's handleBreakpointHit\r
+ * method on the next line it executes if isLineStep is true.\r
+ * May be used from another thread to interrupt execution.\r
+ * \r
+ * @param isLineStep if true, break next line\r
+ */\r
+ public void setBreakNextLine(boolean isLineStep) {\r
+ cx.inLineStepMode = isLineStep;\r
+ }\r
+ \r
+ /**\r
+ * Return the value of the breakNextLine flag.\r
+ * @return true if the engine will break on execution of the \r
+ * next line.\r
+ */\r
+ public boolean getBreakNextLine() {\r
+ return cx.inLineStepMode;\r
+ }\r
+\r
+ /**\r
+ * Set the associated debugger.\r
+ * @param debugger the debugger to be used on callbacks from\r
+ * the engine.\r
+ */\r
+ public void setDebugger(Debugger debugger) {\r
+ cx.debugger = debugger;\r
+ }\r
+ \r
+ /**\r
+ * Return the current debugger.\r
+ * @return the debugger, or null if none is attached.\r
+ */\r
+ public Debugger getDebugger() {\r
+ return cx.debugger;\r
+ }\r
+ \r
+ /**\r
+ * Return the number of frames in current execution.\r
+ * @return the count of current frames\r
+ */\r
+ public int getFrameCount() {\r
+ return cx.frameStack == null ? 0 : cx.frameStack.size();\r
+ }\r
+ \r
+ /**\r
+ * Return a frame from the current execution.\r
+ * Frames are numbered starting from 0 for the innermost\r
+ * frame.\r
+ * @param frameNumber the number of the frame in the range\r
+ * [0,frameCount-1]\r
+ * @return the relevant DebugFrame, or null if frameNumber is out\r
+ * of range or the engine isn't currently saving \r
+ * frames\r
+ */\r
+ public DebugFrame getFrame(int frameNumber) {\r
+ return (DebugFrame) cx.frameStack.elementAt(cx.frameStack.size() - frameNumber - 1);\r
+ }\r
+ \r
+ private Context cx;\r
+}\r
--- /dev/null
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-\r
+ *\r
+ * The contents of this file are subject to the Netscape Public\r
+ * License Version 1.1 (the "License"); you may not use this file\r
+ * except in compliance with the License. You may obtain a copy of\r
+ * the License at http://www.mozilla.org/NPL/\r
+ *\r
+ * Software distributed under the License is distributed on an "AS\r
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr\r
+ * implied. See the License for the specific language governing\r
+ * rights and limitations under the License.\r
+ *\r
+ * The Original Code is Rhino code, released\r
+ * May 6, 1999.\r
+ *\r
+ * The Initial Developer of the Original Code is Netscape\r
+ * Communications Corporation. Portions created by Netscape are\r
+ * Copyright (C) 1997-1999 Netscape Communications Corporation. All\r
+ * Rights Reserved.\r
+ *\r
+ * Contributor(s): \r
+ * Norris Boyd\r
+ *\r
+ * Alternatively, the contents of this file may be used under the\r
+ * terms of the GNU Public License (the "GPL"), in which case the\r
+ * provisions of the GPL are applicable instead of those above.\r
+ * If you wish to allow use of your version of this file only\r
+ * under the terms of the GPL and not to allow others to use your\r
+ * version of this file under the NPL, indicate your decision by\r
+ * deleting the provisions above and replace them with the notice\r
+ * and other provisions required by the GPL. If you do not delete\r
+ * the provisions above, a recipient may use your version of this\r
+ * file under either the NPL or the GPL.\r
+ */\r
+\r
+package org.mozilla.javascript;\r
+\r
+/**\r
+ * This is the default error reporter for JavaScript.\r
+ *\r
+ * @author Norris Boyd\r
+ */\r
+class DefaultErrorReporter implements ErrorReporter {\r
+\r
+ public void warning(String message, String sourceName, int line,\r
+ String lineSource, int lineOffset)\r
+ {\r
+ // do nothing\r
+ }\r
+\r
+ public void error(String message, String sourceName, int line,\r
+ String lineSource, int lineOffset)\r
+ {\r
+ //System.out.println("error at " + sourceName + ":" + line + " -- " + message);\r
+ throw new EvaluatorException(message + " at " + sourceName + ":" + line);\r
+ }\r
+\r
+ public EvaluatorException runtimeError(String message, String sourceName,\r
+ int line, String lineSource, \r
+ int lineOffset)\r
+ {\r
+ //System.out.println("error at " + sourceName + ":" + line + " -- " + message);\r
+ return new EvaluatorException(message + " at " + sourceName + ":" + line);\r
+ }\r
+}\r
--- /dev/null
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-\r
+ * The contents of this file are subject to the Mozilla Public License\r
+ * Version 1.1 (the "License"); you may not use this file except in\r
+ * compliance with the License. You may obtain a copy of the License at\r
+ * http://www.mozilla.org/MPL/\r
+ *\r
+ * Software distributed under the License is distributed on an "AS IS"\r
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the\r
+ * License for the specific language governing rights and limitations\r
+ * under the License.\r
+ *\r
+ * The Original Code is Delegator.java, released Sep 27, 2000.\r
+ *\r
+ * The Initial Developer of the Original Code is Matthias Radestock.\r
+ * <matthias@sorted.org>. Portions created by Matthias Radestock are\r
+ * Copyright (C) 2000 Matthias Radestock. All Rights Reserved.\r
+ *\r
+ * Contributor(s):\r
+ * Redfig Ltd (http://www.redfig.com)\r
+ * LShift Ltd (http://www.lshift.net)\r
+ *\r
+ * Alternatively, the contents of this file may be used under the terms\r
+ * of the GNU Public License (the "GPL License"), in which case the\r
+ * provisions of the GPL License are applicable instead of those\r
+ * above. If you wish to allow use of your version of this file only\r
+ * under the terms of the GPL License and not to allow others to use\r
+ * your version of this file under the MPL, indicate your decision by\r
+ * deleting the provisions above and replace them with the notice and\r
+ * other provisions required by the GPL License. If you do not delete\r
+ * the provisions above, a recipient may use your version of this file\r
+ * under either the MPL or the GPL License.\r
+ */\r
+\r
+// API class\r
+\r
+package org.mozilla.javascript;\r
+\r
+/**\r
+ * This is a helper class for implementing wrappers around Scriptable\r
+ * objects. It implements the Function interface and delegates all\r
+ * invocations to a delegee Scriptable object. The normal use of this\r
+ * class involves creating a sub-class and overriding one or more of\r
+ * the methods.\r
+ *\r
+ * A useful application is the implementation of interceptors,\r
+ * pre/post conditions, debugging.\r
+ *\r
+ * @see Function\r
+ * @see Scriptable\r
+ * @author Matthias Radestock\r
+ */\r
+\r
+public class Delegator implements Function {\r
+\r
+ protected Scriptable obj = null;\r
+\r
+ /**\r
+ * Create a Delegator prototype.\r
+ *\r
+ * This constructor should only be used for creating prototype\r
+ * objects of Delegator.\r
+ *\r
+ * @see org.mozilla.javascript.Delegator#construct\r
+ */\r
+ public Delegator() {\r
+ }\r
+\r
+ /**\r
+ * Create a new Delegator that forwards requests to a delegee\r
+ * Scriptable object.\r
+ *\r
+ * @param obj the delegee\r
+ * @see org.mozilla.javascript.Scriptable\r
+ */\r
+ public Delegator(Scriptable obj) {\r
+ this.obj = obj;\r
+ }\r
+\r
+ /**\r
+ * Retrieve the delegee.\r
+ *\r
+ * @return the delegee\r
+ */\r
+ public Scriptable getDelegee() {\r
+ return obj;\r
+ }\r
+ /**\r
+ * Set the delegee.\r
+ *\r
+ * @param obj the delegee\r
+ * @see org.mozilla.javascript.Scriptable\r
+ */\r
+ public void setDelegee(Scriptable obj) {\r
+ this.obj = obj;\r
+ }\r
+ /**\r
+ * @see org.mozilla.javascript.Scriptable#getClassName\r
+ */\r
+ public String getClassName() {\r
+ return obj.getClassName();\r
+ }\r
+ /**\r
+ * @see org.mozilla.javascript.Scriptable#get\r
+ */\r
+ public Object get(String name, Scriptable start) {\r
+ return obj.get(name,start);\r
+ }\r
+ /**\r
+ * @see org.mozilla.javascript.Scriptable#get\r
+ */\r
+ public Object get(int index, Scriptable start) {\r
+ return obj.get(index,start);\r
+ }\r
+ /**\r
+ * @see org.mozilla.javascript.Scriptable#has\r
+ */\r
+ public boolean has(String name, Scriptable start) {\r
+ return obj.has(name,start);\r
+ }\r
+ /**\r
+ * @see org.mozilla.javascript.Scriptable#has\r
+ */\r
+ public boolean has(int index, Scriptable start) {\r
+ return obj.has(index,start);\r
+ }\r
+ /**\r
+ * @see org.mozilla.javascript.Scriptable#put\r
+ */\r
+ public void put(String name, Scriptable start, Object value) {\r
+ obj.put(name,start,value);\r
+ }\r
+ /**\r
+ * @see org.mozilla.javascript.Scriptable#put\r
+ */\r
+ public void put(int index, Scriptable start, Object value) {\r
+ obj.put(index,start,value);\r
+ }\r
+ /**\r
+ * @see org.mozilla.javascript.Scriptable#delete\r
+ */\r
+ public void delete(String name) {\r
+ obj.delete(name);\r
+ }\r
+ /**\r
+ * @see org.mozilla.javascript.Scriptable#delete\r
+ */\r
+ public void delete(int index) {\r
+ obj.delete(index);\r
+ }\r
+ /**\r
+ * @see org.mozilla.javascript.Scriptable#getPrototype\r
+ */\r
+ public Scriptable getPrototype() {\r
+ return obj.getPrototype();\r
+ }\r
+ /**\r
+ * @see org.mozilla.javascript.Scriptable#setPrototype\r
+ */\r
+ public void setPrototype(Scriptable prototype) {\r
+ obj.setPrototype(prototype);\r
+ }\r
+ /**\r
+ * @see org.mozilla.javascript.Scriptable#getParentScope\r
+ */\r
+ public Scriptable getParentScope() {\r
+ return obj.getParentScope();\r
+ }\r
+ /**\r
+ * @see org.mozilla.javascript.Scriptable#setParentScope\r
+ */\r
+ public void setParentScope(Scriptable parent) {\r
+ obj.setParentScope(parent);\r
+ }\r
+ /**\r
+ * @see org.mozilla.javascript.Scriptable#getIds\r
+ */\r
+ public Object[] getIds() {\r
+ return obj.getIds();\r
+ }\r
+ /**\r
+ * Note that this method does not get forwarded to the delegee if\r
+ * the <code>hint</code> parameter is null,\r
+ * <code>ScriptRuntime.ScriptableClass</code> or\r
+ * <code>ScriptRuntime.FunctionClass</code>. Instead the object\r
+ * itself is returned.\r
+ *\r
+ * @param hint the type hint\r
+ * @return the default value\r
+ *\r
+ * @see org.mozilla.javascript.Scriptable#getDefaultValue\r
+ */\r
+ public Object getDefaultValue(Class hint) {\r
+ return (hint == null ||\r
+ hint == ScriptRuntime.ScriptableClass ||\r
+ hint == ScriptRuntime.FunctionClass) ?\r
+ this : obj.getDefaultValue(hint);\r
+ }\r
+ /**\r
+ * @see org.mozilla.javascript.Scriptable#hasInstance\r
+ */\r
+ public boolean hasInstance(Scriptable instance) {\r
+ return obj.hasInstance(instance);\r
+ }\r
+ /**\r
+ * @see org.mozilla.javascript.Function#call\r
+ */\r
+ public Object call(Context cx, Scriptable scope, Scriptable thisObj,\r
+ Object[] args)\r
+ throws JavaScriptException {\r
+ return ((Function)obj).call(cx,scope,thisObj,args);\r
+ }\r
+\r
+ /**\r
+ * Note that if the <code>delegee</code> is <code>null</code>,\r
+ * this method creates a new instance of the Delegator itself\r
+ * rathert than forwarding the call to the\r
+ * <code>delegee</code>. This permits the use of Delegator\r
+ * prototypes.\r
+ *\r
+ * @param cx the current Context for this thread\r
+ * @param scope an enclosing scope of the caller except\r
+ * when the function is called from a closure.\r
+ * @param args the array of arguments\r
+ * @return the allocated object\r
+ * @exception JavaScriptException if an uncaught exception\r
+ * occurred while executing the constructor\r
+ *\r
+ * @see org.mozilla.javascript.Function#construct\r
+ */\r
+ public Scriptable construct(Context cx, Scriptable scope, Object[] args)\r
+ throws JavaScriptException {\r
+ if (obj == null) {\r
+ //this little trick allows us to declare prototype objects for\r
+ //Delegators\r
+ try {\r
+ Delegator n = (Delegator)this.getClass().newInstance();\r
+ n.setDelegee((Scriptable)args[0]);\r
+ return n;\r
+ }\r
+ catch (Exception e) {\r
+ e.printStackTrace();\r
+ System.exit(0);\r
+ }\r
+ return null;\r
+ }\r
+ else {\r
+ return ((Function)obj).construct(cx,scope,args);\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-\r
+ *\r
+ * The contents of this file are subject to the Netscape Public\r
+ * License Version 1.1 (the "License"); you may not use this file\r
+ * except in compliance with the License. You may obtain a copy of\r
+ * the License at http://www.mozilla.org/NPL/\r
+ *\r
+ * Software distributed under the License is distributed on an "AS\r
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr\r
+ * implied. See the License for the specific language governing\r
+ * rights and limitations under the License.\r
+ *\r
+ * The Original Code is Rhino code, released\r
+ * May 6, 1999.\r
+ *\r
+ * The Initial Developer of the Original Code is Netscape\r
+ * Communications Corporation. Portions created by Netscape are\r
+ * Copyright (C) 1997-1999 Netscape Communications Corporation. All\r
+ * Rights Reserved.\r
+ *\r
+ * Contributor(s): \r
+ * Roger Lawrence\r
+ * \r
+ * Alternatively, the contents of this file may be used under the\r
+ * terms of the GNU Public License (the "GPL"), in which case the\r
+ * provisions of the GPL are applicable instead of those above.\r
+ * If you wish to allow use of your version of this file only\r
+ * under the terms of the GPL and not to allow others to use your\r
+ * version of this file under the NPL, indicate your decision by\r
+ * deleting the provisions above and replace them with the notice\r
+ * and other provisions required by the GPL. If you do not delete\r
+ * the provisions above, a recipient may use your version of this\r
+ * file under either the NPL or the GPL.\r
+ */\r
+\r
+// API class\r
+\r
+package org.mozilla.javascript;\r
+\r
+/**\r
+ * The class of exceptions raised by the engine as described in \r
+ * ECMA edition 3. See section 15.11.6 in particular.\r
+ */\r
+public class EcmaError extends RuntimeException {\r
+\r
+ /**\r
+ * Create an exception with the specified detail message.\r
+ *\r
+ * Errors internal to the JavaScript engine will simply throw a\r
+ * RuntimeException.\r
+ *\r
+ * @param nativeError the NativeError object constructed for this error\r
+ * @param sourceName the name of the source reponsible for the error\r
+ * @param lineNumber the line number of the source\r
+ * @param columnNumber the columnNumber of the source (may be zero if\r
+ * unknown)\r
+ * @param lineSource the source of the line containing the error (may be \r
+ * null if unknown)\r
+ */\r
+ public EcmaError(NativeError nativeError, String sourceName, \r
+ int lineNumber, int columnNumber, String lineSource) \r
+ {\r
+ super("EcmaError");\r
+ errorObject = nativeError;\r
+ this.sourceName = sourceName;\r
+ this.lineNumber = lineNumber;\r
+ this.columnNumber = columnNumber;\r
+ this.lineSource = lineSource;\r
+ }\r
+ \r
+ /**\r
+ * Return a string representation of the error, which currently consists \r
+ * of the name of the error together with the message.\r
+ */\r
+ public String toString() {\r
+ if (sourceName != null && lineNumber > 0)\r
+ return errorObject.toString() + " (" + sourceName + \r
+ "; line " + lineNumber + ")";\r
+ else\r
+ return errorObject.toString();\r
+ }\r
+ \r
+ /**\r
+ * Gets the name of the error.\r
+ * \r
+ * ECMA edition 3 defines the following\r
+ * errors: EvalError, RangeError, ReferenceError, \r
+ * SyntaxError, TypeError, and URIError. Additional error names\r
+ * may be added in the future.\r
+ * \r
+ * See ECMA edition 3, 15.11.7.9.\r
+ * \r
+ * @return the name of the error. \r
+ */\r
+ public String getName() {\r
+ return errorObject.getName();\r
+ }\r
+ \r
+ /**\r
+ * Gets the message corresponding to the error.\r
+ * \r
+ * See ECMA edition 3, 15.11.7.10.\r
+ * \r
+ * @return an implemenation-defined string describing the error.\r
+ */\r
+ public String getMessage() {\r
+ return errorObject.getMessage();\r
+ }\r
+ \r
+ /**\r
+ * Get the name of the source containing the error, or null\r
+ * if that information is not available.\r
+ */\r
+ public String getSourceName() {\r
+ return sourceName;\r
+ }\r
+ \r
+ /**\r
+ * Returns the line number of the statement causing the error,\r
+ * or zero if not available.\r
+ */\r
+ public int getLineNumber() {\r
+ return lineNumber;\r
+ }\r
+ \r
+ /**\r
+ * Get the error object corresponding to this exception.\r
+ */\r
+ public Scriptable getErrorObject() {\r
+ return errorObject;\r
+ }\r
+ \r
+ /**\r
+ * The column number of the location of the error, or zero if unknown.\r
+ */\r
+ public int getColumnNumber() {\r
+ return columnNumber;\r
+ }\r
+ \r
+ /**\r
+ * The source of the line causing the error, or zero if unknown.\r
+ */\r
+ public String getLineSource() {\r
+ return lineSource;\r
+ }\r
+ \r
+ private NativeError errorObject;\r
+ private String sourceName;\r
+ private int lineNumber;\r
+ private int columnNumber;\r
+ private String lineSource;\r
+}\r