# HG changeset patch # User Jaroslav Tulach # Date 1353272595 -3600 # Node ID 6a56c2381b0f25bd2a66beb59b030f99ff30332f # Parent d0aad97dfd2e69426df1c99181feba43f5b602c0# Parent 51d08c49e9b6f620056d59b1f0909a2f69757da0 javap branch achieved its goal: ByteCodeToJavaScript can be executed in bck2brwsr VM. Merging to main branch. diff -r d0aad97dfd2e -r 6a56c2381b0f emul/src/main/java/java/io/ByteArrayInputStream.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/src/main/java/java/io/ByteArrayInputStream.java Sun Nov 18 22:03:15 2012 +0100 @@ -0,0 +1,283 @@ +/* + * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.io; + +/** + * A ByteArrayInputStream contains + * an internal buffer that contains bytes that + * may be read from the stream. An internal + * counter keeps track of the next byte to + * be supplied by the read method. + *

+ * Closing a ByteArrayInputStream has no effect. The methods in + * this class can be called after the stream has been closed without + * generating an IOException. + * + * @author Arthur van Hoff + * @see java.io.StringBufferInputStream + * @since JDK1.0 + */ +public +class ByteArrayInputStream extends InputStream { + + /** + * An array of bytes that was provided + * by the creator of the stream. Elements buf[0] + * through buf[count-1] are the + * only bytes that can ever be read from the + * stream; element buf[pos] is + * the next byte to be read. + */ + protected byte buf[]; + + /** + * The index of the next character to read from the input stream buffer. + * This value should always be nonnegative + * and not larger than the value of count. + * The next byte to be read from the input stream buffer + * will be buf[pos]. + */ + protected int pos; + + /** + * The currently marked position in the stream. + * ByteArrayInputStream objects are marked at position zero by + * default when constructed. They may be marked at another + * position within the buffer by the mark() method. + * The current buffer position is set to this point by the + * reset() method. + *

+ * If no mark has been set, then the value of mark is the offset + * passed to the constructor (or 0 if the offset was not supplied). + * + * @since JDK1.1 + */ + protected int mark = 0; + + /** + * The index one greater than the last valid character in the input + * stream buffer. + * This value should always be nonnegative + * and not larger than the length of buf. + * It is one greater than the position of + * the last byte within buf that + * can ever be read from the input stream buffer. + */ + protected int count; + + /** + * Creates a ByteArrayInputStream + * so that it uses buf as its + * buffer array. + * The buffer array is not copied. + * The initial value of pos + * is 0 and the initial value + * of count is the length of + * buf. + * + * @param buf the input buffer. + */ + public ByteArrayInputStream(byte buf[]) { + this.buf = buf; + this.pos = 0; + this.count = buf.length; + } + + /** + * Creates ByteArrayInputStream + * that uses buf as its + * buffer array. The initial value of pos + * is offset and the initial value + * of count is the minimum of offset+length + * and buf.length. + * The buffer array is not copied. The buffer's mark is + * set to the specified offset. + * + * @param buf the input buffer. + * @param offset the offset in the buffer of the first byte to read. + * @param length the maximum number of bytes to read from the buffer. + */ + public ByteArrayInputStream(byte buf[], int offset, int length) { + this.buf = buf; + this.pos = offset; + this.count = Math.min(offset + length, buf.length); + this.mark = offset; + } + + /** + * Reads the next byte of data from this input stream. The value + * byte is returned as an int in the range + * 0 to 255. If no byte is available + * because the end of the stream has been reached, the value + * -1 is returned. + *

+ * This read method + * cannot block. + * + * @return the next byte of data, or -1 if the end of the + * stream has been reached. + */ + public synchronized int read() { + return (pos < count) ? (buf[pos++] & 0xff) : -1; + } + + /** + * Reads up to len bytes of data into an array of bytes + * from this input stream. + * If pos equals count, + * then -1 is returned to indicate + * end of file. Otherwise, the number k + * of bytes read is equal to the smaller of + * len and count-pos. + * If k is positive, then bytes + * buf[pos] through buf[pos+k-1] + * are copied into b[off] through + * b[off+k-1] in the manner performed + * by System.arraycopy. The + * value k is added into pos + * and k is returned. + *

+ * This read method cannot block. + * + * @param b the buffer into which the data is read. + * @param off the start offset in the destination array b + * @param len the maximum number of bytes read. + * @return the total number of bytes read into the buffer, or + * -1 if there is no more data because the end of + * the stream has been reached. + * @exception NullPointerException If b is null. + * @exception IndexOutOfBoundsException If off is negative, + * len is negative, or len is greater than + * b.length - off + */ + public synchronized int read(byte b[], int off, int len) { + if (b == null) { + throw new NullPointerException(); + } else if (off < 0 || len < 0 || len > b.length - off) { + throw new IndexOutOfBoundsException(); + } + + if (pos >= count) { + return -1; + } + + int avail = count - pos; + if (len > avail) { + len = avail; + } + if (len <= 0) { + return 0; + } + PushbackInputStream.arraycopy(buf, pos, b, off, len); + pos += len; + return len; + } + + /** + * Skips n bytes of input from this input stream. Fewer + * bytes might be skipped if the end of the input stream is reached. + * The actual number k + * of bytes to be skipped is equal to the smaller + * of n and count-pos. + * The value k is added into pos + * and k is returned. + * + * @param n the number of bytes to be skipped. + * @return the actual number of bytes skipped. + */ + public synchronized long skip(long n) { + long k = count - pos; + if (n < k) { + k = n < 0 ? 0 : n; + } + + pos += k; + return k; + } + + /** + * Returns the number of remaining bytes that can be read (or skipped over) + * from this input stream. + *

+ * The value returned is count - pos, + * which is the number of bytes remaining to be read from the input buffer. + * + * @return the number of remaining bytes that can be read (or skipped + * over) from this input stream without blocking. + */ + public synchronized int available() { + return count - pos; + } + + /** + * Tests if this InputStream supports mark/reset. The + * markSupported method of ByteArrayInputStream + * always returns true. + * + * @since JDK1.1 + */ + public boolean markSupported() { + return true; + } + + /** + * Set the current marked position in the stream. + * ByteArrayInputStream objects are marked at position zero by + * default when constructed. They may be marked at another + * position within the buffer by this method. + *

+ * If no mark has been set, then the value of the mark is the + * offset passed to the constructor (or 0 if the offset was not + * supplied). + * + *

Note: The readAheadLimit for this class + * has no meaning. + * + * @since JDK1.1 + */ + public void mark(int readAheadLimit) { + mark = pos; + } + + /** + * Resets the buffer to the marked position. The marked position + * is 0 unless another position was marked or an offset was specified + * in the constructor. + */ + public synchronized void reset() { + pos = mark; + } + + /** + * Closing a ByteArrayInputStream has no effect. The methods in + * this class can be called after the stream has been closed without + * generating an IOException. + *

+ */ + public void close() throws IOException { + } + +} diff -r d0aad97dfd2e -r 6a56c2381b0f emul/src/main/java/java/io/DataInput.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/src/main/java/java/io/DataInput.java Sun Nov 18 22:03:15 2012 +0100 @@ -0,0 +1,635 @@ +/* + * Copyright (c) 1995, 2006, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.io; + +/** + * The DataInput interface provides + * for reading bytes from a binary stream and + * reconstructing from them data in any of + * the Java primitive types. There is also + * a + * facility for reconstructing a String + * from data in + * modified UTF-8 + * format. + *

+ * It is generally true of all the reading + * routines in this interface that if end of + * file is reached before the desired number + * of bytes has been read, an EOFException + * (which is a kind of IOException) + * is thrown. If any byte cannot be read for + * any reason other than end of file, an IOException + * other than EOFException is + * thrown. In particular, an IOException + * may be thrown if the input stream has been + * closed. + * + *

Modified UTF-8

+ *

+ * Implementations of the DataInput and DataOutput interfaces represent + * Unicode strings in a format that is a slight modification of UTF-8. + * (For information regarding the standard UTF-8 format, see section + * 3.9 Unicode Encoding Forms of The Unicode Standard, Version + * 4.0). + * Note that in the following tables, the most significant bit appears in the + * far left-hand column. + *

+ * All characters in the range '\u0001' to + * '\u007F' are represented by a single byte: + * + *

+ * + * + * + * + * + * + * + * + * + *
Bit Values
Byte 1 + * + * + * + *
0
+ *
bits 6-0
+ *
+ *
+ *
+ * + *

+ * The null character '\u0000' and characters in the + * range '\u0080' to '\u07FF' are + * represented by a pair of bytes: + * + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + *
Bit Values
Byte 1 + * + * + * + *
1
+ *
1
+ *
0
+ *
bits 10-6
+ *
+ *
Byte 2 + * + * + * + *
1
+ *
0
+ *
bits 5-0
+ *
+ *
+ *
+ * + *
+ * char values in the range '\u0800' to + * '\uFFFF' are represented by three bytes: + * + *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Bit Values
Byte 1 + * + * + * + *
1
+ *
1
+ *
1
+ *
0
+ *
bits 15-12
+ *
+ *
Byte 2 + * + * + * + *
1
+ *
0
+ *
bits 11-6
+ *
+ *
Byte 3 + * + * + * + *
1
+ *
0
+ *
bits 5-0
+ *
+ *
+ *
+ * + *

+ * The differences between this format and the + * standard UTF-8 format are the following: + *

+ * @author Frank Yellin + * @see java.io.DataInputStream + * @see java.io.DataOutput + * @since JDK1.0 + */ +public +interface DataInput { + /** + * Reads some bytes from an input + * stream and stores them into the buffer + * array b. The number of bytes + * read is equal + * to the length of b. + *

+ * This method blocks until one of the + * following conditions occurs:

+ *

+ *

+ * If b is null, + * a NullPointerException is thrown. + * If b.length is zero, then + * no bytes are read. Otherwise, the first + * byte read is stored into element b[0], + * the next one into b[1], and + * so on. + * If an exception is thrown from + * this method, then it may be that some but + * not all bytes of b have been + * updated with data from the input stream. + * + * @param b the buffer into which the data is read. + * @exception EOFException if this stream reaches the end before reading + * all the bytes. + * @exception IOException if an I/O error occurs. + */ + void readFully(byte b[]) throws IOException; + + /** + * + * Reads len + * bytes from + * an input stream. + *

+ * This method + * blocks until one of the following conditions + * occurs:

+ *

+ *

+ * If b is null, + * a NullPointerException is thrown. + * If off is negative, or len + * is negative, or off+len is + * greater than the length of the array b, + * then an IndexOutOfBoundsException + * is thrown. + * If len is zero, + * then no bytes are read. Otherwise, the first + * byte read is stored into element b[off], + * the next one into b[off+1], + * and so on. The number of bytes read is, + * at most, equal to len. + * + * @param b the buffer into which the data is read. + * @param off an int specifying the offset into the data. + * @param len an int specifying the number of bytes to read. + * @exception EOFException if this stream reaches the end before reading + * all the bytes. + * @exception IOException if an I/O error occurs. + */ + void readFully(byte b[], int off, int len) throws IOException; + + /** + * Makes an attempt to skip over + * n bytes + * of data from the input + * stream, discarding the skipped bytes. However, + * it may skip + * over some smaller number of + * bytes, possibly zero. This may result from + * any of a + * number of conditions; reaching + * end of file before n bytes + * have been skipped is + * only one possibility. + * This method never throws an EOFException. + * The actual + * number of bytes skipped is returned. + * + * @param n the number of bytes to be skipped. + * @return the number of bytes actually skipped. + * @exception IOException if an I/O error occurs. + */ + int skipBytes(int n) throws IOException; + + /** + * Reads one input byte and returns + * true if that byte is nonzero, + * false if that byte is zero. + * This method is suitable for reading + * the byte written by the writeBoolean + * method of interface DataOutput. + * + * @return the boolean value read. + * @exception EOFException if this stream reaches the end before reading + * all the bytes. + * @exception IOException if an I/O error occurs. + */ + boolean readBoolean() throws IOException; + + /** + * Reads and returns one input byte. + * The byte is treated as a signed value in + * the range -128 through 127, + * inclusive. + * This method is suitable for + * reading the byte written by the writeByte + * method of interface DataOutput. + * + * @return the 8-bit value read. + * @exception EOFException if this stream reaches the end before reading + * all the bytes. + * @exception IOException if an I/O error occurs. + */ + byte readByte() throws IOException; + + /** + * Reads one input byte, zero-extends + * it to type int, and returns + * the result, which is therefore in the range + * 0 + * through 255. + * This method is suitable for reading + * the byte written by the writeByte + * method of interface DataOutput + * if the argument to writeByte + * was intended to be a value in the range + * 0 through 255. + * + * @return the unsigned 8-bit value read. + * @exception EOFException if this stream reaches the end before reading + * all the bytes. + * @exception IOException if an I/O error occurs. + */ + int readUnsignedByte() throws IOException; + + /** + * Reads two input bytes and returns + * a short value. Let a + * be the first byte read and b + * be the second byte. The value + * returned + * is: + *

(short)((a << 8) | (b & 0xff))
+     * 
+ * This method + * is suitable for reading the bytes written + * by the writeShort method of + * interface DataOutput. + * + * @return the 16-bit value read. + * @exception EOFException if this stream reaches the end before reading + * all the bytes. + * @exception IOException if an I/O error occurs. + */ + short readShort() throws IOException; + + /** + * Reads two input bytes and returns + * an int value in the range 0 + * through 65535. Let a + * be the first byte read and + * b + * be the second byte. The value returned is: + *

(((a & 0xff) << 8) | (b & 0xff))
+     * 
+ * This method is suitable for reading the bytes + * written by the writeShort method + * of interface DataOutput if + * the argument to writeShort + * was intended to be a value in the range + * 0 through 65535. + * + * @return the unsigned 16-bit value read. + * @exception EOFException if this stream reaches the end before reading + * all the bytes. + * @exception IOException if an I/O error occurs. + */ + int readUnsignedShort() throws IOException; + + /** + * Reads two input bytes and returns a char value. + * Let a + * be the first byte read and b + * be the second byte. The value + * returned is: + *

(char)((a << 8) | (b & 0xff))
+     * 
+ * This method + * is suitable for reading bytes written by + * the writeChar method of interface + * DataOutput. + * + * @return the char value read. + * @exception EOFException if this stream reaches the end before reading + * all the bytes. + * @exception IOException if an I/O error occurs. + */ + char readChar() throws IOException; + + /** + * Reads four input bytes and returns an + * int value. Let a-d + * be the first through fourth bytes read. The value returned is: + *

+     * 
+     * (((a & 0xff) << 24) | ((b & 0xff) << 16) |
+     *  ((c & 0xff) << 8) | (d & 0xff))
+     * 
+ * This method is suitable + * for reading bytes written by the writeInt + * method of interface DataOutput. + * + * @return the int value read. + * @exception EOFException if this stream reaches the end before reading + * all the bytes. + * @exception IOException if an I/O error occurs. + */ + int readInt() throws IOException; + + /** + * Reads eight input bytes and returns + * a long value. Let a-h + * be the first through eighth bytes read. + * The value returned is: + *

 
+     * (((long)(a & 0xff) << 56) |
+     *  ((long)(b & 0xff) << 48) |
+     *  ((long)(c & 0xff) << 40) |
+     *  ((long)(d & 0xff) << 32) |
+     *  ((long)(e & 0xff) << 24) |
+     *  ((long)(f & 0xff) << 16) |
+     *  ((long)(g & 0xff) <<  8) |
+     *  ((long)(h & 0xff)))
+     * 
+ *

+ * This method is suitable + * for reading bytes written by the writeLong + * method of interface DataOutput. + * + * @return the long value read. + * @exception EOFException if this stream reaches the end before reading + * all the bytes. + * @exception IOException if an I/O error occurs. + */ + long readLong() throws IOException; + + /** + * Reads four input bytes and returns + * a float value. It does this + * by first constructing an int + * value in exactly the manner + * of the readInt + * method, then converting this int + * value to a float in + * exactly the manner of the method Float.intBitsToFloat. + * This method is suitable for reading + * bytes written by the writeFloat + * method of interface DataOutput. + * + * @return the float value read. + * @exception EOFException if this stream reaches the end before reading + * all the bytes. + * @exception IOException if an I/O error occurs. + */ + float readFloat() throws IOException; + + /** + * Reads eight input bytes and returns + * a double value. It does this + * by first constructing a long + * value in exactly the manner + * of the readlong + * method, then converting this long + * value to a double in exactly + * the manner of the method Double.longBitsToDouble. + * This method is suitable for reading + * bytes written by the writeDouble + * method of interface DataOutput. + * + * @return the double value read. + * @exception EOFException if this stream reaches the end before reading + * all the bytes. + * @exception IOException if an I/O error occurs. + */ + double readDouble() throws IOException; + + /** + * Reads the next line of text from the input stream. + * It reads successive bytes, converting + * each byte separately into a character, + * until it encounters a line terminator or + * end of + * file; the characters read are then + * returned as a String. Note + * that because this + * method processes bytes, + * it does not support input of the full Unicode + * character set. + *

+ * If end of file is encountered + * before even one byte can be read, then null + * is returned. Otherwise, each byte that is + * read is converted to type char + * by zero-extension. If the character '\n' + * is encountered, it is discarded and reading + * ceases. If the character '\r' + * is encountered, it is discarded and, if + * the following byte converts to the + * character '\n', then that is + * discarded also; reading then ceases. If + * end of file is encountered before either + * of the characters '\n' and + * '\r' is encountered, reading + * ceases. Once reading has ceased, a String + * is returned that contains all the characters + * read and not discarded, taken in order. + * Note that every character in this string + * will have a value less than \u0100, + * that is, (char)256. + * + * @return the next line of text from the input stream, + * or null if the end of file is + * encountered before a byte can be read. + * @exception IOException if an I/O error occurs. + */ + String readLine() throws IOException; + + /** + * Reads in a string that has been encoded using a + * modified UTF-8 + * format. + * The general contract of readUTF + * is that it reads a representation of a Unicode + * character string encoded in modified + * UTF-8 format; this string of characters + * is then returned as a String. + *

+ * First, two bytes are read and used to + * construct an unsigned 16-bit integer in + * exactly the manner of the readUnsignedShort + * method . This integer value is called the + * UTF length and specifies the number + * of additional bytes to be read. These bytes + * are then converted to characters by considering + * them in groups. The length of each group + * is computed from the value of the first + * byte of the group. The byte following a + * group, if any, is the first byte of the + * next group. + *

+ * If the first byte of a group + * matches the bit pattern 0xxxxxxx + * (where x means "may be 0 + * or 1"), then the group consists + * of just that byte. The byte is zero-extended + * to form a character. + *

+ * If the first byte + * of a group matches the bit pattern 110xxxxx, + * then the group consists of that byte a + * and a second byte b. If there + * is no byte b (because byte + * a was the last of the bytes + * to be read), or if byte b does + * not match the bit pattern 10xxxxxx, + * then a UTFDataFormatException + * is thrown. Otherwise, the group is converted + * to the character:

+ *

(char)(((a& 0x1F) << 6) | (b & 0x3F))
+     * 
+ * If the first byte of a group + * matches the bit pattern 1110xxxx, + * then the group consists of that byte a + * and two more bytes b and c. + * If there is no byte c (because + * byte a was one of the last + * two of the bytes to be read), or either + * byte b or byte c + * does not match the bit pattern 10xxxxxx, + * then a UTFDataFormatException + * is thrown. Otherwise, the group is converted + * to the character:

+ *


+     * (char)(((a & 0x0F) << 12) | ((b & 0x3F) << 6) | (c & 0x3F))
+     * 
+ * If the first byte of a group matches the + * pattern 1111xxxx or the pattern + * 10xxxxxx, then a UTFDataFormatException + * is thrown. + *

+ * If end of file is encountered + * at any time during this entire process, + * then an EOFException is thrown. + *

+ * After every group has been converted to + * a character by this process, the characters + * are gathered, in the same order in which + * their corresponding groups were read from + * the input stream, to form a String, + * which is returned. + *

+ * The writeUTF + * method of interface DataOutput + * may be used to write data that is suitable + * for reading by this method. + * @return a Unicode string. + * @exception EOFException if this stream reaches the end + * before reading all the bytes. + * @exception IOException if an I/O error occurs. + * @exception UTFDataFormatException if the bytes do not represent a + * valid modified UTF-8 encoding of a string. + */ + String readUTF() throws IOException; +} diff -r d0aad97dfd2e -r 6a56c2381b0f emul/src/main/java/java/io/DataInputStream.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/src/main/java/java/io/DataInputStream.java Sun Nov 18 22:03:15 2012 +0100 @@ -0,0 +1,704 @@ +/* + * Copyright (c) 1994, 2006, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.io; + +import org.apidesign.bck2brwsr.core.JavaScriptBody; + +/** + * A data input stream lets an application read primitive Java data + * types from an underlying input stream in a machine-independent + * way. An application uses a data output stream to write data that + * can later be read by a data input stream. + *

+ * DataInputStream is not necessarily safe for multithreaded access. + * Thread safety is optional and is the responsibility of users of + * methods in this class. + * + * @author Arthur van Hoff + * @see java.io.DataOutputStream + * @since JDK1.0 + */ +public +class DataInputStream extends FilterInputStream implements DataInput { + + /** + * Creates a DataInputStream that uses the specified + * underlying InputStream. + * + * @param in the specified input stream + */ + public DataInputStream(InputStream in) { + super(in); + } + + /** + * working arrays initialized on demand by readUTF + */ + private byte bytearr[] = new byte[80]; + private char chararr[] = new char[80]; + + /** + * Reads some number of bytes from the contained input stream and + * stores them into the buffer array b. The number of + * bytes actually read is returned as an integer. This method blocks + * until input data is available, end of file is detected, or an + * exception is thrown. + * + *

If b is null, a NullPointerException is + * thrown. If the length of b is zero, then no bytes are + * read and 0 is returned; otherwise, there is an attempt + * to read at least one byte. If no byte is available because the + * stream is at end of file, the value -1 is returned; + * otherwise, at least one byte is read and stored into b. + * + *

The first byte read is stored into element b[0], the + * next one into b[1], and so on. The number of bytes read + * is, at most, equal to the length of b. Let k + * be the number of bytes actually read; these bytes will be stored in + * elements b[0] through b[k-1], leaving + * elements b[k] through b[b.length-1] + * unaffected. + * + *

The read(b) method has the same effect as: + *

+     * read(b, 0, b.length)
+     * 
+ * + * @param b the buffer into which the data is read. + * @return the total number of bytes read into the buffer, or + * -1 if there is no more data because the end + * of the stream has been reached. + * @exception IOException if the first byte cannot be read for any reason + * other than end of file, the stream has been closed and the underlying + * input stream does not support reading after close, or another I/O + * error occurs. + * @see java.io.FilterInputStream#in + * @see java.io.InputStream#read(byte[], int, int) + */ + public final int read(byte b[]) throws IOException { + return in.read(b, 0, b.length); + } + + /** + * Reads up to len bytes of data from the contained + * input stream into an array of bytes. An attempt is made to read + * as many as len bytes, but a smaller number may be read, + * possibly zero. The number of bytes actually read is returned as an + * integer. + * + *

This method blocks until input data is available, end of file is + * detected, or an exception is thrown. + * + *

If len is zero, then no bytes are read and + * 0 is returned; otherwise, there is an attempt to read at + * least one byte. If no byte is available because the stream is at end of + * file, the value -1 is returned; otherwise, at least one + * byte is read and stored into b. + * + *

The first byte read is stored into element b[off], the + * next one into b[off+1], and so on. The number of bytes read + * is, at most, equal to len. Let k be the number of + * bytes actually read; these bytes will be stored in elements + * b[off] through b[off+k-1], + * leaving elements b[off+k] through + * b[off+len-1] unaffected. + * + *

In every case, elements b[0] through + * b[off] and elements b[off+len] through + * b[b.length-1] are unaffected. + * + * @param b the buffer into which the data is read. + * @param off the start offset in the destination array b + * @param len the maximum number of bytes read. + * @return the total number of bytes read into the buffer, or + * -1 if there is no more data because the end + * of the stream has been reached. + * @exception NullPointerException If b is null. + * @exception IndexOutOfBoundsException If off is negative, + * len is negative, or len is greater than + * b.length - off + * @exception IOException if the first byte cannot be read for any reason + * other than end of file, the stream has been closed and the underlying + * input stream does not support reading after close, or another I/O + * error occurs. + * @see java.io.FilterInputStream#in + * @see java.io.InputStream#read(byte[], int, int) + */ + public final int read(byte b[], int off, int len) throws IOException { + return in.read(b, off, len); + } + + /** + * See the general contract of the readFully + * method of DataInput. + *

+ * Bytes + * for this operation are read from the contained + * input stream. + * + * @param b the buffer into which the data is read. + * @exception EOFException if this input stream reaches the end before + * reading all the bytes. + * @exception IOException the stream has been closed and the contained + * input stream does not support reading after close, or + * another I/O error occurs. + * @see java.io.FilterInputStream#in + */ + public final void readFully(byte b[]) throws IOException { + readFully(b, 0, b.length); + } + + /** + * See the general contract of the readFully + * method of DataInput. + *

+ * Bytes + * for this operation are read from the contained + * input stream. + * + * @param b the buffer into which the data is read. + * @param off the start offset of the data. + * @param len the number of bytes to read. + * @exception EOFException if this input stream reaches the end before + * reading all the bytes. + * @exception IOException the stream has been closed and the contained + * input stream does not support reading after close, or + * another I/O error occurs. + * @see java.io.FilterInputStream#in + */ + public final void readFully(byte b[], int off, int len) throws IOException { + if (len < 0) + throw new IndexOutOfBoundsException(); + int n = 0; + while (n < len) { + int count = in.read(b, off + n, len - n); + if (count < 0) + throw new EOFException(); + n += count; + } + } + + /** + * See the general contract of the skipBytes + * method of DataInput. + *

+ * Bytes for this operation are read from the contained + * input stream. + * + * @param n the number of bytes to be skipped. + * @return the actual number of bytes skipped. + * @exception IOException if the contained input stream does not support + * seek, or the stream has been closed and + * the contained input stream does not support + * reading after close, or another I/O error occurs. + */ + public final int skipBytes(int n) throws IOException { + int total = 0; + int cur = 0; + + while ((total 0)) { + total += cur; + } + + return total; + } + + /** + * See the general contract of the readBoolean + * method of DataInput. + *

+ * Bytes for this operation are read from the contained + * input stream. + * + * @return the boolean value read. + * @exception EOFException if this input stream has reached the end. + * @exception IOException the stream has been closed and the contained + * input stream does not support reading after close, or + * another I/O error occurs. + * @see java.io.FilterInputStream#in + */ + public final boolean readBoolean() throws IOException { + int ch = in.read(); + if (ch < 0) + throw new EOFException(); + return (ch != 0); + } + + /** + * See the general contract of the readByte + * method of DataInput. + *

+ * Bytes + * for this operation are read from the contained + * input stream. + * + * @return the next byte of this input stream as a signed 8-bit + * byte. + * @exception EOFException if this input stream has reached the end. + * @exception IOException the stream has been closed and the contained + * input stream does not support reading after close, or + * another I/O error occurs. + * @see java.io.FilterInputStream#in + */ + public final byte readByte() throws IOException { + int ch = in.read(); + if (ch < 0) + throw new EOFException(); + return (byte)(ch); + } + + /** + * See the general contract of the readUnsignedByte + * method of DataInput. + *

+ * Bytes + * for this operation are read from the contained + * input stream. + * + * @return the next byte of this input stream, interpreted as an + * unsigned 8-bit number. + * @exception EOFException if this input stream has reached the end. + * @exception IOException the stream has been closed and the contained + * input stream does not support reading after close, or + * another I/O error occurs. + * @see java.io.FilterInputStream#in + */ + public final int readUnsignedByte() throws IOException { + int ch = in.read(); + if (ch < 0) + throw new EOFException(); + return ch; + } + + /** + * See the general contract of the readShort + * method of DataInput. + *

+ * Bytes + * for this operation are read from the contained + * input stream. + * + * @return the next two bytes of this input stream, interpreted as a + * signed 16-bit number. + * @exception EOFException if this input stream reaches the end before + * reading two bytes. + * @exception IOException the stream has been closed and the contained + * input stream does not support reading after close, or + * another I/O error occurs. + * @see java.io.FilterInputStream#in + */ + public final short readShort() throws IOException { + int ch1 = in.read(); + int ch2 = in.read(); + if ((ch1 | ch2) < 0) + throw new EOFException(); + return (short)((ch1 << 8) + (ch2 << 0)); + } + + /** + * See the general contract of the readUnsignedShort + * method of DataInput. + *

+ * Bytes + * for this operation are read from the contained + * input stream. + * + * @return the next two bytes of this input stream, interpreted as an + * unsigned 16-bit integer. + * @exception EOFException if this input stream reaches the end before + * reading two bytes. + * @exception IOException the stream has been closed and the contained + * input stream does not support reading after close, or + * another I/O error occurs. + * @see java.io.FilterInputStream#in + */ + public final int readUnsignedShort() throws IOException { + int ch1 = in.read(); + int ch2 = in.read(); + if ((ch1 | ch2) < 0) + throw new EOFException(); + return (ch1 << 8) + (ch2 << 0); + } + + /** + * See the general contract of the readChar + * method of DataInput. + *

+ * Bytes + * for this operation are read from the contained + * input stream. + * + * @return the next two bytes of this input stream, interpreted as a + * char. + * @exception EOFException if this input stream reaches the end before + * reading two bytes. + * @exception IOException the stream has been closed and the contained + * input stream does not support reading after close, or + * another I/O error occurs. + * @see java.io.FilterInputStream#in + */ + public final char readChar() throws IOException { + int ch1 = in.read(); + int ch2 = in.read(); + if ((ch1 | ch2) < 0) + throw new EOFException(); + return (char)((ch1 << 8) + (ch2 << 0)); + } + + /** + * See the general contract of the readInt + * method of DataInput. + *

+ * Bytes + * for this operation are read from the contained + * input stream. + * + * @return the next four bytes of this input stream, interpreted as an + * int. + * @exception EOFException if this input stream reaches the end before + * reading four bytes. + * @exception IOException the stream has been closed and the contained + * input stream does not support reading after close, or + * another I/O error occurs. + * @see java.io.FilterInputStream#in + */ + public final int readInt() throws IOException { + int ch1 = in.read(); + int ch2 = in.read(); + int ch3 = in.read(); + int ch4 = in.read(); + if ((ch1 | ch2 | ch3 | ch4) < 0) + throw new EOFException(); + return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0)); + } + + private byte readBuffer[] = new byte[8]; + + /** + * See the general contract of the readLong + * method of DataInput. + *

+ * Bytes + * for this operation are read from the contained + * input stream. + * + * @return the next eight bytes of this input stream, interpreted as a + * long. + * @exception EOFException if this input stream reaches the end before + * reading eight bytes. + * @exception IOException the stream has been closed and the contained + * input stream does not support reading after close, or + * another I/O error occurs. + * @see java.io.FilterInputStream#in + */ + public final long readLong() throws IOException { + readFully(readBuffer, 0, 8); + return (((long)readBuffer[0] << 56) + + ((long)(readBuffer[1] & 255) << 48) + + ((long)(readBuffer[2] & 255) << 40) + + ((long)(readBuffer[3] & 255) << 32) + + ((long)(readBuffer[4] & 255) << 24) + + ((readBuffer[5] & 255) << 16) + + ((readBuffer[6] & 255) << 8) + + ((readBuffer[7] & 255) << 0)); + } + + /** + * See the general contract of the readFloat + * method of DataInput. + *

+ * Bytes + * for this operation are read from the contained + * input stream. + * + * @return the next four bytes of this input stream, interpreted as a + * float. + * @exception EOFException if this input stream reaches the end before + * reading four bytes. + * @exception IOException the stream has been closed and the contained + * input stream does not support reading after close, or + * another I/O error occurs. + * @see java.io.DataInputStream#readInt() + * @see java.lang.Float#intBitsToFloat(int) + */ + public final float readFloat() throws IOException { + return Float.intBitsToFloat(readInt()); + } + + /** + * See the general contract of the readDouble + * method of DataInput. + *

+ * Bytes + * for this operation are read from the contained + * input stream. + * + * @return the next eight bytes of this input stream, interpreted as a + * double. + * @exception EOFException if this input stream reaches the end before + * reading eight bytes. + * @exception IOException the stream has been closed and the contained + * input stream does not support reading after close, or + * another I/O error occurs. + * @see java.io.DataInputStream#readLong() + * @see java.lang.Double#longBitsToDouble(long) + */ + public final double readDouble() throws IOException { + int hi = readInt(); + int low = readInt(); + return toDouble(hi, low); + } + + @JavaScriptBody(args={ "hi", "low" }, + body= + "if (low == 0) {\n" + + " if (hi === 0x7ff00000) return Number.POSITIVE_INFINITY;\n" + + " if (hi === 0xfff00000) return Number.NEGATIVE_INFINITY;\n" + + "}\n" + + "if (hi >= 0x7ff00000 && hi <= 0x7fffffff) return Number.NaN;\n" + + "if (hi >= 0xfff00000 && hi <= 0xffffffff) return Number.NaN;\n" + + "var s = (hi & 0x80000000) === 0 ? 1 : -1;\n" + + "var e = (hi >> 20) & 0x7ff;\n" + + "var to32 = low >> 0;\n" + + "if (e === 0) {\n" + + " if (to32 & 0x80000000) {\n" + + " hi = hi << 1 + 1; low = low << 1;\n" + + " } else {\n" + + " hi = hi << 1; low = low << 1;\n" + + " }\n" + + "} else {\n" + + " hi = (hi & 0xfffff) | 0x100000;\n" + + "}\n" + + "to32 = low >> 0;\n" + + "var m = Math.pow(2.0, 32) * hi + to32;\n" + + "var r = s * m * Math.pow(2.0, e - 1075);\n" + + "//throw 'exp: ' + e + ' sign: ' + s + ' hi:' + hi + ' low: ' + low + ' m: ' + m + ' r: ' + r;\n" + + "return r;\n" + ) + private static double toDouble(int hi, int low) { + long both = hi; + both = (both << 32) & low; + return Double.doubleToLongBits(both); + } + + private char lineBuffer[]; + + /** + * See the general contract of the readLine + * method of DataInput. + *

+ * Bytes + * for this operation are read from the contained + * input stream. + * + * @deprecated This method does not properly convert bytes to characters. + * As of JDK 1.1, the preferred way to read lines of text is via the + * BufferedReader.readLine() method. Programs that use the + * DataInputStream class to read lines can be converted to use + * the BufferedReader class by replacing code of the form: + *

+     *     DataInputStream d = new DataInputStream(in);
+     * 
+ * with: + *
+     *     BufferedReader d
+     *          = new BufferedReader(new InputStreamReader(in));
+     * 
+ * + * @return the next line of text from this input stream. + * @exception IOException if an I/O error occurs. + * @see java.io.BufferedReader#readLine() + * @see java.io.FilterInputStream#in + */ + @Deprecated + public final String readLine() throws IOException { + char buf[] = lineBuffer; + + if (buf == null) { + buf = lineBuffer = new char[128]; + } + + int room = buf.length; + int offset = 0; + int c; + +loop: while (true) { + switch (c = in.read()) { + case -1: + case '\n': + break loop; + + case '\r': + int c2 = in.read(); + if ((c2 != '\n') && (c2 != -1)) { + if (!(in instanceof PushbackInputStream)) { + this.in = new PushbackInputStream(in); + } + ((PushbackInputStream)in).unread(c2); + } + break loop; + + default: + if (--room < 0) { + buf = new char[offset + 128]; + room = buf.length - offset - 1; + arraycopy(lineBuffer, 0, buf, 0, offset); + lineBuffer = buf; + } + buf[offset++] = (char) c; + break; + } + } + if ((c == -1) && (offset == 0)) { + return null; + } + return String.copyValueOf(buf, 0, offset); + } + + /** + * See the general contract of the readUTF + * method of DataInput. + *

+ * Bytes + * for this operation are read from the contained + * input stream. + * + * @return a Unicode string. + * @exception EOFException if this input stream reaches the end before + * reading all the bytes. + * @exception IOException the stream has been closed and the contained + * input stream does not support reading after close, or + * another I/O error occurs. + * @exception UTFDataFormatException if the bytes do not represent a valid + * modified UTF-8 encoding of a string. + * @see java.io.DataInputStream#readUTF(java.io.DataInput) + */ + public final String readUTF() throws IOException { + return readUTF(this); + } + + /** + * Reads from the + * stream in a representation + * of a Unicode character string encoded in + * modified UTF-8 format; + * this string of characters is then returned as a String. + * The details of the modified UTF-8 representation + * are exactly the same as for the readUTF + * method of DataInput. + * + * @param in a data input stream. + * @return a Unicode string. + * @exception EOFException if the input stream reaches the end + * before all the bytes. + * @exception IOException the stream has been closed and the contained + * input stream does not support reading after close, or + * another I/O error occurs. + * @exception UTFDataFormatException if the bytes do not represent a + * valid modified UTF-8 encoding of a Unicode string. + * @see java.io.DataInputStream#readUnsignedShort() + */ + public final static String readUTF(DataInput in) throws IOException { + int utflen = in.readUnsignedShort(); + byte[] bytearr = null; + char[] chararr = null; + if (in instanceof DataInputStream) { + DataInputStream dis = (DataInputStream)in; + if (dis.bytearr.length < utflen){ + dis.bytearr = new byte[utflen*2]; + dis.chararr = new char[utflen*2]; + } + chararr = dis.chararr; + bytearr = dis.bytearr; + } else { + bytearr = new byte[utflen]; + chararr = new char[utflen]; + } + + int c, char2, char3; + int count = 0; + int chararr_count=0; + + in.readFully(bytearr, 0, utflen); + + while (count < utflen) { + c = (int) bytearr[count] & 0xff; + if (c > 127) break; + count++; + chararr[chararr_count++]=(char)c; + } + + while (count < utflen) { + c = (int) bytearr[count] & 0xff; + switch (c >> 4) { + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: + /* 0xxxxxxx*/ + count++; + chararr[chararr_count++]=(char)c; + break; + case 12: case 13: + /* 110x xxxx 10xx xxxx*/ + count += 2; + if (count > utflen) + throw new UTFDataFormatException( + "malformed input: partial character at end"); + char2 = (int) bytearr[count-1]; + if ((char2 & 0xC0) != 0x80) + throw new UTFDataFormatException( + "malformed input around byte " + count); + chararr[chararr_count++]=(char)(((c & 0x1F) << 6) | + (char2 & 0x3F)); + break; + case 14: + /* 1110 xxxx 10xx xxxx 10xx xxxx */ + count += 3; + if (count > utflen) + throw new UTFDataFormatException( + "malformed input: partial character at end"); + char2 = (int) bytearr[count-2]; + char3 = (int) bytearr[count-1]; + if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) + throw new UTFDataFormatException( + "malformed input around byte " + (count-1)); + chararr[chararr_count++]=(char)(((c & 0x0F) << 12) | + ((char2 & 0x3F) << 6) | + ((char3 & 0x3F) << 0)); + break; + default: + /* 10xx xxxx, 1111 xxxx */ + throw new UTFDataFormatException( + "malformed input around byte " + count); + } + } + // The number of chars produced may be less than utflen + return new String(chararr, 0, chararr_count); + } + static void arraycopy(char[] value, int srcBegin, char[] dst, int dstBegin, int count) { + while (count-- > 0) { + dst[dstBegin++] = value[srcBegin++]; + } + } +} diff -r d0aad97dfd2e -r 6a56c2381b0f emul/src/main/java/java/io/EOFException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/src/main/java/java/io/EOFException.java Sun Nov 18 22:03:15 2012 +0100 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.io; + +/** + * Signals that an end of file or end of stream has been reached + * unexpectedly during input. + *

+ * This exception is mainly used by data input streams to signal end of + * stream. Note that many other input operations return a special value on + * end of stream rather than throwing an exception. + *

+ * + * @author Frank Yellin + * @see java.io.DataInputStream + * @see java.io.IOException + * @since JDK1.0 + */ +public +class EOFException extends IOException { + private static final long serialVersionUID = 6433858223774886977L; + + /** + * Constructs an EOFException with null + * as its error detail message. + */ + public EOFException() { + super(); + } + + /** + * Constructs an EOFException with the specified detail + * message. The string s may later be retrieved by the + * {@link java.lang.Throwable#getMessage} method of class + * java.lang.Throwable. + * + * @param s the detail message. + */ + public EOFException(String s) { + super(s); + } +} diff -r d0aad97dfd2e -r 6a56c2381b0f emul/src/main/java/java/io/FilterInputStream.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/src/main/java/java/io/FilterInputStream.java Sun Nov 18 22:03:15 2012 +0100 @@ -0,0 +1,245 @@ +/* + * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.io; + +/** + * A FilterInputStream contains + * some other input stream, which it uses as + * its basic source of data, possibly transforming + * the data along the way or providing additional + * functionality. The class FilterInputStream + * itself simply overrides all methods of + * InputStream with versions that + * pass all requests to the contained input + * stream. Subclasses of FilterInputStream + * may further override some of these methods + * and may also provide additional methods + * and fields. + * + * @author Jonathan Payne + * @since JDK1.0 + */ +public +class FilterInputStream extends InputStream { + /** + * The input stream to be filtered. + */ + protected volatile InputStream in; + + /** + * Creates a FilterInputStream + * by assigning the argument in + * to the field this.in so as + * to remember it for later use. + * + * @param in the underlying input stream, or null if + * this instance is to be created without an underlying stream. + */ + protected FilterInputStream(InputStream in) { + this.in = in; + } + + /** + * Reads the next byte of data from this input stream. The value + * byte is returned as an int in the range + * 0 to 255. If no byte is available + * because the end of the stream has been reached, the value + * -1 is returned. This method blocks until input data + * is available, the end of the stream is detected, or an exception + * is thrown. + *

+ * This method + * simply performs in.read() and returns the result. + * + * @return the next byte of data, or -1 if the end of the + * stream is reached. + * @exception IOException if an I/O error occurs. + * @see java.io.FilterInputStream#in + */ + public int read() throws IOException { + return in.read(); + } + + /** + * Reads up to byte.length bytes of data from this + * input stream into an array of bytes. This method blocks until some + * input is available. + *

+ * This method simply performs the call + * read(b, 0, b.length) and returns + * the result. It is important that it does + * not do in.read(b) instead; + * certain subclasses of FilterInputStream + * depend on the implementation strategy actually + * used. + * + * @param b the buffer into which the data is read. + * @return the total number of bytes read into the buffer, or + * -1 if there is no more data because the end of + * the stream has been reached. + * @exception IOException if an I/O error occurs. + * @see java.io.FilterInputStream#read(byte[], int, int) + */ + public int read(byte b[]) throws IOException { + return read(b, 0, b.length); + } + + /** + * Reads up to len bytes of data from this input stream + * into an array of bytes. If len is not zero, the method + * blocks until some input is available; otherwise, no + * bytes are read and 0 is returned. + *

+ * This method simply performs in.read(b, off, len) + * and returns the result. + * + * @param b the buffer into which the data is read. + * @param off the start offset in the destination array b + * @param len the maximum number of bytes read. + * @return the total number of bytes read into the buffer, or + * -1 if there is no more data because the end of + * the stream has been reached. + * @exception NullPointerException If b is null. + * @exception IndexOutOfBoundsException If off is negative, + * len is negative, or len is greater than + * b.length - off + * @exception IOException if an I/O error occurs. + * @see java.io.FilterInputStream#in + */ + public int read(byte b[], int off, int len) throws IOException { + return in.read(b, off, len); + } + + /** + * Skips over and discards n bytes of data from the + * input stream. The skip method may, for a variety of + * reasons, end up skipping over some smaller number of bytes, + * possibly 0. The actual number of bytes skipped is + * returned. + *

+ * This method simply performs in.skip(n). + * + * @param n the number of bytes to be skipped. + * @return the actual number of bytes skipped. + * @exception IOException if the stream does not support seek, + * or if some other I/O error occurs. + */ + public long skip(long n) throws IOException { + return in.skip(n); + } + + /** + * Returns an estimate of the number of bytes that can be read (or + * skipped over) from this input stream without blocking by the next + * caller of a method for this input stream. The next caller might be + * the same thread or another thread. A single read or skip of this + * many bytes will not block, but may read or skip fewer bytes. + *

+ * This method returns the result of {@link #in in}.available(). + * + * @return an estimate of the number of bytes that can be read (or skipped + * over) from this input stream without blocking. + * @exception IOException if an I/O error occurs. + */ + public int available() throws IOException { + return in.available(); + } + + /** + * Closes this input stream and releases any system resources + * associated with the stream. + * This + * method simply performs in.close(). + * + * @exception IOException if an I/O error occurs. + * @see java.io.FilterInputStream#in + */ + public void close() throws IOException { + in.close(); + } + + /** + * Marks the current position in this input stream. A subsequent + * call to the reset method repositions this stream at + * the last marked position so that subsequent reads re-read the same bytes. + *

+ * The readlimit argument tells this input stream to + * allow that many bytes to be read before the mark position gets + * invalidated. + *

+ * This method simply performs in.mark(readlimit). + * + * @param readlimit the maximum limit of bytes that can be read before + * the mark position becomes invalid. + * @see java.io.FilterInputStream#in + * @see java.io.FilterInputStream#reset() + */ + public synchronized void mark(int readlimit) { + in.mark(readlimit); + } + + /** + * Repositions this stream to the position at the time the + * mark method was last called on this input stream. + *

+ * This method + * simply performs in.reset(). + *

+ * Stream marks are intended to be used in + * situations where you need to read ahead a little to see what's in + * the stream. Often this is most easily done by invoking some + * general parser. If the stream is of the type handled by the + * parse, it just chugs along happily. If the stream is not of + * that type, the parser should toss an exception when it fails. + * If this happens within readlimit bytes, it allows the outer + * code to reset the stream and try another parser. + * + * @exception IOException if the stream has not been marked or if the + * mark has been invalidated. + * @see java.io.FilterInputStream#in + * @see java.io.FilterInputStream#mark(int) + */ + public synchronized void reset() throws IOException { + in.reset(); + } + + /** + * Tests if this input stream supports the mark + * and reset methods. + * This method + * simply performs in.markSupported(). + * + * @return true if this stream type supports the + * mark and reset method; + * false otherwise. + * @see java.io.FilterInputStream#in + * @see java.io.InputStream#mark(int) + * @see java.io.InputStream#reset() + */ + public boolean markSupported() { + return in.markSupported(); + } +} diff -r d0aad97dfd2e -r 6a56c2381b0f emul/src/main/java/java/io/PushbackInputStream.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/src/main/java/java/io/PushbackInputStream.java Sun Nov 18 22:03:15 2012 +0100 @@ -0,0 +1,388 @@ +/* + * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.io; + +/** + * A PushbackInputStream adds + * functionality to another input stream, namely + * the ability to "push back" or "unread" + * one byte. This is useful in situations where + * it is convenient for a fragment of code + * to read an indefinite number of data bytes + * that are delimited by a particular byte + * value; after reading the terminating byte, + * the code fragment can "unread" it, so that + * the next read operation on the input stream + * will reread the byte that was pushed back. + * For example, bytes representing the characters + * constituting an identifier might be terminated + * by a byte representing an operator character; + * a method whose job is to read just an identifier + * can read until it sees the operator and + * then push the operator back to be re-read. + * + * @author David Connelly + * @author Jonathan Payne + * @since JDK1.0 + */ +public +class PushbackInputStream extends FilterInputStream { + /** + * The pushback buffer. + * @since JDK1.1 + */ + protected byte[] buf; + + /** + * The position within the pushback buffer from which the next byte will + * be read. When the buffer is empty, pos is equal to + * buf.length; when the buffer is full, pos is + * equal to zero. + * + * @since JDK1.1 + */ + protected int pos; + + /** + * Check to make sure that this stream has not been closed + */ + private void ensureOpen() throws IOException { + if (in == null) + throw new IOException("Stream closed"); + } + + /** + * Creates a PushbackInputStream + * with a pushback buffer of the specified size, + * and saves its argument, the input stream + * in, for later use. Initially, + * there is no pushed-back byte (the field + * pushBack is initialized to + * -1). + * + * @param in the input stream from which bytes will be read. + * @param size the size of the pushback buffer. + * @exception IllegalArgumentException if size is <= 0 + * @since JDK1.1 + */ + public PushbackInputStream(InputStream in, int size) { + super(in); + if (size <= 0) { + throw new IllegalArgumentException("size <= 0"); + } + this.buf = new byte[size]; + this.pos = size; + } + + /** + * Creates a PushbackInputStream + * and saves its argument, the input stream + * in, for later use. Initially, + * there is no pushed-back byte (the field + * pushBack is initialized to + * -1). + * + * @param in the input stream from which bytes will be read. + */ + public PushbackInputStream(InputStream in) { + this(in, 1); + } + + /** + * Reads the next byte of data from this input stream. The value + * byte is returned as an int in the range + * 0 to 255. If no byte is available + * because the end of the stream has been reached, the value + * -1 is returned. This method blocks until input data + * is available, the end of the stream is detected, or an exception + * is thrown. + * + *

This method returns the most recently pushed-back byte, if there is + * one, and otherwise calls the read method of its underlying + * input stream and returns whatever value that method returns. + * + * @return the next byte of data, or -1 if the end of the + * stream has been reached. + * @exception IOException if this input stream has been closed by + * invoking its {@link #close()} method, + * or an I/O error occurs. + * @see java.io.InputStream#read() + */ + public int read() throws IOException { + ensureOpen(); + if (pos < buf.length) { + return buf[pos++] & 0xff; + } + return super.read(); + } + + /** + * Reads up to len bytes of data from this input stream into + * an array of bytes. This method first reads any pushed-back bytes; after + * that, if fewer than len bytes have been read then it + * reads from the underlying input stream. If len is not zero, the method + * blocks until at least 1 byte of input is available; otherwise, no + * bytes are read and 0 is returned. + * + * @param b the buffer into which the data is read. + * @param off the start offset in the destination array b + * @param len the maximum number of bytes read. + * @return the total number of bytes read into the buffer, or + * -1 if there is no more data because the end of + * the stream has been reached. + * @exception NullPointerException If b is null. + * @exception IndexOutOfBoundsException If off is negative, + * len is negative, or len is greater than + * b.length - off + * @exception IOException if this input stream has been closed by + * invoking its {@link #close()} method, + * or an I/O error occurs. + * @see java.io.InputStream#read(byte[], int, int) + */ + public int read(byte[] b, int off, int len) throws IOException { + ensureOpen(); + if (b == null) { + throw new NullPointerException(); + } else if (off < 0 || len < 0 || len > b.length - off) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) { + return 0; + } + + int avail = buf.length - pos; + if (avail > 0) { + if (len < avail) { + avail = len; + } + arraycopy(buf, pos, b, off, avail); + pos += avail; + off += avail; + len -= avail; + } + if (len > 0) { + len = super.read(b, off, len); + if (len == -1) { + return avail == 0 ? -1 : avail; + } + return avail + len; + } + return avail; + } + + /** + * Pushes back a byte by copying it to the front of the pushback buffer. + * After this method returns, the next byte to be read will have the value + * (byte)b. + * + * @param b the int value whose low-order + * byte is to be pushed back. + * @exception IOException If there is not enough room in the pushback + * buffer for the byte, or this input stream has been closed by + * invoking its {@link #close()} method. + */ + public void unread(int b) throws IOException { + ensureOpen(); + if (pos == 0) { + throw new IOException("Push back buffer is full"); + } + buf[--pos] = (byte)b; + } + + /** + * Pushes back a portion of an array of bytes by copying it to the front + * of the pushback buffer. After this method returns, the next byte to be + * read will have the value b[off], the byte after that will + * have the value b[off+1], and so forth. + * + * @param b the byte array to push back. + * @param off the start offset of the data. + * @param len the number of bytes to push back. + * @exception IOException If there is not enough room in the pushback + * buffer for the specified number of bytes, + * or this input stream has been closed by + * invoking its {@link #close()} method. + * @since JDK1.1 + */ + public void unread(byte[] b, int off, int len) throws IOException { + ensureOpen(); + if (len > pos) { + throw new IOException("Push back buffer is full"); + } + pos -= len; + arraycopy(b, off, buf, pos, len); + } + + /** + * Pushes back an array of bytes by copying it to the front of the + * pushback buffer. After this method returns, the next byte to be read + * will have the value b[0], the byte after that will have the + * value b[1], and so forth. + * + * @param b the byte array to push back + * @exception IOException If there is not enough room in the pushback + * buffer for the specified number of bytes, + * or this input stream has been closed by + * invoking its {@link #close()} method. + * @since JDK1.1 + */ + public void unread(byte[] b) throws IOException { + unread(b, 0, b.length); + } + + /** + * Returns an estimate of the number of bytes that can be read (or + * skipped over) from this input stream without blocking by the next + * invocation of a method for this input stream. The next invocation might be + * the same thread or another thread. A single read or skip of this + * many bytes will not block, but may read or skip fewer bytes. + * + *

The method returns the sum of the number of bytes that have been + * pushed back and the value returned by {@link + * java.io.FilterInputStream#available available}. + * + * @return the number of bytes that can be read (or skipped over) from + * the input stream without blocking. + * @exception IOException if this input stream has been closed by + * invoking its {@link #close()} method, + * or an I/O error occurs. + * @see java.io.FilterInputStream#in + * @see java.io.InputStream#available() + */ + public int available() throws IOException { + ensureOpen(); + int n = buf.length - pos; + int avail = super.available(); + return n > (Integer.MAX_VALUE - avail) + ? Integer.MAX_VALUE + : n + avail; + } + + /** + * Skips over and discards n bytes of data from this + * input stream. The skip method may, for a variety of + * reasons, end up skipping over some smaller number of bytes, + * possibly zero. If n is negative, no bytes are skipped. + * + *

The skip method of PushbackInputStream + * first skips over the bytes in the pushback buffer, if any. It then + * calls the skip method of the underlying input stream if + * more bytes need to be skipped. The actual number of bytes skipped + * is returned. + * + * @param n {@inheritDoc} + * @return {@inheritDoc} + * @exception IOException if the stream does not support seek, + * or the stream has been closed by + * invoking its {@link #close()} method, + * or an I/O error occurs. + * @see java.io.FilterInputStream#in + * @see java.io.InputStream#skip(long n) + * @since 1.2 + */ + public long skip(long n) throws IOException { + ensureOpen(); + if (n <= 0) { + return 0; + } + + long pskip = buf.length - pos; + if (pskip > 0) { + if (n < pskip) { + pskip = n; + } + pos += pskip; + n -= pskip; + } + if (n > 0) { + pskip += super.skip(n); + } + return pskip; + } + + /** + * Tests if this input stream supports the mark and + * reset methods, which it does not. + * + * @return false, since this class does not support the + * mark and reset methods. + * @see java.io.InputStream#mark(int) + * @see java.io.InputStream#reset() + */ + public boolean markSupported() { + return false; + } + + /** + * Marks the current position in this input stream. + * + *

The mark method of PushbackInputStream + * does nothing. + * + * @param readlimit the maximum limit of bytes that can be read before + * the mark position becomes invalid. + * @see java.io.InputStream#reset() + */ + public synchronized void mark(int readlimit) { + } + + /** + * Repositions this stream to the position at the time the + * mark method was last called on this input stream. + * + *

The method reset for class + * PushbackInputStream does nothing except throw an + * IOException. + * + * @exception IOException if this method is invoked. + * @see java.io.InputStream#mark(int) + * @see java.io.IOException + */ + public synchronized void reset() throws IOException { + throw new IOException("mark/reset not supported"); + } + + /** + * Closes this input stream and releases any system resources + * associated with the stream. + * Once the stream has been closed, further read(), unread(), + * available(), reset(), or skip() invocations will throw an IOException. + * Closing a previously closed stream has no effect. + * + * @exception IOException if an I/O error occurs. + */ + public synchronized void close() throws IOException { + if (in == null) + return; + in.close(); + in = null; + buf = null; + } + static void arraycopy(byte[] value, int srcBegin, byte[] dst, int dstBegin, int count) { + while (count-- > 0) { + dst[dstBegin++] = value[srcBegin++]; + } + } +} diff -r d0aad97dfd2e -r 6a56c2381b0f emul/src/main/java/java/io/UTFDataFormatException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/src/main/java/java/io/UTFDataFormatException.java Sun Nov 18 22:03:15 2012 +0100 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.io; + +/** + * Signals that a malformed string in + * modified UTF-8 + * format has been read in a data + * input stream or by any class that implements the data input + * interface. + * See the + * DataInput + * class description for the format in + * which modified UTF-8 strings are read and written. + * + * @author Frank Yellin + * @see java.io.DataInput + * @see java.io.DataInputStream#readUTF(java.io.DataInput) + * @see java.io.IOException + * @since JDK1.0 + */ +public +class UTFDataFormatException extends IOException { + private static final long serialVersionUID = 420743449228280612L; + + /** + * Constructs a UTFDataFormatException with + * null as its error detail message. + */ + public UTFDataFormatException() { + super(); + } + + /** + * Constructs a UTFDataFormatException with the + * specified detail message. The string s can be + * retrieved later by the + * {@link java.lang.Throwable#getMessage} + * method of class java.lang.Throwable. + * + * @param s the detail message. + */ + public UTFDataFormatException(String s) { + super(s); + } +} diff -r d0aad97dfd2e -r 6a56c2381b0f emul/src/main/java/java/lang/AbstractStringBuilder.java --- a/emul/src/main/java/java/lang/AbstractStringBuilder.java Tue Nov 13 07:56:02 2012 +0100 +++ b/emul/src/main/java/java/lang/AbstractStringBuilder.java Sun Nov 18 22:03:15 2012 +0100 @@ -1417,7 +1417,7 @@ static void arraycopy(char[] value, int srcBegin, char[] dst, int dstBegin, int count) { while (count-- > 0) { - dst[dstBegin++] = value[srcBegin++]; + dst[dstBegin + count] = value[srcBegin + count]; } } diff -r d0aad97dfd2e -r 6a56c2381b0f emul/src/main/java/java/lang/Double.java --- a/emul/src/main/java/java/lang/Double.java Tue Nov 13 07:56:02 2012 +0100 +++ b/emul/src/main/java/java/lang/Double.java Sun Nov 18 22:03:15 2012 +0100 @@ -190,7 +190,9 @@ * @param d the {@code double} to be converted. * @return a string representation of the argument. */ - @JavaScriptBody(args="d", body="return d.toString();") + @JavaScriptBody(args="d", body="var r = d.toString();" + + "if (r.indexOf('.') === -1) r = r + '.0';" + + "return r;") public static String toString(double d) { throw new UnsupportedOperationException(); } diff -r d0aad97dfd2e -r 6a56c2381b0f emul/src/main/java/java/lang/Float.java --- a/emul/src/main/java/java/lang/Float.java Tue Nov 13 07:56:02 2012 +0100 +++ b/emul/src/main/java/java/lang/Float.java Sun Nov 18 22:03:15 2012 +0100 @@ -192,10 +192,8 @@ * @param f the float to be converted. * @return a string representation of the argument. */ - @JavaScriptBody(args="d", body="return d.toString();") public static String toString(float f) { - throw new UnsupportedOperationException(); -// return new FloatingDecimal(f).toJavaFormatString(); + return Double.toString(f); } /** @@ -819,6 +817,18 @@ * @return the {@code float} floating-point value with the same bit * pattern. */ + @JavaScriptBody(args = "bits", + body = + "if (bits === 0x7f800000) return Number.POSITIVE_INFINITY;\n" + + "if (bits === 0xff800000) return Number.NEGATIVE_INFINITY;\n" + + "if (bits >= 0x7f800001 && bits <= 0xffffffff) return Number.NaN;\n" + + "var s = ((bits >> 31) == 0) ? 1 : -1;\n" + + "var e = ((bits >> 23) & 0xff);\n" + + "var m = (e == 0) ?\n" + + " (bits & 0x7fffff) << 1 :\n" + + " (bits & 0x7fffff) | 0x800000;\n" + + "return s * m * Math.pow(2.0, e - 150);\n" + ) public static native float intBitsToFloat(int bits); /** diff -r d0aad97dfd2e -r 6a56c2381b0f emul/src/main/java/java/lang/Integer.java --- a/emul/src/main/java/java/lang/Integer.java Tue Nov 13 07:56:02 2012 +0100 +++ b/emul/src/main/java/java/lang/Integer.java Sun Nov 18 22:03:15 2012 +0100 @@ -324,13 +324,14 @@ * @param i an integer to be converted. * @return a string representation of the argument in base 10. */ + @JavaScriptBody(args = "i", body = "return i.toString();") public static String toString(int i) { if (i == Integer.MIN_VALUE) return "-2147483648"; int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i); char[] buf = new char[size]; getChars(i, size, buf); - return new String(0, size, buf); + return new String(buf, 0, size); } /** diff -r d0aad97dfd2e -r 6a56c2381b0f emul/src/main/java/java/lang/Long.java --- a/emul/src/main/java/java/lang/Long.java Tue Nov 13 07:56:02 2012 +0100 +++ b/emul/src/main/java/java/lang/Long.java Sun Nov 18 22:03:15 2012 +0100 @@ -25,6 +25,8 @@ package java.lang; +import org.apidesign.bck2brwsr.core.JavaScriptBody; + /** * The {@code Long} class wraps a value of the primitive type {@code * long} in an object. An object of type {@code Long} contains a @@ -260,13 +262,14 @@ * @param i a {@code long} to be converted. * @return a string representation of the argument in base 10. */ + @JavaScriptBody(args = "i", body = "return i.toString();") public static String toString(long i) { if (i == Long.MIN_VALUE) return "-9223372036854775808"; int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i); char[] buf = new char[size]; getChars(i, size, buf); - return new String(0, size, buf); + return new String(buf, 0, size); } /** diff -r d0aad97dfd2e -r 6a56c2381b0f emul/src/main/java/java/lang/String.java --- a/emul/src/main/java/java/lang/String.java Tue Nov 13 07:56:02 2012 +0100 +++ b/emul/src/main/java/java/lang/String.java Sun Nov 18 22:03:15 2012 +0100 @@ -641,14 +641,6 @@ this.offset = result.offset; } - - // Package private constructor which shares value array for speed. - String(int offset, int count, char value[]) { - this.value = value; - this.offset = offset; - this.count = count; - } - /** * Returns the length of this string. * The length is equal to the number of Unicode @@ -1966,7 +1958,7 @@ throw new StringIndexOutOfBoundsException(endIndex - beginIndex); } return ((beginIndex == 0) && (endIndex == count)) ? this : - new String(offset + beginIndex, endIndex - beginIndex, value); + new String(value, offset + beginIndex, endIndex - beginIndex); } /** @@ -2029,7 +2021,7 @@ char buf[] = new char[count + otherLen]; getChars(0, count, buf, 0); str.getChars(0, otherLen, buf, count); - return new String(0, count + otherLen, buf); + return new String(buf, 0, count + otherLen); } /** @@ -2083,7 +2075,7 @@ buf[i] = (c == oldChar) ? newChar : c; i++; } - return new String(0, len, buf); + return new String(buf, 0, len); } } return this; @@ -2951,7 +2943,7 @@ */ public static String valueOf(char c) { char data[] = {c}; - return new String(0, 1, data); + return new String(data, 0, 1); } /** diff -r d0aad97dfd2e -r 6a56c2381b0f emul/src/main/resources/org/apidesign/vm4brwsr/emul/java_lang_String.js --- a/emul/src/main/resources/org/apidesign/vm4brwsr/emul/java_lang_String.js Tue Nov 13 07:56:02 2012 +0100 +++ b/emul/src/main/resources/org/apidesign/vm4brwsr/emul/java_lang_String.js Sun Nov 18 22:03:15 2012 +0100 @@ -1,16 +1,23 @@ /* */ -function java_lang_String_consVAC(arg0,arg1) { - arg0.r = arg1.join(""); +function java_lang_String_consVAC(self,charArr) { + for (var i = 0; i < charArr.length; i++) { + if (typeof charArr[i] === 'number') charArr[i] = String.fromCharCode(charArr[i]); + } + self.r = charArr.join(""); } function java_lang_String_consVACII(self, charArr, off, cnt) { - self.r = charArr.slice(off, off + cnt).join(""); + var up = off + cnt; + for (var i = off; i < up; i++) { + if (typeof charArr[i] === 'number') charArr[i] = String.fromCharCode(charArr[i]); + } + self.r = charArr.slice(off, up).join(""); } function java_lang_String_charAtCI(arg0,arg1) { - return arg0.toString().charAt(arg1); + return arg0.toString().charCodeAt(arg1); } function java_lang_String_lengthI(arg0) { return arg0.toString().length; @@ -18,6 +25,42 @@ function java_lang_String_isEmptyZ(arg0) { return arg0.toString().length === 0; } +function java_lang_String_valueOfLjava_lang_StringI(n) { + return n.toString(); +} + +function java_lang_String_startsWithZLjava_lang_StringI(self,find,from) { + find = find.toString(); + return self.toString().substring(from, find.length) === find; +} +function java_lang_String_startsWithZLjava_lang_String(self,find) { + find = find.toString(); + return self.toString().substring(0, find.length) === find; +} +function java_lang_String_endsWithZLjava_lang_String(self,find) { + self = self.toString(); + find = find.toString(); + if (find.length > self.length) { + return false; + } + return self.substring(self.length - find.length) === find; +} + +function java_lang_String_indexOfII(arg0,ch) { + if (typeof ch === 'number') ch = String.fromCharCode(ch); + return arg0.toString().indexOf(ch); +} +function java_lang_String_indexOfIII(arg0,ch,from) { + if (typeof ch === 'number') ch = String.fromCharCode(ch); + return arg0.toString().indexOf(ch, from); +} + +function java_lang_String_getCharsVACI(self, arr, to) { + var s = self.toString(); + for (var i = 0; i < s.length; i++) { + arr[to++] = s[i]; + } +} /* function java_lang_String_codePointAtII(arg0,arg1) { @@ -860,116 +903,6 @@ case 63: return stack.pop(); // 172 } } -function java_lang_String_indexOfII(arg0,arg1) { - var arg2; -; - var stack = new Array(3); - var gt = 0; - for(;;) switch(gt) { - case 0: stack.push(arg0); // 42 - case 1: stack.push(arg1); // 27 - case 2: stack.push(0); // 3 - case 3: { var v1 = stack.pop(); var v0 = stack.pop(); var self = stack.pop(); stack.push(self.indexOfIII(self, v0, v1)); } // 182 1 135 - case 6: return stack.pop(); // 172 - } -} -function java_lang_String_indexOfIII(arg0,arg1,arg2) { - var arg3; - var arg4; - var arg5; - var arg6; - var arg7; -; - var stack = new Array(3); - var gt = 0; - for(;;) switch(gt) { - case 0: stack.push(arg0); // 42 - case 1: stack.push(stack.pop().offset); // 180 1 99 - case 4: stack.push(arg0); // 42 - case 5: stack.push(stack.pop().count); // 180 1 97 - case 8: stack.push(stack.pop() + stack.pop()); // 96 - case 9: arg3 = stack.pop(); // 62 - case 10: stack.push(arg0); // 42 - case 11: stack.push(stack.pop().value); // 180 1 100 - case 14: arg4 = stack.pop() // 58 4 - case 16: stack.push(arg2); // 28 - case 17: if (stack.pop() >= 0) { gt = 25; continue; } // 156 0 8 - case 20: stack.push(0); // 3 - case 21: arg2 = stack.pop(); // 61 - case 22: gt = 35; continue; // 167 0 13 - case 25: stack.push(arg2); // 28 - case 26: stack.push(arg0); // 42 - case 27: stack.push(stack.pop().count); // 180 1 97 - case 30: if (stack.pop() > stack.pop()) { gt = 35; continue; } // 161 0 5 - case 33: // 2 - case 34: return stack.pop(); // 172 - case 35: stack.push(arg0); // 42 - case 36: stack.push(stack.pop().offset); // 180 1 99 - case 39: stack.push(arg2); // 28 - case 40: stack.push(stack.pop() + stack.pop()); // 96 - case 41: arg5 = stack.pop() // 54 5 - case 43: stack.push(arg1); // 27 - case 44: stack.push(65536); // 18 3 - case 46: if (stack.pop() <= stack.pop()) { gt = 80; continue; } // 162 0 34 - case 49: stack.push(arg5); // 21 5 - case 51: stack.push(arg3); // 29 - case 52: if (stack.pop() <= stack.pop()) { gt = 78; continue; } // 162 0 26 - case 55: stack.push(arg4); // 25 4 - case 57: stack.push(arg5); // 21 5 - case 59: { var indx = stack.pop(); stack.push(stack.pop()[indx]); } // 52 - case 60: stack.push(arg1); // 27 - case 61: if (stack.pop() != stack.pop()) { gt = 72; continue; } // 160 0 11 - case 64: stack.push(arg5); // 21 5 - case 66: stack.push(arg0); // 42 - case 67: stack.push(stack.pop().offset); // 180 1 99 - case 70: { var tmp = stack.pop(); stack.push(stack.pop() - tmp); } // 100 - case 71: return stack.pop(); // 172 - case 72: arg5++; // 132 5 1 - case 75: gt = 49; continue; // 167 255 230 - case 78: // 2 - case 79: return stack.pop(); // 172 - case 80: stack.push(arg1); // 27 - case 81: stack.push(1114111); // 18 4 - case 83: if (stack.pop() < stack.pop()) { gt = 149; continue; } // 163 0 66 - case 86: stack.push(arg1); // 27 - case 87: { var v0 = stack.pop(); stack.push(java_lang_Character_toCharsACI(v0)); } // 184 1 109 - case 90: arg6 = stack.pop() // 58 6 - case 92: stack.push(arg5); // 21 5 - case 94: stack.push(arg3); // 29 - case 95: if (stack.pop() <= stack.pop()) { gt = 149; continue; } // 162 0 54 - case 98: stack.push(arg4); // 25 4 - case 100: stack.push(arg5); // 21 5 - case 102: { var indx = stack.pop(); stack.push(stack.pop()[indx]); } // 52 - case 103: stack.push(arg6); // 25 6 - case 105: stack.push(0); // 3 - case 106: { var indx = stack.pop(); stack.push(stack.pop()[indx]); } // 52 - case 107: if (stack.pop() != stack.pop()) { gt = 143; continue; } // 160 0 36 - case 110: stack.push(arg5); // 21 5 - case 112: stack.push(1); // 4 - case 113: stack.push(stack.pop() + stack.pop()); // 96 - case 114: stack.push(arg3); // 29 - case 115: if (stack.pop() != stack.pop()) { gt = 121; continue; } // 160 0 6 - case 118: gt = 149; continue; // 167 0 31 - case 121: stack.push(arg4); // 25 4 - case 123: stack.push(arg5); // 21 5 - case 125: stack.push(1); // 4 - case 126: stack.push(stack.pop() + stack.pop()); // 96 - case 127: { var indx = stack.pop(); stack.push(stack.pop()[indx]); } // 52 - case 128: stack.push(arg6); // 25 6 - case 130: stack.push(1); // 4 - case 131: { var indx = stack.pop(); stack.push(stack.pop()[indx]); } // 52 - case 132: if (stack.pop() != stack.pop()) { gt = 143; continue; } // 160 0 11 - case 135: stack.push(arg5); // 21 5 - case 137: stack.push(arg0); // 42 - case 138: stack.push(stack.pop().offset); // 180 1 99 - case 141: { var tmp = stack.pop(); stack.push(stack.pop() - tmp); } // 100 - case 142: return stack.pop(); // 172 - case 143: arg5++; // 132 5 1 - case 146: gt = 92; continue; // 167 255 202 - case 149: // 2 - case 150: return stack.pop(); // 172 - } -} function java_lang_String_lastIndexOfII(arg0,arg1) { var arg2; ; @@ -1367,6 +1300,23 @@ function java_lang_String_substringLjava_lang_StringII(arg0,arg1,arg2) { return arg0.toString().substring(arg1, arg2); } + +function java_lang_String_replaceLjava_lang_StringCC(arg0,arg1,arg2) { + if (typeof arg1 === 'number') arg1 = String.fromCharCode(arg1); + if (typeof arg2 === 'number') arg2 = String.fromCharCode(arg2); + var s = arg0.toString(); + for (;;) { + var ret = s.replace(arg1, arg2); + if (ret === s) { + return ret; + } + s = ret; + } +} +function java_lang_String_containsZLjava_lang_CharSequence(arg0,arg1) { + return arg0.toString().indexOf(arg1.toString()) >= 0; +} + /* function java_lang_String_subSequenceLjava_lang_CharSequenceII(arg0,arg1,arg2) { var arg3; @@ -1428,96 +1378,6 @@ case 57: return stack.pop(); // 176 } } -function java_lang_String_replaceLjava_lang_StringCC(arg0,arg1,arg2) { - var arg3; - var arg4; - var arg5; - var arg6; - var arg7; - var arg8; - var arg9; -; - var stack = new Array(5); - var gt = 0; - for(;;) switch(gt) { - case 0: stack.push(arg1); // 27 - case 1: stack.push(arg2); // 28 - case 2: if (stack.pop() == stack.pop()) { gt = 140; continue; } // 159 0 138 - case 5: stack.push(arg0); // 42 - case 6: stack.push(stack.pop().count); // 180 1 97 - case 9: arg3 = stack.pop(); // 62 - case 10: // 2 - case 11: arg4 = stack.pop() // 54 4 - case 13: stack.push(arg0); // 42 - case 14: stack.push(stack.pop().value); // 180 1 100 - case 17: arg5 = stack.pop() // 58 5 - case 19: stack.push(arg0); // 42 - case 20: stack.push(stack.pop().offset); // 180 1 99 - case 23: arg6 = stack.pop() // 54 6 - case 25: arg4++; // 132 4 1 - case 28: stack.push(arg4); // 21 4 - case 30: stack.push(arg3); // 29 - case 31: if (stack.pop() <= stack.pop()) { gt = 49; continue; } // 162 0 18 - case 34: stack.push(arg5); // 25 5 - case 36: stack.push(arg6); // 21 6 - case 38: stack.push(arg4); // 21 4 - case 40: stack.push(stack.pop() + stack.pop()); // 96 - case 41: { var indx = stack.pop(); stack.push(stack.pop()[indx]); } // 52 - case 42: stack.push(arg1); // 27 - case 43: if (stack.pop() != stack.pop()) { gt = 25; continue; } // 160 255 238 - case 46: gt = 49; continue; // 167 0 3 - case 49: stack.push(arg4); // 21 4 - case 51: stack.push(arg3); // 29 - case 52: if (stack.pop() <= stack.pop()) { gt = 140; continue; } // 162 0 88 - case 55: stack.push(arg3); // 29 - case 56: stack.push(new Array(stack.pop())); // 188 5 - case 58: arg7 = stack.pop() // 58 7 - case 60: stack.push(0); // 3 - case 61: arg8 = stack.pop() // 54 8 - case 63: stack.push(arg8); // 21 8 - case 65: stack.push(arg4); // 21 4 - case 67: if (stack.pop() <= stack.pop()) { gt = 89; continue; } // 162 0 22 - case 70: stack.push(arg7); // 25 7 - case 72: stack.push(arg8); // 21 8 - case 74: stack.push(arg5); // 25 5 - case 76: stack.push(arg6); // 21 6 - case 78: stack.push(arg8); // 21 8 - case 80: stack.push(stack.pop() + stack.pop()); // 96 - case 81: { var indx = stack.pop(); stack.push(stack.pop()[indx]); } // 52 - case 82: { var value = stack.pop(); var indx = stack.pop(); stack.pop()[indx] = value; } // 85 - case 83: arg8++; // 132 8 1 - case 86: gt = 63; continue; // 167 255 233 - case 89: stack.push(arg4); // 21 4 - case 91: stack.push(arg3); // 29 - case 92: if (stack.pop() <= stack.pop()) { gt = 128; continue; } // 162 0 36 - case 95: stack.push(arg5); // 25 5 - case 97: stack.push(arg6); // 21 6 - case 99: stack.push(arg4); // 21 4 - case 101: stack.push(stack.pop() + stack.pop()); // 96 - case 102: { var indx = stack.pop(); stack.push(stack.pop()[indx]); } // 52 - case 103: arg8 = stack.pop() // 54 8 - case 105: stack.push(arg7); // 25 7 - case 107: stack.push(arg4); // 21 4 - case 109: stack.push(arg8); // 21 8 - case 111: stack.push(arg1); // 27 - case 112: if (stack.pop() != stack.pop()) { gt = 119; continue; } // 160 0 7 - case 115: stack.push(arg2); // 28 - case 116: gt = 121; continue; // 167 0 5 - case 119: stack.push(arg8); // 21 8 - case 121: { var value = stack.pop(); var indx = stack.pop(); stack.pop()[indx] = value; } // 85 - case 122: arg4++; // 132 4 1 - case 125: gt = 89; continue; // 167 255 220 - case 128: stack.push(new java_lang_String); // 187 0 200 - case 131: stack.push(stack[stack.length - 1]); // 89 - case 132: stack.push(0); // 3 - case 133: stack.push(arg3); // 29 - case 134: stack.push(arg7); // 25 7 - case 136: { var v2 = stack.pop(); var v1 = stack.pop(); var v0 = stack.pop(); java_lang_String_consVIIAC(stack.pop(), v0, v1, v2); } // 183 1 137 - case 139: return stack.pop(); // 176 - case 140: stack.push(arg0); // 42 - case 141: return stack.pop(); // 176 - } -} function java_lang_String_matchesZLjava_lang_String(arg0,arg1) { var arg2; ; @@ -1530,24 +1390,6 @@ case 5: return stack.pop(); // 172 } } -function java_lang_String_containsZLjava_lang_CharSequence(arg0,arg1) { - var arg2; -; - var stack = new Array(2); - var gt = 0; - for(;;) switch(gt) { - case 0: stack.push(arg0); // 42 - case 1: stack.push(arg1); // 43 - case 2: { var self = stack.pop(); stack.push(self.toStringLjava_lang_String(self)); } // 182 1 132 - case 5: { var v0 = stack.pop(); var self = stack.pop(); stack.push(self.indexOfILjava_lang_String(self, v0)); } // 182 1 149 - case 8: // 2 - case 9: if (stack.pop() >= stack.pop()) { gt = 16; continue; } // 164 0 7 - case 12: stack.push(1); // 4 - case 13: gt = 17; continue; // 167 0 4 - case 16: stack.push(0); // 3 - case 17: return stack.pop(); // 172 - } -} function java_lang_String_replaceFirstLjava_lang_StringLjava_lang_StringLjava_lang_String(arg0,arg1,arg2) { var arg3; ; @@ -2228,29 +2070,10 @@ function java_lang_String_toStringLjava_lang_String(arg0) { return arg0.toString(); } +function java_lang_String_toCharArrayAC(arg0) { + return arg0.toString().split(''); +} /* -function java_lang_String_toCharArrayAC(arg0) { - var arg1; - var arg2; -; - var stack = new Array(5); - var gt = 0; - for(;;) switch(gt) { - case 0: stack.push(arg0); // 42 - case 1: stack.push(stack.pop().count); // 180 1 97 - case 4: stack.push(new Array(stack.pop())); // 188 5 - case 6: arg1 = stack.pop(); // 76 - case 7: stack.push(arg0); // 42 - case 8: stack.push(0); // 3 - case 9: stack.push(arg0); // 42 - case 10: stack.push(stack.pop().count); // 180 1 97 - case 13: stack.push(arg1); // 43 - case 14: stack.push(0); // 3 - case 15: { var v3 = stack.pop(); var v2 = stack.pop(); var v1 = stack.pop(); var v0 = stack.pop(); var self = stack.pop(); self.getCharsVIIACAI(self, v0, v1, v2, v3); } // 182 1 138 - case 18: stack.push(arg1); // 43 - case 19: return stack.pop(); // 176 - } -} function java_lang_String_formatLjava_lang_StringLjava_lang_StringLjava_lang_Object(arg0,arg1) { var stack = new Array(); var gt = 0; @@ -2375,16 +2198,6 @@ case 18: return stack.pop(); // 176 } } -function java_lang_String_valueOfLjava_lang_StringI(arg0) { - var stack = new Array(); - var gt = 0; - for(;;) switch(gt) { - case 0: stack.push(arg0); // 26 - case 1: stack.push(10); // 16 10 - case 3: { var v1 = stack.pop(); var v0 = stack.pop(); stack.push(java_lang_Integer_toStringLjava_lang_StringII(v0, v1)); } // 184 1 125 - case 6: return stack.pop(); // 176 - } -} function java_lang_String_valueOfLjava_lang_StringJ(arg0) { var arg1; var stack = new Array(); @@ -2471,10 +2284,21 @@ String.prototype.lengthI = java_lang_String_lengthI; String.prototype.isEmptyZ = java_lang_String_isEmptyZ; String.prototype.getCharsVIIACI = java_lang_String_getCharsVIIACAI; +String.prototype.getCharsVACI = java_lang_String_getCharsVACI; String.prototype.toStringLjava_lang_String = java_lang_String_toStringLjava_lang_String; String.prototype.substringLjava_lang_StringI = java_lang_String_substringLjava_lang_StringI; String.prototype.substringLjava_lang_StringII = java_lang_String_substringLjava_lang_StringII; +String.prototype.replaceLjava_lang_StringCC = java_lang_String_replaceLjava_lang_StringCC; +String.prototype.containsZLjava_lang_CharSequence = java_lang_String_containsZLjava_lang_CharSequence; String.prototype.equalsZLjava_lang_Object = java_lang_String_equalsZLjava_lang_Object; +String.prototype.toCharArrayAC = java_lang_String_toCharArrayAC; +String.prototype.valueOfLjava_lang_StringI=java_lang_String_valueOfLjava_lang_StringI; +String.prototype.startsWithZLjava_lang_StringI = java_lang_String_startsWithZLjava_lang_StringI; +String.prototype.startsWithZLjava_lang_String=java_lang_String_startsWithZLjava_lang_String; +String.prototype.endsWithZLjava_lang_String=java_lang_String_endsWithZLjava_lang_String; +String.prototype.indexOfII=java_lang_String_indexOfII; +String.prototype.indexOfIII=java_lang_String_indexOfIII; + String.prototype.$instOf_java_lang_String = true; String.prototype.$instOf_java_io_Serializable = true; String.prototype.$instOf_java_lang_Comparable = true; @@ -2532,7 +2356,6 @@ this.toUpperCaseLjava_lang_String = java_lang_String_toUpperCaseLjava_lang_String; this.trimLjava_lang_String = java_lang_String_trimLjava_lang_String; this.toStringLjava_lang_String = java_lang_String_toStringLjava_lang_String; - this.toCharArrayAC = java_lang_String_toCharArrayAC; this.internLjava_lang_String = java_lang_String_internLjava_lang_String; this.compareToILjava_lang_Object = java_lang_String_compareToILjava_lang_Object; */ diff -r d0aad97dfd2e -r 6a56c2381b0f javap/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javap/pom.xml Sun Nov 18 22:03:15 2012 +0100 @@ -0,0 +1,41 @@ + + + 4.0.0 + + org.apidesign + bck2brwsr + 1.0-SNAPSHOT + + org.apidesign.bck2brwsr + javap + 1.0-SNAPSHOT + javap + http://maven.apache.org + + UTF-8 + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.5.1 + + + + + 1.6 + 1.6 + + + + + + + org.apidesign.bck2brwsr + emul + 1.0-SNAPSHOT + + + diff -r d0aad97dfd2e -r 6a56c2381b0f javap/src/main/java/org/apidesign/javap/AnnotationParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javap/src/main/java/org/apidesign/javap/AnnotationParser.java Sun Nov 18 22:03:15 2012 +0100 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.apidesign.javap; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; + +/** An abstract parser for annotation definitions. Analyses the bytes and + * performs some callbacks to the overriden parser methods. + * + * @author Jaroslav Tulach + */ +public class AnnotationParser { + protected AnnotationParser() { + } + + protected void visitAttr(String type, String attr, String value) { + } + + /** Initialize the parsing with constant pool from cd. + * + * @param attr the attribute defining annotations + * @param cd constant pool + * @throws IOException in case I/O fails + */ + public final void parse(byte[] attr, ClassData cd) throws IOException { + ByteArrayInputStream is = new ByteArrayInputStream(attr); + DataInputStream dis = new DataInputStream(is); + try { + read(dis, cd); + } finally { + is.close(); + } + } + + private void read(DataInputStream dis, ClassData cd) throws IOException { + int cnt = dis.readUnsignedShort(); + for (int i = 0; i < cnt; i++) { + readAnno(dis, cd); + } + } + + private void readAnno(DataInputStream dis, ClassData cd) throws IOException { + int type = dis.readUnsignedShort(); + String typeName = cd.StringValue(type); + int cnt = dis.readUnsignedShort(); + for (int i = 0; i < cnt; i++) { + String attrName = cd.StringValue(dis.readUnsignedShort()); + readValue(dis, cd, typeName, attrName); + } + } + + private void readValue(DataInputStream dis, ClassData cd, String typeName, String attrName) + throws IOException { + char type = (char)dis.readByte(); + if (type == '@') { + readAnno(dis, cd); + } else if ("CFJZsSIDB".indexOf(type) >= 0) { // NOI18N + int primitive = dis.readUnsignedShort(); + visitAttr(typeName, attrName, cd.StringValue(primitive)); + } else if (type == 'c') { + int cls = dis.readUnsignedShort(); + } else if (type == '[') { + int cnt = dis.readUnsignedShort(); + for (int i = 0; i < cnt; i++) { + readValue(dis, cd, typeName, attrName); + } + } else if (type == 'e') { + int enumT = dis.readUnsignedShort(); + int enumN = dis.readUnsignedShort(); + } else { + throw new IOException("Unknown type " + type); + } + } +} diff -r d0aad97dfd2e -r 6a56c2381b0f javap/src/main/java/org/apidesign/javap/AttrData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javap/src/main/java/org/apidesign/javap/AttrData.java Sun Nov 18 22:03:15 2012 +0100 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + + +package org.apidesign.javap; + +import java.io.*; + +/** + * Reads and stores attribute information. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ +class AttrData { + ClassData cls; + int name_cpx; + int datalen; + byte data[]; + + public AttrData (ClassData cls) { + this.cls=cls; + } + + /** + * Reads unknown attribute. + */ + public void read(int name_cpx, DataInputStream in) throws IOException { + this.name_cpx=name_cpx; + datalen=in.readInt(); + data=new byte[datalen]; + in.readFully(data); + } + + /** + * Reads just the name of known attribute. + */ + public void read(int name_cpx){ + this.name_cpx=name_cpx; + } + + /** + * Returns attribute name. + */ + public String getAttrName(){ + return cls.getString(name_cpx); + } + + /** + * Returns attribute data. + */ + public byte[] getData(){ + return data; + } +} diff -r d0aad97dfd2e -r 6a56c2381b0f javap/src/main/java/org/apidesign/javap/CPX.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javap/src/main/java/org/apidesign/javap/CPX.java Sun Nov 18 22:03:15 2012 +0100 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.apidesign.javap; + +/** + * Stores constant pool entry information with one field. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ +class CPX { + int cpx; + + CPX (int cpx) { + this.cpx=cpx; + } +} diff -r d0aad97dfd2e -r 6a56c2381b0f javap/src/main/java/org/apidesign/javap/CPX2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javap/src/main/java/org/apidesign/javap/CPX2.java Sun Nov 18 22:03:15 2012 +0100 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.apidesign.javap; + +/** + * Stores constant pool entry information with two fields. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ +class CPX2 { + int cpx1,cpx2; + + CPX2 (int cpx1, int cpx2) { + this.cpx1=cpx1; + this.cpx2=cpx2; + } +} diff -r d0aad97dfd2e -r 6a56c2381b0f javap/src/main/java/org/apidesign/javap/ClassData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javap/src/main/java/org/apidesign/javap/ClassData.java Sun Nov 18 22:03:15 2012 +0100 @@ -0,0 +1,699 @@ +/* + * Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.apidesign.javap; + +import java.io.*; + +/** + * Central data repository of the Java Disassembler. + * Stores all the information in java class file. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ +public final class ClassData implements RuntimeConstants { + + private int magic; + private int minor_version; + private int major_version; + private int cpool_count; + private Object cpool[]; + private int access; + private int this_class = 0;; + private int super_class; + private int interfaces_count; + private int[] interfaces = new int[0];; + private int fields_count; + private FieldData[] fields; + private int methods_count; + private MethodData[] methods; + private InnerClassData[] innerClasses; + private int attributes_count; + private AttrData[] attrs; + private String classname; + private String superclassname; + private int source_cpx=0; + private byte tags[]; + private Hashtable indexHashAscii = new Hashtable(); + private String pkgPrefix=""; + private int pkgPrefixLen=0; + + /** + * Read classfile to disassemble. + */ + public ClassData(InputStream infile) throws IOException { + this.read(new DataInputStream(infile)); + } + + /** + * Reads and stores class file information. + */ + public void read(DataInputStream in) throws IOException { + // Read the header + magic = in.readInt(); + if (magic != JAVA_MAGIC) { + throw new ClassFormatError("wrong magic: " + + toHex(magic) + ", expected " + + toHex(JAVA_MAGIC)); + } + minor_version = in.readShort(); + major_version = in.readShort(); + if (major_version != JAVA_VERSION) { + } + + // Read the constant pool + readCP(in); + access = in.readUnsignedShort(); + this_class = in.readUnsignedShort(); + super_class = in.readUnsignedShort(); + + //Read interfaces. + interfaces_count = in.readUnsignedShort(); + if(interfaces_count > 0){ + interfaces = new int[interfaces_count]; + } + for (int i = 0; i < interfaces_count; i++) { + interfaces[i]=in.readShort(); + } + + // Read the fields + readFields(in); + + // Read the methods + readMethods(in); + + // Read the attributes + attributes_count = in.readUnsignedShort(); + attrs=new AttrData[attributes_count]; + for (int k = 0; k < attributes_count; k++) { + int name_cpx=in.readUnsignedShort(); + if (getTag(name_cpx)==CONSTANT_UTF8 + && getString(name_cpx).equals("SourceFile") + ){ if (in.readInt()!=2) + throw new ClassFormatError("invalid attr length"); + source_cpx=in.readUnsignedShort(); + AttrData attr=new AttrData(this); + attr.read(name_cpx); + attrs[k]=attr; + + } else if (getTag(name_cpx)==CONSTANT_UTF8 + && getString(name_cpx).equals("InnerClasses") + ){ int length=in.readInt(); + int num=in.readUnsignedShort(); + if (2+num*8 != length) + throw new ClassFormatError("invalid attr length"); + innerClasses=new InnerClassData[num]; + for (int j = 0; j < num; j++) { + InnerClassData innerClass=new InnerClassData(this); + innerClass.read(in); + innerClasses[j]=innerClass; + } + AttrData attr=new AttrData(this); + attr.read(name_cpx); + attrs[k]=attr; + } else { + AttrData attr=new AttrData(this); + attr.read(name_cpx, in); + attrs[k]=attr; + } + } + in.close(); + } // end ClassData.read() + + /** + * Reads and stores constant pool info. + */ + void readCP(DataInputStream in) throws IOException { + cpool_count = in.readUnsignedShort(); + tags = new byte[cpool_count]; + cpool = new Object[cpool_count]; + for (int i = 1; i < cpool_count; i++) { + byte tag = in.readByte(); + + switch(tags[i] = tag) { + case CONSTANT_UTF8: + String str=in.readUTF(); + indexHashAscii.put(cpool[i] = str, new Integer(i)); + break; + case CONSTANT_INTEGER: + cpool[i] = new Integer(in.readInt()); + break; + case CONSTANT_FLOAT: + cpool[i] = new Float(in.readFloat()); + break; + case CONSTANT_LONG: + cpool[i++] = new Long(in.readLong()); + break; + case CONSTANT_DOUBLE: + cpool[i++] = new Double(in.readDouble()); + break; + case CONSTANT_CLASS: + case CONSTANT_STRING: + cpool[i] = new CPX(in.readUnsignedShort()); + break; + + case CONSTANT_FIELD: + case CONSTANT_METHOD: + case CONSTANT_INTERFACEMETHOD: + case CONSTANT_NAMEANDTYPE: + cpool[i] = new CPX2(in.readUnsignedShort(), in.readUnsignedShort()); + break; + + case 0: + default: + throw new ClassFormatError("invalid constant type: " + (int)tags[i]); + } + } + } + + /** + * Reads and strores field info. + */ + protected void readFields(DataInputStream in) throws IOException { + int fields_count = in.readUnsignedShort(); + fields=new FieldData[fields_count]; + for (int k = 0; k < fields_count; k++) { + FieldData field=new FieldData(this); + field.read(in); + fields[k]=field; + } + } + + /** + * Reads and strores Method info. + */ + protected void readMethods(DataInputStream in) throws IOException { + int methods_count = in.readUnsignedShort(); + methods=new MethodData[methods_count]; + for (int k = 0; k < methods_count ; k++) { + MethodData method=new MethodData(this); + method.read(in); + methods[k]=method; + } + } + + /** + * get a string + */ + public String getString(int n) { + if (n == 0) { + return null; + } else { + return (String)cpool[n]; + } + } + + /** + * get the type of constant given an index + */ + public byte getTag(int n) { + try{ + return tags[n]; + } catch (ArrayIndexOutOfBoundsException e) { + return (byte)100; + } + } + + static final String hexString="0123456789ABCDEF"; + + public static char hexTable[]=hexString.toCharArray(); + + static String toHex(long val, int width) { + StringBuffer s = new StringBuffer(); + for (int i=width-1; i>=0; i--) + s.append(hexTable[((int)(val>>(4*i)))&0xF]); + return "0x"+s.toString(); + } + + static String toHex(long val) { + int width; + for (width=16; width>0; width--) { + if ((val>>(width-1)*4)!=0) break; + } + return toHex(val, width); + } + + static String toHex(int val) { + int width; + for (width=8; width>0; width--) { + if ((val>>(width-1)*4)!=0) break; + } + return toHex(val, width); + } + + /** + * Returns the name of this class. + */ + public String getClassName() { + String res=null; + if (this_class==0) { + return res; + } + int tcpx; + try { + if (tags[this_class]!=CONSTANT_CLASS) { + return res; //" "; + } + tcpx=((CPX)cpool[this_class]).cpx; + } catch (ArrayIndexOutOfBoundsException e) { + return res; // "#"+cpx+"// invalid constant pool index"; + } catch (Throwable e) { + return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; + } + + try { + return (String)(cpool[tcpx]); + } catch (ArrayIndexOutOfBoundsException e) { + return res; // "class #"+scpx+"// invalid constant pool index"; + } catch (ClassCastException e) { + return res; // "class #"+scpx+"// invalid constant pool reference"; + } catch (Throwable e) { + return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; + } + + } + + /** + * Returns the name of class at perticular index. + */ + public String getClassName(int cpx) { + String res="#"+cpx; + if (cpx==0) { + return res; + } + int scpx; + try { + if (tags[cpx]!=CONSTANT_CLASS) { + return res; //" "; + } + scpx=((CPX)cpool[cpx]).cpx; + } catch (ArrayIndexOutOfBoundsException e) { + return res; // "#"+cpx+"// invalid constant pool index"; + } catch (Throwable e) { + return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; + } + res="#"+scpx; + try { + return (String)(cpool[scpx]); + } catch (ArrayIndexOutOfBoundsException e) { + return res; // "class #"+scpx+"// invalid constant pool index"; + } catch (ClassCastException e) { + return res; // "class #"+scpx+"// invalid constant pool reference"; + } catch (Throwable e) { + return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; + } + } + + /** + * Returns true if it is a class + */ + public boolean isClass() { + if((access & ACC_INTERFACE) == 0) return true; + return false; + } + + /** + * Returns true if it is a interface. + */ + public boolean isInterface(){ + if((access & ACC_INTERFACE) != 0) return true; + return false; + } + + /** + * Returns true if this member is public, false otherwise. + */ + public boolean isPublic(){ + return (access & ACC_PUBLIC) != 0; + } + + /** + * Returns the access of this class or interface. + */ + public String[] getAccess(){ + Vector v = new Vector(); + if ((access & ACC_PUBLIC) !=0) v.addElement("public"); + if ((access & ACC_FINAL) !=0) v.addElement("final"); + if ((access & ACC_ABSTRACT) !=0) v.addElement("abstract"); + String[] accflags = new String[v.size()]; + v.copyInto(accflags); + return accflags; + } + + /** + * Returns list of innerclasses. + */ + public InnerClassData[] getInnerClasses(){ + return innerClasses; + } + + /** + * Returns list of attributes. + */ + final AttrData[] getAttributes(){ + return attrs; + } + + public byte[] findAnnotationData(boolean classRetention) { + String n = classRetention ? + "RuntimeInvisibleAnnotations" : // NOI18N + "RuntimeVisibleAnnotations"; // NOI18N + return findAttr(n, attrs); + } + + /** + * Returns true if superbit is set. + */ + public boolean isSuperSet(){ + if ((access & ACC_SUPER) !=0) return true; + return false; + } + + /** + * Returns super class name. + */ + public String getSuperClassName(){ + String res=null; + if (super_class==0) { + return res; + } + int scpx; + try { + if (tags[super_class]!=CONSTANT_CLASS) { + return res; //" "; + } + scpx=((CPX)cpool[super_class]).cpx; + } catch (ArrayIndexOutOfBoundsException e) { + return res; // "#"+cpx+"// invalid constant pool index"; + } catch (Throwable e) { + return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; + } + + try { + return (String)(cpool[scpx]); + } catch (ArrayIndexOutOfBoundsException e) { + return res; // "class #"+scpx+"// invalid constant pool index"; + } catch (ClassCastException e) { + return res; // "class #"+scpx+"// invalid constant pool reference"; + } catch (Throwable e) { + return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; + } + } + + /** + * Returns list of super interfaces. + */ + public String[] getSuperInterfaces(){ + String interfacenames[] = new String[interfaces.length]; + int interfacecpx = -1; + for(int i = 0; i < interfaces.length; i++){ + interfacecpx=((CPX)cpool[interfaces[i]]).cpx; + interfacenames[i] = (String)(cpool[interfacecpx]); + } + return interfacenames; + } + + /** + * Returns string at prticular constant pool index. + */ + public String getStringValue(int cpoolx) { + try { + return ((String)cpool[cpoolx]); + } catch (ArrayIndexOutOfBoundsException e) { + return "//invalid constant pool index:"+cpoolx; + } catch (ClassCastException e) { + return "//invalid constant pool ref:"+cpoolx; + } + } + + /** + * Returns list of field info. + */ + public FieldData[] getFields(){ + return fields; + } + + /** + * Returns list of method info. + */ + public MethodData[] getMethods(){ + return methods; + } + + /** + * Returns constant pool entry at that index. + */ + public CPX2 getCpoolEntry(int cpx){ + return ((CPX2)(cpool[cpx])); + } + + public Object getCpoolEntryobj(int cpx){ + return (cpool[cpx]); + } + + /** + * Returns index of this class. + */ + public int getthis_cpx(){ + return this_class; + } + + /** + * Returns string at that index. + */ + public String StringValue(int cpx) { + return stringValue(cpx, false); + } + public String stringValue(int cpx, boolean textual) { + if (cpx==0) return "#0"; + int tag; + Object x; + String suffix=""; + try { + tag=tags[cpx]; + x=cpool[cpx]; + } catch (IndexOutOfBoundsException e) { + return ""; + } + + if (x==null) return ""; + switch (tag) { + case CONSTANT_UTF8: { + if (!textual) { + return (String)x; + } + StringBuilder sb=new StringBuilder(); + String s=(String)x; + for (int k=0; k"; + } catch (ClassCastException e) { + return ""; + } + } + + /** + * Returns unqualified class name. + */ + public String getShortClassName(int cpx) { + String classname=javaName(getClassName(cpx)); + pkgPrefixLen=classname.lastIndexOf("/")+1; + if (pkgPrefixLen!=0) { + pkgPrefix=classname.substring(0,pkgPrefixLen); + if (classname.startsWith(pkgPrefix)) { + return classname.substring(pkgPrefixLen); + } + } + return classname; + } + + /** + * Returns source file name. + */ + public String getSourceName(){ + return getName(source_cpx); + } + + /** + * Returns package name. + */ + public String getPkgName(){ + String classname=getClassName(this_class); + pkgPrefixLen=classname.lastIndexOf("/")+1; + if (pkgPrefixLen!=0) { + pkgPrefix=classname.substring(0,pkgPrefixLen); + return("package "+pkgPrefix.substring(0,pkgPrefixLen-1)+";\n"); + }else return null; + } + + /** + * Returns total constant pool entry count. + */ + public int getCpoolCount(){ + return cpool_count; + } + + /** + * Returns minor version of class file. + */ + public int getMinor_version(){ + return minor_version; + } + + /** + * Returns major version of class file. + */ + public int getMajor_version(){ + return major_version; + } + + private boolean isJavaIdentifierStart(int cp) { + return ('a' <= cp && cp <= 'z') || ('A' <= cp && cp <= 'Z'); + } + + private boolean isJavaIdentifierPart(int cp) { + return isJavaIdentifierStart(cp) || ('0' <= cp && cp <= '9'); + } + + public String[] getNameAndType(int indx) { + return getNameAndType(indx, 0, new String[2]); + } + + private String[] getNameAndType(int indx, int at, String[] arr) { + CPX2 c2 = getCpoolEntry(indx); + arr[at] = StringValue(c2.cpx1); + arr[at + 1] = StringValue(c2.cpx2); + return arr; + } + + public String[] getFieldInfoName(int indx) { + CPX2 c2 = getCpoolEntry(indx); + String[] arr = new String[3]; + arr[0] = getClassName(c2.cpx1); + return getNameAndType(c2.cpx2, 1, arr); + } + + static byte[] findAttr(String n, AttrData[] attrs) { + for (AttrData ad : attrs) { + if (n.equals(ad.getAttrName())) { + return ad.getData(); + } + } + return null; + } +} diff -r d0aad97dfd2e -r 6a56c2381b0f javap/src/main/java/org/apidesign/javap/Constants.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javap/src/main/java/org/apidesign/javap/Constants.java Sun Nov 18 22:03:15 2012 +0100 @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + + +package org.apidesign.javap; + +/** + * This interface defines constant that are used + * throughout the compiler. It inherits from RuntimeConstants, + * which is an autogenerated class that contains contstants + * defined in the interpreter. + */ + +public +interface Constants extends RuntimeConstants { + + /** + * End of input + */ + public static final int EOF = -1; + + /* + * Flags + */ + public static final int F_VERBOSE = 1 << 0; + public static final int F_DUMP = 1 << 1; + public static final int F_WARNINGS = 1 << 2; + public static final int F_DEBUG = 1 << 3; + public static final int F_OPTIMIZE = 1 << 4; + public static final int F_DEPENDENCIES = 1 << 5; + + /* + * Type codes + */ + public static final int TC_BOOLEAN = 0; + public static final int TC_BYTE = 1; + public static final int TC_CHAR = 2; + public static final int TC_SHORT = 3; + public static final int TC_INT = 4; + public static final int TC_LONG = 5; + public static final int TC_FLOAT = 6; + public static final int TC_DOUBLE = 7; + public static final int TC_NULL = 8; + public static final int TC_ARRAY = 9; + public static final int TC_CLASS = 10; + public static final int TC_VOID = 11; + public static final int TC_METHOD = 12; + public static final int TC_ERROR = 13; + + /* + * Type Masks + */ + public static final int TM_NULL = 1 << TC_NULL; + public static final int TM_VOID = 1 << TC_VOID; + public static final int TM_BOOLEAN = 1 << TC_BOOLEAN; + public static final int TM_BYTE = 1 << TC_BYTE; + public static final int TM_CHAR = 1 << TC_CHAR; + public static final int TM_SHORT = 1 << TC_SHORT; + public static final int TM_INT = 1 << TC_INT; + public static final int TM_LONG = 1 << TC_LONG; + public static final int TM_FLOAT = 1 << TC_FLOAT; + public static final int TM_DOUBLE = 1 << TC_DOUBLE; + public static final int TM_ARRAY = 1 << TC_ARRAY; + public static final int TM_CLASS = 1 << TC_CLASS; + public static final int TM_METHOD = 1 << TC_METHOD; + public static final int TM_ERROR = 1 << TC_ERROR; + + public static final int TM_INT32 = TM_BYTE | TM_SHORT | TM_CHAR | TM_INT; + public static final int TM_NUM32 = TM_INT32 | TM_FLOAT; + public static final int TM_NUM64 = TM_LONG | TM_DOUBLE; + public static final int TM_INTEGER = TM_INT32 | TM_LONG; + public static final int TM_REAL = TM_FLOAT | TM_DOUBLE; + public static final int TM_NUMBER = TM_INTEGER | TM_REAL; + public static final int TM_REFERENCE = TM_ARRAY | TM_CLASS | TM_NULL; + + /* + * Class status + */ + public static final int CS_UNDEFINED = 0; + public static final int CS_UNDECIDED = 1; + public static final int CS_BINARY = 2; + public static final int CS_SOURCE = 3; + public static final int CS_PARSED = 4; + public static final int CS_COMPILED = 5; + public static final int CS_NOTFOUND = 6; + + /* + * Attributes + */ + public static final int ATT_ALL = -1; + public static final int ATT_CODE = 1; + + /* + * Number of bits used in file offsets + */ + public static final int OFFSETBITS = 19; + public static final int MAXFILESIZE = (1 << OFFSETBITS) - 1; + public static final int MAXLINENUMBER = (1 << (32 - OFFSETBITS)) - 1; + + /* + * Operators + */ + public final int COMMA = 0; + public final int ASSIGN = 1; + + public final int ASGMUL = 2; + public final int ASGDIV = 3; + public final int ASGREM = 4; + public final int ASGADD = 5; + public final int ASGSUB = 6; + public final int ASGLSHIFT = 7; + public final int ASGRSHIFT = 8; + public final int ASGURSHIFT = 9; + public final int ASGBITAND = 10; + public final int ASGBITOR = 11; + public final int ASGBITXOR = 12; + + public final int COND = 13; + public final int OR = 14; + public final int AND = 15; + public final int BITOR = 16; + public final int BITXOR = 17; + public final int BITAND = 18; + public final int NE = 19; + public final int EQ = 20; + public final int GE = 21; + public final int GT = 22; + public final int LE = 23; + public final int LT = 24; + public final int INSTANCEOF = 25; + public final int LSHIFT = 26; + public final int RSHIFT = 27; + public final int URSHIFT = 28; + public final int ADD = 29; + public final int SUB = 30; + public final int DIV = 31; + public final int REM = 32; + public final int MUL = 33; + public final int CAST = 34; // (x)y + public final int POS = 35; // +x + public final int NEG = 36; // -x + public final int NOT = 37; + public final int BITNOT = 38; + public final int PREINC = 39; // ++x + public final int PREDEC = 40; // --x + public final int NEWARRAY = 41; + public final int NEWINSTANCE = 42; + public final int NEWFROMNAME = 43; + public final int POSTINC = 44; // x++ + public final int POSTDEC = 45; // x-- + public final int FIELD = 46; + public final int METHOD = 47; // x(y) + public final int ARRAYACCESS = 48; // x[y] + public final int NEW = 49; + public final int INC = 50; + public final int DEC = 51; + + public final int CONVERT = 55; // implicit conversion + public final int EXPR = 56; // (x) + public final int ARRAY = 57; // {x, y, ...} + public final int GOTO = 58; + + /* + * Value tokens + */ + public final int IDENT = 60; + public final int BOOLEANVAL = 61; + public final int BYTEVAL = 62; + public final int CHARVAL = 63; + public final int SHORTVAL = 64; + public final int INTVAL = 65; + public final int LONGVAL = 66; + public final int FLOATVAL = 67; + public final int DOUBLEVAL = 68; + public final int STRINGVAL = 69; + + /* + * Type keywords + */ + public final int BYTE = 70; + public final int CHAR = 71; + public final int SHORT = 72; + public final int INT = 73; + public final int LONG = 74; + public final int FLOAT = 75; + public final int DOUBLE = 76; + public final int VOID = 77; + public final int BOOLEAN = 78; + + /* + * Expression keywords + */ + public final int TRUE = 80; + public final int FALSE = 81; + public final int THIS = 82; + public final int SUPER = 83; + public final int NULL = 84; + + /* + * Statement keywords + */ + public final int IF = 90; + public final int ELSE = 91; + public final int FOR = 92; + public final int WHILE = 93; + public final int DO = 94; + public final int SWITCH = 95; + public final int CASE = 96; + public final int DEFAULT = 97; + public final int BREAK = 98; + public final int CONTINUE = 99; + public final int RETURN = 100; + public final int TRY = 101; + public final int CATCH = 102; + public final int FINALLY = 103; + public final int THROW = 104; + public final int STAT = 105; + public final int EXPRESSION = 106; + public final int DECLARATION = 107; + public final int VARDECLARATION = 108; + + /* + * Declaration keywords + */ + public final int IMPORT = 110; + public final int CLASS = 111; + public final int EXTENDS = 112; + public final int IMPLEMENTS = 113; + public final int INTERFACE = 114; + public final int PACKAGE = 115; + + /* + * Modifier keywords + */ + public final int PRIVATE = 120; + public final int PUBLIC = 121; + public final int PROTECTED = 122; + public final int CONST = 123; + public final int STATIC = 124; + public final int TRANSIENT = 125; + public final int SYNCHRONIZED = 126; + public final int NATIVE = 127; + public final int FINAL = 128; + public final int VOLATILE = 129; + public final int ABSTRACT = 130; + public final int STRICT = 165; + + /* + * Punctuation + */ + public final int SEMICOLON = 135; + public final int COLON = 136; + public final int QUESTIONMARK = 137; + public final int LBRACE = 138; + public final int RBRACE = 139; + public final int LPAREN = 140; + public final int RPAREN = 141; + public final int LSQBRACKET = 142; + public final int RSQBRACKET = 143; + public final int THROWS = 144; + + /* + * Special tokens + */ + public final int ERROR = 145; // an error + public final int COMMENT = 146; // not used anymore. + public final int TYPE = 147; + public final int LENGTH = 148; + public final int INLINERETURN = 149; + public final int INLINEMETHOD = 150; + public final int INLINENEWINSTANCE = 151; + + /* + * Added for jasm + */ + public final int METHODREF = 152; + public final int FIELDREF = 153; + public final int STACK = 154; + public final int LOCAL = 155; + public final int CPINDEX = 156; + public final int CPNAME = 157; + public final int SIGN = 158; + public final int BITS = 159; + public final int INF = 160; + public final int NAN = 161; + public final int INNERCLASS = 162; + public final int OF = 163; + public final int SYNTHETIC = 164; +// last used=165; + + /* + * Operator precedence + */ + public static final int opPrecedence[] = { + 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 12, 13, 14, 15, 16, 17, 18, + 18, 19, 19, 19, 19, 19, 20, 20, 20, 21, + 21, 22, 22, 22, 23, 24, 24, 24, 24, 24, + 24, 25, 25, 26, 26, 26, 26, 26, 26 + }; + + /* + * Operator names + */ + public static final String opNames[] = { + ",", "=", "*=", "/=", "%=", + "+=", "-=", "<<=", ">>=", "<<<=", + "&=", "|=", "^=", "?:", "||", + "&&", "|", "^", "&", "!=", + "==", ">=", ">", "<=", "<", + "instanceof", "<<", ">>", "<<<", "+", + "-", "/", "%", "*", "cast", + "+", "-", "!", "~", "++", + "--", "new", "new", "new", "++", + "--", "field", "method", "[]", "new", + "++", "--", null, null, null, + + "convert", "expr", "array", "goto", null, + + "Identifier", "Boolean", "Byte", "Char", "Short", + "Integer", "Long", "Float", "Double", "String", + + "byte", "char", "short", "int", "long", + "float", "double", "void", "boolean", null, + + "true", "false", "this", "super", "null", + null, null, null, null, null, + + "if", "else", "for", "while", "do", + "switch", "case", "default", "break", "continue", + "return", "try", "catch", "finally", "throw", + "stat", "expression", "declaration", "declaration", null, + + "import", "class", "extends", "implements", "interface", + "package", null, null, null, null, + + "private", "public", "protected", "const", "static", + "transient", "synchronized", "native", "final", "volatile", + "abstract", null, null, null, null, + + ";", ":", "?", "{", "}", + "(", ")", "[", "]", "throws", + "error", "comment", "type", "length", "inline-return", + "inline-method", "inline-new", + "method", "field", "stack", "locals", "CPINDEX", "CPName", "SIGN", + "bits", "INF", "NaN", "InnerClass", "of", "synthetic" + }; + +} diff -r d0aad97dfd2e -r 6a56c2381b0f javap/src/main/java/org/apidesign/javap/FieldData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javap/src/main/java/org/apidesign/javap/FieldData.java Sun Nov 18 22:03:15 2012 +0100 @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.apidesign.javap; + +import java.io.*; + +/** + * Strores field data informastion. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ + +public class FieldData implements RuntimeConstants { + + ClassData cls; + int access; + int name_index; + int descriptor_index; + int attributes_count; + int value_cpx=0; + boolean isSynthetic=false; + boolean isDeprecated=false; + Vector attrs; + + public FieldData(ClassData cls){ + this.cls=cls; + } + + /** + * Read and store field info. + */ + public void read(DataInputStream in) throws IOException { + access = in.readUnsignedShort(); + name_index = in.readUnsignedShort(); + descriptor_index = in.readUnsignedShort(); + // Read the attributes + int attributes_count = in.readUnsignedShort(); + attrs=new Vector(attributes_count); + for (int i = 0; i < attributes_count; i++) { + int attr_name_index=in.readUnsignedShort(); + if (cls.getTag(attr_name_index)!=CONSTANT_UTF8) continue; + String attr_name=cls.getString(attr_name_index); + if (attr_name.equals("ConstantValue")){ + if (in.readInt()!=2) + throw new ClassFormatError("invalid ConstantValue attr length"); + value_cpx=in.readUnsignedShort(); + AttrData attr=new AttrData(cls); + attr.read(attr_name_index); + attrs.addElement(attr); + } else if (attr_name.equals("Synthetic")){ + if (in.readInt()!=0) + throw new ClassFormatError("invalid Synthetic attr length"); + isSynthetic=true; + AttrData attr=new AttrData(cls); + attr.read(attr_name_index); + attrs.addElement(attr); + } else if (attr_name.equals("Deprecated")){ + if (in.readInt()!=0) + throw new ClassFormatError("invalid Synthetic attr length"); + isDeprecated = true; + AttrData attr=new AttrData(cls); + attr.read(attr_name_index); + attrs.addElement(attr); + } else { + AttrData attr=new AttrData(cls); + attr.read(attr_name_index, in); + attrs.addElement(attr); + } + } + + } // end read + + public boolean isStatic() { + return (access & ACC_STATIC) != 0; + } + + /** + * Returns access of a field. + */ + public String[] getAccess(){ + Vector v = new Vector(); + if ((access & ACC_PUBLIC) !=0) v.addElement("public"); + if ((access & ACC_PRIVATE) !=0) v.addElement("private"); + if ((access & ACC_PROTECTED) !=0) v.addElement("protected"); + if ((access & ACC_STATIC) !=0) v.addElement("static"); + if ((access & ACC_FINAL) !=0) v.addElement("final"); + if ((access & ACC_VOLATILE) !=0) v.addElement("volatile"); + if ((access & ACC_TRANSIENT) !=0) v.addElement("transient"); + String[] accflags = new String[v.size()]; + v.copyInto(accflags); + return accflags; + } + + /** + * Returns name of a field. + */ + public String getName(){ + return cls.getStringValue(name_index); + } + + /** + * Returns internal signature of a field + */ + public String getInternalSig(){ + return cls.getStringValue(descriptor_index); + } + + /** + * Returns java type signature of a field. + */ + public String getType(){ + return new TypeSignature(getInternalSig()).getFieldType(); + } + + /** + * Returns true if field is synthetic. + */ + public boolean isSynthetic(){ + return isSynthetic; + } + + /** + * Returns true if field is deprecated. + */ + public boolean isDeprecated(){ + return isDeprecated; + } + + /** + * Returns index of constant value in cpool. + */ + public int getConstantValueIndex(){ + return (value_cpx); + } + + /** + * Returns list of attributes of field. + */ + public Vector getAttributes(){ + return attrs; + } +} diff -r d0aad97dfd2e -r 6a56c2381b0f javap/src/main/java/org/apidesign/javap/Hashtable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javap/src/main/java/org/apidesign/javap/Hashtable.java Sun Nov 18 22:03:15 2012 +0100 @@ -0,0 +1,81 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.apidesign.javap; + +/** A JavaScript optimized replacement for Hashtable. + * + * @author Jaroslav Tulach + */ +final class Hashtable { + private Object[] keys; + private Object[] values; + + Hashtable(int i) { + this(); + } + + Hashtable(int i, double d) { + this(); + } + + Hashtable() { + } + + synchronized void put(Object key, Object val) { + int[] where = { -1, -1 }; + Object found = get(key, where); + if (where[0] != -1) { + // key exists + values[where[0]] = val; + } else { + if (where[1] != -1) { + // null found + keys[where[1]] = key; + values[where[1]] = val; + } else { + if (keys == null) { + keys = new Object[11]; + values = new Object[11]; + keys[0] = key; + values[0] = val; + } else { + Object[] newKeys = new Object[keys.length * 2]; + Object[] newValues = new Object[values.length * 2]; + for (int i = 0; i < keys.length; i++) { + newKeys[i] = keys[i]; + newValues[i] = values[i]; + } + newKeys[keys.length] = key; + newValues[keys.length] = val; + keys = newKeys; + values = newValues; + } + } + } + } + + Object get(Object key) { + return get(key, null); + } + private synchronized Object get(Object key, int[] foundAndNull) { + if (keys == null) { + return null; + } + for (int i = 0; i < keys.length; i++) { + if (keys[i] == null) { + if (foundAndNull != null) { + foundAndNull[1] = i; + } + } else if (keys[i].equals(key)) { + if (foundAndNull != null) { + foundAndNull[0] = i; + } + return values[i]; + } + } + return null; + } + +} diff -r d0aad97dfd2e -r 6a56c2381b0f javap/src/main/java/org/apidesign/javap/InnerClassData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javap/src/main/java/org/apidesign/javap/InnerClassData.java Sun Nov 18 22:03:15 2012 +0100 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.apidesign.javap; + +import java.io.*; +import java.util.*; + +/** + * Strores InnerClass data informastion. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ +class InnerClassData implements RuntimeConstants { + ClassData cls; + + + int inner_class_info_index + ,outer_class_info_index + ,inner_name_index + ,access + ; + + public InnerClassData(ClassData cls) { + this.cls=cls; + + } + + /** + * Read Innerclass attribute data. + */ + public void read(DataInputStream in) throws IOException { + inner_class_info_index = in.readUnsignedShort(); + outer_class_info_index = in.readUnsignedShort(); + inner_name_index = in.readUnsignedShort(); + access = in.readUnsignedShort(); + } // end read + + /** + * Returns the access of this class or interface. + */ + public String[] getAccess(){ + Vector v = new Vector(); + if ((access & ACC_PUBLIC) !=0) v.addElement("public"); + if ((access & ACC_FINAL) !=0) v.addElement("final"); + if ((access & ACC_ABSTRACT) !=0) v.addElement("abstract"); + String[] accflags = new String[v.size()]; + v.copyInto(accflags); + return accflags; + } + +} // end InnerClassData diff -r d0aad97dfd2e -r 6a56c2381b0f javap/src/main/java/org/apidesign/javap/LineNumData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javap/src/main/java/org/apidesign/javap/LineNumData.java Sun Nov 18 22:03:15 2012 +0100 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.apidesign.javap; + +import java.util.*; +import java.io.*; + +/** + * Strores LineNumberTable data information. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ +class LineNumData { + short start_pc, line_number; + + public LineNumData() {} + + /** + * Read LineNumberTable attribute. + */ + public LineNumData(DataInputStream in) throws IOException { + start_pc = in.readShort(); + line_number=in.readShort(); + + } +} diff -r d0aad97dfd2e -r 6a56c2381b0f javap/src/main/java/org/apidesign/javap/LocVarData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javap/src/main/java/org/apidesign/javap/LocVarData.java Sun Nov 18 22:03:15 2012 +0100 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.apidesign.javap; + +import java.util.*; +import java.io.*; + +/** + * Strores LocalVariableTable data information. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ +class LocVarData { + short start_pc, length, name_cpx, sig_cpx, slot; + + public LocVarData() { + } + + /** + * Read LocalVariableTable attribute. + */ + public LocVarData(DataInputStream in) throws IOException { + start_pc = in.readShort(); + length=in.readShort(); + name_cpx=in.readShort(); + sig_cpx=in.readShort(); + slot=in.readShort(); + + } +} diff -r d0aad97dfd2e -r 6a56c2381b0f javap/src/main/java/org/apidesign/javap/MethodData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javap/src/main/java/org/apidesign/javap/MethodData.java Sun Nov 18 22:03:15 2012 +0100 @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2002, 2005, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.apidesign.javap; + +import java.io.*; +import org.apidesign.bck2brwsr.core.JavaScriptBody; + +import static org.apidesign.javap.RuntimeConstants.*; + +/** + * Strores method data informastion. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ +public class MethodData { + + ClassData cls; + int access; + int name_index; + int descriptor_index; + int attributes_count; + byte[] code; + Vector exception_table = new Vector(0); + Vector lin_num_tb = new Vector(0); + Vector loc_var_tb = new Vector(0); + StackMapTableData[] stackMapTable; + StackMapData[] stackMap; + int[] exc_index_table=null; + Vector attrs=new Vector(0); + Vector code_attrs=new Vector(0); + int max_stack, max_locals; + boolean isSynthetic=false; + boolean isDeprecated=false; + + public MethodData(ClassData cls){ + this.cls=cls; + } + + /** + * Read method info. + */ + public void read(DataInputStream in) throws IOException { + access = in.readUnsignedShort(); + name_index=in.readUnsignedShort(); + descriptor_index =in.readUnsignedShort(); + int attributes_count = in.readUnsignedShort(); + for (int i = 0; i < attributes_count; i++) { + int attr_name_index=in.readUnsignedShort(); + + readAttr: { + if (cls.getTag(attr_name_index)==CONSTANT_UTF8) { + String attr_name=cls.getString(attr_name_index); + if ( attr_name.equals("Code")){ + readCode (in); + AttrData attr=new AttrData(cls); + attr.read(attr_name_index); + attrs.addElement(attr); + break readAttr; + } else if ( attr_name.equals("Exceptions")){ + readExceptions(in); + AttrData attr=new AttrData(cls); + attr.read(attr_name_index); + attrs.addElement(attr); + break readAttr; + } else if (attr_name.equals("Synthetic")){ + if (in.readInt()!=0) + throw new ClassFormatError("invalid Synthetic attr length"); + isSynthetic=true; + AttrData attr=new AttrData(cls); + attr.read(attr_name_index); + attrs.addElement(attr); + break readAttr; + } else if (attr_name.equals("Deprecated")){ + if (in.readInt()!=0) + throw new ClassFormatError("invalid Synthetic attr length"); + isDeprecated = true; + AttrData attr=new AttrData(cls); + attr.read(attr_name_index); + attrs.addElement(attr); + break readAttr; + } + } + AttrData attr=new AttrData(cls); + attr.read(attr_name_index, in); + attrs.addElement(attr); + } + } + } + + /** + * Read code attribute info. + */ + public void readCode(DataInputStream in) throws IOException { + + int attr_length = in.readInt(); + max_stack=in.readUnsignedShort(); + max_locals=in.readUnsignedShort(); + int codelen=in.readInt(); + + code=new byte[codelen]; + int totalread = 0; + while(totalread < codelen){ + totalread += in.read(code, totalread, codelen-totalread); + } + // in.read(code, 0, codelen); + int clen = 0; + readExceptionTable(in); + int code_attributes_count = in.readUnsignedShort(); + + for (int k = 0 ; k < code_attributes_count ; k++) { + int table_name_index=in.readUnsignedShort(); + int table_name_tag=cls.getTag(table_name_index); + AttrData attr=new AttrData(cls); + if (table_name_tag==CONSTANT_UTF8) { + String table_name_tstr=cls.getString(table_name_index); + if (table_name_tstr.equals("LineNumberTable")) { + readLineNumTable(in); + attr.read(table_name_index); + } else if (table_name_tstr.equals("LocalVariableTable")) { + readLocVarTable(in); + attr.read(table_name_index); + } else if (table_name_tstr.equals("StackMapTable")) { + readStackMapTable(in); + attr.read(table_name_index); + } else if (table_name_tstr.equals("StackMap")) { + readStackMap(in); + attr.read(table_name_index); + } else { + attr.read(table_name_index, in); + } + code_attrs.addElement(attr); + continue; + } + + attr.read(table_name_index, in); + code_attrs.addElement(attr); + } + } + + /** + * Read exception table info. + */ + void readExceptionTable (DataInputStream in) throws IOException { + int exception_table_len=in.readUnsignedShort(); + exception_table=new Vector(exception_table_len); + for (int l = 0; l < exception_table_len; l++) { + exception_table.addElement(new TrapData(in, l)); + } + } + + /** + * Read LineNumberTable attribute info. + */ + void readLineNumTable (DataInputStream in) throws IOException { + int attr_len = in.readInt(); // attr_length + int lin_num_tb_len = in.readUnsignedShort(); + lin_num_tb=new Vector(lin_num_tb_len); + for (int l = 0; l < lin_num_tb_len; l++) { + lin_num_tb.addElement(new LineNumData(in)); + } + } + + /** + * Read LocalVariableTable attribute info. + */ + void readLocVarTable (DataInputStream in) throws IOException { + int attr_len=in.readInt(); // attr_length + int loc_var_tb_len = in.readUnsignedShort(); + loc_var_tb = new Vector(loc_var_tb_len); + for (int l = 0; l < loc_var_tb_len; l++) { + loc_var_tb.addElement(new LocVarData(in)); + } + } + + /** + * Read Exception attribute info. + */ + public void readExceptions(DataInputStream in) throws IOException { + int attr_len=in.readInt(); // attr_length in prog + int num_exceptions = in.readUnsignedShort(); + exc_index_table=new int[num_exceptions]; + for (int l = 0; l < num_exceptions; l++) { + int exc=in.readShort(); + exc_index_table[l]=exc; + } + } + + /** + * Read StackMapTable attribute info. + */ + void readStackMapTable(DataInputStream in) throws IOException { + int attr_len = in.readInt(); //attr_length + int stack_map_tb_len = in.readUnsignedShort(); + stackMapTable = new StackMapTableData[stack_map_tb_len]; + for (int i=0; i (JVMSignature.indexOf("("))){ + //Get parameter signature. + parameterdes = + JVMSignature.substring(JVMSignature.indexOf("(")+1, + JVMSignature.indexOf(")")); + this.parameters = getParametersHelper(parameterdes); + }else this.parameters = "()"; + //Get return type signature. + String returndes = JVMSignature.substring(JVMSignature.lastIndexOf(")")+1); + this.returntype = getReturnTypeHelper(returndes); + } + } + } + + /** + * Returns java type signature of a field. + */ + public String getFieldTypeSignature(String fielddes){ + if(fielddes.startsWith("L")){ + return(getObjectType(fielddes)); + }else if(fielddes.startsWith("[")){ + return(getArrayType(fielddes)); + }else + return(getBaseType(fielddes)); + } + + /** + * Returns java type signature of a parameter. + */ + public String getParametersHelper(String parameterdes){ + Vector parameters = new Vector(); + int startindex = -1; + int endindex = -1; + String param = ""; + + while(parameterdes != null){ + + if(parameterdes.startsWith("L")){ + //parameter is a object. + startindex = parameterdes.indexOf("L"); + endindex = parameterdes.indexOf(";"); + if(startindex < parameterdes.length()) { + if(endindex == parameterdes.length()-1) { + //last parameter + param = parameterdes.substring(startindex); + parameterdes = null; + }else if(endindex+1 < parameterdes.length()){ + //rest parameters + param = parameterdes.substring(startindex, endindex+1); + parameterdes = parameterdes.substring(endindex+1); + + } + parameters.add(getObjectType(param)); + } + }else if(parameterdes.startsWith("[")){ + //parameter is an array. + String componentType = ""; + int enddim = -1; + int st = 0; + while(true){ + if(st < parameterdes.length()){ + if(parameterdes.charAt(st) == '['){ + + enddim = st; + st++; + } + else break; + } + else break; + } + + if(enddim+1 < parameterdes.length()){ + /* Array dimension.*/ + param = parameterdes.substring(0,enddim+1); + + } + + int stotherparam = param.lastIndexOf("[")+1; + + if(stotherparam < parameterdes.length()){ + componentType = parameterdes.substring(stotherparam); + } + + if(componentType.startsWith("L")){ + //parameter is array of objects. + startindex = parameterdes.indexOf("L"); + endindex = parameterdes.indexOf(";"); + + if(endindex == parameterdes.length()-1){ + //last parameter + param += parameterdes.substring(startindex); + parameterdes = null; + }else if(endindex+1 < parameterdes.length()){ + //rest parameters + param += parameterdes.substring(startindex, endindex+1); + parameterdes = parameterdes.substring(endindex+1); + } + }else{ + //parameter is array of base type. + if(componentType.length() == 1){ + //last parameter. + param += componentType; + parameterdes = null; + } + else if (componentType.length() > 1) { + //rest parameters. + param += componentType.substring(0,1); + parameterdes = componentType.substring(1); + } + } + parameters.add(getArrayType(param)); + + + }else { + + //parameter is of base type. + if(parameterdes.length() == 1){ + //last parameter + param = parameterdes; + parameterdes = null; + } + else if (parameterdes.length() > 1) { + //rest parameters. + param = parameterdes.substring(0,1); + parameterdes = parameterdes.substring(1); + } + parameters.add(getBaseType(param)); + } + } + + /* number of arguments of a method.*/ + argumentlength = parameters.size(); + + /* java type signature.*/ + String parametersignature = "("; + int i; + + for(i = 0; i < parameters.size(); i++){ + parametersignature += (String)parameters.elementAt(i); + if(i != parameters.size()-1){ + parametersignature += ", "; + } + } + parametersignature += ")"; + return parametersignature; + } + + /** + * Returns java type signature for a return type. + */ + public String getReturnTypeHelper(String returndes){ + return getFieldTypeSignature(returndes); + } + + /** + * Returns java type signature for a base type. + */ + public String getBaseType(String baseType){ + if(baseType != null){ + if(baseType.equals("B")) return "byte"; + else if(baseType.equals("C")) return "char"; + else if(baseType.equals("D")) return "double"; + else if(baseType.equals("F")) return "float"; + else if(baseType.equals("I")) return "int"; + else if(baseType.equals("J")) return "long"; + else if(baseType.equals("S")) return "short"; + else if(baseType.equals("Z")) return "boolean"; + else if(baseType.equals("V")) return "void"; + } + return null; + } + + /** + * Returns java type signature for a object type. + */ + public String getObjectType(String JVMobjectType) { + String objectType = ""; + int startindex = JVMobjectType.indexOf("L")+1; + int endindex = JVMobjectType.indexOf(";"); + if((startindex != -1) && (endindex != -1)){ + if((startindex < JVMobjectType.length()) && (endindex < JVMobjectType.length())){ + objectType = JVMobjectType.substring(startindex, endindex); + } + objectType = objectType.replace('/','.'); + return objectType; + } + return null; + } + + /** + * Returns java type signature for array type. + */ + public String getArrayType(String arrayType) { + if(arrayType != null){ + String dimention = ""; + + while(arrayType.indexOf("[") != -1){ + dimention += "[]"; + + int startindex = arrayType.indexOf("[")+1; + if(startindex <= arrayType.length()){ + arrayType = arrayType.substring(startindex); + } + } + + String componentType = ""; + if(arrayType.startsWith("L")){ + componentType = getObjectType(arrayType); + }else { + componentType = getBaseType(arrayType); + } + return componentType+dimention; + } + return null; + } + + /** + * Returns java type signature for parameters. + */ + public String getParameters(){ + return parameters; + } + + /** + * Returns java type signature for return type. + */ + public String getReturnType(){ + return returntype; + } + + /** + * Returns java type signature for field type. + */ + public String getFieldType(){ + return fieldtype; + } + + /** + * Return number of arguments of a method. + */ + public int getArgumentlength(){ + return argumentlength; + } +} diff -r d0aad97dfd2e -r 6a56c2381b0f javap/src/main/java/org/apidesign/javap/Vector.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javap/src/main/java/org/apidesign/javap/Vector.java Sun Nov 18 22:03:15 2012 +0100 @@ -0,0 +1,57 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.apidesign.javap; + +/** A JavaScript ready replacement for java.util.Vector + * + * @author Jaroslav Tulach + */ +final class Vector { + private Object[] arr; + + Vector() { + } + + Vector(int i) { + this(); + } + + void add(Object objectType) { + addElement(objectType); + } + void addElement(Object obj) { + final int s = size(); + setSize(s + 1); + setElementAt(obj, s); + } + + int size() { + return arr == null ? 0 : arr.length; + } + + void copyInto(Object[] newArr) { + if (arr == null) { + return; + } + int min = Math.min(newArr.length, arr.length); + for (int i = 0; i < min; i++) { + newArr[i] = arr[i]; + } + } + + Object elementAt(int index) { + return arr[index]; + } + + void setSize(int len) { + Object[] newArr = new Object[len]; + copyInto(newArr); + arr = newArr; + } + + void setElementAt(Object val, int index) { + arr[index] = val; + } +} diff -r d0aad97dfd2e -r 6a56c2381b0f mojo/pom.xml --- a/mojo/pom.xml Tue Nov 13 07:56:02 2012 +0100 +++ b/mojo/pom.xml Sun Nov 18 22:03:15 2012 +0100 @@ -64,6 +64,12 @@ ${project.groupId} vm4brwsr 0.1-SNAPSHOT + + + emul + org.apidesign.bck2brwsr + + org.apache.maven diff -r d0aad97dfd2e -r 6a56c2381b0f mojo/src/main/java/org/apidesign/bck2brwsr/mojo/Bck2BrswrMojo.java --- a/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/Bck2BrswrMojo.java Tue Nov 13 07:56:02 2012 +0100 +++ b/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/Bck2BrswrMojo.java Sun Nov 18 22:03:15 2012 +0100 @@ -74,10 +74,10 @@ URLClassLoader url = buildClassLoader(classes, prj.getDependencyArtifacts()); Class c = Class.forName("org.apidesign.vm4brwsr.GenJS"); - Method m = c.getDeclaredMethod("compile", ClassLoader.class, Appendable.class, List.class); + Method m = c.getDeclaredMethod("compile", ClassLoader.class, Appendable.class, String[].class); m.setAccessible(true); FileWriter w = new FileWriter(javascript); - m.invoke(null, url, w, arr); + m.invoke(null, url, w, arr.toArray(new String[0])); w.close(); } catch (Exception ex) { throw new MojoExecutionException("Can't compile", ex); diff -r d0aad97dfd2e -r 6a56c2381b0f pom.xml --- a/pom.xml Tue Nov 13 07:56:02 2012 +0100 +++ b/pom.xml Sun Nov 18 22:03:15 2012 +0100 @@ -12,6 +12,7 @@ core mojo javaquery + javap @@ -66,6 +67,7 @@ true emul/** + javap/** * .*/** @@ -105,4 +107,4 @@ COPYING - \ No newline at end of file + diff -r d0aad97dfd2e -r 6a56c2381b0f vm/pom.xml --- a/vm/pom.xml Tue Nov 13 07:56:02 2012 +0100 +++ b/vm/pom.xml Sun Nov 18 22:03:15 2012 +0100 @@ -83,11 +83,6 @@ - org.netbeans.api - org-netbeans-modules-classfile - jar - - org.apidesign.bck2brwsr core 1.0-SNAPSHOT @@ -99,5 +94,10 @@ 1.0-SNAPSHOT test + + ${project.groupId} + javap + 1.0-SNAPSHOT + diff -r d0aad97dfd2e -r 6a56c2381b0f vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java --- a/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Tue Nov 13 07:56:02 2012 +0100 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Sun Nov 18 22:03:15 2012 +0100 @@ -19,104 +19,81 @@ import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import org.apidesign.bck2brwsr.core.ExtraJavaScript; import org.apidesign.bck2brwsr.core.JavaScriptBody; -import org.netbeans.modules.classfile.Annotation; -import org.netbeans.modules.classfile.AnnotationComponent; -import org.netbeans.modules.classfile.ArrayElementValue; -import static org.netbeans.modules.classfile.ByteCodes.*; -import org.netbeans.modules.classfile.CPClassInfo; -import org.netbeans.modules.classfile.CPEntry; -import org.netbeans.modules.classfile.CPFieldInfo; -import org.netbeans.modules.classfile.CPMethodInfo; -import org.netbeans.modules.classfile.CPStringInfo; -import org.netbeans.modules.classfile.ClassFile; -import org.netbeans.modules.classfile.ClassName; -import org.netbeans.modules.classfile.Code; -import org.netbeans.modules.classfile.ElementValue; -import org.netbeans.modules.classfile.Method; -import org.netbeans.modules.classfile.Parameter; -import org.netbeans.modules.classfile.PrimitiveElementValue; -import org.netbeans.modules.classfile.Variable; +import org.apidesign.javap.AnnotationParser; +import org.apidesign.javap.ClassData; +import org.apidesign.javap.FieldData; +import org.apidesign.javap.MethodData; +import static org.apidesign.javap.RuntimeConstants.*; /** Translator of the code inside class files to JavaScript. * * @author Jaroslav Tulach */ -public final class ByteCodeToJavaScript { - private final ClassFile jc; +public abstract class ByteCodeToJavaScript { + private ClassData jc; private final Appendable out; - private final Collection references; - private ByteCodeToJavaScript( - ClassFile jc, Appendable out, Collection references - ) { - this.jc = jc; + protected ByteCodeToJavaScript(Appendable out) { this.out = out; - this.references = references; } + + /* Collects additional required resources. + * + * @param internalClassName classes that were referenced and should be loaded in order the + * generated JavaScript code works properly. The names are in internal + * JVM form so String is java/lang/String. + */ + protected abstract boolean requireReference(String internalClassName); + + /* + * @param resourcePath name of resources to read + */ + protected abstract void requireScript(String resourcePath); /** * Converts a given class file to a JavaScript version. * * @param classFile input stream with code of the .class file - * @param out a {@link StringBuilder} or similar to generate the output to - * @param references a write only collection where the system adds list of - * other classes that were referenced and should be loaded in order the - * generated JavaScript code works properly. The names are in internal - * JVM form so String is java/lang/String. Can be null - * if one is not interested in knowing references - * @param scripts write only collection with names of resources to read * @return the initialization code for this class, if any. Otherwise null * * @throws IOException if something goes wrong during read or write or translating */ - public static String compile( - InputStream classFile, Appendable out, - Collection references, - Collection scripts - ) throws IOException { - ClassFile jc = new ClassFile(classFile, true); - final ClassName extraAnn = ClassName.getClassName(ExtraJavaScript.class.getName().replace('.', '/')); - Annotation a = jc.getAnnotation(extraAnn); - if (a != null) { - final ElementValue annVal = a.getComponent("resource").getValue(); - String res = ((PrimitiveElementValue)annVal).getValue().getValue().toString(); - scripts.add(res); - final AnnotationComponent process = a.getComponent("processByteCode"); - if (process != null && "const=0".equals(process.getValue().toString())) { + public String compile(InputStream classFile) throws IOException { + this.jc = new ClassData(classFile); + byte[] arrData = jc.findAnnotationData(true); + String[] arr = findAnnotation(arrData, jc, + "org.apidesign.bck2brwsr.core.ExtraJavaScript", + "resource", "processByteCode" + ); + if (arr != null) { + requireScript(arr[0]); + if ("0".equals(arr[1])) { return null; } } - - ByteCodeToJavaScript compiler = new ByteCodeToJavaScript( - jc, out, references - ); - List toInitilize = new ArrayList(); - for (Method m : jc.getMethods()) { + StringArray toInitilize = new StringArray(); + for (MethodData m : jc.getMethods()) { if (m.isStatic()) { - compiler.generateStaticMethod(m, toInitilize); + generateStaticMethod(m, toInitilize); } else { - compiler.generateInstanceMethod(m); + generateInstanceMethod(m); } } - for (Variable v : jc.getVariables()) { + for (FieldData v : jc.getFields()) { if (v.isStatic()) { - compiler.generateStaticField(v); + generateStaticField(v); } } - final String className = jc.getName().getInternalName().replace('/', '_'); + final String className = className(jc); out.append("\nfunction ").append(className); out.append("() {"); - for (Variable v : jc.getVariables()) { + for (FieldData v : jc.getFields()) { if (!v.isStatic()) { out.append("\n this.fld_"). - append(v.getName()).append(" = 0;"); + append(v.getName()).append(initField(v)); } } out.append("\n}\n\nfunction ").append(className).append("_proto() {"); @@ -124,112 +101,112 @@ append(".prototype.$instOf_").append(className).append(") {"); out.append("\n return new ").append(className).append(";"); out.append("\n }"); - ClassName sc = jc.getSuperClass(); + // ClassName sc = jc.getSuperClass(); + String sc = jc.getSuperClassName(); // with _ if (sc != null) { out.append("\n var p = ").append(className) .append(".prototype = "). - append(sc.getInternalName().replace('/', '_')).append("_proto();"); + append(sc.replace('/', '_')).append("_proto();"); } else { out.append("\n var p = ").append(className).append(".prototype;"); } - for (Method m : jc.getMethods()) { + for (MethodData m : jc.getMethods()) { if (!m.getName().contains("") && !m.getName().contains("")) { - compiler.generateMethodReference("\n p.", m); + generateMethodReference("\n p.", m); } } out.append("\n p.$instOf_").append(className).append(" = true;"); - for (ClassName superInterface : jc.getInterfaces()) { - out.append("\n p.$instOf_").append(superInterface.getInternalName().replace('/', '_')).append(" = true;"); + for (String superInterface : jc.getSuperInterfaces()) { + out.append("\n p.$instOf_").append(superInterface.replace('/', '_')).append(" = true;"); } out.append("\n return new ").append(className).append(";"); out.append("\n}"); out.append("\n").append(className).append("_proto();"); StringBuilder sb = new StringBuilder(); - for (String init : toInitilize) { + for (String init : toInitilize.toArray()) { sb.append("\n").append(init).append("();"); } return sb.toString(); } - private void generateStaticMethod(Method m, List toInitilize) throws IOException { + private void generateStaticMethod(MethodData m, StringArray toInitilize) throws IOException { if (javaScriptBody(m, true)) { return; } - final String mn = findMethodName(m); + StringBuilder argsCnt = new StringBuilder(); + final String mn = findMethodName(m, argsCnt); out.append("\nfunction ").append( - jc.getName().getInternalName().replace('/', '_') + className(jc) ).append('_').append(mn); if (mn.equals("classV")) { - toInitilize.add(jc.getName().getInternalName().replace('/', '_') + '_' + mn); + toInitilize.add(className(jc) + '_' + mn); } out.append('('); String space = ""; - List args = m.getParameters(); - for (int index = 0, i = 0; i < args.size(); i++) { + for (int index = 0, i = 0; i < argsCnt.length(); i++) { out.append(space); out.append("arg").append(String.valueOf(index)); space = ","; - final String desc = findDescriptor(args.get(i).getDescriptor()); - if ("D".equals(desc) || "J".equals(desc)) { + final String desc = null;// XXX findDescriptor(args.get(i).getDescriptor()); + if (argsCnt.charAt(i) == '1') { index += 2; } else { index++; } } out.append(") {").append("\n"); - final Code code = m.getCode(); + final byte[] code = m.getCode(); if (code != null) { - int len = code.getMaxLocals(); - for (int index = args.size(), i = args.size(); i < len; i++) { + int len = m.getMaxLocals(); + for (int index = argsCnt.length(), i = argsCnt.length(); i < len; i++) { out.append(" var "); out.append("arg").append(String.valueOf(i)).append(";\n"); } out.append(" var stack = new Array();\n"); - produceCode(code.getByteCodes()); + produceCode(code); } else { - out.append(" /* no code found for ").append(m.getTypeSignature()).append(" */\n"); + out.append(" /* no code found for ").append(m.getInternalSig()).append(" */\n"); } out.append("}"); } - private void generateMethodReference(String prefix, Method m) throws IOException { - final String name = findMethodName(m); + private void generateMethodReference(String prefix, MethodData m) throws IOException { + final String name = findMethodName(m, new StringBuilder()); out.append(prefix).append(name).append(" = ") - .append(jc.getName().getInternalName().replace('/', '_')) + .append(className(jc)) .append('_').append(name).append(";"); } - private void generateInstanceMethod(Method m) throws IOException { + private void generateInstanceMethod(MethodData m) throws IOException { if (javaScriptBody(m, false)) { return; } + StringBuilder argsCnt = new StringBuilder(); out.append("\nfunction ").append( - jc.getName().getInternalName().replace('/', '_') - ).append('_').append(findMethodName(m)); + className(jc) + ).append('_').append(findMethodName(m, argsCnt)); out.append("(arg0"); String space = ","; - List args = m.getParameters(); - for (int index = 1, i = 0; i < args.size(); i++) { + for (int index = 1, i = 0; i < argsCnt.length(); i++) { out.append(space); out.append("arg").append(String.valueOf(index)); - final String desc = findDescriptor(args.get(i).getDescriptor()); - if ("D".equals(desc) || "J".equals(desc)) { + if (argsCnt.charAt(i) == '1') { index += 2; } else { index++; } } out.append(") {").append("\n"); - final Code code = m.getCode(); + final byte[] code = m.getCode(); if (code != null) { - int len = code.getMaxLocals(); - for (int index = args.size(), i = args.size(); i < len; i++) { + int len = m.getMaxLocals(); + for (int index = argsCnt.length(), i = argsCnt.length(); i < len; i++) { out.append(" var "); out.append("arg").append(String.valueOf(i + 1)).append(";\n"); } out.append(";\n var stack = new Array();\n"); - produceCode(code.getByteCodes()); + produceCode(code); } else { - out.append(" /* no code found for ").append(m.getTypeSignature()).append(" */\n"); + out.append(" /* no code found for ").append(m.getInternalSig()).append(" */\n"); } out.append("}"); } @@ -241,137 +218,143 @@ out.append(" case " + i).append(": "); final int c = readByte(byteCodes, i); switch (c) { - case bc_aload_0: - case bc_iload_0: - case bc_lload_0: - case bc_fload_0: - case bc_dload_0: + case opc_aload_0: + case opc_iload_0: + case opc_lload_0: + case opc_fload_0: + case opc_dload_0: out.append("stack.push(arg0);"); break; - case bc_aload_1: - case bc_iload_1: - case bc_lload_1: - case bc_fload_1: - case bc_dload_1: + case opc_aload_1: + case opc_iload_1: + case opc_lload_1: + case opc_fload_1: + case opc_dload_1: out.append("stack.push(arg1);"); break; - case bc_aload_2: - case bc_iload_2: - case bc_lload_2: - case bc_fload_2: - case bc_dload_2: + case opc_aload_2: + case opc_iload_2: + case opc_lload_2: + case opc_fload_2: + case opc_dload_2: out.append("stack.push(arg2);"); break; - case bc_aload_3: - case bc_iload_3: - case bc_lload_3: - case bc_fload_3: - case bc_dload_3: + case opc_aload_3: + case opc_iload_3: + case opc_lload_3: + case opc_fload_3: + case opc_dload_3: out.append("stack.push(arg3);"); break; - case bc_iload: - case bc_lload: - case bc_fload: - case bc_dload: - case bc_aload: { + case opc_iload: + case opc_lload: + case opc_fload: + case opc_dload: + case opc_aload: { final int indx = readByte(byteCodes, ++i); out.append("stack.push(arg").append(indx + ");"); break; } - case bc_istore: - case bc_lstore: - case bc_fstore: - case bc_dstore: - case bc_astore: { + case opc_istore: + case opc_lstore: + case opc_fstore: + case opc_dstore: + case opc_astore: { final int indx = readByte(byteCodes, ++i); - out.append("arg" + indx).append(" = stack.pop()"); + out.append("arg" + indx).append(" = stack.pop();"); break; } - case bc_astore_0: - case bc_istore_0: - case bc_lstore_0: - case bc_fstore_0: - case bc_dstore_0: + case opc_astore_0: + case opc_istore_0: + case opc_lstore_0: + case opc_fstore_0: + case opc_dstore_0: out.append("arg0 = stack.pop();"); break; - case bc_astore_1: - case bc_istore_1: - case bc_lstore_1: - case bc_fstore_1: - case bc_dstore_1: + case opc_astore_1: + case opc_istore_1: + case opc_lstore_1: + case opc_fstore_1: + case opc_dstore_1: out.append("arg1 = stack.pop();"); break; - case bc_astore_2: - case bc_istore_2: - case bc_lstore_2: - case bc_fstore_2: - case bc_dstore_2: + case opc_astore_2: + case opc_istore_2: + case opc_lstore_2: + case opc_fstore_2: + case opc_dstore_2: out.append("arg2 = stack.pop();"); break; - case bc_astore_3: - case bc_istore_3: - case bc_lstore_3: - case bc_fstore_3: - case bc_dstore_3: + case opc_astore_3: + case opc_istore_3: + case opc_lstore_3: + case opc_fstore_3: + case opc_dstore_3: out.append("arg3 = stack.pop();"); break; - case bc_iadd: - case bc_ladd: - case bc_fadd: - case bc_dadd: + case opc_iadd: + case opc_ladd: + case opc_fadd: + case opc_dadd: out.append("stack.push(stack.pop() + stack.pop());"); break; - case bc_isub: - case bc_lsub: - case bc_fsub: - case bc_dsub: + case opc_isub: + case opc_lsub: + case opc_fsub: + case opc_dsub: out.append("{ var tmp = stack.pop(); stack.push(stack.pop() - tmp); }"); break; - case bc_imul: - case bc_lmul: - case bc_fmul: - case bc_dmul: + case opc_imul: + case opc_lmul: + case opc_fmul: + case opc_dmul: out.append("stack.push(stack.pop() * stack.pop());"); break; - case bc_idiv: - case bc_ldiv: + case opc_idiv: + case opc_ldiv: out.append("{ var tmp = stack.pop(); stack.push(Math.floor(stack.pop() / tmp)); }"); break; - case bc_fdiv: - case bc_ddiv: + case opc_fdiv: + case opc_ddiv: out.append("{ var tmp = stack.pop(); stack.push(stack.pop() / tmp); }"); break; - case bc_iand: - case bc_land: + case opc_irem: + case opc_lrem: + case opc_frem: + case opc_drem: + out.append("{ var d = stack.pop(); stack.push(stack.pop() % d); }"); + break; + case opc_iand: + case opc_land: out.append("stack.push(stack.pop() & stack.pop());"); break; - case bc_ior: - case bc_lor: + case opc_ior: + case opc_lor: out.append("stack.push(stack.pop() | stack.pop());"); break; - case bc_ixor: - case bc_lxor: + case opc_ixor: + case opc_lxor: out.append("stack.push(stack.pop() ^ stack.pop());"); break; - case bc_ineg: - case bc_lneg: - case bc_fneg: - case bc_dneg: + case opc_ineg: + case opc_lneg: + case opc_fneg: + case opc_dneg: out.append("stack.push(- stack.pop());"); break; - case bc_ishl: - case bc_lshl: + case opc_ishl: + case opc_lshl: out.append("{ var v = stack.pop(); stack.push(stack.pop() << v); }"); break; - case bc_ishr: - case bc_lshr: + case opc_ishr: + case opc_lshr: out.append("{ var v = stack.pop(); stack.push(stack.pop() >> v); }"); break; - case bc_iushr: - case bc_lushr: + case opc_iushr: + case opc_lushr: out.append("{ var v = stack.pop(); stack.push(stack.pop() >>> v); }"); break; - case bc_iinc: { + case opc_iinc: { final int varIndx = readByte(byteCodes, ++i); final int incrBy = byteCodes[++i]; if (incrBy == 1) { @@ -381,181 +364,179 @@ } break; } - case bc_return: + case opc_return: out.append("return;"); break; - case bc_ireturn: - case bc_lreturn: - case bc_freturn: - case bc_dreturn: - case bc_areturn: + case opc_ireturn: + case opc_lreturn: + case opc_freturn: + case opc_dreturn: + case opc_areturn: out.append("return stack.pop();"); break; - case bc_i2l: - case bc_i2f: - case bc_i2d: - case bc_l2i: + case opc_i2l: + case opc_i2f: + case opc_i2d: + case opc_l2i: // max int check? - case bc_l2f: - case bc_l2d: - case bc_f2d: - case bc_d2f: + case opc_l2f: + case opc_l2d: + case opc_f2d: + case opc_d2f: out.append("/* number conversion */"); break; - case bc_f2i: - case bc_f2l: - case bc_d2i: - case bc_d2l: + case opc_f2i: + case opc_f2l: + case opc_d2i: + case opc_d2l: out.append("stack.push(Math.floor(stack.pop()));"); break; - case bc_i2b: - case bc_i2c: - case bc_i2s: + case opc_i2b: + case opc_i2c: + case opc_i2s: out.append("/* number conversion */"); break; - case bc_aconst_null: + case opc_aconst_null: out.append("stack.push(null);"); break; - case bc_iconst_m1: + case opc_iconst_m1: out.append("stack.push(-1);"); break; - case bc_iconst_0: - case bc_dconst_0: - case bc_lconst_0: - case bc_fconst_0: + case opc_iconst_0: + case opc_dconst_0: + case opc_lconst_0: + case opc_fconst_0: out.append("stack.push(0);"); break; - case bc_iconst_1: - case bc_lconst_1: - case bc_fconst_1: - case bc_dconst_1: + case opc_iconst_1: + case opc_lconst_1: + case opc_fconst_1: + case opc_dconst_1: out.append("stack.push(1);"); break; - case bc_iconst_2: - case bc_fconst_2: + case opc_iconst_2: + case opc_fconst_2: out.append("stack.push(2);"); break; - case bc_iconst_3: + case opc_iconst_3: out.append("stack.push(3);"); break; - case bc_iconst_4: + case opc_iconst_4: out.append("stack.push(4);"); break; - case bc_iconst_5: + case opc_iconst_5: out.append("stack.push(5);"); break; - case bc_ldc: { + case opc_ldc: { int indx = readByte(byteCodes, ++i); - CPEntry entry = jc.getConstantPool().get(indx); - String v = encodeConstant(entry); + String v = encodeConstant(indx); out.append("stack.push(").append(v).append(");"); break; } - case bc_ldc_w: - case bc_ldc2_w: { + case opc_ldc_w: + case opc_ldc2_w: { int indx = readIntArg(byteCodes, i); - CPEntry entry = jc.getConstantPool().get(indx); i += 2; - String v = encodeConstant(entry); + String v = encodeConstant(indx); out.append("stack.push(").append(v).append(");"); break; } - case bc_lcmp: - case bc_fcmpl: - case bc_fcmpg: - case bc_dcmpl: - case bc_dcmpg: { + case opc_lcmp: + case opc_fcmpl: + case opc_fcmpg: + case opc_dcmpl: + case opc_dcmpg: { out.append("{ var delta = stack.pop() - stack.pop(); stack.push(delta < 0 ?-1 : (delta == 0 ? 0 : 1)); }"); break; } - case bc_if_acmpeq: + case opc_if_acmpeq: i = generateIf(byteCodes, i, "==="); break; - case bc_if_acmpne: + case opc_if_acmpne: i = generateIf(byteCodes, i, "!="); break; - case bc_if_icmpeq: { + case opc_if_icmpeq: { i = generateIf(byteCodes, i, "=="); break; } - case bc_ifeq: { + case opc_ifeq: { int indx = i + readIntArg(byteCodes, i); out.append("if (stack.pop() == 0) { gt = " + indx); out.append("; continue; }"); i += 2; break; } - case bc_ifne: { + case opc_ifne: { int indx = i + readIntArg(byteCodes, i); out.append("if (stack.pop() != 0) { gt = " + indx); out.append("; continue; }"); i += 2; break; } - case bc_iflt: { + case opc_iflt: { int indx = i + readIntArg(byteCodes, i); out.append("if (stack.pop() < 0) { gt = " + indx); out.append("; continue; }"); i += 2; break; } - case bc_ifle: { + case opc_ifle: { int indx = i + readIntArg(byteCodes, i); out.append("if (stack.pop() <= 0) { gt = " + indx); out.append("; continue; }"); i += 2; break; } - case bc_ifgt: { + case opc_ifgt: { int indx = i + readIntArg(byteCodes, i); out.append("if (stack.pop() > 0) { gt = " + indx); out.append("; continue; }"); i += 2; break; } - case bc_ifge: { + case opc_ifge: { int indx = i + readIntArg(byteCodes, i); out.append("if (stack.pop() >= 0) { gt = " + indx); out.append("; continue; }"); i += 2; break; } - case bc_ifnonnull: { + case opc_ifnonnull: { int indx = i + readIntArg(byteCodes, i); - out.append("if (stack.pop()) { gt = " + indx); + out.append("if (stack.pop() !== null) { gt = " + indx); out.append("; continue; }"); i += 2; break; } - case bc_ifnull: { + case opc_ifnull: { int indx = i + readIntArg(byteCodes, i); - out.append("if (!stack.pop()) { gt = " + indx); + out.append("if (stack.pop() === null) { gt = " + indx); out.append("; continue; }"); i += 2; break; } - case bc_if_icmpne: + case opc_if_icmpne: i = generateIf(byteCodes, i, "!="); break; - case bc_if_icmplt: + case opc_if_icmplt: i = generateIf(byteCodes, i, ">"); break; - case bc_if_icmple: + case opc_if_icmple: i = generateIf(byteCodes, i, ">="); break; - case bc_if_icmpgt: + case opc_if_icmpgt: i = generateIf(byteCodes, i, "<"); break; - case bc_if_icmpge: + case opc_if_icmpge: i = generateIf(byteCodes, i, "<="); break; - case bc_goto: { + case opc_goto: { int indx = i + readIntArg(byteCodes, i); out.append("gt = " + indx).append("; continue;"); i += 2; break; } - case bc_lookupswitch: { + case opc_lookupswitch: { int table = i / 4 * 4 + 4; int dflt = i + readInt4(byteCodes, table); table += 4; @@ -573,7 +554,7 @@ i = table - 1; break; } - case bc_tableswitch: { + case opc_tableswitch: { int table = i / 4 * 4 + 4; int dflt = i + readInt4(byteCodes, table); table += 4; @@ -592,50 +573,50 @@ i = table - 1; break; } - case bc_invokeinterface: { + case opc_invokeinterface: { i = invokeVirtualMethod(byteCodes, i) + 2; break; } - case bc_invokevirtual: + case opc_invokevirtual: i = invokeVirtualMethod(byteCodes, i); break; - case bc_invokespecial: + case opc_invokespecial: i = invokeStaticMethod(byteCodes, i, false); break; - case bc_invokestatic: + case opc_invokestatic: i = invokeStaticMethod(byteCodes, i, true); break; - case bc_new: { + case opc_new: { int indx = readIntArg(byteCodes, i); - CPClassInfo ci = jc.getConstantPool().getClass(indx); + String ci = jc.getClassName(indx); out.append("stack.push("); - out.append("new ").append(ci.getClassName().getInternalName().replace('/','_')); + out.append("new ").append(ci.replace('/','_')); out.append(");"); - addReference(ci.getClassName().getInternalName()); + addReference(ci); i += 2; break; } - case bc_newarray: { + case opc_newarray: { int type = byteCodes[i++]; - out.append("stack.push(new Array(stack.pop()));"); + out.append("stack.push(new Array(stack.pop()).fillNulls());"); break; } - case bc_anewarray: { + case opc_anewarray: { i += 2; // skip type of array - out.append("stack.push(new Array(stack.pop()));"); + out.append("stack.push(new Array(stack.pop()).fillNulls());"); break; } - case bc_multianewarray: { + case opc_multianewarray: { i += 2; int dim = readByte(byteCodes, ++i); - out.append("{ var a0 = new Array(stack.pop());"); + out.append("{ var a0 = new Array(stack.pop()).fillNulls();"); for (int d = 1; d < dim; d++) { out.append("\n var l" + d).append(" = stack.pop();"); out.append("\n for (var i" + d).append (" = 0; i" + d). append(" < a" + (d - 1)). append(".length; i" + d).append("++) {"); out.append("\n var a" + d). - append (" = new Array(l" + d).append(");"); + append (" = new Array(l" + d).append(").fillNulls();"); out.append("\n a" + (d - 1)).append("[i" + d).append("] = a" + d). append(";"); } @@ -645,86 +626,89 @@ out.append("\nstack.push(a0); }"); break; } - case bc_arraylength: + case opc_arraylength: out.append("stack.push(stack.pop().length);"); break; - case bc_iastore: - case bc_lastore: - case bc_fastore: - case bc_dastore: - case bc_aastore: - case bc_bastore: - case bc_castore: - case bc_sastore: { + case opc_iastore: + case opc_lastore: + case opc_fastore: + case opc_dastore: + case opc_aastore: + case opc_bastore: + case opc_castore: + case opc_sastore: { out.append("{ var value = stack.pop(); var indx = stack.pop(); stack.pop()[indx] = value; }"); break; } - case bc_iaload: - case bc_laload: - case bc_faload: - case bc_daload: - case bc_aaload: - case bc_baload: - case bc_caload: - case bc_saload: { + case opc_iaload: + case opc_laload: + case opc_faload: + case opc_daload: + case opc_aaload: + case opc_baload: + case opc_caload: + case opc_saload: { out.append("{ var indx = stack.pop(); stack.push(stack.pop()[indx]); }"); break; } - case bc_pop2: + case opc_pop2: out.append("stack.pop();"); - case bc_pop: + case opc_pop: out.append("stack.pop();"); break; - case bc_dup: + case opc_dup: out.append("stack.push(stack[stack.length - 1]);"); break; - case bc_bipush: + case opc_dup_x1: + out.append("{ var v1 = stack.pop(); var v2 = stack.pop(); stack.push(v1); stack.push(v2); stack.push(v1); }"); + break; + case opc_dup_x2: + out.append("{ var v1 = stack.pop(); var v2 = stack.pop(); var v3 = stack.pop(); stack.push(v1); stack.push(v3); stack.push(v2); stack.push(v1); }"); + break; + case opc_bipush: out.append("stack.push(" + byteCodes[++i] + ");"); break; - case bc_sipush: + case opc_sipush: out.append("stack.push(" + readIntArg(byteCodes, i) + ");"); i += 2; break; - case bc_getfield: { + case opc_getfield: { int indx = readIntArg(byteCodes, i); - CPFieldInfo fi = (CPFieldInfo) jc.getConstantPool().get(indx); + String[] fi = jc.getFieldInfoName(indx); out.append("stack.push(stack.pop().fld_"). - append(fi.getFieldName()).append(");"); + append(fi[1]).append(");"); i += 2; break; } - case bc_getstatic: { + case opc_getstatic: { int indx = readIntArg(byteCodes, i); - CPFieldInfo fi = (CPFieldInfo) jc.getConstantPool().get(indx); - final String in = fi.getClassName().getInternalName(); - out.append("stack.push(").append(in.replace('/', '_')); - out.append('_').append(fi.getFieldName()).append(");"); + String[] fi = jc.getFieldInfoName(indx); + out.append("stack.push(").append(fi[0].replace('/', '_')); + out.append('_').append(fi[1]).append(");"); i += 2; - addReference(in); + addReference(fi[0]); break; } - case bc_putstatic: { + case opc_putstatic: { int indx = readIntArg(byteCodes, i); - CPFieldInfo fi = (CPFieldInfo) jc.getConstantPool().get(indx); - final String in = fi.getClassName().getInternalName(); - out.append(in.replace('/', '_')); - out.append('_').append(fi.getFieldName()).append(" = stack.pop();"); + String[] fi = jc.getFieldInfoName(indx); + out.append(fi[0].replace('/', '_')); + out.append('_').append(fi[1]).append(" = stack.pop();"); i += 2; - addReference(in); + addReference(fi[0]); break; } - case bc_putfield: { + case opc_putfield: { int indx = readIntArg(byteCodes, i); - CPFieldInfo fi = (CPFieldInfo) jc.getConstantPool().get(indx); + String[] fi = jc.getFieldInfoName(indx); out.append("{ var v = stack.pop(); stack.pop().fld_") - .append(fi.getFieldName()).append(" = v; }"); + .append(fi[1]).append(" = v; }"); i += 2; break; } - case bc_checkcast: { + case opc_checkcast: { int indx = readIntArg(byteCodes, i); - CPClassInfo ci = jc.getConstantPool().getClass(indx); - final String type = ci.getClassName().getType(); + final String type = jc.getClassName(indx); if (!type.startsWith("[")) { // no way to check arrays right now out.append("if(stack[stack.length - 1].$instOf_") @@ -734,16 +718,16 @@ i += 2; break; } - case bc_instanceof: { + case opc_instanceof: { int indx = readIntArg(byteCodes, i); - CPClassInfo ci = jc.getConstantPool().getClass(indx); + final String type = jc.getClassName(indx); out.append("stack.push(stack.pop().$instOf_") - .append(ci.getClassName().getInternalName().replace('/', '_')) + .append(type.replace('/', '_')) .append(" ? 1 : 0);"); i += 2; break; } - case bc_athrow: { + case opc_athrow: { out.append("{ var t = stack.pop(); stack = new Array(1); stack[0] = t; throw t; }"); break; } @@ -786,8 +770,7 @@ return (byteCodes[offsetInstruction] + 256) % 256; } - private static int countArgs(String descriptor, boolean[] hasReturnType, StringBuilder sig) { - int cnt = 0; + private static void countArgs(String descriptor, boolean[] hasReturnType, StringBuilder sig, StringBuilder cnt) { int i = 0; Boolean count = null; boolean array = false; @@ -813,11 +796,15 @@ case 'S': case 'Z': if (count) { - cnt++; if (array) { sig.append('A'); } sig.append(ch); + if (ch == 'J' || ch == 'D') { + cnt.append('1'); + } else { + cnt.append('0'); + } } else { hasReturnType[0] = true; sig.insert(firstPos, ch); @@ -835,12 +822,12 @@ case 'L': int next = descriptor.indexOf(';', i); if (count) { - cnt++; if (array) { sig.append('A'); } sig.append(ch); sig.append(descriptor.substring(i, next).replace('/', '_')); + cnt.append('0'); } else { sig.insert(firstPos, descriptor.substring(i, next).replace('/', '_')); sig.insert(firstPos, ch); @@ -858,18 +845,16 @@ break; // invalid character } } - return cnt; } - private void generateStaticField(Variable v) throws IOException { + private void generateStaticField(FieldData v) throws IOException { out.append("\nvar ") - .append(jc.getName().getInternalName().replace('/', '_')) - .append('_').append(v.getName()).append(" = 0;"); + .append(className(jc)) + .append('_').append(v.getName()).append(initField(v)); } - private String findMethodName(Method m) { + private String findMethodName(MethodData m, StringBuilder cnt) { StringBuilder name = new StringBuilder(); - String descr = m.getDescriptor(); if ("".equals(m.getName())) { // NOI18N name.append("cons"); // NOI18N } else if ("".equals(m.getName())) { // NOI18N @@ -879,38 +864,39 @@ } boolean hasReturn[] = { false }; - countArgs(findDescriptor(m.getDescriptor()), hasReturn, name); + countArgs(findDescriptor(m.getInternalSig()), hasReturn, name, cnt); return name.toString(); } - private String findMethodName(CPMethodInfo mi, int[] cnt, boolean[] hasReturn) { + private String findMethodName(String[] mi, StringBuilder cnt, boolean[] hasReturn) { StringBuilder name = new StringBuilder(); - String descr = mi.getDescriptor(); - if ("".equals(mi.getName())) { // NOI18N + String descr = mi[2];//mi.getDescriptor(); + String nm= mi[1]; + if ("".equals(nm)) { // NOI18N name.append("cons"); // NOI18N } else { - name.append(mi.getName()); + name.append(nm); } - cnt[0] = countArgs(findDescriptor(mi.getDescriptor()), hasReturn, name); + countArgs(findDescriptor(descr), hasReturn, name, cnt); return name.toString(); } private int invokeStaticMethod(byte[] byteCodes, int i, boolean isStatic) throws IOException { int methodIndex = readIntArg(byteCodes, i); - CPMethodInfo mi = (CPMethodInfo) jc.getConstantPool().get(methodIndex); + String[] mi = jc.getFieldInfoName(methodIndex); boolean[] hasReturn = { false }; - int[] cnt = { 0 }; + StringBuilder cnt = new StringBuilder(); String mn = findMethodName(mi, cnt, hasReturn); out.append("{ "); - for (int j = cnt[0] - 1; j >= 0; j--) { + for (int j = cnt.length() - 1; j >= 0; j--) { out.append("var v" + j).append(" = stack.pop(); "); } if (hasReturn[0]) { out.append("stack.push("); } - final String in = mi.getClassName().getInternalName(); + final String in = mi[0]; out.append(in.replace('/', '_')); if (isStatic) { out.append(".prototype."); @@ -924,7 +910,7 @@ out.append("stack.pop()"); sep = ", "; } - for (int j = 0; j < cnt[0]; j++) { + for (int j = 0; j < cnt.length(); j++) { out.append(sep); out.append("v" + j); sep = ", "; @@ -941,12 +927,12 @@ private int invokeVirtualMethod(byte[] byteCodes, int i) throws IOException { int methodIndex = readIntArg(byteCodes, i); - CPMethodInfo mi = (CPMethodInfo) jc.getConstantPool().get(methodIndex); + String[] mi = jc.getFieldInfoName(methodIndex); boolean[] hasReturn = { false }; - int[] cnt = { 0 }; + StringBuilder cnt = new StringBuilder(); String mn = findMethodName(mi, cnt, hasReturn); out.append("{ "); - for (int j = cnt[0] - 1; j >= 0; j--) { + for (int j = cnt.length() - 1; j >= 0; j--) { out.append("var v" + j).append(" = stack.pop(); "); } out.append("var self = stack.pop(); "); @@ -957,7 +943,7 @@ out.append(mn); out.append('('); out.append("self"); - for (int j = 0; j < cnt[0]; j++) { + for (int j = 0; j < cnt.length(); j++) { out.append(", "); out.append("v" + j); } @@ -971,10 +957,8 @@ } private void addReference(String cn) throws IOException { - if (references != null) { - if (references.add(cn)) { - out.append(" /* needs ").append(cn).append(" */"); - } + if (requireReference(cn)) { + out.append(" /* needs ").append(cn).append(" */"); } } @@ -992,67 +976,118 @@ } } - private String encodeConstant(CPEntry entry) { - final String v; - if (entry instanceof CPClassInfo) { - v = "new java_lang_Class"; - } else if (entry instanceof CPStringInfo) { - v = "\"" + entry.getValue().toString(). - replace("\\", "\\\\"). - replace("\n", "\\n"). - replace("\r", "\\r"). - replace("\t", "\\t"). - replace("\"", "\\\"") - + "\""; - } else { - v = entry.getValue().toString(); - } - return v; + private String encodeConstant(int entryIndex) { + String s = jc.stringValue(entryIndex, true); + return s; } private String findDescriptor(String d) { return d.replace('[', 'A'); } - private boolean javaScriptBody(Method m, boolean isStatic) throws IOException { - final ClassName extraAnn = ClassName.getClassName(JavaScriptBody.class.getName().replace('.', '/')); - Annotation a = m.getAnnotation(extraAnn); - if (a != null) { - final ElementValue annVal = a.getComponent("body").getValue(); - String body = ((PrimitiveElementValue) annVal).getValue().getValue().toString(); + private boolean javaScriptBody(MethodData m, boolean isStatic) throws IOException { + byte[] arr = m.findAnnotationData(true); + if (arr == null) { + return false; + } + final String jvmType = "L" + JavaScriptBody.class.getName().replace('.', '/') + ";"; + class P extends AnnotationParser { + int cnt; + String[] args = new String[30]; + String body; - final ArrayElementValue arrVal = (ArrayElementValue) a.getComponent("args").getValue(); - final int len = arrVal.getValues().length; - String[] names = new String[len]; - for (int i = 0; i < len; i++) { - names[i] = ((PrimitiveElementValue) arrVal.getValues()[i]).getValue().getValue().toString(); + @Override + protected void visitAttr(String type, String attr, String value) { + if (type.equals(jvmType)) { + if ("body".equals(attr)) { + body = value; + } else if ("args".equals(attr)) { + args[cnt++] = value; + } else { + throw new IllegalArgumentException(attr); + } + } } - out.append("\nfunction ").append( - jc.getName().getInternalName().replace('/', '_')).append('_').append(findMethodName(m)); - out.append("("); - String space; - int index; - if (!isStatic) { - out.append(names[0]); - space = ","; - index = 1; - } else { - space = ""; - index = 0; + } + P p = new P(); + p.parse(arr, jc); + if (p.body == null) { + return false; + } + StringBuilder cnt = new StringBuilder(); + out.append("\nfunction ").append(className(jc)).append('_'). + append(findMethodName(m, cnt)); + out.append("("); + String space; + int index; + if (!isStatic) { + out.append(p.args[0]); + space = ","; + index = 1; + } else { + space = ""; + index = 0; + } + for (int i = 0; i < cnt.length(); i++) { + out.append(space); + out.append(p.args[index]); + index++; + space = ","; + } + out.append(") {").append("\n"); + out.append(p.body); + out.append("\n}\n"); + return true; + } + private static String className(ClassData jc) { + //return jc.getName().getInternalName().replace('/', '_'); + return jc.getClassName().replace('/', '_'); + } + + private static String[] findAnnotation( + byte[] arr, ClassData cd, final String className, + final String... attrNames + ) throws IOException { + if (arr == null) { + return null; + } + final String[] values = new String[attrNames.length]; + final boolean[] found = { false }; + final String jvmType = "L" + className.replace('.', '/') + ";"; + AnnotationParser ap = new AnnotationParser() { + @Override + protected void visitAttr(String type, String attr, String value) { + if (type.equals(jvmType)) { + found[0] = true; + for (int i = 0; i < attrNames.length; i++) { + if (attrNames[i].equals(attr)) { + values[i] = value; + } + } + } } - List args = m.getParameters(); - for (int i = 0; i < args.size(); i++) { - out.append(space); - out.append(names[index]); - final String desc = findDescriptor(args.get(i).getDescriptor()); - index++; - space = ","; + + }; + ap.parse(arr, cd); + return found[0] ? values : null; + } + + private CharSequence initField(FieldData v) { + final String is = v.getInternalSig(); + if (is.length() == 1) { + switch (is.charAt(0)) { + case 'S': + case 'J': + case 'B': + case 'Z': + case 'C': + case 'I': return " = 0;"; + case 'F': + case 'D': return " = 0.0;"; + default: + throw new IllegalStateException(is); } - out.append(") {").append("\n"); - out.append(body); - out.append("\n}\n"); - return true; } - return false; + return " = null;"; } } diff -r d0aad97dfd2e -r 6a56c2381b0f vm/src/main/java/org/apidesign/vm4brwsr/GenJS.java --- a/vm/src/main/java/org/apidesign/vm4brwsr/GenJS.java Tue Nov 13 07:56:02 2012 +0100 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/GenJS.java Sun Nov 18 22:03:15 2012 +0100 @@ -20,49 +20,44 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; import java.util.Enumeration; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; /** Generator of JavaScript from bytecode of classes on classpath of the VM. * * @author Jaroslav Tulach */ -final class GenJS { - private GenJS() {} +final class GenJS extends ByteCodeToJavaScript { + public GenJS(Appendable out) { + super(out); + } static void compile(Appendable out, String... names) throws IOException { - compile(out, Arrays.asList(names)); + compile(out, StringArray.asList(names)); } - static void compile(Appendable out, List names) throws IOException { + static void compile(ClassLoader l, Appendable out, String... names) throws IOException { + compile(l, out, StringArray.asList(names)); + } + static void compile(Appendable out, StringArray names) throws IOException { compile(GenJS.class.getClassLoader(), out, names); } - static void compile(ClassLoader l, Appendable out, List names) throws IOException { - final Map processed = new HashMap(); - for (String baseClass : names) { - LinkedHashSet toProcess = new LinkedHashSet() { - @Override - public boolean add(String e) { - if (processed.containsKey(e)) { - return false; - } - return super.add(e); - } - }; - toProcess.add(baseClass); + static void compile(ClassLoader l, Appendable out, StringArray names) throws IOException { + out.append("Array.prototype.fillNulls = function() {\n" + + " for(var i = 0; i < this.length; i++) {\n" + + " this[i] = null;\n" + + " }\n" + + " return this;\n" + + "};"); + + + StringArray processed = new StringArray(); + StringArray initCode = new StringArray(); + for (String baseClass : names.toArray()) { + GenJS js = new GenJS(out); + js.references.add(baseClass); for (;;) { String name = null; - Iterator it = toProcess.iterator(); - while (it.hasNext() && name == null) { - String n = it.next(); - if (processed.get(n) != null) { + for (String n : js.references.toArray()) { + if (processed.contains(n)) { continue; } name = n; @@ -70,23 +65,19 @@ if (name == null) { break; } - if (name.startsWith("sun/")) { - processed.put(name, ""); - continue; - } InputStream is = loadClass(l, name); if (is == null) { throw new IOException("Can't find class " + name); } - LinkedList scripts = new LinkedList(); try { - String initCode = ByteCodeToJavaScript.compile(is, out, toProcess, scripts); - processed.put(name, initCode == null ? "" : initCode); + String ic = js.compile(is); + processed.add(name); + initCode.add(ic == null ? "" : ic); } catch (RuntimeException ex) { if (out instanceof CharSequence) { CharSequence seq = (CharSequence)out; int lastBlock = seq.length(); - while (lastBlock-- >= 0) { + while (lastBlock-- > 0) { if (seq.charAt(lastBlock) == '{') { break; } @@ -100,7 +91,7 @@ ); } } - for (String resource : scripts) { + for (String resource : js.scripts.toArray()) { while (resource.startsWith("/")) { resource = resource.substring(1); } @@ -112,14 +103,14 @@ } } - List toInit = new ArrayList(toProcess); - Collections.reverse(toInit); + StringArray toInit = StringArray.asList(js.references.toArray()); + toInit.reverse(); - for (String clazz : toInit) { - String initCode = processed.get(clazz); - if (initCode != null && !initCode.isEmpty()) { - out.append(initCode).append("\n"); - processed.put(clazz, ""); + for (String ic : toInit.toArray()) { + int indx = processed.indexOf(ic); + if (indx >= 0) { + out.append(initCode.toArray()[indx]).append("\n"); + initCode.toArray()[indx] = ""; } } @@ -180,6 +171,9 @@ if (u == null) { throw new IOException("Can't find " + name); } + if (u.toExternalForm().contains("rt.jar!")) { + throw new IOException("No emulation for " + u); + } return u.openStream(); } @@ -188,4 +182,21 @@ compile(sb, name); return sb.toString().toString(); } + + private StringArray scripts = new StringArray(); + private StringArray references = new StringArray(); + + @Override + protected boolean requireReference(String cn) { + if (references.contains(cn)) { + return false; + } + references.add(cn); + return true; + } + + @Override + protected void requireScript(String resourcePath) { + scripts.add(resourcePath); + } } diff -r d0aad97dfd2e -r 6a56c2381b0f vm/src/main/java/org/apidesign/vm4brwsr/Main.java --- a/vm/src/main/java/org/apidesign/vm4brwsr/Main.java Tue Nov 13 07:56:02 2012 +0100 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/Main.java Sun Nov 18 22:03:15 2012 +0100 @@ -21,8 +21,6 @@ import java.io.FileWriter; import java.io.IOException; import java.io.Writer; -import java.util.Arrays; -import java.util.List; /** Generator of JavaScript from bytecode of classes on classpath of the VM * with a Main method. @@ -39,7 +37,8 @@ } Writer w = new BufferedWriter(new FileWriter(args[0])); - List classes = Arrays.asList(args).subList(1, args.length); + StringArray classes = StringArray.asList(args); + classes.delete(0); GenJS.compile(w, classes); w.close(); } diff -r d0aad97dfd2e -r 6a56c2381b0f vm/src/main/java/org/apidesign/vm4brwsr/StringArray.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/StringArray.java Sun Nov 18 22:03:15 2012 +0100 @@ -0,0 +1,97 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ +package org.apidesign.vm4brwsr; + +/** + * + * @author Jaroslav Tulach + */ +class StringArray { + private String[] arr; + + public StringArray() { + } + + private StringArray(String[] arr) { + this.arr = arr; + } + + public void add(String s) { + if (arr == null) { + arr = new String[1]; + } else { + String[] tmp = new String[arr.length + 1]; + for (int i = 0; i < arr.length; i++) { + tmp[i] = arr[i]; + } + arr = tmp; + } + arr[arr.length - 1] = s; + } + + public String[] toArray() { + return arr == null ? new String[0] : arr; + } + + static StringArray asList(String[] names) { + return new StringArray(names); + } + + void reverse() { + for (int i = 0, j = arr.length; i < j; i++) { + String s = arr[i]; + arr[i] = arr[--j]; + arr[j] = s; + } + } + + boolean contains(String n) { + if (arr == null) { + return false; + } + for (int i = 0; i < arr.length; i++) { + if (n.equals(arr[i])) { + return true; + } + } + return false; + } + + void delete(int indx) { + if (arr == null) { + return; + } + String[] tmp = new String[arr.length - 1]; + for (int i = 0, j = 0; i < arr.length; i++) { + tmp[j] = arr[i]; + if (j == indx) { + continue; + } + } + } + + int indexOf(String ic) { + for (int i = 0; i < arr.length; i++) { + if (ic.equals(arr[i])) { + return i; + } + } + return -1; + } + +} diff -r d0aad97dfd2e -r 6a56c2381b0f vm/src/test/java/org/apidesign/vm4brwsr/ArrayTest.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/ArrayTest.java Tue Nov 13 07:56:02 2012 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/ArrayTest.java Sun Nov 18 22:03:15 2012 +0100 @@ -64,9 +64,9 @@ try { ret = code.invokeFunction(methodName, args); } catch (ScriptException ex) { - fail("Execution failed in\n" + codeSeq, ex); + fail("Execution failed in\n" + StaticMethodTest.dumpJS(codeSeq), ex); } catch (NoSuchMethodException ex) { - fail("Cannot find method in\n" + codeSeq, ex); + fail("Cannot find method in\n" + StaticMethodTest.dumpJS(codeSeq), ex); } if (ret == null && expRes == null) { return; diff -r d0aad97dfd2e -r 6a56c2381b0f vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java Tue Nov 13 07:56:02 2012 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java Sun Nov 18 22:03:15 2012 +0100 @@ -17,6 +17,11 @@ */ package org.apidesign.vm4brwsr; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; import javax.script.Invocable; import javax.script.ScriptException; import static org.testng.Assert.*; @@ -55,7 +60,94 @@ Double.valueOf(3.0), 1000.0 ); } + + @Test public void javaRem() { + assertEquals(3, Numbers.rem(303, 10)); + } + @Test public void jsRem() throws Exception { + assertExec("Should be three", "org_apidesign_vm4brwsr_Numbers_remIII", + Double.valueOf(3.0), 303, 10 + ); + } + + @Test public void deserializeInt() throws Exception { + int exp = Numbers.deserInt(); + assertExec("Should be the same", "org_apidesign_vm4brwsr_Numbers_deserIntI", + Double.valueOf(exp) + ); + } + @Test public void deserializeSimpleLong() throws Exception { + assertExec("Should be 3454", "org_apidesign_vm4brwsr_Numbers_deserLongJAB", + Double.valueOf(3454), + new byte[] { (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)13, (byte)126 } + ); + } + /* XXX: JavaScript cannot represent as big longs as Java. + @Test public void deserializeLargeLong() throws Exception { + final byte[] arr = new byte[] { + (byte)64, (byte)8, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0 + }; + long exp = Numbers.deserLong(arr); + assertExec("Should be " + exp, "org_apidesign_vm4brwsr_Numbers_deserLongJAB", + Double.valueOf(exp), arr); + } + */ + + @Test public void deserializeFloatInJava() throws Exception { + float f = 54324.32423f; + float r = Numbers.deserFloat(); + assertEquals(r, f, "Floats are the same"); + } + + @Test public void deserializeFloatInJS() throws Exception { + float f = 54324.32423f; + assertExec("Should be the same", "org_apidesign_vm4brwsr_Numbers_deserFloatF", + Double.valueOf(f) + ); + } + + @Test public void deserializeDoubleInJava() throws Exception { + double f = 3.0; + double r = Numbers.deserDouble(); + assertEquals(r, f, 0.001, "Doubles are the same"); + } + + @Test public void deserializeDoubleInJS() throws Exception { + double f = 3.0; + assertExec("Should be the same", "org_apidesign_vm4brwsr_Numbers_deserDoubleD", f); + } + /* + @Test public void serDouble() throws IOException { + double f = 3.0; + ByteArrayOutputStream os = new ByteArrayOutputStream(); + DataOutputStream d = new DataOutputStream(os); + d.writeLong(3454); + d.close(); + + StringBuilder sb = new StringBuilder(); + byte[] arr = os.toByteArray(); + for (int i = 0; i < arr.length; i++) { + sb.append("(byte)").append(arr[i]).append(", "); + } + fail("" + sb); + } +*/ + @Test public void fiveInStringJS() throws Exception { + String s = Numbers.intToString(); + assertExec("Should be the same: " + s, + "org_apidesign_vm4brwsr_Numbers_intToStringLjava_lang_String", + s + ); + } + + @Test public void sevenInStringJS() throws Exception { + String s = Numbers.floatToString(); + assertExec("Should be the same: " + s, + "org_apidesign_vm4brwsr_Numbers_floatToStringLjava_lang_String", + s + ); + } private static CharSequence codeSeq; private static Invocable code; diff -r d0aad97dfd2e -r 6a56c2381b0f vm/src/test/java/org/apidesign/vm4brwsr/Numbers.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/Numbers.java Tue Nov 13 07:56:02 2012 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/Numbers.java Sun Nov 18 22:03:15 2012 +0100 @@ -17,6 +17,10 @@ */ package org.apidesign.vm4brwsr; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; + /** * * @author Jaroslav Tulach @@ -28,4 +32,39 @@ public static String autoboxDblToString() { return autoboxDbl().toString().toString(); } + public static int rem(int a, int b) { + return a % b; + } + + static float deserFloat() throws IOException { + byte[] arr = {(byte) 71, (byte) 84, (byte) 52, (byte) 83}; + ByteArrayInputStream is = new ByteArrayInputStream(arr); + DataInputStream dis = new DataInputStream(is); + float r = dis.readFloat(); + return r; + } + static double deserDouble() throws IOException { + byte[] arr = {(byte)64, (byte)8, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0}; + ByteArrayInputStream is = new ByteArrayInputStream(arr); + DataInputStream dis = new DataInputStream(is); + return dis.readDouble(); + } + static long deserLong(byte[] arr) throws IOException { + ByteArrayInputStream is = new ByteArrayInputStream(arr); + DataInputStream dis = new DataInputStream(is); + return dis.readLong(); + } + static int deserInt() throws IOException { + byte[] arr = {(byte) 71, (byte) 84, (byte) 52, (byte) 83}; + ByteArrayInputStream is = new ByteArrayInputStream(arr); + DataInputStream dis = new DataInputStream(is); + return dis.readInt(); + } + + static String intToString() { + return new Integer(5).toString().toString(); + } + static String floatToString() { + return new Float(7.0).toString().toString(); + } } diff -r d0aad97dfd2e -r 6a56c2381b0f vm/src/test/java/org/apidesign/vm4brwsr/StaticMethod.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/StaticMethod.java Tue Nov 13 07:56:02 2012 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/StaticMethod.java Sun Nov 18 22:03:15 2012 +0100 @@ -25,6 +25,7 @@ */ public class StaticMethod { private static int cnt; + private static Object NULL; public static int minusOne() { return -1; @@ -42,6 +43,10 @@ return toRet; } + public static boolean isNull() { + return NULL == null; + } + public static int sum(int x, int y) { return x + y; } @@ -95,7 +100,7 @@ } @JavaScriptBody( - args={"i","j"}, body="return (i + j).toString();" + args={"i","j"}, body="\n\r\treturn (i + j).toString();" ) public static String i2s(int i, int j) { throw new IllegalStateException(); diff -r d0aad97dfd2e -r 6a56c2381b0f vm/src/test/java/org/apidesign/vm4brwsr/StaticMethodTest.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/StaticMethodTest.java Tue Nov 13 07:56:02 2012 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/StaticMethodTest.java Sun Nov 18 22:03:15 2012 +0100 @@ -42,6 +42,14 @@ ); } + @Test public void checkReallyInitializedValues() throws Exception { + assertExec( + "Return true", + "org_apidesign_vm4brwsr_StaticMethod_isNullZ", + Double.valueOf(1) + ); + } + @Test public void powerOfThree() throws Exception { assertExec( "Should be nine", @@ -275,15 +283,17 @@ return (Invocable)js; } catch (Exception ex) { if (sb.length() > 2000) { - File f = File.createTempFile("execution", ".js"); - FileWriter w = new FileWriter(f); - w.append(sb); - w.close(); - sb.setLength(0); - sb.append(f.getPath()); + dumpJS(sb); } fail("Could not compile:\n" + sb, ex); return null; } } + static String dumpJS(CharSequence sb) throws IOException { + File f = File.createTempFile("execution", ".js"); + FileWriter w = new FileWriter(f); + w.append(sb); + w.close(); + return f.getPath(); + } } diff -r d0aad97dfd2e -r 6a56c2381b0f vm/src/test/java/org/apidesign/vm4brwsr/StringSample.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/StringSample.java Tue Nov 13 07:56:02 2012 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/StringSample.java Sun Nov 18 22:03:15 2012 +0100 @@ -44,6 +44,40 @@ return new String(arr).toString(); } + public static String charsFromNumbers() { + return chars((char)65, (char)66, (char)67); + } + + public static String charsFromChars() { + return chars('A', 'B', 'C'); + } + + public static String chars(char a, char b, char c) { + return ("" + a + b +c).toString(); + } + + public static String replace(String s, char a, char b) { + return s.replace(a, b); + } + + public static String insertBuffer() { + StringBuilder sb = new StringBuilder(); + sb.append("Jardo!"); + sb.insert(0, "Ahoj "); + return sb.toString().toString(); + } + + public static int countAB(String txt) { + int cnt = 0; + for (int i = 0; i < txt.length(); i++) { + switch (txt.charAt(i)) { + case 'A': cnt++; break; + case 'B': cnt += 2; break; + } + } + return cnt; + } + public static String toStringTest(int howMuch) { counter = 0; StringSample ss = null; diff -r d0aad97dfd2e -r 6a56c2381b0f vm/src/test/java/org/apidesign/vm4brwsr/StringTest.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/StringTest.java Tue Nov 13 07:56:02 2012 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/StringTest.java Sun Nov 18 22:03:15 2012 +0100 @@ -32,7 +32,7 @@ assertExec( "First char in Hello is H", "org_apidesign_vm4brwsr_StringSample_sayHelloCI", - "H", 0 + 72, 0 ); } @@ -44,6 +44,30 @@ ); } + @Test public void concatChars() throws Exception { + assertExec( + "Composing yields ABC", + "org_apidesign_vm4brwsr_StringSample_charsLjava_lang_StringCCC", + "ABC", 'A', 'B', 'C' + ); + } + + @Test public void concatCharsFromInts() throws Exception { + assertExec( + "Composing yields ABC", + "org_apidesign_vm4brwsr_StringSample_charsFromNumbersLjava_lang_String", + "ABC" + ); + } + + @Test public void concatCharsFromChars() throws Exception { + assertExec( + "Composing yields ABC", + "org_apidesign_vm4brwsr_StringSample_charsFromCharsLjava_lang_String", + "ABC" + ); + } + @Test(timeOut=10000) public void toStringConcatenation() throws Exception { assertExec( "Five executions should generate 5Hello World!", @@ -63,13 +87,45 @@ ); } - public void equalsAndSubstring() throws Exception { + @Test public void equalsAndSubstring() throws Exception { assertExec( "Composes are OK", "org_apidesign_vm4brwsr_StringSample_equalToHelloZII", - Double.valueOf(1), 0, 5 + true, 0, 5 ); } + @Test public void replaceChars() throws Exception { + assertExec( + "Can replace slashes by underscores", + "org_apidesign_vm4brwsr_StringSample_replaceLjava_lang_StringLjava_lang_StringCC", + "x_y_z", "x/y/z", '/', '_' + ); + } + @Test public void replaceIntChars() throws Exception { + assertExec( + "Can replace slashes by underscores", + "org_apidesign_vm4brwsr_StringSample_replaceLjava_lang_StringLjava_lang_StringCC", + "x_y_z", "x/y/z", (int)'/', (int)'_' + ); + } + + @Test public void insertBuilder() throws Exception { + assertExec( + "Can insert something into a buffer?", + "org_apidesign_vm4brwsr_StringSample_insertBufferLjava_lang_String", + "Ahoj Jardo!" + ); + } + + @Test public void countAB() throws Exception { + assertEquals(StringSample.countAB("Ahoj Bedo!"), 3, "Verify Java code is sane"); + assertExec( + "One A and one B adds to 3", + "org_apidesign_vm4brwsr_StringSample_countABILjava_lang_String", + Double.valueOf(3), "Ahoj Bedo!" + ); + + } private static CharSequence codeSeq; private static Invocable code; diff -r d0aad97dfd2e -r 6a56c2381b0f vm/src/test/java/org/apidesign/vm4brwsr/VMinVM.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/VMinVM.java Sun Nov 18 22:03:15 2012 +0100 @@ -0,0 +1,46 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ +package org.apidesign.vm4brwsr; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +/** + * + * @author Jaroslav Tulach + */ +class VMinVM extends ByteCodeToJavaScript { + private VMinVM(Appendable out) { + super(out); + } + + static String toJavaScript(byte[] is) throws IOException { + StringBuilder sb = new StringBuilder(); + new VMinVM(sb).compile(new ByteArrayInputStream(is)); + return sb.toString().toString(); + } + + @Override + protected boolean requireReference(String internalClassName) { + return false; + } + + @Override + protected void requireScript(String resourcePath) { + } +} diff -r d0aad97dfd2e -r 6a56c2381b0f vm/src/test/java/org/apidesign/vm4brwsr/VMinVMTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/VMinVMTest.java Sun Nov 18 22:03:15 2012 +0100 @@ -0,0 +1,92 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ +package org.apidesign.vm4brwsr; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import static org.testng.Assert.*; +import javax.script.Invocable; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** + * + * @author Jaroslav Tulach + */ +public class VMinVMTest { + + private static CharSequence codeSeq; + private static Invocable code; + + @Test public void compareTheGeneratedCode() throws Exception { + byte[] arr = readClass("/org/apidesign/vm4brwsr/Array.class"); + String ret1 = VMinVM.toJavaScript(arr); + + Object ret; + try { + ret = code.invokeFunction( + "org_apidesign_vm4brwsr_VMinVM_toJavaScriptLjava_lang_StringAB", + arr + ); + } catch (Exception ex) { + File f = File.createTempFile("execution", ".js"); + FileWriter w = new FileWriter(f); + w.append("var byteCode = [\n "); + String sep = ""; + for (int i = 0; i < arr.length; i++) { + w.append(sep).append(Integer.toString((arr[i] + 256) % 256)); + sep = ", "; + if (i % 20 == 0) { + w.append("\n "); + } + } + w.append("\n];\n"); + w.append(codeSeq); + w.close(); + throw new Exception(ex.getMessage() + " file: " + f, ex); + } + + + assertTrue(ret instanceof String, "It is string: " + ret); + + assertEquals((String)ret, ret1.toString(), "The code is the same"); + } + + @BeforeClass + public void compileTheCode() throws Exception { + StringBuilder sb = new StringBuilder(); + code = StaticMethodTest.compileClass(sb, + "org/apidesign/vm4brwsr/VMinVM" + ); + codeSeq = sb; + } + + private static byte[] readClass(String res) throws IOException { + InputStream is1 = VMinVMTest.class.getResourceAsStream(res); + assertNotNull(is1, "Stream found"); + byte[] arr = new byte[is1.available()]; + int len = is1.read(arr); + is1.close(); + if (len != arr.length) { + throw new IOException("Wrong len " + len + " for arr: " + arr.length); + } + return arr; + } +}