Add 'sgx-jvm/avian/' from commit '09e4fe60d01f4f4bfb6b2976973bb4913ef61edc'

git-subtree-dir: sgx-jvm/avian
git-subtree-mainline: f978eab8d1
git-subtree-split: 09e4fe60d0
This commit is contained in:
Andras Slemmer 2017-03-13 12:18:24 +00:00
commit 9bb3d6b972
723 changed files with 140833 additions and 0 deletions

View File

@ -0,0 +1,7 @@
---
BasedOnStyle: Chromium
IndentCaseLabels: false
BreakBeforeBraces: Stroustrup
AllowShortFunctionsOnASingleLine: false
BreakBeforeBinaryOperators: true
...

17
sgx-jvm/avian/.gitignore vendored Normal file
View File

@ -0,0 +1,17 @@
.gdb_history
/build
*~
.classpath
.project
.settings
bin
/lib
/distrib
*.pdb
*.swp
/.gradle
/*.sublime-*
workspace/
src/.cproject
/cmake-build
/cmake-build

27
sgx-jvm/avian/.mailmap Normal file
View File

@ -0,0 +1,27 @@
Carsten Elton Sørensen <ces@HADDOCK.premitech.net>
Carsten Elton Sørensen <csoren@gmail.com>
Dain Darnell <dain.darnell@readytalk.com>
Dain Darnell <dain@dazar.(none)>
Edison Guo <hydra1983@gmail.com>
Jason Treadwell <derBierBrauer@yahoo.com>
Jason Treadwell <jason.treadwell@readytalk.com>
Jason Treadwell <jet@debian-armel.(none)>
Jason Treadwell <jet@jet-lappy.(none)>
Jason Treadwell <jet@jet.ecovate.com>
Jason Treadwell <jet@jet.readytalk.com>
Jason Treadwell <jet@jetl.readytalk.com>
Jason Treadwell <jet@jetp.(none)>
Jason Treadwell <jet@nonames-power-mac-g4-agp-graphics.local>
Joel Dice <Joel Dice@joeldicexpvm.(none)>
Joel Dice <Joel@JDICEVM7.(none)>
Joel Dice <dicej@bstevenstestnb.readytalk.com>
Joel Dice <dicej@osxdesktop-2.local>
Anonymous <anonymous@example.com>
Joshua Warner <jwarner@radio.ecovate.com>
Matt Weaver <mweaver@gorgotron.readytalk.com>
Mike Jensen <jentfoo@gmail.com>
Mike Jensen <mjensen@jentbox.ecovate.com>
Mike Jensen <mjensen@lennyjent.ecovate.com>
Terek Campbell <terek.campbell@colorado.edu>
Thiago Bedin Frustaci <frustaci@gmail.com>
Zsombor Gegesy <gzsombor@gmail.com>

25
sgx-jvm/avian/.travis.yml Normal file
View File

@ -0,0 +1,25 @@
language: cpp
cache: apt
os:
- linux
- osx
env:
matrix:
- BUILD_STEP=""
# disabled until/unless jfrog.org credentials are updated and someone
# decides they care about published artifacts:
# - BUILD_STEP="PUBLISH"
global:
- TERM=dumb
- secure: rh1utD4shKmYtokItuRYEF9WsfTnvZO5XqnTU4DHTS7quHHgLihtOO2/3+B+2W2hEd5Obr2or8zx+zmzWcNUyLokZ0j/FRLWSScNkLzTtm12pupLrncY+/g1NIdfbhn+OLRIzBz6zB6m6a2qWFEJ+bScUNGD/7wZVtzkujqlDEE=
- secure: j9DOzZMCYk/BzhKK9u4XMKpCzyGOsvP2cLTp6cXE7/tkWDAPVv6BFmeqNbiLTEqk0aGX+HYbY/2YVtpRZmDzfeWtnBFF5mL1Y1tgzx1Kf155C+P6rZgt5PiQTUdXlp2umuRifY1BbXAPc3DZ2UOPUjWKnLHVbZLQRgO1zimmMx8=
matrix:
fast_finish: true
exclude:
- os: osx
env: BUILD_STEP=""
script: ./test/ci.sh ${BUILD_STEP}

View File

@ -0,0 +1,31 @@
#!/bin/bash
# This script was originally written by maxiaohao in the aws-mock GitHub project.
# https://github.com/treelogic-swe/aws-mock/
if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then
echo "Start to publish lastest Javadoc to gh-pages..."
cd build/
if test -d gh-pages/avian-web
then
cd gh-pages/avian-web
git pull
else
git clone --quiet https://${GH_TOKEN}@github.com/ReadyTalk/readytalk.github.io gh-pages > /dev/null
cd gh-pages/avian-web
git config user.email "travis@travis-ci.org"
git config user.name "travis-ci"
fi
git rm -rf ./javadoc
cp -Rf ../javadoc ./javadoc
git add -f .
git commit -m "Latest javadoc on successful Travis build $TRAVIS_BUILD_NUMBER auto-pushed to readytalk.github.io"
if ! git push -fq origin master &> /dev/null; then
echo "Error pushing gh-pages to origin. Bad GH_TOKEN? GitHub down?"
else
echo "Done magic with auto publishment to readytalk.github.io."
fi
fi

View File

@ -0,0 +1,29 @@
# NOTE that this CMake file doesn't current build all of avian.
# It only builds what's required for example/kaleidoscope.
cmake_minimum_required (VERSION 2.6)
project (avian)
include_directories (include src)
add_definitions (
-DAVIAN_TARGET_FORMAT=AVIAN_FORMAT_MACHO
-DAVIAN_TARGET_ARCH=AVIAN_ARCH_X86_64
-DTARGET_BYTES_PER_WORD=8
-D__STDC_LIMIT_MACROS
-D__STDC_CONSTANT_MACROS
)
include ("cmake/Platform.cmake")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PLATFORM_CXX_FLAGS}")
include (CTest)
# Sadly, we can't use the 'test' target, as that's coopted by ctest
add_custom_target(check ${CMAKE_CTEST_COMMAND} -V)
add_subdirectory (src)
add_subdirectory (unittest)

15
sgx-jvm/avian/LICENSE.txt Normal file
View File

@ -0,0 +1,15 @@
ISC License
Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

750
sgx-jvm/avian/README.md Normal file
View File

@ -0,0 +1,750 @@
Avian - A lightweight Java Virtual Machine (JVM)
================================================
[![Build Status](https://travis-ci.org/ReadyTalk/avian.png?branch=master)](https://travis-ci.org/ReadyTalk/avian)
Quick Start
-----------
These are examples of building Avian on various operating systems for
the x86_64 architecture. You may need to modify JAVA_HOME according
to where the JDK is installed on your system. In all cases, be sure
to use forward slashes in the path.
#### on Linux:
$ export JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64
$ make
$ build/linux-x86_64/avian -cp build/linux-x86_64/test Hello
#### on Mac OS X:
$ export JAVA_HOME=$(/usr/libexec/java_home)
$ make
$ build/macosx-x86_64/avian -cp build/macosx-x86_64/test Hello
#### on Windows (Cygwin):
$ git clone git@github.com:ReadyTalk/win64.git ../win64
$ export JAVA_HOME="/cygdrive/c/Program Files/Java/jdk1.7.0_45"
$ make
$ build/windows-x86_64/avian -cp build/windows-x86_64/test Hello
#### on FreeBSD:
$ export JAVA_HOME=/usr/local/openjdk7
$ gmake
$ build/freebsd-x86_64/avian -cp build/freebsd-x86_64/test Hello
Introduction
------------
Avian is a lightweight virtual machine and class library designed to
provide a useful subset of Java's features, suitable for building
self-contained applications. More information is available at the
project [web site](http://readytalk.github.io/avian).
If you have any trouble building, running, or embedding Avian, please
post a message to our [discussion group](http://groups.google.com/group/avian).
That's also the place for any other questions, comments, or
suggestions you might have.
Supported Platforms
-------------------
Avian can currently target the following platforms:
* Linux (i386, x86_64, ARM, and ARM64)
* Windows (i386 and x86_64)
* Mac OS X (i386 and x86_64)
* Apple iOS (i386, x86_64, ARM, and ARM64)
* FreeBSD (i386, x86_64)
Building
--------
Build requirements include:
* GNU make 3.80 or later
* GCC 4.6 or later
or LLVM Clang 3.1 or later (see use-clang option below)
* JDK 1.6 or later
* MinGW 3.4 or later (only if compiling for Windows)
* zlib 1.2.3 or later
Earlier versions of some of these packages may also work but have not
been tested.
The build is directed by a single makefile and may be influenced via
certain flags described below, all of which are optional.
$ make \
platform={linux,windows,macosx,ios,freebsd} \
arch={i386,x86_64,arm,arm64} \
process={compile,interpret} \
mode={debug,debug-fast,fast,small} \
lzma=<lzma source directory> \
bootimage={true,false} \
tails={true,false} \
continuations={true,false} \
use-clang={true,false} \
openjdk=<openjdk installation directory> \
openjdk-src=<openjdk source directory> \
android=<android source directory>
* `platform` - the target platform
* _default:_ output of $(uname -s | tr [:upper:] [:lower:]),
normalized in some cases (e.g. CYGWIN_NT-5.1 -> windows)
* `arch` - the target architecture
* _default:_ output of $(uname -m), normalized in some cases
(e.g. i686 -> i386)
* `process` - choice between pure interpreter or JIT compiler
* _default:_ compile
* `mode` - which set of compilation flags to use to determine
optimization level, debug symbols, and whether to enable
assertions
* _default:_ fast
* `lzma` - if set, support use of LZMA to compress embedded JARs and
boot images. The value of this option should be a directory
containing a recent LZMA SDK (available [here](http://www.7-zip.org/sdk.html)). Currently, only version 9.20 of
the SDK has been tested, but other versions might work.
* _default:_ not set
* `armv6` - if true, don't use any instructions newer than armv6. By
default, we assume the target is armv7 or later, and thus requires explicit
memory barrier instructions to ensure cache coherency
* `bootimage` - if true, create a boot image containing the pre-parsed
class library and ahead-of-time compiled methods. This option is
only valid for process=compile builds. Note that you may need to
specify both build-arch=x86_64 and arch=x86_64 on 64-bit systems
where "uname -m" prints "i386".
* _default:_ false
* `tails` - if true, optimize each tail call by replacing the caller's
stack frame with the callee's. This convention ensures proper
tail recursion, suitable for languages such as Scheme. This
option is only valid for process=compile builds.
* _default:_ false
* `continuations` - if true, support continuations via the
avian.Continuations methods callWithCurrentContinuation and
dynamicWind. See Continuations.java for details. This option is
only valid for process=compile builds.
* _default:_ false
* `use-clang` - if true, use LLVM's clang instead of GCC to build.
Note that this does not currently affect cross compiles, only
native builds.
* _default:_ false
* `openjdk` - if set, use the OpenJDK class library instead of the
default Avian class library. See "Building with the OpenJDK Class
Library" below for details.
* _default:_ not set
* `openjdk-src` - if this and the openjdk option above are both set,
build an embeddable VM using the OpenJDK class library. The JNI
components of the OpenJDK class library will be built from the
sources found under the specified directory. See "Building with
the OpenJDK Class Library" below for details.
* _default:_ not set
* `android` - if set, use the Android class library instead of the
default Avian class library. See "Building with the Android Class
Library" below for details.
* _default:_ not set
These flags determine the name of the directory used for the build.
The name always starts with _${platform}-${arch}_, and each non-default
build option is appended to the name. For example, a debug build with
bootimage enabled on Linux/x86_64 would be built in
_build/linux-x86_64-debug-bootimage_. This allows you to build with
several different sets of options independently and even
simultaneously without doing a clean build each time.
Note that not all combinations of these flags are valid. For instance,
non-jailbroken iOS devices do not allow JIT compilation, so only
process=interpret or bootimage=true builds will run on such
devices. See [here](https://github.com/ReadyTalk/hello-ios) for an
example of an Xcode project for iOS which uses Avian.
If you are compiling for Windows, you may either cross-compile using
MinGW or build natively on Windows under Cygwin.
#### Installing Cygwin:
__1.__ Download and run setup.exe from [cygwin's website](http://www.cygwin.com), installing the base
system and these packages: make, gcc-mingw-g++,
mingw64-i686-gcc-g++, mingw64-x86_64-gcc-g++, and (optionally) git.
You may also find our win32 repository useful: (run this from the
directory containing the avian directory)
$ git clone git@github.com:ReadyTalk/win32.git
This gives you the Windows JNI headers, zlib headers and library, and
a few other useful libraries like OpenSSL, libjpeg, and libpng.
There's also a win64 repository for 64-bit builds:
$ git clone git@github.com:ReadyTalk/win64.git
Building with the Microsoft Visual C++ Compiler
-----------------------------------------------
You can also build using the MSVC compiler, which makes debugging with
tools like WinDbg and Visual Studio much easier. Note that you will
still need to have GCC installed - MSVC is only used to compile the
C++ portions of the VM, while the assembly code and helper tools are
built using GCC.
*Note that the MSVC build isn't tested regularly, so is fairly likely to be broken.*
Avian targets MSVC 11 and above (it uses c++ features not available in older versions).
To build with MSVC, install Cygwin as described above and set the
following environment variables:
$ export PATH="/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/cygdrive/c/Program Files/Microsoft Visual Studio 11.0/Common7/IDE:/cygdrive/c/Program Files/Microsoft Visual Studio 11.0/VC/BIN:/cygdrive/c/Program Files/Microsoft Visual Studio 11.0/Common7/Tools:/cygdrive/c/WINDOWS/Microsoft.NET/Framework/v3.5:/cygdrive/c/WINDOWS/Microsoft.NET/Framework/v2.0.50727:/cygdrive/c/Program Files/Microsoft Visual Studio 11.0/VC/VCPackages:/cygdrive/c/Program Files/Microsoft SDKs/Windows/v6.0A/bin:/cygdrive/c/WINDOWS/system32:/cygdrive/c/WINDOWS:/cygdrive/c/WINDOWS/System32/Wbem"
$ export LIBPATH="C:\WINDOWS\Microsoft.NET\Framework\v3.5;C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727;C:\Program Files\Microsoft Visual Studio 11.0\VC\LIB;"
$ export VCINSTALLDIR="C:\Program Files\Microsoft Visual Studio 11.0\VC"
$ export LIB="C:\Program Files\Microsoft Visual Studio 11.0\VC\LIB;C:\Program Files\Microsoft SDKs\Windows\v6.0A\lib;"
$ export INCLUDE="C:\Program Files\Microsoft Visual Studio 11.0\VC\INCLUDE;C:\Program Files\Microsoft SDKs\Windows\v6.0A\include;"
Adjust these definitions as necessary according to your MSVC
installation.
Finally, build with the msvc flag set to the MSVC tool directory:
$ make msvc="/cygdrive/c/Program Files/Microsoft Visual Studio 11.0/VC"
Building with the OpenJDK Class Library
---------------------------------------
By default, Avian uses its own lightweight class library. However,
that library only contains a relatively small subset of the classes
and methods included in the JRE. If your application requires
features beyond that subset, you may want to tell Avian to use
OpenJDK's class library instead. To do so, specify the directory
where OpenJDK is installed, e.g.:
$ make openjdk=/usr/lib/jvm/java-7-openjdk
This will build Avian as a conventional JVM (e.g. libjvm.so) which
loads its boot class library and native libraries (e.g. libjava.so)
from _/usr/lib/jvm/java-7-openjdk/jre_ at runtime. Note that you must
use an absolute path here, or else the result will not work when run
from other directories. In this configuration, OpenJDK needs to
remain installed for Avian to work, and you can run applications like
this:
$ build/linux-x86_64-openjdk/avian-dynamic -cp /path/to/my/application \
com.example.MyApplication
Alternatively, you can enable a stand-alone build using OpenJDK by
specifying the location of the OpenJDK source code, e.g.:
$ make openjdk=$(pwd)/../jdk7/build/linux-amd64/j2sdk-image \
openjdk-src=$(pwd)/../jdk7/jdk/src
You must ensure that the path specified for openjdk-src does not have
any spaces in it; make gets confused when dependency paths include
spaces, and we haven't found away around that except to avoid paths
with spaces entirely.
The result of such a build is a self-contained binary which does not
depend on external libraries, jars, or other files. In this case, the
specified paths are used only at build time; anything needed at
runtime is embedded in the binary. Thus, the process of running an
application is simplified:
$ build/linux-x86_64-openjdk-src/avian -cp /path/to/my/application \
com.example.MyApplication
Note that the resulting binary will be very large due to the size of
OpenJDK's class library. This can be mitigated using UPX, preferably
an LZMA-enabled version:
$ upx --lzma --best build/linux-x86_64-openjdk-src/avian
You can reduce the size futher for embedded builds by using ProGuard
and the supplied openjdk.pro configuration file (see "Embedding with
ProGuard and a Boot Image" below). Note that you'll still need to use
vm.pro in that case -- openjdk.pro just adds additional constraints
specific to the OpenJDK port. Also see
[app.mk](https://github.com/ReadyTalk/avian-swt-examples/blob/master/app.mk)
in the _avian-swt-examples_ project for an example of using Avian,
OpenJDK, ProGuard, and UPX in concert.
Here are some examples of how to install OpenJDK and build Avian with
it on various OSes:
#### Debian-based Linux:
_Conventional build:_
$ apt-get install openjdk-7-jdk
$ make openjdk=/usr/lib/jvm/java-7-openjdk test
_Stand-alone build:_
$ apt-get install openjdk-7-jdk
$ apt-get source openjdk-7-jdk
$ apt-get build-dep openjdk-7-jdk
$ (cd openjdk-7-7~b147-2.0 && dpkg-buildpackage)
$ make openjdk=/usr/lib/jvm/java-7-openjdk \
openjdk-src=$(pwd)/openjdk-7-7~b147-2.0/build/openjdk/jdk/src \
test
####Mac OS X:
_Prerequisite:_ Build OpenJDK 7 according to [this site](https://wikis.oracle.com/display/OpenJDK/Mac+OS+X+Port).
_Conventional build:_
$ make openjdk=$(pwd)/../jdk7u-dev/build/macosx-amd64/j2sdk-image test
_Stand-alone build:_
$ make openjdk=$(pwd)/../jdk7u-dev/build/macosx-amd64/j2sdk-image \
openjdk-src=$(pwd)/../p/jdk7u-dev/jdk/src test
####Windows (Cygwin):
_Prerequisite:_ Build OpenJDK 7 according to [this site](http://weblogs.java.net/blog/simonis/archive/2011/10/28/yaojowbi-yet-another-openjdk-windows-build-instruction). Alternatively, use https://github.com/alexkasko/openjdk-unofficial-builds.
_Conventional build:_
$ make openjdk=$(pwd)/../jdk7u-dev/build/windows-i586/j2sdk-image test
_Stand-alone build:_
$ make openjdk=$(pwd)/../jdk7u-dev/build/windows-i586/j2sdk-image \
openjdk-src=$(pwd)/../p/jdk7u-dev/jdk/src test
Currently, only OpenJDK 7 is supported. Later versions might work,
but have not yet been tested.
Building with the Android Class Library
---------------------------------------
As an alternative to both the Avian and OpenJDK class libaries, you
can also build with the Android class library. Now it should work on Linux, OS X and Windows.
The simpliest way to build Avian with Android classpath is to use `avian-pack` project: https://github.com/bigfatbrowncat/avian-pack
Avian-pack consists of Avian itself with some Android components (such as libcore and icu4c).
Note that we use the upstream OpenSSL repository and apply the
Android patches to it. This is because it is not clear how to build
the Android fork of OpenSSL directly without checking out and building
the entire platform. As of this writing, the patches apply cleanly
against OpenSSL 1.0.1h, so that's the tag we check out, but this may
change in the future when the Android fork rebases against a new
OpenSSL version.
Installing
----------
Installing Avian is as simple as copying the executable to the desired
directory:
$ cp build/${platform}-${arch}/avian ~/bin/
Embedding
---------
The following series of commands illustrates how to produce a
stand-alone executable out of a Java application using Avian.
Note: if you are building on Cygwin, prepend "x86_64-w64-mingw32-" or
"i686-w64-mingw32-" to the ar, g++, gcc, strip, and dlltool commands
below (e.g. x86_64-w64-mingw32-gcc).
__1.__ Build Avian, create a new directory, and populate it with the
VM object files and bootstrap classpath jar.
$ make
$ mkdir hello
$ cd hello
$ ar x ../build/${platform}-${arch}/libavian.a
$ cp ../build/${platform}-${arch}/classpath.jar boot.jar
__2.__ Build the Java code and add it to the jar.
$ cat >Hello.java <<EOF
public class Hello {
public static void main(String[] args) {
System.out.println("hello, world!");
}
}
EOF
$ javac -bootclasspath boot.jar Hello.java
$ jar u0f boot.jar Hello.class
__3.__ Make an object file out of the jar.
$ ../build/${platform}-${arch}/binaryToObject/binaryToObject boot.jar \
boot-jar.o _binary_boot_jar_start _binary_boot_jar_end ${platform} ${arch}
If you've built Avian using the `lzma` option, you may optionally
compress the jar before generating the object:
../build/$(platform}-${arch}-lzma/lzma/lzma encode boot.jar boot.jar.lzma
&& ../build/${platform}-${arch}-lzma/binaryToObject/binaryToObject \
boot.jar.lzma boot-jar.o _binary_boot_jar_start _binary_boot_jar_end \
${platform} ${arch}
Note that you'll need to specify "-Xbootclasspath:[lzma.bootJar]"
instead of "-Xbootclasspath:[bootJar]" in the next step if you've used
LZMA to compress the jar.
__4.__ Write a driver which starts the VM and runs the desired main
method. Note the bootJar function, which will be called by the VM to
get a handle to the embedded jar. We tell the VM about this jar by
setting the boot classpath to "[bootJar]".
$ cat >embedded-jar-main.cpp <<EOF
#include "stdint.h"
#include "jni.h"
#include "stdlib.h"
#if (defined __MINGW32__) || (defined _MSC_VER)
# define EXPORT __declspec(dllexport)
#else
# define EXPORT __attribute__ ((visibility("default"))) \
__attribute__ ((used))
#endif
#if (! defined __x86_64__) && ((defined __MINGW32__) || (defined _MSC_VER))
# define SYMBOL(x) binary_boot_jar_##x
#else
# define SYMBOL(x) _binary_boot_jar_##x
#endif
extern "C" {
extern const uint8_t SYMBOL(start)[];
extern const uint8_t SYMBOL(end)[];
EXPORT const uint8_t*
bootJar(size_t* size)
{
*size = SYMBOL(end) - SYMBOL(start);
return SYMBOL(start);
}
} // extern "C"
extern "C" void __cxa_pure_virtual(void) { abort(); }
int
main(int ac, const char** av)
{
JavaVMInitArgs vmArgs;
vmArgs.version = JNI_VERSION_1_2;
vmArgs.nOptions = 1;
vmArgs.ignoreUnrecognized = JNI_TRUE;
JavaVMOption options[vmArgs.nOptions];
vmArgs.options = options;
options[0].optionString = const_cast<char*>("-Xbootclasspath:[bootJar]");
JavaVM* vm;
void* env;
JNI_CreateJavaVM(&vm, &env, &vmArgs);
JNIEnv* e = static_cast<JNIEnv*>(env);
jclass c = e->FindClass("Hello");
if (not e->ExceptionCheck()) {
jmethodID m = e->GetStaticMethodID(c, "main", "([Ljava/lang/String;)V");
if (not e->ExceptionCheck()) {
jclass stringClass = e->FindClass("java/lang/String");
if (not e->ExceptionCheck()) {
jobjectArray a = e->NewObjectArray(ac-1, stringClass, 0);
if (not e->ExceptionCheck()) {
for (int i = 1; i < ac; ++i) {
e->SetObjectArrayElement(a, i-1, e->NewStringUTF(av[i]));
}
e->CallStaticVoidMethod(c, m, a);
}
}
}
}
int exitCode = 0;
if (e->ExceptionCheck()) {
exitCode = -1;
e->ExceptionDescribe();
}
vm->DestroyJavaVM();
return exitCode;
}
EOF
__on Linux:__
$ g++ -I$JAVA_HOME/include -I$JAVA_HOME/include/linux \
-D_JNI_IMPLEMENTATION_ -c embedded-jar-main.cpp -o main.o
__on Mac OS X:__
$ g++ -I$JAVA_HOME/include -I$JAVA_HOME/include/darwin \
-D_JNI_IMPLEMENTATION_ -c embedded-jar-main.cpp -o main.o
__on Windows:__
$ g++ -fno-exceptions -fno-rtti -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/win32" \
-D_JNI_IMPLEMENTATION_ -c embedded-jar-main.cpp -o main.o
__5.__ Link the objects produced above to produce the final
executable, and optionally strip its symbols.
__on Linux:__
$ g++ -rdynamic *.o -ldl -lpthread -lz -o hello
$ strip --strip-all hello
__on Mac OS X:__
$ g++ -rdynamic *.o -ldl -lpthread -lz -o hello -framework CoreFoundation
$ strip -S -x hello
__on Windows:__
$ dlltool -z hello.def *.o
$ dlltool -d hello.def -e hello.exp
$ gcc hello.exp *.o -L../../win32/lib -lmingwthrd -lm -lz -lws2_32 \
-lIphlpapi -mwindows -mconsole -o hello.exe
$ strip --strip-all hello.exe
Embedding with ProGuard and a Boot Image
----------------------------------------
The following illustrates how to embed an application as above, except
this time we preprocess the code using ProGuard and build a boot image
from it for quicker startup. The pros and cons of using ProGuard are
as follow:
* Pros: ProGuard will eliminate unused code, optimize the rest, and
obfuscate it as well for maximum space savings
* Cons: increased build time, especially for large applications, and
extra effort needed to configure it for applications which rely
heavily on reflection and/or calls to Java from native code
For boot image builds:
* Pros: the boot image build pre-parses all the classes and compiles
all the methods, obviating the need for JIT compilation at runtime.
This also makes garbage collection faster, since the pre-parsed
classes are never visited.
* Cons: the pre-parsed classes and AOT-compiled methods take up more
space in the executable than the equivalent class files. In
practice, this can make the executable 30-50% larger. Also, AOT
compilation does not yet yield significantly faster or smaller code
than JIT compilation. Finally, floating point code may be slower
on 32-bit x86 since the compiler cannot assume SSE2 support will be
available at runtime, and the x87 FPU is not supported except via
out-of-line helper functions.
Note you can use ProGuard without using a boot image and vice-versa,
as desired.
The following instructions assume we are building for Linux/x86_64.
Please refer to the previous example for guidance on other platforms.
__1.__ Build Avian, create a new directory, and populate it with the
VM object files.
$ make bootimage=true
$ mkdir hello
$ cd hello
$ ar x ../build/linux-x86_64-bootimage/libavian.a
__2.__ Create a stage1 directory and extract the contents of the
class library jar into it.
$ mkdir stage1
$ (cd stage1 && jar xf ../../build/linux-x86_64-bootimage/classpath.jar)
__3.__ Build the Java code and add it to stage1.
$ cat >Hello.java <<EOF
public class Hello {
public static void main(String[] args) {
System.out.println("hello, world!");
}
}
EOF
$ javac -bootclasspath stage1 -d stage1 Hello.java
__4.__ Create a ProGuard configuration file specifying Hello.main as
the entry point.
$ cat >hello.pro <<EOF
-keep class Hello {
public static void main(java.lang.String[]);
}
EOF
__5.__ Run ProGuard with stage1 as input and stage2 as output.
$ java -jar ../../proguard4.6/lib/proguard.jar \
-dontusemixedcaseclassnames -injars stage1 -outjars stage2 \
@../vm.pro @hello.pro
(note: The -dontusemixedcaseclassnames option is only needed when
building on systems with case-insensitive filesystems such as Windows
and OS X. Also, you'll need to add -ignorewarnings if you use the
OpenJDK class library since the openjdk-src build does not include all
the JARs from OpenJDK, and thus ProGuard will not be able to resolve
all referenced classes. If you actually plan to use such classes at
runtime, you'll need to add them to stage1 before running ProGuard.
Finally, you'll need to add @../openjdk.pro to the above command when
using the OpenJDK library.)
__6.__ Build the boot and code images.
$ ../build/linux-x86_64-bootimage/bootimage-generator \
-cp stage2 \
-bootimage bootimage-bin.o \
-codeimage codeimage-bin.o \
-hostvm ../build/linux-x86_64-interpret/libjvm.so
Note that you can override the default names for the start and end
symbols in the boot/code image by also passing:
-bootimage-symbols my_bootimage_start:my_bootimage_end \
-codeimage-symbols my_codeimage_start:my_codeimage_end
__7.__ Write a driver which starts the VM and runs the desired main
method. Note the bootimageBin function, which will be called by the
VM to get a handle to the embedded boot image. We tell the VM about
this function via the "avian.bootimage" property.
Note also that this example includes no resources besides class files.
If our application loaded resources such as images and properties
files via the classloader, we would also need to embed the jar file
containing them. See the previous example for instructions.
$ cat >bootimage-main.cpp <<EOF
#include "stdint.h"
#include "jni.h"
#if (defined __MINGW32__) || (defined _MSC_VER)
# define EXPORT __declspec(dllexport)
#else
# define EXPORT __attribute__ ((visibility("default")))
#endif
#if (! defined __x86_64__) && ((defined __MINGW32__) || (defined _MSC_VER))
# define BOOTIMAGE_BIN(x) binary_bootimage_bin_##x
# define CODEIMAGE_BIN(x) binary_codeimage_bin_##x
#else
# define BOOTIMAGE_BIN(x) _binary_bootimage_bin_##x
# define CODEIMAGE_BIN(x) _binary_codeimage_bin_##x
#endif
extern "C" {
extern const uint8_t BOOTIMAGE_BIN(start)[];
extern const uint8_t BOOTIMAGE_BIN(end)[];
EXPORT const uint8_t*
bootimageBin(size_t* size)
{
*size = BOOTIMAGE_BIN(end) - BOOTIMAGE_BIN(start);
return BOOTIMAGE_BIN(start);
}
extern const uint8_t CODEIMAGE_BIN(start)[];
extern const uint8_t CODEIMAGE_BIN(end)[];
EXPORT const uint8_t*
codeimageBin(size_t* size)
{
*size = CODEIMAGE_BIN(end) - CODEIMAGE_BIN(start);
return CODEIMAGE_BIN(start);
}
} // extern "C"
int
main(int ac, const char** av)
{
JavaVMInitArgs vmArgs;
vmArgs.version = JNI_VERSION_1_2;
vmArgs.nOptions = 2;
vmArgs.ignoreUnrecognized = JNI_TRUE;
JavaVMOption options[vmArgs.nOptions];
vmArgs.options = options;
options[0].optionString
= const_cast<char*>("-Davian.bootimage=bootimageBin");
options[1].optionString
= const_cast<char*>("-Davian.codeimage=codeimageBin");
JavaVM* vm;
void* env;
JNI_CreateJavaVM(&vm, &env, &vmArgs);
JNIEnv* e = static_cast<JNIEnv*>(env);
jclass c = e->FindClass("Hello");
if (not e->ExceptionCheck()) {
jmethodID m = e->GetStaticMethodID(c, "main", "([Ljava/lang/String;)V");
if (not e->ExceptionCheck()) {
jclass stringClass = e->FindClass("java/lang/String");
if (not e->ExceptionCheck()) {
jobjectArray a = e->NewObjectArray(ac-1, stringClass, 0);
if (not e->ExceptionCheck()) {
for (int i = 1; i < ac; ++i) {
e->SetObjectArrayElement(a, i-1, e->NewStringUTF(av[i]));
}
e->CallStaticVoidMethod(c, m, a);
}
}
}
}
int exitCode = 0;
if (e->ExceptionCheck()) {
exitCode = -1;
e->ExceptionDescribe();
}
vm->DestroyJavaVM();
return exitCode;
}
EOF
$ g++ -I$JAVA_HOME/include -I$JAVA_HOME/include/linux \
-D_JNI_IMPLEMENTATION_ -c bootimage-main.cpp -o main.o
__8.__ Link the objects produced above to produce the final
executable, and optionally strip its symbols.
$ g++ -rdynamic *.o -ldl -lpthread -lz -o hello
$ strip --strip-all hello
Trademarks
----------
Oracle and Java are registered trademarks of Oracle and/or its
affiliates. Other names may be trademarks of their respective owners.
The Avian project is not affiliated with Oracle.

89
sgx-jvm/avian/android.pro Normal file
View File

@ -0,0 +1,89 @@
# these are referenced in JniConstants.cpp:
-keep class java.text.Bidi$Run
-keep class java.math.BigDecimal
-keep class java.lang.Boolean
-keep class java.lang.Byte
-keep class java.nio.charset.CharsetICU {
CharsetICU(java.lang.String, java.lang.String, java.lang.String[]);
}
-keep class java.lang.reflect.Constructor
-keep class java.util.zip.Deflater
-keep class java.lang.Double
-keep class libcore.io.ErrnoException
-keep class java.lang.reflect.Field
-keep class libcore.icu.NativeDecimalFormat$FieldPositionIterator {
void setData(int[]);
}
-keep class java.io.FileDescriptor
-keep class libcore.io.GaiException
-keep class java.net.Inet6Address
-keep class java.net.InetAddress
-keep class java.net.InetSocketAddress
-keep class java.net.InetUnixAddress
-keep class java.util.zip.Inflater
-keep class java.lang.Integer
-keep class libcore.icu.LocaleData
-keep class java.lang.Long
-keep class java.lang.reflect.Method
-keep class libcore.util.MutableInt
-keep class libcore.util.MutableLong
-keep class java.text.ParsePosition
-keep class java.util.regex.PatternSyntaxException
-keep class java.lang.RealToString
-keep class java.net.Socket
-keep class java.net.SocketImpl
-keep class java.lang.String
-keep class libcore.io.StructAddrinfo {
<fields>;
}
-keep class libcore.io.StructFlock
-keep class libcore.io.StructGroupReq
-keep class libcore.io.StructLinger
-keep class libcore.io.StructPasswd {
StructPasswd(java.lang.String, int, int, java.lang.String, java.lang.String);
}
-keep class libcore.io.StructPollfd
-keep class libcore.io.StructStat {
StructStat(long, long, int, long, int, int, long, long, long, long, long, long, long);
}
-keep class libcore.io.StructStatFs
-keep class libcore.io.StructTimeval
-keep class libcore.io.StructUtsname {
StructUtsname(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
}
-keep class libcore.io.StructUcred
# referenced from libcore native code
-keep class libcore.icu.LocaleData {
<fields>;
}
-keep class org.conscrypt.OpenSSLBIOInputStream {
<methods>;
}
-keep class java.util.Calendar {
void set(int, int, int, int, int, int);
}
# called from the VM
-keep class java.lang.Thread {
Thread(java.lang.ThreadGroup, java.lang.String, int, boolean);
}
-keep class avian.Classes {
java.lang.Class forName(java.lang.String, boolean, java.lang.ClassLoader);
int findField(avian.VMClass, java.lang.String);
int findMethod(avian.VMClass, java.lang.String, java.lang.Class[]);
java.lang.annotation.Annotation getAnnotation(java.lang.ClassLoader, java.lang.Object[]);
}
-keep class java.lang.VMThread {
VMThread(java.lang.Thread);
}
# loaded reflectively to handle embedded resources:
-keep class avian.avianvmresource.Handler

323
sgx-jvm/avian/build.gradle Normal file
View File

@ -0,0 +1,323 @@
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'org.jfrog.buildinfo:build-info-extractor-gradle:2.2.4'
}
}
apply plugin: 'native-component'
apply plugin: 'ivy-publish'
apply plugin: 'java'
apply plugin: 'artifactory-publish'
enum SupportedOS implements OperatingSystem {
LINUX, WINDOWS, MACOSX;
public static final SupportedOS CURRENT;
static {
String p = System.properties['os.name']
switch(p.replaceAll(' ', '').toLowerCase()) {
case ~/.*linux.*/: CURRENT = LINUX; break;
case ~/.*darwin.*/: CURRENT = MACOSX; break;
case ~/.*osx.*/: CURRENT = MACOSX; break;
case ~/.*win.*/: CURRENT = WINDOWS; break;
default:
String m = "SupportedOS: unrecognized platform: ${p}"
println(m)
throw new IllegalArgumentException(m)
}
}
public String getName() {
return toString().toLowerCase()
}
public String getDisplayName() {
return getName()
}
public boolean isCurrent() { return this == CURRENT }
public boolean isFreeBSD() { return false }
public boolean isLinux() { return this == LINUX }
public boolean isMacOsX() { return this == MACOSX }
public boolean isSolaris() { return false }
public boolean isWindows() { return this == WINDOWS }
}
public String adjustArch(String arch) {
switch(arch) {
case ~/.*64.*/: return 'x86_64'
default: return 'i386'
}
}
ext {
currentPlatform = SupportedOS.CURRENT.getName()
currentArch = adjustArch(System.properties['os.arch'])
currentPlatformArch = "${currentPlatform}-${currentArch}"
platform = project.hasProperty('platform') ? platform : currentPlatform
arch = project.hasProperty('arch') ? arch : currentArch
platformArch = "${platform}-${arch}"
java_home = System.properties.'java.home'
if(java_home.endsWith("/jre")) {
java_home = java_home.substring(0, java_home.length() - "/jre".length())
}
java_home = java_home
libDir = "${buildDir}/lib"
lzmaDir = "${libDir}/lzma"
buildOptions = ['', '-lzma']
}
repositories {
ivy {
name "ivyLocal"
url "${System.env.HOME}/.ivy2/local"
layout 'maven'
}
ivy {
name "jcenter"
if(version.contains("SNAPSHOT")) {
url "http://oss.jfrog.org/artifactory/oss-snapshot-local"
} else {
url "http://oss.jfrog.org/artifactory/oss-release-local"
}
layout 'maven'
}
}
configurations {
create('windows-i386')
create('windows-x86_64')
}
dependencies {
'windows-i386' "com.readytalk:win32:1.0.0-SNAPSHOT"
'windows-x86_64' "com.readytalk:win64:1.0.0-SNAPSHOT"
}
model {
platforms {
create(platformArch) {
operatingSystem SupportedOS.valueOf(platform.toUpperCase())
architecture "${arch}"
}
}
tasks {
buildOptions.each { buildOption ->
platforms.each { platform ->
if(platform.operatingSystem.name == "windows") {
def artifactName = platform.architecture.name == "i386" ? 'win32' : 'win64'
task "extract${platform.name}${buildOption}"(type: Copy) {
from {
tarTree(configurations."${platform.name}".find { it.name =~ artifactName })
}
into "${libDir}/tools"
}
}
task "build${platform.name}${buildOption}"(type: Exec) {
executable "make"
args "platform=${platform.operatingSystem.name}",
"arch=${platform.architecture.name}"
if(buildOption == "-lzma") {
dependsOn 'extractLzma'
args "lzma=${lzmaDir}"
}
if(platform.operatingSystem.name == "windows") {
dependsOn "extract${platform.name}${buildOption}"
args "win32=${libDir}/tools/win32",
"win64=${libDir}/tools/win64"
}
environment JAVA_HOME: java_home
}
assemble {
dependsOn "build${platform.name}${buildOption}"
}
}
}
}
}
tasks.withType(JavaCompile) {
sourceCompatibility = "1.6"
targetCompatibility = "1.6"
options.with {
encoding = "UTF-8"
bootClasspath = sourceSets.main.output.classesDir
}
}
sourceSets {
main {
java {
srcDir 'classpath'
}
}
}
javadoc {
title = "Avian v${version} Class Library API"
}
task javadocJar(type: Jar) {
dependsOn javadoc
classifier = 'javadoc'
from {
javadoc.destinationDir
}
}
jar {
baseName "classpath-avian"
}
task downloadLzma(type: Exec) {
commandLine "curl"
args "--create-dirs", "-o", "${lzmaDir}/lzma920.tar.bz2", "-f", "http://oss.readytalk.com/avian-web/lzma920.tar.bz2"
}
task extractLzma(type: Copy) {
dependsOn downloadLzma
from {
tarTree(resources.bzip2("${lzmaDir}/lzma920.tar.bz2"))
}
into lzmaDir
}
task install {
dependsOn assemble, publish
}
publishing {
repositories {
add(project.repositories."ivyLocal")
}
publications {
ivy(IvyPublication) {
from components.java
artifact(javadocJar)
artifact("vm.pro") {
name "vm"
type "proguard"
extension "pro"
}
module "classpath-avian"
}
create("tools-avian-${currentPlatformArch}", IvyPublication) {
module "tools-avian-${currentPlatformArch}"
def publishBinSuffix = currentPlatform == "windows" ? "exe" : "bin"
def binSuffix = currentPlatform == "windows" ? ".exe" : ""
artifact("${buildDir}/${currentPlatform}-${currentArch}/binaryToObject/binaryToObject${binSuffix}") {
name "binaryToObject"
type publishBinSuffix
extension publishBinSuffix
}
}
buildOptions.each { buildOption ->
platforms.each { platform ->
def binSuffix=""
def publishBinSuffix="bin"
create("${platform.name}${buildOption}", IvyPublication) {
def nativeBuildDir = "${buildDir}/${platform.operatingSystem.name}-${platform.architecture.name}${buildOption}"
if(platform.operatingSystem.name == "windows") {
publishBinSuffix = "exe"
binSuffix = ".${publishBinSuffix}"
}
module "runtime-avian${buildOption}-${platform.name}"
artifact("${nativeBuildDir}/avian${binSuffix}") {
name "avian"
type publishBinSuffix
extension publishBinSuffix
}
artifact("${nativeBuildDir}/libavian.a") {
name "libavian"
type "a"
extension "a"
}
if (buildOption == "-lzma") {
artifact("${nativeBuildDir}/libavian-lzma.a") {
name "libavian-lzma"
type "a"
extension "a"
}
artifact("${nativeBuildDir}/lzma/lzma${binSuffix}") {
name "lzma"
type publishBinSuffix
extension publishBinSuffix
}
}
}
}
}
}
}
artifactoryPublish {
onlyIf {
// TRAVIS_BRANCH reports master if it is a master build or a PR going to master
// TRAVIS_PULL_REQUEST reports false if not a pull request and the PR number if it is
System.env.'TRAVIS_BRANCH' == "master" && System.env.'TRAVIS_PULL_REQUEST' == "false"
}
dependsOn assemble
}
artifactory {
contextUrl = "http://oss.jfrog.org"
resolve {
repository {
repoKey = 'libs-releases'
}
}
publish {
repository {
repoKey = 'oss-snapshot-local'
username = System.env.BINTRAY_USER
password = System.env.BINTRAY_API_KEY
ivy {
ivyLayout = "[organisation]/[module]/[revision]/ivy-[revision].xml"
}
}
defaults {
platforms.each {
publications it.name
}
}
}
}
task wrapper(type: Wrapper) {
distributionUrl = 'http://services.gradle.org/distributions/gradle-2.0-bin.zip'
}

View File

@ -0,0 +1,17 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
public class Addendum {
public Singleton pool;
public Object annotationTable;
public Object signature;
}

View File

@ -0,0 +1,32 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationHandler;
public class AnnotationInvocationHandler implements InvocationHandler {
private Object[] data;
public AnnotationInvocationHandler(Object[] data) {
this.data = data;
}
public Object invoke(Object proxy, Method method, Object[] arguments) {
String name = method.getName();
for (int i = 2; i < data.length; i += 2) {
if (name.equals(data[i])) {
return data[i + 1];
}
}
return method.getDefaultValue();
}
}

View File

@ -0,0 +1,135 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
import static avian.Stream.write1;
import static avian.Stream.write2;
import static avian.Stream.write4;
import avian.ConstantPool.PoolEntry;
import java.util.List;
import java.io.OutputStream;
import java.io.IOException;
public class Assembler {
public static final int ACC_PUBLIC = 1 << 0;
public static final int ACC_STATIC = 1 << 3;
public static final int aaload = 0x32;
public static final int aastore = 0x53;
public static final int aload = 0x19;
public static final int aload_0 = 0x2a;
public static final int aload_1 = 0x2b;
public static final int astore_0 = 0x4b;
public static final int anewarray = 0xbd;
public static final int areturn = 0xb0;
public static final int dload = 0x18;
public static final int dreturn = 0xaf;
public static final int dup = 0x59;
public static final int fload = 0x17;
public static final int freturn = 0xae;
public static final int getfield = 0xb4;
public static final int goto_ = 0xa7;
public static final int iload = 0x15;
public static final int invokeinterface = 0xb9;
public static final int invokespecial = 0xb7;
public static final int invokestatic = 0xb8;
public static final int invokevirtual = 0xb6;
public static final int ireturn = 0xac;
public static final int jsr = 0xa8;
public static final int ldc_w = 0x13;
public static final int lload = 0x16;
public static final int lreturn = 0xad;
public static final int new_ = 0xbb;
public static final int pop = 0x57;
public static final int putfield = 0xb5;
public static final int ret = 0xa9;
public static final int return_ = 0xb1;
public static void writeClass(OutputStream out,
List<PoolEntry> pool,
int name,
int super_,
int[] interfaces,
FieldData[] fields,
MethodData[] methods)
throws IOException
{
int codeAttributeName = ConstantPool.addUtf8(pool, "Code");
write4(out, 0xCAFEBABE);
write2(out, 0); // minor version
write2(out, 50); // major version
write2(out, pool.size() + 1);
for (PoolEntry e: pool) {
e.writeTo(out);
}
write2(out, ACC_PUBLIC); // flags
write2(out, name + 1);
write2(out, super_ + 1);
write2(out, interfaces.length);
for (int i: interfaces) {
write2(out, i + 1);
}
write2(out, fields.length);
for (FieldData f: fields) {
write2(out, f.flags);
write2(out, f.nameIndex + 1);
write2(out, f.specIndex + 1);
write2(out, 0); // attribute count
}
write2(out, methods.length);
for (MethodData m: methods) {
write2(out, m.flags);
write2(out, m.nameIndex + 1);
write2(out, m.specIndex + 1);
write2(out, 1); // attribute count
write2(out, codeAttributeName + 1);
write4(out, m.code.length);
out.write(m.code);
}
write2(out, 0); // attribute count
}
public static class MethodData {
public final int flags;
public final int nameIndex;
public final int specIndex;
public final byte[] code;
public MethodData(int flags, int nameIndex, int specIndex, byte[] code) {
this.flags = flags;
this.nameIndex = nameIndex;
this.specIndex = specIndex;
this.code = code;
}
}
public static class FieldData {
public final int flags;
public final int nameIndex;
public final int specIndex;
public FieldData(int flags, int nameIndex, int specIndex) {
this.flags = flags;
this.nameIndex = nameIndex;
this.specIndex = specIndex;
}
}
}

View File

@ -0,0 +1,20 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
import java.lang.reflect.Field;
public class Atomic {
public static native long getOffset(Field field);
public static native boolean compareAndSwapObject
(Object o, long offset, Object old, Object new_);
}

View File

@ -0,0 +1,16 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
public interface Callback<T> {
public void handleResult(T result);
public void handleException(Throwable exception);
}

View File

@ -0,0 +1,54 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
public class Cell <T> {
public T value;
public Cell<T> next;
public Cell(T value, Cell<T> next) {
this.value = value;
this.next = next;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("(");
for (Cell c = this; c != null; c = c.next) {
sb.append(value);
if (c.next != null) {
sb.append(" ");
}
}
sb.append(")");
return sb.toString();
}
public static <Car> Cell<Car> cons(Car car, Cell<Car> cdr) {
return new Cell(car, cdr);
}
public static <T> boolean equal(T a, T b) {
return (a == null && b == null) || (a != null && a.equals(b));
}
public static <Car> boolean equal(Cell<Car> a, Cell<Car> b) {
while (a != null) {
if (b == null || (! equal(a.value, b.value))) {
return false;
}
a = a.next;
b = b.next;
}
return b == null;
}
}

View File

@ -0,0 +1,32 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
public class ClassAddendum extends Addendum {
public Object[] interfaceTable;
public InnerClassReference[] innerClassTable;
/**
* If this value is negative, all the methods in VMClass.methodTable
* were declared in that class. Otherwise, only the first
* declaredMethodCount methods in that table were declared in that
* class, while the rest were declared in interfaces implemented or
* extended by that class.
*/
public int declaredMethodCount;
public byte[] enclosingClass;
public Pair enclosingMethod;
public VMMethod[] bootstrapMethodTable;
public VMMethod[] bootstrapLambdaTable;
}

View File

@ -0,0 +1,604 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
import static avian.Stream.read1;
import static avian.Stream.read2;
import java.net.URL;
import java.net.MalformedURLException;
import java.security.CodeSource;
import java.security.AllPermission;
import java.security.Permissions;
import java.security.ProtectionDomain;
import java.security.cert.Certificate;
import java.lang.reflect.Modifier;
import java.lang.reflect.Method;
import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
import java.lang.annotation.Annotation;
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
public class Classes {
private static final int LinkFlag = 1 << 8;
public static native VMClass defineVMClass
(ClassLoader loader, byte[] b, int offset, int length);
public static native VMClass primitiveClass(char name);
public static native void initialize(VMClass vmClass);
public static native boolean isAssignableFrom(VMClass a, VMClass b);
public static native VMClass getVMClass(Object o);
public static native VMClass toVMClass(Class c);
public static native VMMethod toVMMethod(Method m);
private static native VMClass resolveVMClass(ClassLoader loader, byte[] spec)
throws ClassNotFoundException;
public static VMClass loadVMClass(ClassLoader loader,
byte[] nameBytes, int offset, int length)
{
byte[] spec = new byte[length + 1];
System.arraycopy(nameBytes, offset, spec, 0, length);
try {
VMClass c = resolveVMClass(loader, spec);
if (c == null) {
throw new NoClassDefFoundError();
}
return c;
} catch (ClassNotFoundException e) {
NoClassDefFoundError error = new NoClassDefFoundError
(new String(nameBytes, offset, length));
error.initCause(e);
throw error;
}
}
private static Object parseAnnotationValue(ClassLoader loader,
Object pool,
InputStream in)
throws IOException
{
switch (read1(in)) {
case 'Z':
return Boolean.valueOf(Singleton.getInt(pool, read2(in) - 1) != 0);
case 'B':
return Byte.valueOf((byte) Singleton.getInt(pool, read2(in) - 1));
case 'C':
return Character.valueOf((char) Singleton.getInt(pool, read2(in) - 1));
case 'S':
return Short.valueOf((short) Singleton.getInt(pool, read2(in) - 1));
case 'I':
return Integer.valueOf(Singleton.getInt(pool, read2(in) - 1));
case 'F':
return Float.valueOf
(Float.intBitsToFloat(Singleton.getInt(pool, read2(in) - 1)));
case 'J': {
return Long.valueOf(Singleton.getLong(pool, read2(in) - 1));
}
case 'D': {
return Double.valueOf
(Double.longBitsToDouble(Singleton.getLong(pool, read2(in) - 1)));
}
case 's': {
byte[] data = (byte[]) Singleton.getObject(pool, read2(in) - 1);
return new String(data, 0, data.length - 1);
}
case 'e': {
byte[] typeName = (byte[]) Singleton.getObject(pool, read2(in) - 1);
byte[] name = (byte[]) Singleton.getObject(pool, read2(in) - 1);
return Enum.valueOf
(SystemClassLoader.getClass
(loadVMClass(loader, typeName, 1, typeName.length - 3)),
new String(name, 0, name.length - 1));
}
case 'c':{
byte[] name = (byte[]) Singleton.getObject(pool, read2(in) - 1);
return SystemClassLoader.getClass
(loadVMClass(loader, name, 1, name.length - 3));
}
case '@':
return getAnnotation(loader, parseAnnotation(loader, pool, in));
case '[': {
Object[] array = new Object[read2(in)];
for (int i = 0; i < array.length; ++i) {
array[i] = parseAnnotationValue(loader, pool, in);
}
return array;
}
default: throw new AssertionError();
}
}
private static Object[] parseAnnotation(ClassLoader loader,
Object pool,
InputStream in)
throws IOException
{
byte[] typeName = (byte[]) Singleton.getObject(pool, read2(in) - 1);
Object[] annotation = new Object[(read2(in) + 1) * 2];
annotation[1] = SystemClassLoader.getClass
(loadVMClass(loader, typeName, 1, typeName.length - 3));
for (int i = 2; i < annotation.length; i += 2) {
byte[] name = (byte[]) Singleton.getObject(pool, read2(in) - 1);
annotation[i] = new String(name, 0, name.length - 1);
annotation[i + 1] = parseAnnotationValue(loader, pool, in);
}
return annotation;
}
private static Object[] parseAnnotationTable(ClassLoader loader,
Object pool,
InputStream in)
throws IOException
{
Object[] table = new Object[read2(in)];
for (int i = 0; i < table.length; ++i) {
table[i] = parseAnnotation(loader, pool, in);
}
return table;
}
private static void parseAnnotationTable(ClassLoader loader,
Addendum addendum)
{
if (addendum != null && addendum.annotationTable instanceof byte[]) {
try {
addendum.annotationTable = parseAnnotationTable
(loader, addendum.pool, new ByteArrayInputStream
((byte[]) addendum.annotationTable));
} catch (IOException e) {
AssertionError error = new AssertionError();
error.initCause(e);
throw error;
}
}
}
private static int resolveSpec(ClassLoader loader, byte[] spec, int start) {
int result;
int end;
switch (spec[start]) {
case 'L':
++ start;
end = start;
while (spec[end] != ';') ++ end;
result = end + 1;
break;
case '[':
end = start + 1;
while (spec[end] == '[') ++ end;
switch (spec[end]) {
case 'L':
++ end;
while (spec[end] != ';') ++ end;
++ end;
break;
default:
++ end;
}
result = end;
break;
default:
return start + 1;
}
loadVMClass(loader, spec, start, end - start);
return result;
}
private static int declaredMethodCount(VMClass c) {
ClassAddendum a = c.addendum;
if (a != null) {
int count = a.declaredMethodCount;
if (count >= 0) {
return count;
}
}
VMMethod[] table = c.methodTable;
return table == null ? 0 : table.length;
}
public static void link(VMClass c, ClassLoader loader) {
acquireClassLock();
try {
if ((c.vmFlags & LinkFlag) == 0) {
if (c.super_ != null) {
link(c.super_, loader);
}
parseAnnotationTable(loader, c.addendum);
if (c.interfaceTable != null) {
int stride = ((c.flags & Modifier.INTERFACE) != 0 ? 1 : 2);
for (int i = 0; i < c.interfaceTable.length; i += stride) {
link((VMClass) c.interfaceTable[i], loader);
}
}
VMMethod[] methodTable = c.methodTable;
if (methodTable != null) {
for (int i = 0; i < methodTable.length; ++i) {
VMMethod m = methodTable[i];
for (int j = 1; j < m.spec.length;) {
j = resolveSpec(loader, m.spec, j);
}
parseAnnotationTable(loader, m.addendum);
}
}
if (c.fieldTable != null) {
for (int i = 0; i < c.fieldTable.length; ++i) {
VMField f = c.fieldTable[i];
resolveSpec(loader, f.spec, 0);
parseAnnotationTable(loader, f.addendum);
}
}
c.vmFlags |= LinkFlag;
}
} finally {
releaseClassLock();
}
}
public static void link(VMClass c) {
link(c, c.loader);
}
public static Class forName(String name, boolean initialize,
ClassLoader loader)
throws ClassNotFoundException
{
if (loader == null) {
loader = Class.class.getClassLoader();
}
Class c = loader.loadClass(name);
VMClass vmc = SystemClassLoader.vmClass(c);
link(vmc, loader);
if (initialize) {
initialize(vmc);
}
return c;
}
public static Class forCanonicalName(String name) {
return forCanonicalName(null, name);
}
public static Class forCanonicalName(ClassLoader loader, String name) {
try {
if (name.startsWith("[")) {
return forName(name, true, loader);
} else if (name.startsWith("L")) {
return forName(name.substring(1, name.length() - 1), true, loader);
} else {
if (name.length() == 1) {
return SystemClassLoader.getClass
(primitiveClass(name.charAt(0)));
} else {
throw new ClassNotFoundException(name);
}
}
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
private static int next(char c, String s, int start) {
for (int i = start; i < s.length(); ++i) {
if (s.charAt(i) == c) return i;
}
throw new RuntimeException();
}
public static Class[] getParameterTypes(VMMethod vmMethod) {
int count = vmMethod.parameterCount;
Class[] types = new Class[count];
int index = 0;
String spec = new String
(vmMethod.spec, 1, vmMethod.spec.length - 2);
try {
for (int i = 0; i < spec.length(); ++i) {
char c = spec.charAt(i);
if (c == ')') {
break;
} else if (c == 'L') {
int start = i + 1;
i = next(';', spec, start);
String name = spec.substring(start, i).replace('/', '.');
types[index++] = Class.forName(name, true, vmMethod.class_.loader);
} else if (c == '[') {
int start = i;
while (spec.charAt(i) == '[') ++i;
if (spec.charAt(i) == 'L') {
i = next(';', spec, i + 1);
String name = spec.substring(start, i).replace('/', '.');
types[index++] = Class.forName
(name, true, vmMethod.class_.loader);
} else {
String name = spec.substring(start, i + 1);
types[index++] = forCanonicalName(vmMethod.class_.loader, name);
}
} else {
String name = spec.substring(i, i + 1);
types[index++] = forCanonicalName(vmMethod.class_.loader, name);
}
}
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
return types;
}
public static int findField(VMClass vmClass, String name) {
if (vmClass.fieldTable != null) {
link(vmClass);
for (int i = 0; i < vmClass.fieldTable.length; ++i) {
if (toString(vmClass.fieldTable[i].name).equals(name)) {
return i;
}
}
}
return -1;
}
public static String toString(byte[] array) {
return new String(array, 0, array.length - 1);
}
private static boolean match(VMClass a, VMClass b) {
// TODO: in theory we should be able to just do an == comparison
// here instead of recursively comparing array element types.
// However, the VM currently can create multiple array classes for
// the same element type. We should fix that so that there's only
// ever one of each per classloader, eliminating the need for a
// recursive comparison. See also the native implementation of
// isAssignableFrom.
if (a.arrayDimensions > 0) {
return match(a.arrayElementClass, b.arrayElementClass);
} else {
return a == b;
}
}
public static boolean match(Class[] a, Class[] b) {
if (a.length == b.length) {
for (int i = 0; i < a.length; ++i) {
if (! match(toVMClass(a[i]), toVMClass(b[i]))) {
return false;
}
}
return true;
} else {
return false;
}
}
public static VMMethod findMethod(ClassLoader loader,
String class_,
String name,
String spec)
throws ClassNotFoundException
{
VMClass c = SystemClassLoader.vmClass(loader.loadClass(class_));
VMMethod[] methodTable = c.methodTable;
if (methodTable != null) {
link(c);
for (int i = 0; i < methodTable.length; ++i) {
VMMethod m = methodTable[i];
if (toString(m.name).equals(name) && toString(m.spec).equals(spec)) {
return m;
}
}
}
return null;
}
public static int findMethod(VMClass vmClass, String name,
Class[] parameterTypes)
{
VMMethod[] methodTable = vmClass.methodTable;
if (methodTable != null) {
link(vmClass);
if (parameterTypes == null) {
parameterTypes = new Class[0];
}
for (int i = 0; i < methodTable.length; ++i) {
VMMethod m = methodTable[i];
if (toString(m.name).equals(name)
&& match(parameterTypes, getParameterTypes(m)))
{
return i;
}
}
}
return -1;
}
public static int countMethods(VMClass vmClass, boolean publicOnly) {
int count = 0;
VMMethod[] methodTable = vmClass.methodTable;
if (methodTable != null) {
for (int i = 0, j = declaredMethodCount(vmClass); i < j; ++i) {
VMMethod m = methodTable[i];
if (((! publicOnly) || ((m.flags & Modifier.PUBLIC)) != 0)
&& (! toString(m.name).startsWith("<")))
{
++ count;
}
}
}
return count;
}
public static Method[] getMethods(VMClass vmClass, boolean publicOnly) {
Method[] array = new Method[countMethods(vmClass, publicOnly)];
VMMethod[] methodTable = vmClass.methodTable;
if (methodTable != null) {
link(vmClass);
int ai = 0;
for (int i = 0, j = declaredMethodCount(vmClass); i < j; ++i) {
VMMethod m = methodTable[i];
if (((! publicOnly) || ((m.flags & Modifier.PUBLIC) != 0))
&& ! toString(m.name).startsWith("<"))
{
array[ai++] = makeMethod(SystemClassLoader.getClass(vmClass), i);
}
}
}
return array;
}
public static int countFields(VMClass vmClass, boolean publicOnly) {
int count = 0;
if (vmClass.fieldTable != null) {
for (int i = 0; i < vmClass.fieldTable.length; ++i) {
if ((! publicOnly)
|| ((vmClass.fieldTable[i].flags & Modifier.PUBLIC))
!= 0)
{
++ count;
}
}
}
return count;
}
public static Field[] getFields(VMClass vmClass, boolean publicOnly) {
Field[] array = new Field[countFields(vmClass, publicOnly)];
if (vmClass.fieldTable != null) {
link(vmClass);
int ai = 0;
for (int i = 0; i < vmClass.fieldTable.length; ++i) {
if (((vmClass.fieldTable[i].flags & Modifier.PUBLIC) != 0)
|| (! publicOnly))
{
array[ai++] = makeField(SystemClassLoader.getClass(vmClass), i);
}
}
}
return array;
}
public static Annotation getAnnotation(ClassLoader loader, Object[] a) {
if (a[0] == null) {
a[0] = Proxy.newProxyInstance
(loader, new Class[] { (Class) a[1] },
new AnnotationInvocationHandler(a));
}
return (Annotation) a[0];
}
public static Object getAnnotationDefaultValue(ClassLoader loader,
MethodAddendum addendum) {
if (addendum == null) {
return null;
}
byte[] annotationDefault = (byte[]) addendum.annotationDefault;
if (annotationDefault == null) {
return null;
}
try {
return parseAnnotationValue(loader, addendum.pool,
new ByteArrayInputStream(annotationDefault));
} catch (IOException e) {
AssertionError error = new AssertionError();
error.initCause(e);
throw error;
}
}
private static int index(VMMethod m) {
VMMethod[] table = m.class_.methodTable;
for (int i = 0; i < table.length; ++i) {
if (m == table[i]) return i;
}
throw new AssertionError();
}
public static Method makeMethod(VMMethod m) {
return makeMethod(SystemClassLoader.getClass(m.class_), index(m));
}
public static ProtectionDomain getProtectionDomain(VMClass c) {
CodeSource source = null;
if (c.source != null) {
try {
source = new CodeSource
(new URL(new String(c.source, 0, c.source.length - 1)),
(Certificate[]) null);
} catch (MalformedURLException ignored) { }
}
Permissions p = new Permissions();
p.add(new AllPermission());
return new ProtectionDomain(source, p);
}
public static native Method makeMethod(Class c, int slot);
public static native Field makeField(Class c, int slot);
private static native void acquireClassLock();
private static native void releaseClassLock();
public static native String makeString(byte[] array, int offset, int length);
}

View File

@ -0,0 +1,5 @@
package avian;
abstract class Code {
// VM-visible fields in types.def
}

View File

@ -0,0 +1,242 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
import static avian.Stream.write1;
import static avian.Stream.write2;
import static avian.Stream.write4;
import java.util.List;
import java.io.OutputStream;
import java.io.IOException;
public class ConstantPool {
private static final int CONSTANT_Integer = 3;
private static final int CONSTANT_Utf8 = 1;
private static final int CONSTANT_String = 8;
private static final int CONSTANT_Class = 7;
private static final int CONSTANT_NameAndType = 12;
private static final int CONSTANT_Fieldref = 9;
private static final int CONSTANT_Methodref = 10;
public static int add(List<PoolEntry> pool, PoolEntry e) {
int i = 0;
for (PoolEntry existing: pool) {
if (existing.equals(e)) {
return i;
} else {
++i;
}
}
pool.add(e);
return pool.size() - 1;
}
public static int addInteger(List<PoolEntry> pool, int value) {
return add(pool, new IntegerPoolEntry(value));
}
public static int addUtf8(List<PoolEntry> pool, String value) {
return add(pool, new Utf8PoolEntry(value));
}
public static int addString(List<PoolEntry> pool, String value) {
return add(pool, new StringPoolEntry(addUtf8(pool, value)));
}
public static int addClass(List<PoolEntry> pool, String name) {
return add(pool, new ClassPoolEntry(addUtf8(pool, name)));
}
public static int addNameAndType(List<PoolEntry> pool,
String name,
String type)
{
return add(pool, new NameAndTypePoolEntry
(addUtf8(pool, name),
addUtf8(pool, type)));
}
public static int addFieldRef(List<PoolEntry> pool,
String className,
String name,
String spec)
{
return add(pool, new FieldRefPoolEntry
(addClass(pool, className),
addNameAndType(pool, name, spec)));
}
public static int addMethodRef(List<PoolEntry> pool,
String className,
String name,
String spec)
{
return add(pool, new MethodRefPoolEntry
(addClass(pool, className),
addNameAndType(pool, name, spec)));
}
public interface PoolEntry {
public void writeTo(OutputStream out) throws IOException;
}
private static class IntegerPoolEntry implements PoolEntry {
private final int value;
public IntegerPoolEntry(int value) {
this.value = value;
}
public void writeTo(OutputStream out) throws IOException {
write1(out, CONSTANT_Integer);
write4(out, value);
}
public boolean equals(Object o) {
return o instanceof IntegerPoolEntry
&& ((IntegerPoolEntry) o).value == value;
}
}
private static class Utf8PoolEntry implements PoolEntry {
private final String data;
public Utf8PoolEntry(String data) {
this.data = data;
}
public void writeTo(OutputStream out) throws IOException {
write1(out, CONSTANT_Utf8);
byte[] bytes = data.getBytes();
write2(out, bytes.length);
out.write(bytes);
}
public boolean equals(Object o) {
return o instanceof Utf8PoolEntry
&& ((Utf8PoolEntry) o).data.equals(data);
}
}
private static class StringPoolEntry implements PoolEntry {
private final int valueIndex;
public StringPoolEntry(int valueIndex) {
this.valueIndex = valueIndex;
}
public void writeTo(OutputStream out) throws IOException {
write1(out, CONSTANT_String);
write2(out, valueIndex + 1);
}
public boolean equals(Object o) {
return o instanceof StringPoolEntry
&& ((StringPoolEntry) o).valueIndex == valueIndex;
}
}
private static class ClassPoolEntry implements PoolEntry {
private final int nameIndex;
public ClassPoolEntry(int nameIndex) {
this.nameIndex = nameIndex;
}
public void writeTo(OutputStream out) throws IOException {
write1(out, CONSTANT_Class);
write2(out, nameIndex + 1);
}
public boolean equals(Object o) {
return o instanceof ClassPoolEntry
&& ((ClassPoolEntry) o).nameIndex == nameIndex;
}
}
private static class NameAndTypePoolEntry implements PoolEntry {
private final int nameIndex;
private final int typeIndex;
public NameAndTypePoolEntry(int nameIndex, int typeIndex) {
this.nameIndex = nameIndex;
this.typeIndex = typeIndex;
}
public void writeTo(OutputStream out) throws IOException {
write1(out, CONSTANT_NameAndType);
write2(out, nameIndex + 1);
write2(out, typeIndex + 1);
}
public boolean equals(Object o) {
if (o instanceof NameAndTypePoolEntry) {
NameAndTypePoolEntry other = (NameAndTypePoolEntry) o;
return other.nameIndex == nameIndex && other.typeIndex == typeIndex;
} else {
return false;
}
}
}
private static class FieldRefPoolEntry implements PoolEntry {
private final int classIndex;
private final int nameAndTypeIndex;
public FieldRefPoolEntry(int classIndex, int nameAndTypeIndex) {
this.classIndex = classIndex;
this.nameAndTypeIndex = nameAndTypeIndex;
}
public void writeTo(OutputStream out) throws IOException {
write1(out, CONSTANT_Fieldref);
write2(out, classIndex + 1);
write2(out, nameAndTypeIndex + 1);
}
public boolean equals(Object o) {
if (o instanceof FieldRefPoolEntry) {
FieldRefPoolEntry other = (FieldRefPoolEntry) o;
return other.classIndex == classIndex
&& other.nameAndTypeIndex == nameAndTypeIndex;
} else {
return false;
}
}
}
private static class MethodRefPoolEntry implements PoolEntry {
private final int classIndex;
private final int nameAndTypeIndex;
public MethodRefPoolEntry(int classIndex, int nameAndTypeIndex) {
this.classIndex = classIndex;
this.nameAndTypeIndex = nameAndTypeIndex;
}
public void writeTo(OutputStream out) throws IOException {
write1(out, CONSTANT_Methodref);
write2(out, classIndex + 1);
write2(out, nameAndTypeIndex + 1);
}
public boolean equals(Object o) {
if (o instanceof MethodRefPoolEntry) {
MethodRefPoolEntry other = (MethodRefPoolEntry) o;
return other.classIndex == classIndex
&& other.nameAndTypeIndex == nameAndTypeIndex;
} else {
return false;
}
}
}
}

View File

@ -0,0 +1,327 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
import java.util.concurrent.Callable;
/**
* This class provides methods to capture continuations and manage
* control flow when calling continuations.
*
* <p>A continuation is a snapshot of a thread's call stack which can
* be captured via <code>callWithCurrentContinuation</code> and later
* restored any number of times. The program may restore this
* snapshot by either feeding it a result (to be returned by
* <code>callWithCurrentContinuation</code>) or feeding it an
* exception (to be thrown by
* <code>callWithCurrentContinuation</code>). Continuations may be
* used to implement features such as coroutines, generators, and
* cooperative multitasking.
*
* <p>This class provides two static methods,
* <code>callWithCurrentContinuation</code> and
* <code>dynamicWind</code>, with similar semantics to the Scheme
* functions <code>call-with-current-continuation</code> and
* <code>dynamic-wind</code>, respectively. In addition, we define
* how continuations work with respect to native code, exceptions,
* try/finally blocks, synchronized blocks, and multithreading.
*
* <h3>Continuations and Continuation Contexts</h3>
*
* <p>A continuation can be thought of as a singly-linked list of
* stack frames representing the call trace, where the head of the
* list is the frame of the method most recently called (i.e. the top
* of the stack). However, this trace only extends as far as the most
* recent chain of Java frames - it ends just prior to the most recent
* native frame in the stack. The reason for this is that the VM
* cannot, in general, safely capture and restore native frames.
* Therefore, each call from native code to Java (including the
* original invocation of <code>main(String[])</code> or
* <code>Thread.run()</code>) represents a new continuation context in
* which continuations may be captured, and these will only contain
* frames from within that context.
*
* <p>Calling a continuation (i.e. feeding it a result or exception)
* causes the current continuation to be replaced with the called
* continuation. When the last method in this new continuation
* returns, it returns to the native frame which created the current
* context, which may or may not be the same as the context in which
* that continuation was created.
*
* <p>We define the return type of a continuation context as the
* return type of the first method called in that context. A
* continuation may be called from a different context than the one in
* which it was created, provided the return type of the latter is
* compatible with the current context.
*
* <p>Given a thread executing in context "A" which wants to call a
* continuation created in context "B", the following rules apply:
*
* <ul>
*
* <li>If the return type of "A" is <code>void</code>, the return
* type of "B" may be anything, including <code>void</code></li>
*
* <li>If the return type of "A" is a primitive type, the return
* type of "B" must match exactly</li>
*
* <li>If the return type of "A" is an object type, that type must
* be assignable from the return type of "B" (i.e. the latter must
* either be the same as the former or a superclass or
* superinterface of it)</li>
*
* </ul>
*
* <p>A thread may call a continuation created by a different thread
* provided the return types are compatible. Multiple threads may
* safely call the same continuation simultaneously without
* synchronization. Any attempt to call a continuation from a context
* with an incompatible return type will throw an {@link
* avian.IncompatibleContinuationException}.
*
* <h3>Winding, Unwinding, and Rewinding</h3>
*
* <p>Traditionally, Java provides one way to wind the execution stack
* (method calls) and two ways to unwind it (normal returns and
* exception unwinding). With continuations, we add a new way to
* rewind the stack and a new way to unwind it.
*
* <p>The call stack of a continuation may share frames with other
* continuations - in which case they share a common history. When
* calling a continuation "B" from the current continuation "A", the
* VM must unwind past any frames which are in "A" but not in "B" and
* rewind past any frames in "B" but not in "A". During this
* unwinding and rewinding, control may pass through synchronized and
* try/finally blocks while going down the old stack and up the new
* stack.
*
* <p>However, unlike the traditional processes of winding and
* unwinding, the VM will ignore these blocks - monitors will not be
* released or acquired and finally blocks will not execute. This is
* by design. The purpose of such a block is to acquire a resource,
* such as a file handle or monitor, once before executing a task and
* release it after the task is finished, regardless of how often the
* task might temporarily yield control to other continuations.
*
* <p>Alternatively, one might wish to acquire and release a resource
* each time control (re)winds to or unwinds from a continuation,
* respectively. In this case, one may use <code>dynamicWind</code>
* to register functions which will run every time that frame is
* passed, regardless of how the stack is wound or unwound.
*/
public class Continuations {
private Continuations() { }
private static final ThreadLocal<Reset> latestReset = new ThreadLocal();
/**
* Captures the current continuation, passing a reference to the
* specified receiver.
*
* <p>This method will either return the result returned by
* <code>receiver.call(Callback)</code>, propagate the exception
* thrown by that method, return the result passed to the
* handleResult(T) method of the continuation, or throw the
* exception passed to the handleException(Throwable) method of the
* continuation.
*/
public static native <T> T callWithCurrentContinuation
(Function<Callback<T>,T> receiver) throws Exception;
/**
* Calls the specified "before" and "after" tasks each time a
* continuation containing the call is wound or unwound,
* respectively.
*
* <p>This method first calls <code>before.run()</code>, then
* <code>thunk.call()</code>, and finally <code>after.run()</code>,
* returning the result of the second call. If
* <code>before.run()</code> does not return normally, the second
* and third calls will not happen. If <code>thunk.call()</code>
* throws an exception, <code>after.run()</code>, will be called
* before the exception is propagated.
*
* <p>If <code>thunk.call()</code> calls a continuation (directly or
* via a subroutine) which does not include the current call to
* <code>dynamicWind</code>, <code>after.run()</code> will be called
* before control passes to that continuation. If this call throws
* an exception, the exception will propagate to the current caller
* of <code>dynamicWind</code>.
*
* <p>If <code>thunk.call()</code> creates a continuation which is
* later called from a continuation which does not include the
* current call to <code>dynamicWind</code>,
* <code>before.run()</code> will be called before control passes to
* that continuation. As above, if this call throws an exception,
* the exception will propagate to the current caller of
* <code>dynamicWind</code>.
*/
public static <T> T dynamicWind(Runnable before,
Callable<T> thunk,
Runnable after)
throws Exception
{
UnwindResult result = dynamicWind2(before, thunk, after);
if (result.continuation != null) {
after.run();
if (result.exception != null) {
result.continuation.handleException(result.exception);
} else {
result.continuation.handleResult(result.result);
}
throw new AssertionError();
} else {
return (T) result.result;
}
}
public static <B,C> C reset(final Callable<B> thunk) throws Exception {
final Reset reset = new Reset(latestReset.get());
latestReset.set(reset);
try {
Object result = callWithCurrentContinuation
(new Function<Callback<Object>,Object>() {
public Object call(Callback continuation) throws Exception {
reset.continuation = continuation;
return thunk.call();
}
});
while (true) {
Cell<Function> shift = reset.shifts;
if (shift != null) {
reset.shifts = shift.next;
result = shift.value.call(result);
} else {
return (C) result;
}
}
} finally {
latestReset.set(reset.next);
}
}
public static <A,B,C> A shift
(final Function<Function<A,B>,C> receiver)
throws Exception
{
return (A) callWithCurrentContinuation
(new Function<Callback<Object>,Object>() {
public Object call(final Callback continuation) {
final Reset reset = latestReset.get();
reset.shifts = new Cell(new Function() {
public Object call(Object ignored) throws Exception {
return receiver.call
(new Function() {
public Object call(final Object argument)
throws Exception
{
return callWithCurrentContinuation
(new Function<Callback<Object>,Object>() {
public Object call
(final Callback shiftContinuation)
throws Exception
{
reset.shifts = new Cell
(new Function() {
public Object call(Object result)
throws Exception
{
shiftContinuation.handleResult(result);
throw new AssertionError();
}
},
reset.shifts);
continuation.handleResult(argument);
throw new AssertionError();
}
});
}
});
}
public void handleException(Throwable exception) {
throw new AssertionError();
}
}, reset.shifts);
reset.continuation.handleResult(null);
throw new AssertionError();
}
});
}
private static native UnwindResult dynamicWind2(Runnable before,
Callable thunk,
Runnable after)
throws Exception;
private static UnwindResult wind(Runnable before,
Callable thunk,
Runnable after)
throws Exception
{
before.run();
try {
return new UnwindResult(null, thunk.call(), null);
} finally {
after.run();
}
}
private static void rewind(Runnable before,
Callback continuation,
Object result,
Throwable exception)
throws Exception
{
before.run();
if (exception != null) {
continuation.handleException(exception);
} else {
continuation.handleResult(result);
}
throw new AssertionError();
}
private static class Continuation<T> implements Callback<T> {
public native void handleResult(T result);
public native void handleException(Throwable exception);
}
private static class UnwindResult {
public final Continuation continuation;
public final Object result;
public final Throwable exception;
public UnwindResult(Continuation continuation, Object result,
Throwable exception)
{
this.continuation = continuation;
this.result = result;
this.exception = exception;
}
}
private static class Reset {
public Callback continuation;
public final Reset next;
public Cell<Function> shifts;
public Reset(Reset next) {
this.next = next;
}
}
}

View File

@ -0,0 +1,310 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
import java.util.Map;
import java.util.Map.Entry;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Iterator;
import java.util.Collections;
public class Data {
public static int nextPowerOfTwo(int n) {
int r = 1;
while (r < n) r <<= 1;
return r;
}
public static <V> boolean equal(V a, V b) {
return a == null ? b == null : a.equals(b);
}
public static <T> T[] toArray(Collection collection, T[] array) {
Class c = array.getClass().getComponentType();
if (array.length < collection.size()) {
array = (T[]) java.lang.reflect.Array.newInstance(c, collection.size());
}
int i = 0;
for (Object o: collection) {
if (c.isInstance(o)) {
array[i++] = (T) o;
} else {
throw new ArrayStoreException();
}
}
return array;
}
public static String toString(Collection c) {
StringBuilder sb = new StringBuilder();
sb.append("[");
for (Iterator it = c.iterator(); it.hasNext();) {
sb.append(it.next());
if (it.hasNext()) {
sb.append(",");
}
}
sb.append("]");
return sb.toString();
}
public static String toString(Map m) {
StringBuilder sb = new StringBuilder();
sb.append("{");
for (Iterator<Entry> it = m.entrySet().iterator(); it.hasNext();) {
Entry e = it.next();
sb.append(e.getKey())
.append("=")
.append(e.getValue());
if (it.hasNext()) {
sb.append(",");
}
}
sb.append("}");
return sb.toString();
}
public interface EntryMap<K,V> {
public int size();
public Entry<K,V> find(Object key);
public Entry<K,V> remove(Object key);
public void clear();
public Iterator<Entry<K,V>> iterator();
}
public static class EntrySet<K, V> extends AbstractSet<Entry<K, V>> {
private final EntryMap<K, V> map;
public EntrySet(EntryMap<K, V> map) {
this.map = map;
}
public int size() {
return map.size();
}
public boolean isEmpty() {
return map.size() == 0;
}
public boolean contains(Object o) {
return (o instanceof Entry<?,?>)
&& map.find(((Entry<?,?>)o).getKey()) != null;
}
public boolean add(Entry<K, V> e) {
throw new UnsupportedOperationException();
}
public boolean remove(Object o) {
return (o instanceof Entry<?,?>)
&& map.remove(((Entry<?,?>) o).getKey()) != null;
}
public boolean remove(Entry<K, V> e) {
return map.remove(e.getKey()) != null;
}
public Object[] toArray() {
return toArray(new Object[size()]);
}
public <T> T[] toArray(T[] array) {
return Data.toArray(this, array);
}
public void clear() {
map.clear();
}
public Iterator<Entry<K, V>> iterator() {
return map.iterator();
}
}
public static class KeySet<K> extends AbstractSet<K> {
private final EntryMap<K, ?> map;
public KeySet(EntryMap<K, ?> map) {
this.map = map;
}
public int size() {
return map.size();
}
public boolean isEmpty() {
return map.size() == 0;
}
public boolean contains(Object key) {
return map.find(key) != null;
}
public boolean add(K key) {
throw new UnsupportedOperationException();
}
public boolean remove(Object key) {
return map.remove(key) != null;
}
public Object[] toArray() {
return toArray(new Object[size()]);
}
public <T> T[] toArray(T[] array) {
return Data.toArray(this, array);
}
public void clear() {
map.clear();
}
public Iterator<K> iterator() {
return new KeyIterator(map.iterator());
}
}
public static class Values<K, V> implements Collection<V> {
private final EntryMap<K, V> map;
public Values(EntryMap<K, V> map) {
this.map = map;
}
public int size() {
return map.size();
}
public boolean isEmpty() {
return map.size() == 0;
}
public boolean contains(Object value) {
for (Iterator<Entry<K, V>> it = map.iterator(); it.hasNext();) {
if (equal(it.next().getValue(), value)) {
return true;
}
}
return false;
}
public boolean containsAll(Collection<?> c) {
if (c == null) {
throw new NullPointerException("collection is null");
}
for (Iterator<?> it = c.iterator(); it.hasNext();) {
if (! contains(it.next())) {
return false;
}
}
return true;
}
public boolean add(V value) {
throw new UnsupportedOperationException();
}
public boolean addAll(Collection<? extends V> collection) {
throw new UnsupportedOperationException();
}
public boolean remove(Object value) {
for (Iterator<Entry<K, V>> it = map.iterator();
it.hasNext();)
{
if (equal(it.next().getValue(), value)) {
it.remove();
return true;
}
}
return false;
}
public boolean removeAll(Collection<?> c) {
boolean changed = false;
for (Iterator<Entry<K, V>> it = map.iterator(); it.hasNext();) {
if (c.contains(it.next().getValue())) {
it.remove();
changed = true;
}
}
return changed;
}
public Object[] toArray() {
return toArray(new Object[size()]);
}
public <T> T[] toArray(T[] array) {
return Data.toArray(this, array);
}
public void clear() {
map.clear();
}
public Iterator<V> iterator() {
return new ValueIterator(map.iterator());
}
}
public static class KeyIterator<K, V> implements Iterator<K> {
private final Iterator<Entry<K, V>> it;
public KeyIterator(Iterator<Entry<K, V>> it) {
this.it = it;
}
public K next() {
return it.next().getKey();
}
public boolean hasNext() {
return it.hasNext();
}
public void remove() {
it.remove();
}
}
public static class ValueIterator<K, V> implements Iterator<V> {
private final Iterator<Entry<K, V>> it;
public ValueIterator(Iterator<Entry<K, V>> it) {
this.it = it;
}
public V next() {
return it.next().getValue();
}
public boolean hasNext() {
return it.hasNext();
}
public void remove() {
it.remove();
}
}
}

View File

@ -0,0 +1,13 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
public class FieldAddendum extends Addendum { }

View File

@ -0,0 +1,992 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
import java.io.IOException;
import java.util.ArrayList;
import java.util.IllegalFormatException;
import java.util.List;
// ------------------------------------------------------------------------- //
// things that must be done in order to call this semi-complete:
// ------------------------------------------------------------------------- //
// * get the date formatter working for individual fields at a minimum
// ------------------------------------------------------------------------- //
/**
* A Java flavored printf for classpath-challenged JVMs.
*
* Each instance of this class is a threadsafe pre-parsed format pattern. Refer
* to the very detailed class description of java.util.Formatter in the OpenJDK
* API documentation for an explanation of the supported formats.
*
* Should be easily portable to other Java runtimes that do not include the
* printf functionality that was introduced in Java 5.
*
* Aims to be lightweight and reasonably fast, and provide reasonably complete
* API compatibility with the OpenJDK implementation. To clarify what
* "reasonably complete" means in this context, this implementation should
* accept any valid format string that the OpenJDK version accepts. However,
* it should not be relied upon to throw an Exception for every format pattern
* that the OpenJDK implementation does.
*
* If your program's behavior relies on the side effects from an Exception
* being thrown for an invalid format string, this might not be for you.
*
* Perhaps more troubling is the fact that the correct localization of numbers
* and temporal values is barely even attempted, even though the parser accepts
* the flags without even a warning. However, now you have been warned.
*
* @author bcg
*/
public final class FormatString {
/** Parses a format string and returns a compiled representation of it. */
public static final FormatString compile(String fmt) {
return new FormatString(fmt);
}
/** The original string value that was parsed */
public String source() {
return _source;
}
/** Processes the supplied arguments through the compiled format string
and returns the result as a String. */
public final String format(Object... args) {
final StringBuilder bldr = new StringBuilder();
try {
format(bldr, args);
return bldr.toString();
} catch (IOException e) {
throw new IllegalStateException(
"Should not get IOException when writing to StringBuilder", e
);
}
}
/** Processes the supplied arguments through the compiled format string
and writes the result of each component directly to an Appendable */
public final void format(final Appendable a, Object... fmt_args)
throws IOException {
final Object[] args = fmt_args != null ? fmt_args : new Object[0];
int cntr = 0;
for (final FmtCmpnt cmp : _components) {
if (cmp._conversion == CONV_LITRL) {
a.append(cmp._source);
continue;
}
final Object arg;
if (!acceptsArgument(cmp._conversion)) {
arg = null;
} else {
final int index = cmp._argument_index;
switch (index) {
case AIDX_NONE:
if ((cntr) >= args.length) {
throw new IllegalFormatException(
"Format specified at least " + (cntr+1) +
" arguments, but " + cntr + " were supplied."
);
}
arg = args[cntr++];
break;
case AIDX_PREV:
arg = args[cntr];
break;
default:
if (index < 1) {
throw new IllegalArgumentException();
} else if (index > args.length) {
throw new IllegalArgumentException();
} else {
arg = args[index - 1];
}
}
}
convert(a, arg, cmp._conversion, cmp._flags, cmp._width, cmp._precision);
}
}
//- conversions
static final byte CONV_LITRL = 0x0;
static final byte CONV_NLINE = 0x1;
static final byte CONV_PRCNT = 0x2;
static final byte CONV_BOOLN = 0x3;
static final byte CONV_DTIME = 0x4;
static final byte CONV_STRNG = 0x5;
static final byte CONV_HCODE = 0x6;
static final byte CONV_CHRCT = 0x7;
static final byte CONV_DECML = 0x8;
static final byte CONV_OCTAL = 0x9;
static final byte CONV_HXDEC = 0xA;
static final byte CONV_CPSCI = 0xB;
static final byte CONV_GNSCI = 0xC;
static final byte CONV_FLOAT = 0xD;
static final byte CONV_HXEXP = 0xE;
//- format component flags
static final byte FLAG_FORCE_UPPER_CASE = (byte)(1<<7);
static final byte FLAG_NEGATIVES_IN_PARENS = (byte)(1<<6); // ('(')
static final byte FLAG_GROUPING_SEPARATORS = (byte)(1<<5); // (',')
static final byte FLAG_LEADING_ZERO_PADDED = (byte)(1<<4); // ('0')
static final byte FLAG_LEADING_SPACE_PADDED = (byte)(1<<3); // (' ')
static final byte FLAG_ALWAYS_INCLUDES_SIGN = (byte)(1<<2); // ('+')
static final byte FLAG_ALTERNATE_FORM = (byte)(1<<1); // ('#')
static final byte FLAG_LEFT_JUSTIFIED = (byte)(1<<0); // ('-')
//- conversion capability flags
static final byte CFLG_WDTH_SUPPRT = CONV_PRCNT;
static final byte CFLG_ACCEPTS_ARG = CONV_BOOLN;
static final byte CFLG_NUMERIC_VAL = CONV_DECML;
static final byte CFLG_PREC_SUPPRT = CONV_STRNG;
//- special argument indices
static final int AIDX_PREV = -1;
static final int AIDX_NONE = 0;
/** the original serialized format string */
private final String _source;
/** array of components parsed from the source string */
private final FmtCmpnt[] _components;
/*/ keeping this private for now to encourage access through the static
compile method, which might allow caching format string instances if it
turns out there is an advantage to that. /*/
/** Constructor */
private FormatString(final String fmt) {
this._source = fmt;
final List<FmtCmpnt> cmps = new ArrayList<FmtCmpnt>();
for ( int i = 0; (i = next(fmt, cmps, i)) > -1; );
this._components = cmps.toArray(new FmtCmpnt[cmps.size()]);
}
/** Iterates over the tokens in an input string to extract the components */
private static final int next(
final String fmt, final List<FmtCmpnt> cmps, final int startIndex) {
final int strln = fmt.length();
if (startIndex >= strln) {
return -1;
}
final char c = fmt.charAt(startIndex);
if (c == '%') {
// this is the start of a specifier
final FmtSpecBldr bldr = new FmtSpecBldr();
for (int i = startIndex + 1; i < strln; i++) {
final char ch = fmt.charAt(i);
final FmtCmpnt cmp = bldr.append(ch);
if (cmp != null) {
cmps.add(cmp);
return (i+1);
}
}
throw new IllegalFormatException("Incomplete specifier at end of fmt");
} else {
// this is the start of a literal
final StringBuilder literal = new StringBuilder();
literal.append(c);
for (int i = startIndex + 1; i < strln; i++) {
final char ch = fmt.charAt(i);
// write the current buffer if the next character starts a specifier
if (ch == '%') {
final FmtCmpnt cmp = new FmtCmpnt(literal.toString());
cmps.add(cmp);
return i;
}
literal.append(ch);
}
// write the current buffer if the end of the format has been reached
final FmtCmpnt cmp = new FmtCmpnt(literal.toString());
cmps.add(cmp);
return -1;
}
}
/** Checks a flag byte to see if a given flag is set. Only FLAG_* constants
from the enclosing class should be passed in for toCheck... otherwise the
behavior is undefined. */
static final boolean checkFlag(final byte flags, final byte toCheck) {
return (flags & toCheck) != 0;
}
/** Checks if a given conversion accepts(requires) an argument. Only the CONV_
flags from the enclosing class should be passed in, otherwise the result
of this method is undefined as should not be used. */
static final boolean acceptsArgument(final byte conversion) {
return conversion >= CFLG_ACCEPTS_ARG;
}
/** Checks if a given conversion allows specifying a precision. Only the CONV_
flags from the enclosing class should be passed in, otherwise the result
of this method is undefined as should not be used. */
static final boolean precisionSupported(final byte conversion) {
return conversion >= CFLG_PREC_SUPPRT;
}
/** Checks if a given conversion allows specifying a width. Only the CONV_
flags from the enclosing class should be passed in, otherwise the result
of this method is undefined and should not be trusted. */
static final boolean widthSupported(final byte conversion) {
return conversion >= CFLG_WDTH_SUPPRT;
}
/** Checks if a given conversion expects a numeric value. Only the CONV_
flags from the enclosing class should be passed in, otherwise the result
of this method is undefined and should not be trusted. */
static final boolean isNumeric(final byte conversion) {
return conversion >= CFLG_NUMERIC_VAL;
}
/** The newline character for the current platform. */
static final String NEWLINE = System.getProperty("line.separator");
/** Performs conversion on the supplied argument */
static final void convert(
final Appendable appendable,
final Object arg,
final byte conversion,
final byte flags,
final int width,
final int precision) throws IOException {
int radix = 0;
switch (conversion) {
case CONV_LITRL:
throw new IllegalArgumentException("cannot convert a literal");
case CONV_NLINE:
appendable.append(NEWLINE);
return;
case CONV_PRCNT:
convertPercent(appendable, arg, flags, width, precision);
return;
case CONV_BOOLN:
convertBoolean(appendable, arg, flags, width, precision);
return;
case CONV_DTIME:
convertDate(appendable, arg, flags, width, precision);
return;
case CONV_STRNG:
convertString(appendable, arg, flags, width, precision);
return;
case CONV_HCODE:
convertHashcode(appendable, arg, flags, width, precision);
return;
case CONV_CHRCT:
convertChar(appendable, arg, flags, width, precision);
return;
case CONV_DECML: if (radix == 0) { radix = 10; };
case CONV_OCTAL: if (radix == 0) { radix = 8; };
case CONV_HXDEC: if (radix == 0) { radix = 16; };
if (arg instanceof Long) {
convertLong(appendable, (Long) arg, flags, width, precision, radix);
} else {
convertInteger(appendable, arg, flags, width, precision, radix);
}
return;
case CONV_CPSCI:
case CONV_GNSCI:
case CONV_FLOAT:
case CONV_HXEXP:
convertFloat(appendable, arg, flags, width, precision, 10);
return;
}
throw new IllegalStateException("not implemented: " + conversion);
}
static void convertPercent(
final Appendable a,
final Object arg,
final byte flags,
final int width,
final int precision) throws IOException {
final String val = "%";
appendify(a, val, flags, width, precision);
}
static void convertDate(
final Appendable a,
final Object arg,
final byte flags,
final int width,
final int precision) throws IOException {
final String val = (arg == null) ? "null" : arg.toString();
appendify(a, val, flags, width, precision);
}
static void convertString(
final Appendable a,
final Object arg,
final byte flags,
final int width,
final int precision) throws IOException {
final String val = (arg == null) ? "null" : arg.toString();
appendify(a, val, flags, width, precision);
}
static void convertHashcode(
final Appendable a,
final Object arg,
final byte flags,
final int width,
final int precision) throws IOException {
final String val = (arg == null)
? "null"
: Integer.toHexString(arg.hashCode());
appendify(a, val, flags, width, precision);
}
static void convertBoolean(
final Appendable a,
final Object arg,
final byte flags,
final int width,
final int precision) throws IOException {
final String val;
if (arg == null) {
val = "false";
} else if (arg instanceof Boolean) {
val = String.valueOf(arg);
} else {
val = "true";
}
appendify(a, val, flags, width, precision);
}
static void convertChar(
final Appendable a,
final Object arg,
final byte flags,
final int width,
final int precision) throws IOException {
final String val;
if (arg instanceof Character) {
val = ((Character) arg).toString();
} else if ( arg instanceof Byte ||
arg instanceof Short ||
arg instanceof Integer ){
final int codePoint = ((Number) arg).intValue();
if (codePoint >= 0 && codePoint <= 0x10FFFF) { //<-- isValidCodePoint()?
val = new String(Character.toChars(codePoint));
} else {
throw new IllegalFormatException("Invalid code point: " + arg);
}
} else {
throw new IllegalFormatException("Cannot do char conversion: " + arg);
}
appendify(a, val, flags, width, precision);
}
// FIXME: this is broken for octal formats with negative values
static void convertLong(
final Appendable a,
final Long arg,
final byte flags,
final int width,
final int precision,
final int radix) throws IOException {
final String val;
final Long n = arg;
final long longValue = n.longValue();
if (radix == 10 || longValue > -1) {
val = Long.toString(longValue, radix);
} else {
final long upper = 0xFFFFFFFFL&(longValue>>31);
final long lower = 0xFFFFFFFFL&(longValue);
val = Long.toString(upper, radix) + Long.toString(lower, radix);
}
appendify(a, val, flags, width, precision);
}
static void convertInteger(
final Appendable a,
final Object arg,
final byte flags,
final int width,
final int precision,
final int radix) throws IOException {
final String val;
final Number n = (Number) arg;
final long longValue = n.longValue();
final long modifier;
if (arg instanceof Integer) modifier = 0xFFFFFFFFL+1; else
if (arg instanceof Short) modifier = 0xFFFFL+1; else
if (arg instanceof Byte) modifier = 0xFFL+1;
else throw new IllegalFormatException(
"not an integer number: " + (arg != null ? arg.getClass() : null)
);
if (radix != 10 && longValue < 0) {
val = Long.toString(longValue + modifier, radix);
} else {
val = Long.toString(longValue, radix);
}
appendify(a, val, flags, width, precision);
}
// FIXME: I'm lazy, so hexidecimal exponential isn't implemented, sorry - bcg
static void convertFloat(
final Appendable a,
final Object arg,
final byte flags,
final int width,
final int precision,
final int radix) throws IOException {
final String val;
final Number n = (Number) arg;
if (arg instanceof Float) {
val = Float.toString(n.floatValue());
} else if (arg instanceof Double) {
val = Double.toString(n.doubleValue());
} else {
throw new IllegalFormatException(
"not a floating point number: " + (arg != null ? arg.getClass() : null)
);
}
appendify(a, val, flags, width, precision);
}
static void appendify(
final Appendable a,
final String val,
final byte flags,
final int width,
final int precision) throws IOException {
String result = val;
if (checkFlag(flags, FLAG_FORCE_UPPER_CASE)) {
result = result.toUpperCase();
}
// TODO: implement other flags
// (+) always include sign
// (,) grouping separators
// (() negatives in parentheses
if (precision > 0) {
// FIXME: this behavior should be different for floating point numbers
final int difference = result.length() - precision;
if (difference > 0) {
result = result.substring(0, precision);
a.append(result);
return;
}
}
if (width > 0) {
final int difference = width - result.length();
final boolean leftJustified = checkFlag(flags, FLAG_LEFT_JUSTIFIED);
if (!leftJustified && difference > 0) {
char fill = checkFlag(flags, FLAG_LEADING_ZERO_PADDED) ? '0' : ' ';
fill(a, difference, fill);
}
a.append(result);
if (leftJustified && difference > 0) {
fill(a, difference, ' ');
}
return;
}
a.append(result);
}
private static void fill(Appendable a, int num, char c) throws IOException {
while (num > 0) {
a.append(c);
num--;
}
}
/** Represents a single chunk of the format string, either a literal or one of
the specifiers documented in OpenJDK's javadoc for java.util.Formatter.
This struct is immutable so can be safely shared across threads. */
private static final class FmtCmpnt {
private final String _source;
private final byte _conversion;
private final int _argument_index;
private final int _width;
private final int _precision;
private final byte _flags;
private FmtCmpnt(final String literal) {
this(literal, CONV_LITRL, 0, 0, 0, (byte)0);
}
private FmtCmpnt(
final String src,
final byte conversion,
final int argumentIndex,
final int width,
final int precision,
final byte flags) {
this._source = src;
this._conversion = conversion;
this._argument_index = argumentIndex;
this._width = width;
this._precision = precision;
this._flags = flags;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("{ ")
.append("source = '").append(_source).append("', ")
.append("conversion = ").append(_conversion).append(", ")
.append("flags = ").append(Byte.toString(_flags, 2)).append(", ")
.append("arg_index = ").append(_argument_index).append(", ")
.append("width = ").append(_width).append(", ")
.append("precision = ").append(_precision).append(", ")
.append("}");
return sb.toString();
}
}
/**
* Helper class for parsing a stream of characters into FmtCmpnt objects.
*/
private static final class FmtSpecBldr {
private StringBuilder _source;
private byte _conversion;
private int _argument_index;
private int _width;
private int _precision;
private byte _flags;
private FmtSpecBldr() {
this.init();
}
private final void init() {
_argument_index =
_width =
_precision =
_conversion =
_flags = 0;
_source = null;
}
private final FmtCmpnt build() {
final FmtCmpnt result = new FmtCmpnt(
_source.toString(),
_conversion,
_argument_index,
_width,
_precision,
_flags
);
init();
return result;
}
private final FmtCmpnt append(char c) {
if (_source == null) {
_source = new StringBuilder();
}
_source.append(c);
// FIXME: none of these date formats are implemented, because lazy
// if a datetime is specified, after the conversion character a time
// format specifier is expected. This is the only case where a character
// is allowed after the conversion character.
if (_conversion == CONV_DTIME) switch (c) {
// Hour of the day for the 24-hour clock, formatted as two digits with a
// leading zero as necessary i.e. 00 - 23.
case 'H':
// Hour for the 12-hour clock, formatted as two digits with a leading
// zero as necessary, i.e. 01 - 12.
case 'I':
// Hour of the day for the 24-hour clock, i.e. 0 - 23.
case 'k':
// Hour for the 12-hour clock, i.e. 1 - 12.
case 'l':
// Minute within the hour formatted as two digits with a leading zero
// as necessary, i.e. 00 - 59.
case 'M':
// Seconds within the minute, formatted as two digits with a leading
// zero as necessary, i.e. 00 - 60 ("60" is a special value required to
// support leap seconds).
case 'S':
// Millisecond within the second formatted as three digits with leading
// zeros as necessary, i.e. 000 - 999.
case 'L':
// Nanosecond within the second, formatted as nine digits with leading
// zeros as necessary, i.e. 000000000 - 999999999.
case 'N':
// Locale-specific morning or afternoon marker in lower case,
// e.g."am" or "pm". Use of the conversion prefix 'T' forces this
// output to upper case.
case 'p':
// RFC 822 style numeric time zone offset from GMT, e.g. -0800.
case 'z':
// A string representing the abbreviation for the time zone. The
// Formatter's locale will supersede the locale of the argument
// (if any).
case 'Z':
// Seconds since the beginning of the epoch
// starting at 1 January 1970 00:00:00 UTC,
// i.e. Long.MIN_VALUE/1000 to Long.MAX_VALUE/1000.
case 's':
// Milliseconds since the beginning of the epoch
// starting at 1 January 1970 00:00:00 UTC,
// i.e. Long.MIN_VALUE to Long.MAX_VALUE.
case 'Q':
// ------------------------------------------------------------------
// The following conversion characters are used for formatting dates:
// ------------------------------------------------------------------
// Locale-specific full month name, e.g. "January", "February".
case 'B':
// Locale-specific abbreviated month name, e.g. "Jan", "Feb".
case 'b':
// Same as 'b'.
case 'h':
// Locale-specific full name of the day of the week, e.g. "Sunday"
case 'A':
// Locale-specific short name of the day of the week, e.g. "Sun"
case 'a':
// Four-digit year divided by 100, formatted as two digits with leading
// zero as necessary, i.e. 00 - 99
case 'C':
// Year, formatted as at least four digits with leading zeros
// as necessary, e.g. 0092 equals 92 CE for the Gregorian calendar.
case 'Y':
// Last two digits of the year, formatted with leading zeros
// as necessary, i.e. 00 - 99.
case 'y':
// Day of year, formatted as three digits with leading zeros
// as necessary, e.g. 001 - 366 for the Gregorian calendar.
case 'j':
// Month, formatted as two digits with leading zeros as necessary,
// i.e. 01 - 13.
case 'm':
// Day of month, formatted as two digits with leading zeros as
// necessary, i.e. 01 - 31
case 'd':
// Day of month, formatted as two digits, i.e. 1 - 31.
case 'e':
// -------------------------------------------------------------------
// The following conversion characters are used for formatting common
// date/time compositions.
// -------------------------------------------------------------------
// Time formatted for the 24-hour clock as "%tH:%tM"
case 'R':
// Time formatted for the 24-hour clock as "%tH:%tM:%tS".
case 'T':
// Time formatted for the 12-hour clock as "%tI:%tM:%tS %Tp". The location
// of the morning or afternoon marker ('%Tp') may be locale-dependent.
case 'r':
// Date formatted as "%tm/%td/%ty".
case 'D':
// ISO 8601 complete date formatted as "%tY-%tm-%td".
case 'F':
// Date and time formatted as "%ta %tb %td %tT %tZ %tY", e.g.
// "Sun Jul 20 16:17:00 EDT 1969".
case 'c':
return seal(CONV_DTIME);
default:
throw new IllegalFormatException("Illegal date/time modifier: " + c);
}
// -- Flags and Switches -----------------------------------------------
// these are the possible characters for flags, width, etc. if the input
// is not one of these characters, it needs to be a valid conversion char.
// because the possible flags can vary based on the type of conversion,
// it is easiest to just buffer the flags, argument index, etc. until a
// conversion character has been reached. The seal() method will then
// work out if the specified flags are valid for the given conversion.
switch (c) {
case '$':
case '<':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '-':
case '+':
case '\'':
case ' ':
case '#':
case ',':
case '.':
case '(':
return null;
// -- End of Flags and Switches ----------------------------------------
// -- Conversion characters --------------------------------------------
// If this point is reached, then the current character must be a valid
// conversion character. If it is not, it should fall through the rest
// of the switch statement below and throw an IllegalFormatException
// string conversion
case 'S':
setFlagTrue(FLAG_FORCE_UPPER_CASE);
case 's':
return seal(CONV_STRNG);
// newline conversion
case 'n':
return seal(CONV_NLINE);
// percent conversion
case '%':
return seal(CONV_PRCNT);
// decimal numeric conversion
case 'd':
return seal(CONV_DECML);
// hexidecimal numeric conversion
case 'X':
setFlagTrue(FLAG_FORCE_UPPER_CASE);
case 'x':
return seal(CONV_HXDEC);
// datetime conversion
case 'T':
setFlagTrue(FLAG_FORCE_UPPER_CASE);
case 't':
_conversion = CONV_DTIME;
return null;
// boolean conversion
case 'B':
setFlagTrue(FLAG_FORCE_UPPER_CASE);
case 'b':
return seal(CONV_BOOLN);
// hashcode conversion
case 'H':
setFlagTrue(FLAG_FORCE_UPPER_CASE);
case 'h':
return seal(CONV_HCODE);
// character conversion
case 'C':
setFlagTrue(FLAG_FORCE_UPPER_CASE);
case 'c':
return seal(CONV_CHRCT);
// octal numeric conversion
case 'o':
return seal(CONV_OCTAL);
// computerized scientific conversion
case 'E':
setFlagTrue(FLAG_FORCE_UPPER_CASE);
case 'e':
return seal(CONV_CPSCI);
// floating point conversion
case 'f':
return seal(CONV_FLOAT);
// general scientific floating point conversion
case 'G':
setFlagTrue(FLAG_FORCE_UPPER_CASE);
case 'g':
return seal(CONV_GNSCI);
// hexidecimal exponential floating point conversion
case 'A':
setFlagTrue(FLAG_FORCE_UPPER_CASE);
case 'a':
return seal(CONV_HXEXP);
// -- End of Conversion characters --------------------------------------
default:
throw new IllegalFormatException(
"Invalid character encountered while parsing specifier: " + c);
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("{ ")
.append("source = '").append(_source).append("', ")
.append("conversion = ").append(_conversion).append(", ")
.append("flags = ").append(Byte.toString(_flags, 2)).append(", ")
.append("arg_index = ").append(_argument_index).append(", ")
.append("width = ").append(_width).append(", ")
.append("precision = ").append(_precision).append(", ")
.append("}");
return sb.toString();
}
private final FmtCmpnt seal(final byte conversion) {
// throwing IllegalStateException instead of IllegalFormatException
// because this should only occur if there is a bug in the append()
// method. In that case I'd prefer to fail fast even if the user is
// explicitly trying to catch IllegalFormatException.
if (conversion < 0 || conversion > 0xE) {
throw new IllegalArgumentException();
}
this._conversion = conversion;
// if the length is less than 2, it must mean that only the conversion
// character was specified. Since a conversion character by itself is a
// valid pattern, just build and return
if (_source.length() < 2) {
return build();
}
// ---------------------------------------------------------------------
// spec format: [argument_index$][flags][width][.precision]
// ---------------------------------------------------------------------
// the last character of the spec is the conversion character which has
// already been translated the appropriate byte by the append() method,
// so the last character gets chopped off before processing
final String spec = _source.substring(0, _source.length() - 1);
// if argument index is supported, it should be followed by a '$' and be
// comprised only of digit characters, or it should be a single '<' char
final int dollarIndex = spec.indexOf('$');
if (dollarIndex > -1) {
if (acceptsArgument(conversion)) {
if (spec.charAt(dollarIndex - 1) == '<') {
_argument_index = AIDX_PREV;
} else {
_argument_index = Integer.valueOf(spec.substring(0, dollarIndex));
}
} else {
throw new IllegalFormatException(
"Formats that do not accept arguments cannot specify an index."
);
}
}
if (dollarIndex == (spec.length() - 1)) {
return build();
}
// if precision is supported, look for the first period and assume that
// everything before is the width and everything after is the precision
final int dotIndex = spec.indexOf('.');
if (dotIndex > -1) {
if (precisionSupported(conversion)) {
_precision = Integer.valueOf(spec.substring(dotIndex + 1));
} else {
throw new IllegalFormatException(
"Precision is not supported for " + conversion
);
}
}
// Now loop over the remaining characters to get the width as well as any
// applicable flags. Note: 0 is a valid flag so must be handled carefully
final String remaining = spec.substring(
Math.max(dollarIndex, 0), dotIndex > -1 ? dotIndex : spec.length()
);
int flagsEnd = -1;
for (int i = 0, n = remaining.length(); i < n && (flagsEnd == -1); i++) {
final char c = remaining.charAt(i);
switch (c) {
case '-':
ensureLeftJustifySupported();
setFlagTrue(FLAG_LEFT_JUSTIFIED);
break;
case '#':
ensureNumeric(c);
setFlagTrue(FLAG_ALTERNATE_FORM);
break;
case '+':
ensureNumeric(c);
setFlagTrue(FLAG_ALWAYS_INCLUDES_SIGN);
break;
case ' ':
ensureNumeric(c);
setFlagTrue(FLAG_LEADING_SPACE_PADDED);
break;
case ',':
ensureNumeric(c);
setFlagTrue(FLAG_GROUPING_SEPARATORS);
break;
case '(':
ensureNumeric(c);
setFlagTrue(FLAG_NEGATIVES_IN_PARENS);
break;
case '0':
ensureNumeric(c);
setFlagTrue(FLAG_LEADING_ZERO_PADDED);
break;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
flagsEnd = i;
_width = Integer.valueOf(remaining.substring(flagsEnd));
return build();
}
}
throw new IllegalStateException();
}
private final void ensureLeftJustifySupported() {
if (!widthSupported(_conversion)) {
throw new IllegalFormatException(
"Conversion must support width if specifying left justified."
);
}
}
private final void ensureNumeric(final char c) {
if (!isNumeric(_conversion)) {
throw new IllegalFormatException(
"flag " + c + " only supported on numeric specifiers."
);
}
}
private final void setFlagTrue(final byte flag) {
_flags |= flag;
}/*
final void setFlagFalse(final byte flag) {
_flags &= ~flag;
}*/
}
}

View File

@ -0,0 +1,15 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
public interface Function<A,B> {
public B call(A argument) throws Exception;
}

View File

@ -0,0 +1,21 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
public class IncompatibleContinuationException extends Exception {
public IncompatibleContinuationException(String message) {
super(message);
}
public IncompatibleContinuationException() {
super();
}
}

View File

@ -0,0 +1,18 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
public class InnerClassReference {
public byte[] inner;
public byte[] outer;
public byte[] name;
public short flags;
}

View File

@ -0,0 +1,26 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
import java.io.ByteArrayOutputStream;
public class Iso88591 {
public static byte[] encode(char[] s16, int offset, int length) {
ByteArrayOutputStream buf = new ByteArrayOutputStream();
for (int i = offset; i < offset+length; ++i) {
// ISO-88591-1/Latin-1 is the same as UTF-16 under 0x100
buf.write(s16[i]);
}
return buf.toByteArray();
}
}

View File

@ -0,0 +1,240 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
import avian.VMClass;
import java.util.HashMap;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PushbackReader;
import java.io.StreamCorruptedException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class LegacyObjectInputStream extends InputStream {
private final InputStream in;
private final PushbackReader r;
public LegacyObjectInputStream(InputStream in) {
this.in = in;
this.r = new PushbackReader(new InputStreamReader(in));
}
public int read() throws IOException {
return in.read();
}
public int read(byte[] b, int offset, int length) throws IOException {
return in.read(b, offset, length);
}
public void close() throws IOException {
in.close();
}
public Object readObject() throws IOException, ClassNotFoundException {
return readObject(new HashMap<Integer, Object>());
}
public boolean readBoolean() throws IOException {
read('z');
return readLongToken() != 0;
}
public byte readByte() throws IOException {
read('b');
return (byte) readLongToken();
}
public char readChar() throws IOException {
read('c');
return (char) readLongToken();
}
public short readShort() throws IOException {
read('s');
return (short) readLongToken();
}
public int readInt() throws IOException {
read('i');
return (int) readLongToken();
}
public long readLong() throws IOException {
read('j');
return readLongToken();
}
public float readFloat() throws IOException {
read('f');
return (float) readDoubleToken();
}
public double readDouble() throws IOException {
read('d');
return readDoubleToken();
}
public void defaultReadObject() throws IOException {
throw new UnsupportedOperationException();
}
private void skipSpace() throws IOException {
int c;
while ((c = r.read()) != -1 && Character.isWhitespace((char) c));
if (c != -1) {
r.unread(c);
}
}
private void read(char v) throws IOException {
skipSpace();
int c = r.read();
if (c != v) {
if (c == -1) {
throw new EOFException();
} else {
throw new StreamCorruptedException();
}
}
}
private String readStringToken() throws IOException {
skipSpace();
StringBuilder sb = new StringBuilder();
int c;
while ((c = r.read()) != -1 && ! Character.isWhitespace((char) c) && c != ')') {
sb.append((char) c);
}
if (c != -1) {
r.unread(c);
}
return sb.toString();
}
private long readLongToken() throws IOException {
return Long.parseLong(readStringToken());
}
private double readDoubleToken() throws IOException {
return Double.parseDouble(readStringToken());
}
private Object readObject(HashMap<Integer, Object> map)
throws IOException, ClassNotFoundException
{
skipSpace();
switch (r.read()) {
case 'a':
return deserializeArray(map);
case 'l':
return deserializeObject(map);
case 'n':
return null;
case -1:
throw new EOFException();
default:
throw new StreamCorruptedException();
}
}
private Object deserialize(HashMap<Integer, Object> map)
throws IOException, ClassNotFoundException
{
skipSpace();
switch (r.read()) {
case 'a':
return deserializeArray(map);
case 'l':
return deserializeObject(map);
case 'r':
return map.get((int) readLongToken());
case 'n':
return null;
case 'z':
return (readLongToken() != 0);
case 'b':
return (byte) readLongToken();
case 'c':
return (char) readLongToken();
case 's':
return (short) readLongToken();
case 'i':
return (int) readLongToken();
case 'j':
return readLongToken();
case 'f':
return (float) readDoubleToken();
case 'd':
return readDoubleToken();
case -1:
throw new EOFException();
default:
throw new StreamCorruptedException();
}
}
private Object deserializeArray(HashMap<Integer, Object> map)
throws IOException, ClassNotFoundException
{
read('(');
int id = (int) readLongToken();
Class<?> c = Class.forName(readStringToken());
int length = (int) readLongToken();
Class<?> t = c.getComponentType();
Object o = Array.newInstance(t, length);
map.put(id, o);
for (int i = 0; i < length; ++i) {
Array.set(o, i, deserialize(map));
}
read(')');
return o;
}
private static native Object makeInstance(VMClass c);
private Object deserializeObject(HashMap<Integer, Object> map)
throws IOException, ClassNotFoundException
{
read('(');
int id = (int) readLongToken();
Class<?> c = Class.forName(readStringToken());
Object o = makeInstance(c.vmClass);
map.put(id, o);
for (Field<?> f: c.getAllFields()) {
int modifiers = f.getModifiers();
if ((modifiers & (Modifier.TRANSIENT | Modifier.STATIC)) == 0) {
try {
f.set(o, deserialize(map));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
read(')');
return o;
}
}

View File

@ -0,0 +1,211 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
import java.util.IdentityHashMap;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.Serializable;
import java.io.NotSerializableException;
public class LegacyObjectOutputStream extends OutputStream {
private final PrintStream out;
public LegacyObjectOutputStream(OutputStream out) {
this.out = new PrintStream(out);
}
public void write(int c) throws IOException {
out.write(c);
}
public void write(byte[] b, int offset, int length) throws IOException {
out.write(b, offset, length);
}
public void flush() throws IOException {
out.flush();
}
public void close() throws IOException {
out.close();
}
public void writeObject(Object o) throws IOException {
writeObject(o, new IdentityHashMap(), new int[] {0});
}
public void writeBoolean(boolean v) {
out.print("z");
out.print((v ? 1 : 0));
}
public void writeByte(byte v) {
out.print("b");
out.print((int) v);
}
public void writeChar(char v) {
out.print("c");
out.print((int) v);
}
public void writeShort(short v) {
out.print("s");
out.print((int) v);
}
public void writeInt(int v) {
out.print("i");
out.print(v);
}
public void writeLong(long v) {
out.print("j");
out.print(v);
}
public void writeFloat(float v) {
out.print("f");
out.print(v);
}
public void writeDouble(double v) {
out.print("d");
out.print(v);
}
public void defaultWriteObject() throws IOException {
throw new UnsupportedOperationException();
}
private void writeObject(Object o, IdentityHashMap<Object, Integer> map,
int[] nextId)
throws IOException
{
if (o == null) {
out.print("n");
} else {
Integer id = map.get(o);
if (id == null) {
map.put(o, nextId[0]);
Class c = o.getClass();
if (c.isArray()) {
serializeArray(o, map, nextId);
} else if (Serializable.class.isAssignableFrom(c)) {
serializeObject(o, map, nextId);
} else {
throw new NotSerializableException(c.getName());
}
} else {
out.print("r");
out.print(id.intValue());
}
}
}
private void serializeArray(Object o, IdentityHashMap<Object, Integer> map,
int[] nextId)
throws IOException
{
Class c = o.getClass();
Class t = c.getComponentType();
int length = Array.getLength(o);
out.print("a(");
out.print(nextId[0]++);
out.print(" ");
out.print(c.getName());
out.print(" ");
out.print(length);
for (int i = 0; i < length; ++i) {
out.print(" ");
Object v = Array.get(o, i);
if (t.equals(boolean.class)) {
writeBoolean((Boolean) v);
} else if (t.equals(byte.class)) {
writeByte((Byte) v);
} else if (t.equals(char.class)) {
writeChar((Character) v);
} else if (t.equals(short.class)) {
writeShort((Short) v);
} else if (t.equals(int.class)) {
writeInt((Integer) v);
} else if (t.equals(long.class)) {
writeLong((Long) v);
} else if (t.equals(float.class)) {
writeFloat((Float) v);
} else if (t.equals(double.class)) {
writeDouble((Double) v);
} else {
writeObject(v, map, nextId);
}
}
out.print(")");
}
private void serializeObject(Object o, IdentityHashMap<Object, Integer> map,
int[] nextId)
throws IOException
{
Class c = o.getClass();
out.print("l(");
out.print(nextId[0]++);
out.print(" ");
out.print(c.getName());
for (Field f: c.getAllFields()) {
int modifiers = f.getModifiers();
if ((modifiers & (Modifier.TRANSIENT | Modifier.STATIC)) == 0) {
out.print(" ");
Object v;
try {
v = f.get(o);
} catch (Exception e) {
throw new RuntimeException(e);
}
Class t = f.getType();
if (t.equals(boolean.class)) {
writeBoolean((Boolean) v);
} else if (t.equals(byte.class)) {
writeByte((Byte) v);
} else if (t.equals(char.class)) {
writeChar((Character) v);
} else if (t.equals(short.class)) {
writeShort((Short) v);
} else if (t.equals(int.class)) {
writeInt((Integer) v);
} else if (t.equals(long.class)) {
writeLong((Long) v);
} else if (t.equals(float.class)) {
writeFloat((Float) v);
} else if (t.equals(double.class)) {
writeDouble((Double) v);
} else {
writeObject(v, map, nextId);
}
}
}
out.print(")");
}
}

View File

@ -0,0 +1,67 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
public abstract class Machine {
private static final Unsafe unsafe;
static {
Unsafe u;
try {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
u = (Unsafe)f.get(null);
} catch (Exception e) {
u = null;
}
unsafe = u;
}
public static native void dumpHeap(String outputFile);
public static Unsafe getUnsafe() {
return unsafe;
}
/**
* Short version: Don't use this function -- it's evil.
*
* Long version: This is kind of a poor man's, cross-platform
* version of Microsoft's Structured Exception Handling. The idea
* is that you can call a native function with the specified
* argument such that any OS signals raised (e.g. SIGSEGV, SIGBUS,
* SIGFPE, EXC_ACCESS_VIOLATION, etc.) prior to the function
* returning are converted into the appropriate Java exception
* (e.g. NullPointerException, ArithmeticException, etc.) and thrown
* from this method. This may be useful in very specific
* circumstances, e.g. to work around a bug in a library that would
* otherwise crash your app. On the other hand, you'd be much
* better off just fixing the library if possible.
*
* Caveats: The specified function should return quickly without
* blocking, since it will block critical VM features such as
* garbage collection. The implementation is equivalent to using
* setjmp/longjmp to achieve a non-local return from the signal
* handler, meaning C++ destructors and other cleanup code might not
* be run if a signal is raised. It might melt your keyboard and
* burn your fingertips. Caveat lector.
*
* @param function a function pointer of type int64_t (*)(int64_t)
* @param argument the argument to pass to the function
* @return the return value of the function
*/
public static native long tryNative(long function, long argument);
}

View File

@ -0,0 +1,17 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
public class MethodAddendum extends Addendum {
public Object exceptionTable;
public Object annotationDefault;
public Object parameterAnnotationTable;
}

View File

@ -0,0 +1,5 @@
package avian;
abstract class Pair {
// VM-visible fields in types.def
}

View File

@ -0,0 +1,594 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
import java.util.Comparator;
public class PersistentSet <T> implements Iterable <T> {
private static final Node NullNode = new Node(null);
static {
NullNode.left = NullNode;
NullNode.right = NullNode;
}
private final Node<T> root;
private final Comparator<T> comparator;
private final int size;
public PersistentSet() {
this(NullNode, new Comparator<T>() {
public int compare(T a, T b) {
return ((Comparable<T>) a).compareTo(b);
}
}, 0);
}
public PersistentSet(Comparator<T> comparator) {
this(NullNode, comparator, 0);
}
private PersistentSet(Node<T> root, Comparator<T> comparator, int size) {
this.root = root;
this.comparator = comparator;
this.size = size;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("{");
for (java.util.Iterator it = iterator(); it.hasNext();) {
sb.append(it.next());
if (it.hasNext()) {
sb.append(",");
}
}
sb.append("}");
return sb.toString();
}
public Comparator<T> comparator() {
return comparator;
}
public PersistentSet<T> add(T value) {
return add(value, false);
}
public int size() {
return size;
}
public PersistentSet<T> add(T value, boolean replaceExisting) {
Path<T> p = find(value);
if (! p.fresh) {
if (replaceExisting) {
return p.replaceWith(value);
} else {
return this;
}
}
return add(p);
}
private PersistentSet<T> add(Path<T> p) {
if (! p.fresh) throw new IllegalArgumentException();
Node<T> new_ = p.node;
Node<T> newRoot = p.root.root;
Cell<Node<T>> ancestors = p.ancestors;
// rebalance
new_.red = true;
while (ancestors != null && ancestors.value.red) {
if (ancestors.value == ancestors.next.value.left) {
if (ancestors.next.value.right.red) {
ancestors.value.red = false;
ancestors.next.value.right = new Node(ancestors.next.value.right);
ancestors.next.value.right.red = false;
ancestors.next.value.red = true;
new_ = ancestors.next.value;
ancestors = ancestors.next.next;
} else {
if (new_ == ancestors.value.right) {
new_ = ancestors.value;
ancestors = ancestors.next;
Node<T> n = leftRotate(new_);
if (ancestors.value.right == new_) {
ancestors.value.right = n;
} else {
ancestors.value.left = n;
}
ancestors = new Cell(n, ancestors);
}
ancestors.value.red = false;
ancestors.next.value.red = true;
Node<T> n = rightRotate(ancestors.next.value);
if (ancestors.next.next == null) {
newRoot = n;
} else if (ancestors.next.next.value.right == ancestors.next.value) {
ancestors.next.next.value.right = n;
} else {
ancestors.next.next.value.left = n;
}
// done
}
} else {
if (ancestors.next.value.left.red) {
ancestors.value.red = false;
ancestors.next.value.left = new Node(ancestors.next.value.left);
ancestors.next.value.left.red = false;
ancestors.next.value.red = true;
new_ = ancestors.next.value;
ancestors = ancestors.next.next;
} else {
if (new_ == ancestors.value.left) {
new_ = ancestors.value;
ancestors = ancestors.next;
Node<T> n = rightRotate(new_);
if (ancestors.value.right == new_) {
ancestors.value.right = n;
} else {
ancestors.value.left = n;
}
ancestors = new Cell(n, ancestors);
}
ancestors.value.red = false;
ancestors.next.value.red = true;
Node<T> n = leftRotate(ancestors.next.value);
if (ancestors.next.next == null) {
newRoot = n;
} else if (ancestors.next.next.value.right == ancestors.next.value) {
ancestors.next.next.value.right = n;
} else {
ancestors.next.next.value.left = n;
}
// done
}
}
}
newRoot.red = false;
return new PersistentSet(newRoot, comparator, size + 1);
}
private static <T> Node<T> leftRotate(Node<T> n) {
Node<T> child = new Node(n.right);
n.right = child.left;
child.left = n;
return child;
}
private static <T> Node<T> rightRotate(Node<T> n) {
Node<T> child = new Node(n.left);
n.left = child.right;
child.right = n;
return child;
}
public PersistentSet<T> remove(T value) {
Path<T> p = find(value);
if (! p.fresh) {
return remove(p);
}
return this;
}
private PersistentSet<T> remove(Path<T> p) {
if (size == 1) {
if (p.node != root) {
throw new IllegalArgumentException();
}
return new PersistentSet(NullNode, comparator, 0);
}
Node<T> new_ = p.node;
Node<T> newRoot = p.root.root;
Cell<Node<T>> ancestors = p.ancestors;
Node<T> dead;
if (new_.left == NullNode || new_.right == NullNode) {
dead = new_;
} else {
Cell<Node<T>> path = successor(new_, ancestors);
dead = path.value;
ancestors = path.next;
}
Node<T> child;
if (dead.left != NullNode) {
child = new Node(dead.left);
} else if (dead.right != NullNode) {
child = new Node(dead.right);
} else {
child = NullNode;
}
if (ancestors == null) {
child.red = false;
return new PersistentSet(child, comparator, 1);
} else if (dead == ancestors.value.left) {
ancestors.value.left = child;
} else {
ancestors.value.right = child;
}
if (dead != new_) {
new_.value = dead.value;
}
if (! dead.red) {
// rebalance
while (ancestors != null && ! child.red) {
if (child == ancestors.value.left) {
Node<T> sibling = ancestors.value.right
= new Node(ancestors.value.right);
if (sibling.red) {
sibling.red = false;
ancestors.value.red = true;
Node<T> n = leftRotate(ancestors.value);
if (ancestors.next == null) {
newRoot = n;
} else if (ancestors.next.value.right == ancestors.value) {
ancestors.next.value.right = n;
} else {
ancestors.next.value.left = n;
}
ancestors.next = new Cell(n, ancestors.next);
sibling = ancestors.value.right = new Node(ancestors.value.right);
}
if (! (sibling.left.red || sibling.right.red)) {
sibling.red = true;
child = ancestors.value;
ancestors = ancestors.next;
} else {
if (! sibling.right.red) {
sibling.left = new Node(sibling.left);
sibling.left.red = false;
sibling.red = true;
sibling = ancestors.value.right = rightRotate(sibling);
}
sibling.red = ancestors.value.red;
ancestors.value.red = false;
sibling.right = new Node(sibling.right);
sibling.right.red = false;
Node<T> n = leftRotate(ancestors.value);
if (ancestors.next == null) {
newRoot = n;
} else if (ancestors.next.value.right == ancestors.value) {
ancestors.next.value.right = n;
} else {
ancestors.next.value.left = n;
}
child = newRoot;
ancestors = null;
}
} else {
Node<T> sibling = ancestors.value.left
= new Node(ancestors.value.left);
if (sibling.red) {
sibling.red = false;
ancestors.value.red = true;
Node<T> n = rightRotate(ancestors.value);
if (ancestors.next == null) {
newRoot = n;
} else if (ancestors.next.value.left == ancestors.value) {
ancestors.next.value.left = n;
} else {
ancestors.next.value.right = n;
}
ancestors.next = new Cell(n, ancestors.next);
sibling = ancestors.value.left = new Node(ancestors.value.left);
}
if (! (sibling.right.red || sibling.left.red)) {
sibling.red = true;
child = ancestors.value;
ancestors = ancestors.next;
} else {
if (! sibling.left.red) {
sibling.right = new Node(sibling.right);
sibling.right.red = false;
sibling.red = true;
sibling = ancestors.value.left = leftRotate(sibling);
}
sibling.red = ancestors.value.red;
ancestors.value.red = false;
sibling.left = new Node(sibling.left);
sibling.left.red = false;
Node<T> n = rightRotate(ancestors.value);
if (ancestors.next == null) {
newRoot = n;
} else if (ancestors.next.value.left == ancestors.value) {
ancestors.next.value.left = n;
} else {
ancestors.next.value.right = n;
}
child = newRoot;
ancestors = null;
}
}
}
child.red = false;
}
return new PersistentSet(newRoot, comparator, size - 1);
}
private static <T> Cell<Node<T>> minimum(Node<T> n,
Cell<Node<T>> ancestors)
{
while (n.left != NullNode) {
n.left = new Node(n.left);
ancestors = new Cell(n, ancestors);
n = n.left;
}
return new Cell(n, ancestors);
}
private static <T> Cell<Node<T>> maximum(Node<T> n,
Cell<Node<T>> ancestors)
{
while (n.right != NullNode) {
n.right = new Node(n.right);
ancestors = new Cell(n, ancestors);
n = n.right;
}
return new Cell(n, ancestors);
}
private static <T> Cell<Node<T>> successor(Node<T> n,
Cell<Node<T>> ancestors)
{
if (n.right != NullNode) {
n.right = new Node(n.right);
return minimum(n.right, new Cell(n, ancestors));
}
while (ancestors != null && n == ancestors.value.right) {
n = ancestors.value;
ancestors = ancestors.next;
}
return ancestors;
}
private static <T> Cell<Node<T>> predecessor(Node<T> n,
Cell<Node<T>> ancestors)
{
if (n.left != NullNode) {
n.left = new Node(n.left);
return maximum(n.left, new Cell(n, ancestors));
}
while (ancestors != null && n == ancestors.value.left) {
n = ancestors.value;
ancestors = ancestors.next;
}
return ancestors;
}
public Path<T> find(T value) {
Node<T> newRoot = new Node(root);
Cell<Node<T>> ancestors = null;
Node<T> old = root;
Node<T> new_ = newRoot;
while (old != NullNode) {
ancestors = new Cell(new_, ancestors);
int difference = comparator.compare(value, old.value);
if (difference < 0) {
old = old.left;
new_ = new_.left = new Node(old);
} else if (difference > 0) {
old = old.right;
new_ = new_.right = new Node(old);
} else {
return new Path(false, new_,
new PersistentSet(newRoot, comparator, size),
ancestors.next);
}
}
new_.value = value;
return new Path(true, new_,
new PersistentSet(newRoot, comparator, size),
ancestors);
}
public Path<T> first() {
if (root == NullNode) return null;
Node<T> newRoot = new Node(root);
Cell<Node<T>> ancestors = null;
Node<T> old = root;
Node<T> new_ = newRoot;
while (old.left != NullNode) {
ancestors = new Cell(new_, ancestors);
old = old.left;
new_ = new_.left = new Node(old);
}
return new Path(true, new_,
new PersistentSet(newRoot, comparator, size),
ancestors);
}
public Path<T> last() {
if (root == NullNode) return null;
Node<T> newRoot = new Node(root);
Cell<Node<T>> ancestors = null;
Node<T> old = root;
Node<T> new_ = newRoot;
while (old.right != NullNode) {
ancestors = new Cell(new_, ancestors);
old = old.right;
new_ = new_.right = new Node(old);
}
return new Path(true, new_,
new PersistentSet(newRoot, comparator, size),
ancestors);
}
public java.util.Iterator<T> iterator() {
return new Iterator(first());
}
private Path<T> successor(Path<T> p) {
Cell<Node<T>> s = successor(p.node, p.ancestors);
if (s == null) {
return null;
} else {
return new Path(false, s.value, p.root, s.next);
}
}
private Path<T> predecessor(Path<T> p) {
Cell<Node<T>> s = predecessor(p.node, p.ancestors);
if (s == null) {
return null;
} else {
return new Path(false, s.value, p.root, s.next);
}
}
private static class Node <T> {
public T value;
public Node left;
public Node right;
public boolean red;
public Node(Node<T> basis) {
if (basis != null) {
value = basis.value;
left = basis.left;
right = basis.right;
red = basis.red;
}
}
}
public static class Path <T> {
private final boolean fresh;
private final Node<T> node;
private final PersistentSet<T> root;
private final Cell<Node<T>> ancestors;
public Path(boolean fresh, Node<T> node, PersistentSet<T> root,
Cell<Node<T>> ancestors)
{
this.fresh = fresh;
this.node = node;
this.root = root;
this.ancestors = ancestors;
}
public T value() {
return node.value;
}
public boolean fresh() {
return fresh;
}
public PersistentSet<T> root() {
return root;
}
public Path<T> successor() {
return root.successor(this);
}
public Path<T> predecessor() {
return root.predecessor(this);
}
public PersistentSet<T> remove() {
if (fresh) throw new IllegalStateException();
return root.remove(this);
}
public PersistentSet<T> add() {
if (! fresh) throw new IllegalStateException();
return root.add(this);
}
public PersistentSet<T> replaceWith(T value) {
if (fresh) throw new IllegalStateException();
if (root.comparator.compare(node.value, value) != 0)
throw new IllegalArgumentException();
node.value = value;
return root;
}
}
public class Iterator <T> implements java.util.Iterator <T> {
private PersistentSet.Path<T> path;
private Iterator(PersistentSet.Path<T> path) {
this.path = path;
}
private Iterator(Iterator<T> start) {
path = start.path;
}
public boolean hasNext() {
return path != null;
}
public T next() {
PersistentSet.Path<T> p = path;
path = path.successor();
return p.value();
}
public void remove() {
throw new UnsupportedOperationException();
}
}
}

View File

@ -0,0 +1,19 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
public abstract class Singleton {
public static native int getInt(Object singleton, int offset);
public static native long getLong(Object singleton, int offset);
public static native Object getObject(Object singleton, int offset);
// Fields in types.def
}

View File

@ -0,0 +1,80 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.io.EOFException;
public abstract class Stream {
public static void write1(OutputStream out, int v) throws IOException {
out.write(v & 0xFF);
}
public static int read1(InputStream in) throws IOException {
return in.read();
}
public static void write2(OutputStream out, int v) throws IOException {
out.write((v >>> 8) & 0xFF);
out.write((v ) & 0xFF);
}
public static int read2(InputStream in) throws IOException {
int b1 = in.read();
int b2 = in.read();
if (b2 == -1) throw new EOFException();
return ((b1 << 8) | (b2 & 0xFF));
}
public static void write4(OutputStream out, int v) throws IOException {
out.write((v >>> 24) & 0xFF);
out.write((v >>> 16) & 0xFF);
out.write((v >>> 8) & 0xFF);
out.write((v ) & 0xFF);
}
public static int read4(InputStream in) throws IOException {
int b1 = in.read();
int b2 = in.read();
int b3 = in.read();
int b4 = in.read();
if (b4 == -1) throw new EOFException();
return ((b1 << 24) | (b2 << 16) | (b3 << 8) | (b4));
}
public static void write8(OutputStream out, long v) throws IOException {
write4(out, (int) (v >>> 32) & 0xFFFFFFFF);
write4(out, (int) (v ) & 0xFFFFFFFF);
}
public static long read8(InputStream in) throws IOException {
long b1 = in.read();
long b2 = in.read();
long b3 = in.read();
long b4 = in.read();
long b5 = in.read();
long b6 = in.read();
long b7 = in.read();
long b8 = in.read();
if (b8 == -1) throw new EOFException();
return ((b1 << 56) | (b2 << 48) | (b3 << 40) | (b4 << 32) |
(b5 << 24) | (b6 << 16) | (b7 << 8) | (b8));
}
public static void set4(byte[] array, int offset, int v) {
array[offset ] = (byte) ((v >>> 24) & 0xFF);
array[offset + 1] = (byte) ((v >>> 16) & 0xFF);
array[offset + 2] = (byte) ((v >>> 8) & 0xFF);
array[offset + 3] = (byte) ((v ) & 0xFF);
}
}

View File

@ -0,0 +1,176 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
import java.net.URL;
import java.net.MalformedURLException;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.NoSuchElementException;
public class SystemClassLoader extends ClassLoader {
public static native ClassLoader appLoader();
private native VMClass findVMClass(String name)
throws ClassNotFoundException;
protected Class findClass(String name) throws ClassNotFoundException {
return getClass(findVMClass(name));
}
public static native Class getClass(VMClass vmClass);
public static native VMClass vmClass(Class jClass);
private native VMClass findLoadedVMClass(String name);
protected Class reallyFindLoadedClass(String name){
VMClass c = findLoadedVMClass(name);
return c == null ? null : getClass(c);
}
protected Class loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
Class c = findLoadedClass(name);
if (c == null) {
ClassLoader parent = getParent();
if (parent != null) {
try {
c = parent.loadClass(name);
} catch (ClassNotFoundException ok) { }
}
if (c == null) {
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
private native String resourceURLPrefix(String name);
protected URL findResource(String name) {
String prefix = resourceURLPrefix(name);
if (prefix != null) {
try {
return new URL(prefix + name);
} catch (MalformedURLException ignored) { }
}
return null;
}
protected Package getPackage(String name) {
Package p = super.getPackage(name);
if (p == null) {
String source = getPackageSource(name);
if (source != null) {
// todo: load attributes from JAR manifest
definePackage(name, null, null, null, null, null, null, null);
} else {
definePackage(name, null, null, null, null, null, null, null);
}
}
return super.getPackage(name);
}
protected static native String getPackageSource(String name);
// OpenJDK's java.lang.ClassLoader.getResource makes use of
// sun.misc.Launcher to load bootstrap resources, which is not
// appropriate for the Avian build, so we override it to ensure we
// get the behavior we want. This implementation is the same as
// that of Avian's java.lang.ClassLoader.getResource.
public URL getResource(String path) {
URL url = null;
ClassLoader parent = getParent();
if (parent != null) {
url = parent.getResource(path);
}
if (url == null) {
url = findResource(path);
}
return url;
}
// As above, we override this method to avoid inappropriate behavior
// in OpenJDK's java.lang.ClassLoader.getResources.
public Enumeration<URL> getResources(String name) throws IOException {
Collection<URL> urls = new ArrayList<URL>(5);
ClassLoader parent = getParent();
if (parent != null) {
for (Enumeration<URL> e = parent.getResources(name);
e.hasMoreElements();)
{
urls.add(e.nextElement());
}
}
Enumeration<URL> urls2 = findResources(name);
while (urls2.hasMoreElements()) {
urls.add(urls2.nextElement());
}
return Collections.enumeration(urls);
}
private class ResourceEnumeration implements Enumeration<URL> {
private long[] finderElementPtrPtr;
private String name, urlPrefix;
public ResourceEnumeration(String name) {
this.name = name;
finderElementPtrPtr = new long[1];
urlPrefix = nextResourceURLPrefix();
}
private native String nextResourceURLPrefix(SystemClassLoader loader,
String name, long[] finderElementPtrPtr);
private String nextResourceURLPrefix() {
return nextResourceURLPrefix(SystemClassLoader.this, name,
finderElementPtrPtr);
}
public boolean hasMoreElements() {
return urlPrefix != null;
}
public URL nextElement() {
if (urlPrefix == null) throw new NoSuchElementException();
URL result;
try {
result = new URL(urlPrefix + name);
} catch (MalformedURLException ignored) {
result = null;
}
if (finderElementPtrPtr[0] == 0l) urlPrefix = null;
else urlPrefix = nextResourceURLPrefix();
return result;
}
}
protected Enumeration<URL> findResources(String name) {
return new ResourceEnumeration(name);
}
}

View File

@ -0,0 +1,71 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
public class Traces {
private static final String Newline = System.getProperty("line.separator");
private static String traceAllThreads() {
StringBuilder buffer = new StringBuilder();
Thread[] threads = new Thread[Thread.activeCount()];
int count = Thread.enumerate(threads);
for (int i = 0; i < count; ++i) {
traceThread(threads[i], buffer);
}
return buffer.toString();
}
private static String traceThread(Thread thread) {
StringBuilder buffer = new StringBuilder();
traceThread(thread, buffer);
return buffer.toString();
}
private static void traceThread(Thread thread, StringBuilder buffer) {
buffer.append(thread).append(Newline);
for (StackTraceElement e: thread.getStackTrace()) {
buffer.append("\tat ").append(e).append(Newline);
}
}
public static void startTraceListener(final String host, final int port) {
Thread t = new Thread(new Runnable() {
public void run() {
try {
ServerSocketChannel server = ServerSocketChannel.open();
server.socket().bind(new InetSocketAddress(host, port));
while (true) {
SocketChannel c = server.accept();
try {
c.write(ByteBuffer.wrap(traceAllThreads().getBytes()));
} finally {
c.close();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
t.setDaemon(true);
t.start();
}
}

View File

@ -0,0 +1,118 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
import java.io.ByteArrayOutputStream;
public class Utf8 {
public static boolean test(Object data) {
if (!(data instanceof byte[])) return false;
byte[] b = (byte[])data;
for (int i = 0; i < b.length; ++i) {
if (((int)b[i] & 0x080) != 0) return true;
}
return false;
}
public static byte[] encode(char[] s16, int offset, int length) {
ByteArrayOutputStream buf = new ByteArrayOutputStream();
for (int i = offset; i < offset+length; ++i) {
char c = s16[i];
if (c == '\u0000') { // null char
buf.write(0);
buf.write(0);
} else if (c < 0x080) { // 1 byte char
buf.write(c);
} else if (c < 0x0800) { // 2 byte char
buf.write(0x0c0 | (c >>> 6));
buf.write(0x080 | (c & 0x03f));
} else { // 3 byte char
buf.write(0x0e0 | ((c >>> 12) & 0x0f));
buf.write(0x080 | ((c >>> 6) & 0x03f));
buf.write(0x080 | (c & 0x03f));
}
}
return buf.toByteArray();
}
public static Object decode(byte[] s8, int offset, int length) {
Object buf = new byte[length];
boolean isMultiByte = false;
int i=offset, j=0;
while (i < offset+length) {
int x = s8[i++];
if ((x & 0x080) == 0x0) { // 1 byte char
if (x == 0) { // 2 byte null char
if (i == offset + length) {
return null;
}
++ i;
}
cram(buf, j++, x);
} else if ((x & 0x0e0) == 0x0c0) { // 2 byte char
if (i == offset + length) {
return null;
}
if (!isMultiByte) {
buf = widen(buf, j, length-1);
isMultiByte = true;
}
int y = s8[i++];
cram(buf, j++, ((x & 0x1f) << 6) | (y & 0x3f));
} else if ((x & 0x0f0) == 0x0e0) { // 3 byte char
if (i + 1 >= offset + length) {
return null;
}
if (!isMultiByte) {
buf = widen(buf, j, length-2);
isMultiByte = true;
}
int y = s8[i++]; int z = s8[i++];
cram(buf, j++, ((x & 0xf) << 12) | ((y & 0x3f) << 6) | (z & 0x3f));
}
}
return trim(buf, j);
}
public static char[] decode16(byte[] s8, int offset, int length) {
Object decoded = decode(s8, offset, length);
if (decoded == null) {
return null;
} else if (decoded instanceof char[]) {
return (char[])decoded;
} else {
return (char[])widen(decoded, length, length);
}
}
private static void cram(Object data, int index, int val) {
if (data instanceof byte[]) ((byte[])data)[index] = (byte)val;
else ((char[])data)[index] = (char)val;
}
private static Object widen(Object data, int length, int capacity) {
byte[] src = (byte[])data;
char[] result = new char[capacity];
for (int i = 0; i < length; ++i) result[i] = (char)((int)src[i] & 0x0ff);
return result;
}
private static Object trim(Object data, int length) {
if (data instanceof byte[]) return data;
if (((char[])data).length == length) return data;
char[] result = new char[length];
System.arraycopy(data, 0, result, 0, length);
return result;
}
}

View File

@ -0,0 +1,42 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
public class VMClass {
public short flags;
public short vmFlags;
public short fixedSize;
public byte arrayElementSize;
public byte arrayDimensions;
public VMClass arrayElementClass;
public int runtimeDataIndex;
public int[] objectMask;
public byte[] name;
public byte[] sourceFile;
public VMClass super_;
public Object[] interfaceTable;
public VMMethod[] virtualTable;
public VMField[] fieldTable;
/**
* Methods declared in this class, plus any abstract virtual methods
* inherited from implemented or extended interfaces. If addendum
* is non-null and addendum.declaredMethodCount is non-negative,
* then the first addendum.declaredMethodCount methods are declared
* methods, while the rest are abstract virtual methods. If
* addendum is null or addendum.declaredMethodCount is negative, all
* are declared methods.
*/
public VMMethod[] methodTable;
public ClassAddendum addendum;
public Singleton staticTable;
public ClassLoader loader;
public byte[] source;
}

View File

@ -0,0 +1,23 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
public class VMField {
public byte vmFlags;
public byte code;
public short flags;
public short offset;
public int nativeID;
public byte[] name;
public byte[] spec;
public FieldAddendum addendum;
public VMClass class_;
}

View File

@ -0,0 +1,31 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
public class VMMethod {
public byte vmFlags;
public byte returnCode;
public byte parameterCount;
public byte parameterFootprint;
public short flags;
public short offset;
public int nativeID;
public int runtimeDataIndex;
public byte[] name;
public byte[] spec;
public MethodAddendum addendum;
public VMClass class_;
public Code code;
public boolean hasAnnotations() {
return addendum != null && addendum.annotationTable != null;
}
}

View File

@ -0,0 +1,111 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian.avianvmresource;
import java.net.URL;
import java.net.URLStreamHandler;
import java.net.URLConnection;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.InputStream;
public class Handler extends URLStreamHandler {
protected URLConnection openConnection(URL url) {
return new ResourceConnection(url);
}
private static class ResourceConnection extends URLConnection {
public ResourceConnection(URL url) {
super(url);
}
public int getContentLength() {
return ResourceInputStream.getContentLength(url.getFile());
}
public InputStream getInputStream() throws IOException {
return new ResourceInputStream(url.getFile());
}
public void connect() {
// ignore
}
}
private static class ResourceInputStream extends InputStream {
private long peer;
private int position;
public ResourceInputStream(String path) throws IOException {
peer = open(path);
if (peer == 0) {
throw new FileNotFoundException(path);
}
}
private static native int getContentLength(String path);
private static native long open(String path) throws IOException;
private static native int read(long peer, int position) throws IOException;
private static native int read(long peer, int position,
byte[] b, int offset, int length)
throws IOException;
public static native void close(long peer) throws IOException;
public static native int available(long peer, int position);
public int available() {
return available(peer, position);
}
public int read() throws IOException {
if (peer != 0) {
int c = read(peer, position);
if (c >= 0) {
++ position;
}
return c;
} else {
throw new IOException();
}
}
public int read(byte[] b, int offset, int length) throws IOException {
if (peer != 0) {
if (b == null) {
throw new NullPointerException();
}
if (offset < 0 || offset + length > b.length) {
throw new ArrayIndexOutOfBoundsException();
}
int c = read(peer, position, b, offset, length);
if (c >= 0) {
position += c;
}
return c;
} else {
throw new IOException();
}
}
public void close() throws IOException {
if (peer != 0) {
close(peer);
peer = 0;
}
}
}
}

View File

@ -0,0 +1,44 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian.file;
import java.net.URL;
import java.net.URLStreamHandler;
import java.net.URLConnection;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class Handler extends URLStreamHandler {
protected URLConnection openConnection(URL url) {
return new FileURLConnection(url);
}
private static class FileURLConnection extends URLConnection {
public FileURLConnection(URL url) {
super(url);
}
public int getContentLength() {
return (int) new File(url.getFile()).length();
}
public InputStream getInputStream() throws IOException {
return new FileInputStream(new File(url.getFile()));
}
public void connect() {
// ignore
}
}
}

View File

@ -0,0 +1,120 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian.http;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.util.HashMap;
import java.util.Map;
public class Handler extends URLStreamHandler
{
public URLConnection openConnection(URL url) throws IOException
{
return new HttpURLConnection(url);
}
class HttpURLConnection extends URLConnection
{
Socket socket;
private BufferedWriter writer;
private InputStream bin;
private Map<String,String> header = new HashMap<String, String>();
private int status;
protected HttpURLConnection(URL url)
{
super(url);
}
@Override
public void connect() throws IOException
{
if(socket == null)
{
URLConnection con = null;
String host = url.getHost();
int port =url.getPort();
if(port < 0) port = 80;
socket = new Socket(host, port);
OutputStream out = socket.getOutputStream();
writer = new BufferedWriter(new OutputStreamWriter(out));
writer.write("GET " + url.getPath() + " HTTP/1.1");
writer.write("\r\nHost: " + host);
writer.write("\r\n\r\n");
writer.flush();
bin = new BufferedInputStream(socket.getInputStream());
readHeader();
// System.out.println("Status: " + status);
// System.out.println("Headers: " + header);
}
}
private void readHeader() throws IOException
{
byte[] buf = new byte[8192];
int b = 0;
int index = 0;
while(b >= 0)
{
if(index >= 4 && buf[index-4] == '\r' && buf[index-3] == '\n' && buf[index-2] == '\r' && buf[index-1] == '\n')
{
break;
}
b = bin.read();
buf[index] = (byte) b;
index++;
if(index >= buf.length)
{
throw new IOException("Header exceeded maximum size of 8k.");
}
}
BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(buf, 0, index)));
String line = reader.readLine();
int x = line.indexOf(' ');
status = Integer.parseInt(line.substring(x + 1 , line.indexOf(' ', x+1)));
while(line != null)
{
int i = line.indexOf(':');
if(i > 0)
{
header.put(line.substring(0, i), line.substring(i + 1) .trim());
}
line = reader.readLine();
}
reader.close();
}
@Override
public InputStream getInputStream() throws IOException
{
connect();
return bin;
}
@Override
public OutputStream getOutputStream() throws IOException
{
throw new UnsupportedOperationException("Can' write to HTTP Connection");
}
}
}

View File

@ -0,0 +1,84 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian.jar;
import java.net.URL;
import java.net.MalformedURLException;
import java.net.URLStreamHandler;
import java.net.JarURLConnection;
import java.net.URLConnection;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.jar.JarFile;
import java.util.jar.JarEntry;
public class Handler extends URLStreamHandler {
protected URLConnection openConnection(URL url) {
return new MyJarURLConnection(url);
}
protected void parseURL(URL url, String s, int start, int end)
throws MalformedURLException
{
// skip "jar:"
s = s.toString().substring(4);
int index = s.indexOf("!/");
if (index < 0) {
throw new MalformedURLException();
}
URL file = new URL(s.substring(0, index));
if (! "file".equals(file.getProtocol())) {
throw new RuntimeException
("protocol " + file.getProtocol() + " not yet supported");
}
url.set("jar", null, -1, s, null);
}
private static class MyJarURLConnection extends JarURLConnection {
private final JarFile file;
private final JarEntry entry;
public MyJarURLConnection(URL url) {
super(url);
String s = url.getFile();
int index = s.indexOf("!/");
try {
this.file = new JarFile(new URL(s.substring(0, index)).getFile());
this.entry = this.file.getJarEntry(s.substring(index + 2));
} catch (MalformedURLException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public JarFile getJarFile() throws IOException {
return file;
}
public int getContentLength() {
return (int)entry.getSize();
}
public InputStream getInputStream() throws IOException {
return file.getInputStream(entry);
}
public void connect() {
// ignore
}
}
}

View File

@ -0,0 +1,5 @@
package dalvik.system;
public class BaseDexClassLoader extends ClassLoader {
public native String getLdLibraryPath();
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,145 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
#ifndef SGX
#include "jni.h"
#include "avian/machine.h"
#include "sockets.h"
#include "jni-util.h"
using namespace avian::classpath::sockets;
extern "C" JNIEXPORT void JNICALL Java_java_net_Socket_init(JNIEnv* e, jclass)
{
init(e);
}
extern "C" JNIEXPORT SOCKET JNICALL
Java_java_net_Socket_create(JNIEnv* e, jclass)
{
return create(e);
}
extern "C" JNIEXPORT void JNICALL Java_java_net_Socket_connect(JNIEnv* e,
jclass,
jlong sock,
jlong addr,
jshort port)
{
connect(e, static_cast<SOCKET>(sock), addr, port);
}
extern "C" JNIEXPORT void JNICALL Java_java_net_Socket_bind(JNIEnv* e,
jclass,
jlong sock,
jlong addr,
jshort port)
{
bind(e, static_cast<SOCKET>(sock), addr, port);
}
extern "C" JNIEXPORT void JNICALL
Java_java_net_Socket_abort(JNIEnv* e, jclass, jlong sock)
{
abort(e, static_cast<SOCKET>(sock));
}
extern "C" JNIEXPORT void JNICALL
Java_java_net_Socket_close(JNIEnv* e, jclass, jlong sock)
{
close(e, static_cast<SOCKET>(sock));
}
extern "C" JNIEXPORT void JNICALL
Java_java_net_Socket_closeOutput(JNIEnv* e, jclass, jlong sock)
{
close_output(e, static_cast<SOCKET>(sock));
}
extern "C" JNIEXPORT void JNICALL
Java_java_net_Socket_closeInput(JNIEnv* e, jclass, jlong sock)
{
close_input(e, static_cast<SOCKET>(sock));
}
extern "C" JNIEXPORT void JNICALL
Avian_java_net_Socket_send(vm::Thread* t, vm::object, uintptr_t* arguments)
{ /* SOCKET s, object buffer_obj, int start_pos, int count */
SOCKET& s = *(reinterpret_cast<SOCKET*>(&arguments[0]));
vm::GcByteArray* buffer_obj = vm::cast<vm::GcByteArray>(
t, reinterpret_cast<vm::object>(arguments[2]));
int32_t& start_pos = *(reinterpret_cast<int32_t*>(&arguments[3]));
int32_t& count = *(reinterpret_cast<int32_t*>(&arguments[4]));
char* buffer = reinterpret_cast<char*>(&buffer_obj->body()[start_pos]);
avian::classpath::sockets::send((JNIEnv*)t, s, buffer, count);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_net_Socket_recv(vm::Thread* t, vm::object, uintptr_t* arguments)
{ /* SOCKET s, object buffer_obj, int start_pos, int count */
SOCKET& s = *(reinterpret_cast<SOCKET*>(&arguments[0]));
vm::GcByteArray* buffer_obj = vm::cast<vm::GcByteArray>(
t, reinterpret_cast<vm::object>(arguments[2]));
int32_t& start_pos = *(reinterpret_cast<int32_t*>(&arguments[3]));
int32_t& count = *(reinterpret_cast<int32_t*>(&arguments[4]));
char* buffer = reinterpret_cast<char*>(&buffer_obj->body()[start_pos]);
return avian::classpath::sockets::recv((JNIEnv*)t, s, buffer, count);
}
extern "C" JNIEXPORT jint JNICALL
Java_java_net_InetAddress_ipv4AddressForName(JNIEnv* e,
jclass,
jstring name)
{
if(!name) {
throwNew(e, "java/lang/NullPointerException", 0);
return 0;
}
const char* chars = e->GetStringUTFChars(name, 0);
if (chars) {
#ifdef PLATFORM_WINDOWS
hostent* host = gethostbyname(chars);
e->ReleaseStringUTFChars(name, chars);
if (host) {
return ntohl(reinterpret_cast<in_addr*>(host->h_addr_list[0])->s_addr);
} else {
throwNew(e, "java/net/UnknownHostException", 0);
return 0;
}
#else
addrinfo hints;
memset(&hints, 0, sizeof(addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
addrinfo* result;
int r = getaddrinfo(chars, 0, &hints, &result);
e->ReleaseStringUTFChars(name, chars);
if (r != 0) {
throwNew(e, "java/net/UnknownHostException", 0);
return 0;
} else {
int address = ntohl(
reinterpret_cast<sockaddr_in*>(result->ai_addr)->sin_addr.s_addr);
freeaddrinfo(result);
return address;
}
#endif
} else {
throwNew(e, "java/lang/OutOfMemoryError", 0);
return 0;
}
}
#endif // !SGX

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,172 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
#include "stdlib.h"
#include "string.h"
#include "avian/zlib-custom.h"
#include "jni.h"
#include "jni-util.h"
extern "C" JNIEXPORT jlong JNICALL
Java_java_util_zip_Inflater_make(JNIEnv* e, jclass, jboolean nowrap)
{
z_stream* s = static_cast<z_stream*>(malloc(sizeof(z_stream)));
if (s == 0) {
throwNew(e, "java/lang/OutOfMemoryError", 0);
return 0;
}
memset(s, 0, sizeof(z_stream));
int r = inflateInit2(s, (nowrap ? -15 : 15));
if (r != Z_OK) {
free(s);
throwNew(e, "java/lang/RuntimeException", zError(r));
return 0;
}
return reinterpret_cast<jlong>(s);
}
extern "C" JNIEXPORT void JNICALL
Java_java_util_zip_Inflater_dispose(JNIEnv*, jclass, jlong peer)
{
z_stream* s = reinterpret_cast<z_stream*>(peer);
inflateEnd(s);
free(s);
}
extern "C" JNIEXPORT void JNICALL
Java_java_util_zip_Inflater_inflate(JNIEnv* e,
jclass,
jlong peer,
jbyteArray input,
jint inputOffset,
jint inputLength,
jbyteArray output,
jint outputOffset,
jint outputLength,
jintArray results)
{
z_stream* s = reinterpret_cast<z_stream*>(peer);
jbyte* in = static_cast<jbyte*>(malloc(inputLength));
if (in == 0) {
throwNew(e, "java/lang/OutOfMemoryError", 0);
return;
}
jbyte* out = static_cast<jbyte*>(malloc(outputLength));
if (out == 0) {
free(in);
throwNew(e, "java/lang/OutOfMemoryError", 0);
return;
}
e->GetByteArrayRegion(input, inputOffset, inputLength, in);
s->next_in = reinterpret_cast<Bytef*>(in);
s->avail_in = inputLength;
s->next_out = reinterpret_cast<Bytef*>(out);
s->avail_out = outputLength;
int r = inflate(s, Z_SYNC_FLUSH);
jint resultArray[3] = {r,
static_cast<jint>(inputLength - s->avail_in),
static_cast<jint>(outputLength - s->avail_out)};
free(in);
e->SetByteArrayRegion(output, outputOffset, resultArray[2], out);
free(out);
e->SetIntArrayRegion(results, 0, 3, resultArray);
}
extern "C" JNIEXPORT jlong JNICALL
Java_java_util_zip_Deflater_make(JNIEnv* e,
jclass,
jboolean nowrap,
jint level)
{
z_stream* s = static_cast<z_stream*>(malloc(sizeof(z_stream)));
if (s == 0) {
throwNew(e, "java/lang/OutOfMemoryError", 0);
return 0;
}
memset(s, 0, sizeof(z_stream));
int r = deflateInit2(s, level, (nowrap ? -15 : 15));
if (r != Z_OK) {
free(s);
throwNew(e, "java/lang/RuntimeException", zError(r));
return 0;
}
return reinterpret_cast<jlong>(s);
}
extern "C" JNIEXPORT void JNICALL
Java_java_util_zip_Deflater_dispose(JNIEnv*, jclass, jlong peer)
{
z_stream* s = reinterpret_cast<z_stream*>(peer);
deflateEnd(s);
free(s);
}
extern "C" JNIEXPORT void JNICALL
Java_java_util_zip_Deflater_deflate(JNIEnv* e,
jclass,
jlong peer,
jbyteArray input,
jint inputOffset,
jint inputLength,
jbyteArray output,
jint outputOffset,
jint outputLength,
jboolean finish,
jintArray results)
{
z_stream* s = reinterpret_cast<z_stream*>(peer);
jbyte* in = static_cast<jbyte*>(malloc(inputLength));
if (in == 0) {
throwNew(e, "java/lang/OutOfMemoryError", 0);
return;
}
jbyte* out = static_cast<jbyte*>(malloc(outputLength));
if (out == 0) {
free(in);
throwNew(e, "java/lang/OutOfMemoryError", 0);
return;
}
e->GetByteArrayRegion(input, inputOffset, inputLength, in);
s->next_in = reinterpret_cast<Bytef*>(in);
s->avail_in = inputLength;
s->next_out = reinterpret_cast<Bytef*>(out);
s->avail_out = outputLength;
int r = deflate(s, finish ? Z_FINISH : Z_NO_FLUSH);
jint resultArray[3] = {r,
static_cast<jint>(inputLength - s->avail_in),
static_cast<jint>(outputLength - s->avail_out)};
free(in);
e->SetByteArrayRegion(output, outputOffset, resultArray[2], out);
free(out);
e->SetIntArrayRegion(results, 0, 3, resultArray);
}

View File

@ -0,0 +1,58 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
#include "time.h"
#include "jni.h"
#include "jni-util.h"
namespace {
#if (!defined PLATFORM_WINDOWS) || (defined _MSC_VER)
void removeNewline(char* s)
{
for (; s; ++s) {
if (*s == '\n') {
*s = 0;
break;
}
}
}
#endif
} // namespace
extern "C" JNIEXPORT jstring JNICALL
Java_java_util_Date_toString(JNIEnv* e, jclass c UNUSED, jlong when)
{
const unsigned BufferSize UNUSED = 27;
time_t time = when / 1000;
#ifdef PLATFORM_WINDOWS
e->MonitorEnter(c);
#ifdef _MSC_VER
char buffer[BufferSize];
ctime_s(buffer, BufferSize, &time);
removeNewline(buffer);
#else
char* buffer = ctime(&time);
#endif
jstring r = e->NewStringUTF(buffer);
e->MonitorExit(c);
return r;
#else
char buffer[BufferSize];
ctime_r(&time, buffer);
removeNewline(buffer);
return e->NewStringUTF(buffer);
#endif
}

View File

@ -0,0 +1,88 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
import java.io.IOException;
import java.io.InputStream;
public class BufferedInputStream extends InputStream {
private final InputStream in;
private final byte[] buffer;
private int position;
private int limit;
public BufferedInputStream(InputStream in, int size) {
this.in = in;
this.buffer = new byte[size];
}
public BufferedInputStream(InputStream in) {
this(in, 4096);
}
private int fill() throws IOException {
position = 0;
limit = in.read(buffer);
return limit;
}
public int read() throws IOException {
if (position >= limit && fill() == -1) {
return -1;
}
return buffer[position++] & 0xFF;
}
public int read(byte[] b, int offset, int length) throws IOException {
int count = 0;
if (position >= limit && fill() == -1) {
return -1;
}
if (position < limit) {
int remaining = limit - position;
if (remaining > length) {
remaining = length;
}
System.arraycopy(buffer, position, b, offset, remaining);
count += remaining;
position += remaining;
offset += remaining;
length -= remaining;
}
while (length > 0 && in.available() > 0)
{
int c = in.read(b, offset, length);
if (c == -1) {
if (count == 0) {
count = -1;
}
break;
} else {
offset += c;
count += c;
length -= c;
}
}
return count;
}
public int available() throws IOException {
return in.available() + (limit - position);
}
public void close() throws IOException {
in.close();
}
}

View File

@ -0,0 +1,61 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class BufferedOutputStream extends OutputStream {
private final OutputStream out;
private final byte[] buffer;
private int position;
public BufferedOutputStream(OutputStream out, int size) {
this.out = out;
this.buffer = new byte[size];
}
public BufferedOutputStream(OutputStream out) {
this(out, 4096);
}
private void drain() throws IOException {
if (position > 0) {
out.write(buffer, 0, position);
position = 0;
}
}
public void write(int c) throws IOException {
if (position >= buffer.length) {
drain();
}
buffer[position++] = (byte) (c & 0xFF);
}
public void write(byte[] b, int offset, int length) throws IOException {
if (length > buffer.length - position) {
drain();
out.write(b, offset, length);
} else {
System.arraycopy(b, offset, buffer, position, length);
position += length;
}
}
public void flush() throws IOException {
drain();
out.flush();
}
public void close() throws IOException {
flush();
out.close();
}
}

View File

@ -0,0 +1,101 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class BufferedReader extends Reader {
private final Reader in;
private final char[] buffer;
private int position;
private int limit;
public BufferedReader(Reader in, int bufferSize) {
this.in = in;
this.buffer = new char[bufferSize];
}
public BufferedReader(Reader in) {
this(in, 32);
}
private void fill() throws IOException {
position = 0;
limit = in.read(buffer);
}
public String readLine() throws IOException {
StringBuilder sb = new StringBuilder();
while (true) {
if (position >= limit) {
fill();
}
if (position >= limit) {
return sb.length() == 0 ? null : sb.toString();
}
for (int i = position; i < limit; ++i) {
if(buffer[i] == '\r') {
sb.append(buffer, position, i - position);
position = i + 1;
if(i+1 < limit && buffer[i+1] == '\n') {
position = i + 2;
}
return sb.toString();
} else if (buffer[i] == '\n') {
sb.append(buffer, position, i - position);
position = i + 1;
return sb.toString();
}
}
sb.append(buffer, position, limit-position);
position = limit;
}
}
public int read(char[] b, int offset, int length) throws IOException {
int count = 0;
if (position >= limit && length < buffer.length) {
fill();
}
if (position < limit) {
int remaining = limit - position;
if (remaining > length) {
remaining = length;
}
System.arraycopy(buffer, position, b, offset, remaining);
count += remaining;
position += remaining;
offset += remaining;
length -= remaining;
}
if (length > 0) {
int c = in.read(b, offset, length);
if (c == -1) {
if (count == 0) {
count = -1;
}
} else {
count += c;
}
}
return count;
}
public void close() throws IOException {
in.close();
}
}

View File

@ -0,0 +1,53 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class BufferedWriter extends Writer {
private final Writer out;
private final char[] buffer;
private int position;
public BufferedWriter(Writer out, int size) {
this.out = out;
this.buffer = new char[size];
}
public BufferedWriter(Writer out) {
this(out, 4096);
}
private void drain() throws IOException {
if (position > 0) {
out.write(buffer, 0, position);
position = 0;
}
}
public void write(char[] b, int offset, int length) throws IOException {
if (length > buffer.length - position) {
drain();
out.write(b, offset, length);
} else {
System.arraycopy(b, offset, buffer, position, length);
position += length;
}
}
public void flush() throws IOException {
drain();
out.flush();
}
public void close() throws IOException {
flush();
out.close();
}
}

View File

@ -0,0 +1,55 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class ByteArrayInputStream extends InputStream {
private final byte[] array;
private int position;
private final int limit;
public ByteArrayInputStream(byte[] array, int offset, int length) {
this.array = array;
position = offset;
this.limit = offset + length;
}
public ByteArrayInputStream(byte[] array) {
this(array, 0, array.length);
}
public int read() {
if (position < limit) {
return array[position++] & 0xff;
} else {
return -1;
}
}
public int read(byte[] buffer, int offset, int bufferLength) {
if (bufferLength == 0) {
return 0;
}
if (position >= limit) {
return -1;
}
int remaining = limit-position;
if (remaining < bufferLength) {
bufferLength = remaining;
}
System.arraycopy(array, position, buffer, offset, bufferLength);
position += bufferLength;
return bufferLength;
}
public int available() {
return limit - position;
}
}

View File

@ -0,0 +1,148 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class ByteArrayOutputStream extends OutputStream {
private static final int BufferSize = 32;
private Cell firstCell;
private Cell curCell;
private int length;
private byte[] buffer;
private int position;
public ByteArrayOutputStream(int capacity) { }
public ByteArrayOutputStream() {
this(0);
}
public void reset() {
firstCell = null;
curCell = null;
length = 0;
buffer = null;
position = 0;
}
public int size() {
return length;
}
public void write(int c) {
if (buffer == null) {
buffer = new byte[BufferSize];
} else if (position >= buffer.length) {
flushBuffer();
buffer = new byte[BufferSize];
}
buffer[position++] = (byte) (c & 0xFF);
++ length;
}
private byte[] copy(byte[] b, int offset, int length) {
byte[] array = new byte[length];
System.arraycopy(b, offset, array, 0, length);
return array;
}
public void write(byte[] b, int offset, int length) {
if (b == null) {
throw new NullPointerException();
}
if (offset < 0 || offset + length > b.length) {
throw new ArrayIndexOutOfBoundsException();
}
if (length == 0) return;
if (buffer != null && length <= buffer.length - position) {
System.arraycopy(b, offset, buffer, position, length);
position += length;
} else {
flushBuffer();
chainCell( new Cell(copy(b, offset, length), 0, length) );
}
this.length += length;
}
private void chainCell(Cell cell){
if (curCell == null){
firstCell = cell;
curCell = cell;
}else{
curCell.next = cell;
curCell = cell;
}
}
private void flushBuffer() {
if (position > 0) {
byte[] b = buffer;
int p = position;
buffer = null;
position = 0;
chainCell( new Cell(b, 0, p) );
}
}
public byte[] toByteArray() {
flushBuffer();
byte[] array = new byte[length];
int pos = 0;
for (Cell c = firstCell; c != null; c = c.next) {
System.arraycopy(c.array, c.offset, array, pos, c.length);
pos += c.length;
}
return array;
}
public synchronized void writeTo(OutputStream out) throws IOException {
if (length==0) return;
if (out == null){
throw new NullPointerException();
}
flushBuffer();
for (Cell c = firstCell; c != null; c = c.next) {
out.write(c.array, c.offset, c.length);
}
}
@Override
public String toString() {
return new String(toByteArray());
}
public String toString(String encoding) throws UnsupportedEncodingException {
return new String(toByteArray(), encoding);
}
private static class Cell {
public byte[] array;
public int offset;
public int length;
public Cell next = null;
public Cell(byte[] array, int offset, int length) {
this.array = array;
this.offset = offset;
this.length = length;
}
}
}

View File

@ -0,0 +1,16 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public interface Closeable extends AutoCloseable {
void close()
throws IOException;
}

View File

@ -0,0 +1,29 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public interface DataInput {
boolean readBoolean() throws IOException;
byte readByte() throws IOException;
char readChar() throws IOException;
double readDouble() throws IOException;
float readFloat() throws IOException;
void readFully(byte[] b) throws IOException;
void readFully(byte[] b, int off, int len) throws IOException;
int readInt() throws IOException;
String readLine() throws IOException;
long readLong() throws IOException;
short readShort() throws IOException;
int readUnsignedByte() throws IOException;
int readUnsignedShort() throws IOException;
String readUTF() throws IOException;
int skipBytes(int n) throws IOException;
}

View File

@ -0,0 +1,132 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class DataInputStream extends InputStream implements DataInput {
private InputStream in;
public DataInputStream(InputStream in) {
this.in = in;
}
public void close() throws IOException {
in.close();
}
public int read(byte[] buffer) throws IOException {
return in.read(buffer);
}
public int read(byte[] buffer, int offset, int length) throws IOException {
return in.read(buffer, offset, length);
}
public void readFully(byte[] b) throws IOException {
readFully(b, 0, b.length);
}
public void readFully(byte[] b, int offset, int length) throws IOException {
while (length > 0) {
int count = read(b, offset, length);
if (count < 0) {
throw new EOFException("Reached EOF " + length + " bytes too early");
}
offset += count;
length -= count;
}
}
public int read() throws IOException {
return in.read();
}
private int read0() throws IOException {
int b = in.read();
if (b < 0) {
throw new EOFException();
}
return b;
}
public boolean readBoolean() throws IOException {
return read0() != 0;
}
public byte readByte() throws IOException {
return (byte)read0();
}
public short readShort() throws IOException {
return (short)((read0() << 8) | read0());
}
public int readInt() throws IOException {
return ((read0() << 24) | (read0() << 16) | (read0() << 8) | read0());
}
public float readFloat() throws IOException {
return Float.floatToIntBits(readInt());
}
public double readDouble() throws IOException {
return Double.doubleToLongBits(readLong());
}
public long readLong() throws IOException {
return ((readInt() & 0xffffffffl) << 32) | (readInt() & 0xffffffffl);
}
public char readChar() throws IOException {
return (char)readShort();
}
public int readUnsignedByte() throws IOException {
return readByte() & 0xff;
}
public int readUnsignedShort() throws IOException {
return readShort() & 0xffff;
}
public String readUTF() throws IOException {
int length = readUnsignedShort();
byte[] bytes = new byte[length];
readFully(bytes);
return new String(bytes, "UTF-8");
}
@Deprecated
public String readLine() throws IOException {
int c = read();
if (c < 0) {
return null;
} else if (c == '\n') {
return "";
}
StringBuilder builder = new StringBuilder();
for (;;) {
builder.append((char)c);
c = read();
if (c < 0 || c == '\n') {
return builder.toString();
}
}
}
public int skipBytes(int n) throws IOException {
for (int count = 0; count < n; ++count) {
if (read() < 0) {;
return count;
}
}
return n;
}
}

View File

@ -0,0 +1,28 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public interface DataOutput {
void write(byte[] b) throws IOException;
void write(byte[] b, int off, int len) throws IOException;
void write(int b) throws IOException;
void writeBoolean(boolean v) throws IOException;
void writeByte(int v) throws IOException;
void writeBytes(String s) throws IOException;
void writeChar(int v) throws IOException;
void writeChars(String s) throws IOException;
void writeDouble(double v) throws IOException;
void writeFloat(float v) throws IOException;
void writeInt(int v) throws IOException;
void writeLong(long v) throws IOException;
void writeShort(int v) throws IOException;
void writeUTF(String s) throws IOException;
}

View File

@ -0,0 +1,99 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class DataOutputStream extends OutputStream implements DataOutput {
private OutputStream out;
public DataOutputStream(OutputStream out) {
this.out = out;
}
public void close() throws IOException {
out.close();
}
public void flush() throws IOException {
out.flush();
}
public void write(byte[] buffer) throws IOException {
out.write(buffer);
}
public void write(byte[] buffer, int offset, int length) throws IOException {
out.write(buffer, offset, length);
}
public void write(int b) throws IOException {
out.write(b);
}
public void writeBoolean(boolean b) throws IOException {
writeByte(b ? 1 : 0);
}
public void writeByte(int b) throws IOException {
out.write(b);
}
public void writeShort(int s) throws IOException {
write((byte)(s >> 8));
write((byte)s);
}
public void writeInt(int i) throws IOException {
write((byte)(i >> 24));
write((byte)(i >> 16));
write((byte)(i >> 8));
write((byte)i);
}
public void writeFloat(float f) throws IOException {
writeInt(Float.floatToIntBits(f));
}
public void writeDouble(double d) throws IOException {
writeLong(Double.doubleToLongBits(d));
}
public void writeLong(long l) throws IOException {
write((byte)(l >> 56));
write((byte)(l >> 48));
write((byte)(l >> 40));
write((byte)(l >> 32));
write((byte)(l >> 24));
write((byte)(l >> 16));
write((byte)(l >> 8));
write((byte)l);
}
public void writeChar(int ch) throws IOException {
write((byte)(ch >> 8));
write((byte)ch);
}
public void writeChars(String s) throws IOException {
for (char ch : s.toCharArray()) {
writeChar(ch & 0xffff);
}
}
public void writeBytes(String s) throws IOException {
out.write(s.getBytes());
}
public void writeUTF(String s) throws IOException {
byte[] bytes = s.getBytes("UTF-8");
writeShort((short)bytes.length);
out.write(bytes);
}
}

View File

@ -0,0 +1,21 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class EOFException extends IOException {
public EOFException(String message) {
super(message);
}
public EOFException() {
this(null);
}
}

View File

@ -0,0 +1,16 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public interface Externalizable {
public void readExternal(ObjectInput in);
public void writeExternal(ObjectOutput out);
}

View File

@ -0,0 +1,335 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class File implements Serializable {
private static final String FileSeparator
= System.getProperty("file.separator");
private static final boolean IsWindows
= System.getProperty("os.name").equals("Windows");
public static final String separator = FileSeparator;
public static final char separatorChar = FileSeparator.charAt(0);
private static final String PathSeparator
= System.getProperty("path.separator");
public static final String pathSeparator = PathSeparator;
public static final char pathSeparatorChar = PathSeparator.charAt(0);
// static {
// System.loadLibrary("natives");
// }
private final String path;
public File(String path) {
if (path == null) throw new NullPointerException();
this.path = normalize(path);
}
public File(String parent, String child) {
this(parent + FileSeparator + child);
}
public File(File parent, String child) {
this(parent.getPath() + FileSeparator + child);
}
public static File createTempFile(String prefix, String suffix)
throws IOException
{
return createTempFile(prefix, suffix, null);
}
public static File createTempFile(String prefix, String suffix,
File directory)
throws IOException
{
if(directory == null) {
directory = new File(System.getProperty("java.io.tmpdir"));
}
if(suffix == null) {
suffix = ".tmp";
}
File ret;
long state = System.currentTimeMillis();
do {
ret = generateFile(directory, prefix, state, suffix);
state *= 7;
state += 3;
} while(ret == null);
ret.createNewFile();
return ret;
}
private static File generateFile(File directory, String prefix, long state, String suffix) {
File ret = new File(directory, prefix + state + suffix);
if(ret.exists()) {
return null;
} else {
return ret;
}
}
private static String stripSeparators(String p) {
while (p.endsWith(FileSeparator)) {
p = p.substring(0, p.length() - 1);
}
return p;
}
private static String normalize(String path) {
if(IsWindows
&& path.length() > 2
&& path.charAt(0) == '/'
&& path.charAt(2) == ':')
{
// remove a leading slash on Windows
path = path.substring(1);
}
return stripSeparators
("\\".equals(FileSeparator) ? path.replace('/', '\\') : path);
}
public static native boolean rename(String old, String new_);
public boolean renameTo(File newName) {
return rename(path, newName.path);
}
private static native boolean isDirectory(String path);
public boolean isDirectory() {
return isDirectory(path);
}
private static native boolean isFile(String path);
public boolean isFile() {
return isFile(path);
}
public boolean isAbsolute() {
return path.equals(toAbsolutePath(path));
}
private static native boolean canRead(String path);
public boolean canRead() {
return canRead(path);
}
private static native boolean canWrite(String path);
public boolean canWrite() {
return canWrite(path);
}
private static native boolean canExecute(String path);
public boolean canExecute() {
return canExecute(path);
}
private static native boolean setExecutable(String path, boolean executable, boolean ownerOnly);
public boolean setExecutable(boolean executable) {
return setExecutable(executable, true);
}
public boolean setExecutable(boolean executable, boolean ownerOnly) {
return setExecutable(path, executable, ownerOnly);
}
public String getName() {
int index = path.lastIndexOf(FileSeparator);
if (index >= 0) {
return path.substring(index + 1);
} else {
return path;
}
}
public String toString() {
return getPath();
}
public String getPath() {
return path;
}
public String getParent() {
int index = path.lastIndexOf(FileSeparator);
if (index >= 0) {
return normalize(path.substring(0, index));
} else {
return null;
}
}
public File getParentFile() {
String s = getParent();
return (s == null ? null : new File(s));
}
private static native String toCanonicalPath(String path);
public String getCanonicalPath() {
return toCanonicalPath(path);
}
public File getCanonicalFile() {
return new File(getCanonicalPath());
}
private static native String toAbsolutePath(String path);
public String getAbsolutePath() {
return toAbsolutePath(path);
}
public File getAbsoluteFile() {
return new File(getAbsolutePath());
}
private static native long length(String path);
public long length() {
return length(path);
}
private static native boolean exists(String path);
public boolean exists() {
return exists(path);
}
private static native void mkdir(String path) throws IOException;
public boolean mkdir() {
try {
mkdir(path);
return true;
} catch (IOException e) {
return false;
}
}
private static native boolean createNewFile(String path) throws IOException;
public boolean createNewFile() throws IOException {
return createNewFile(path);
}
public static native void delete(String path) throws IOException;
public boolean delete() {
try {
delete(path);
return true;
} catch (IOException e) {
return false;
}
}
public boolean mkdirs() {
File parent = getParentFile();
if (parent != null) {
if (!parent.exists()) {
if (!parent.mkdirs()) {
return false;
}
}
}
return mkdir();
}
public File[] listFiles() {
return listFiles(null);
}
public File[] listFiles(FilenameFilter filter) {
String[] list = list(filter);
if (list != null) {
File[] result = new File[list.length];
for (int i = 0; i < list.length; ++i) {
result[i] = new File(this, list[i]);
}
return result;
} else {
return null;
}
}
public String[] list() {
return list(null);
}
public String[] list(FilenameFilter filter) {
long handle = 0;
try {
handle = openDir(path);
if (handle != 0) {
Pair list = null;
int count = 0;
for (String s = readDir(handle); s != null; s = readDir(handle)) {
if (filter == null || filter.accept(this, s)) {
list = new Pair(s, list);
++ count;
}
}
String[] result = new String[count];
for (int i = count - 1; i >= 0; --i) {
result[i] = list.value;
list = list.next;
}
return result;
} else {
return null;
}
} finally {
if (handle != 0) {
closeDir(handle);
}
}
}
public long lastModified() {
return lastModified(path);
}
private static native long openDir(String path);
private static native long lastModified(String path);
private static native String readDir(long handle);
private static native void closeDir(long handle);
private static class Pair {
public final String value;
public final Pair next;
public Pair(String value, Pair next) {
this.value = value;
this.next = next;
}
}
}

View File

@ -0,0 +1,27 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class FileDescriptor {
public static final FileDescriptor in = new FileDescriptor(0);
public static final FileDescriptor out = new FileDescriptor(1);
public static final FileDescriptor err = new FileDescriptor(2);
final int value;
public FileDescriptor(int value) {
this.value = value;
}
public FileDescriptor() {
this(-1);
}
}

View File

@ -0,0 +1,77 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class FileInputStream extends InputStream {
// static {
// System.loadLibrary("natives");
// }
private int fd;
private int remaining;
public FileInputStream(FileDescriptor fd) {
this.fd = fd.value;
}
public FileInputStream(String path) throws IOException {
fd = open(path);
remaining = (int) new File(path).length();
}
public FileInputStream(File file) throws IOException {
this(file.getPath());
}
public int available() throws IOException {
return remaining;
}
private static native int open(String path) throws IOException;
private static native int read(int fd) throws IOException;
private static native int read(int fd, byte[] b, int offset, int length)
throws IOException;
public static native void close(int fd) throws IOException;
public int read() throws IOException {
int c = read(fd);
if (c >= 0 && remaining > 0) {
-- remaining;
}
return c;
}
public int read(byte[] b, int offset, int length) throws IOException {
if (b == null) {
throw new NullPointerException();
}
if (offset < 0 || offset + length > b.length) {
throw new ArrayIndexOutOfBoundsException();
}
int c = read(fd, b, offset, length);
if (c > 0 && remaining > 0) {
remaining -= c;
}
return c;
}
public void close() throws IOException {
if (fd != -1) {
close(fd);
fd = -1;
}
}
}

View File

@ -0,0 +1,21 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class FileNotFoundException extends IOException {
public FileNotFoundException(String message) {
super(message);
}
public FileNotFoundException() {
this(null);
}
}

View File

@ -0,0 +1,68 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class FileOutputStream extends OutputStream {
// static {
// System.loadLibrary("natives");
// }
private int fd;
public FileOutputStream(FileDescriptor fd) {
this.fd = fd.value;
}
public FileOutputStream(String path) throws IOException {
this(path, false);
}
public FileOutputStream(String path, boolean append) throws IOException {
fd = open(path, append);
}
public FileOutputStream(File file) throws IOException {
this(file.getPath());
}
private static native int open(String path, boolean append) throws IOException;
private static native void write(int fd, int c) throws IOException;
private static native void write(int fd, byte[] b, int offset, int length)
throws IOException;
private static native void close(int fd) throws IOException;
public void write(int c) throws IOException {
write(fd, c);
}
public void write(byte[] b, int offset, int length) throws IOException {
if (b == null) {
throw new NullPointerException();
}
if (offset < 0 || offset + length > b.length) {
throw new ArrayIndexOutOfBoundsException();
}
write(fd, b, offset, length);
}
public void close() throws IOException {
if (fd != -1) {
close(fd);
fd = -1;
}
}
}

View File

@ -0,0 +1,39 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class FileReader extends Reader {
private final Reader in;
public FileReader(FileInputStream in) {
this.in = new InputStreamReader(in);
}
public FileReader(FileDescriptor fd) {
this(new FileInputStream(fd));
}
public FileReader(String path) throws IOException {
this(new FileInputStream(path));
}
public FileReader(File file) throws IOException {
this(new FileInputStream(file));
}
public int read(char[] b, int offset, int length) throws IOException {
return in.read(b, offset, length);
}
public void close() throws IOException {
in.close();
}
}

View File

@ -0,0 +1,43 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class FileWriter extends Writer {
private final Writer out;
private FileWriter(FileOutputStream out) {
this.out = new OutputStreamWriter(out);
}
public FileWriter(FileDescriptor fd) {
this(new FileOutputStream(fd));
}
public FileWriter(String path) throws IOException {
this(new FileOutputStream(path));
}
public FileWriter(File file) throws IOException {
this(new FileOutputStream(file));
}
public void write(char[] b, int offset, int length) throws IOException {
out.write(b, offset, length);
}
public void flush() throws IOException {
out.flush();
}
public void close() throws IOException {
out.close();
}
}

View File

@ -0,0 +1,17 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public interface FilenameFilter {
boolean accept(File dir, String name);
}

View File

@ -0,0 +1,35 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class FilterInputStream extends InputStream {
protected InputStream in;
public FilterInputStream(InputStream in) {
this.in = in;
}
public void close() throws IOException {
in.close();
}
public int read(byte[] b) throws IOException {
return in.read(b);
}
public int read(byte[] b, int off, int len) throws IOException {
return in.read(b, off, len);
}
public int read() throws IOException {
return in.read();
}
}

View File

@ -0,0 +1,40 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class FilterOutputStream extends OutputStream {
protected OutputStream out;
public FilterOutputStream(OutputStream out) {
this.out = out;
}
public void close() throws IOException {
out.close();
}
public void flush() throws IOException {
out.flush();
}
public void write(byte[] b) throws IOException {
out.write(b);
}
public void write(byte[] b, int off, int len) throws IOException {
out.write(b, off, len);
}
public void write(int b) throws IOException {
out.write(b);
}
}

View File

@ -0,0 +1,51 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public abstract class FilterReader extends Reader {
protected Reader in;
protected FilterReader(Reader in) {
this.in = in;
}
public int read() throws IOException {
return in.read();
}
public int read(char[] buffer, int offset, int length) throws IOException {
return in.read(buffer, offset, length);
}
public boolean ready() throws IOException {
throw new UnsupportedOperationException();
}
public long skip(long n) throws IOException {
throw new UnsupportedOperationException();
}
public void close() throws IOException {
in.close();
}
public boolean markSupported() {
return in.markSupported();
}
public void mark(int readAheadLimit) throws IOException {
in.mark(readAheadLimit);
}
public void reset() throws IOException {
in.reset();
}
}

View File

@ -0,0 +1,16 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public interface Flushable {
void flush()
throws IOException;
}

View File

@ -0,0 +1,29 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class IOException extends Exception {
public IOException(String message, Throwable cause) {
super(message, cause);
}
public IOException(String message) {
this(message, null);
}
public IOException(Throwable cause) {
this(null, cause);
}
public IOException() {
this(null, null);
}
}

View File

@ -0,0 +1,67 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public abstract class InputStream implements Closeable {
public abstract int read() throws IOException;
public int read(byte[] buffer) throws IOException {
return read(buffer, 0, buffer.length);
}
public int read(byte[] buffer, int offset, int length) throws IOException {
for (int i = 0; i < length; ++i) {
int c = read();
if (c == -1) {
if (i == 0) {
return -1;
} else {
return i;
}
} else {
buffer[offset + i] = (byte) (c & 0xFF);
}
}
return length;
}
public long skip(long count) throws IOException {
final long Max = 8 * 1024;
int size = (int) (count < Max ? count : Max);
byte[] buffer = new byte[size];
long remaining = count;
int c;
while ((c = read(buffer, 0, (int) (size < remaining ? size : remaining)))
>= 0
&& remaining > 0) {
remaining -= c;
}
return count - remaining;
}
public int available() throws IOException {
return 0;
}
public void mark(int limit) {
// ignore
}
public void reset() throws IOException {
throw new IOException("mark/reset not supported");
}
public boolean markSupported() {
return false;
}
public void close() throws IOException { }
}

View File

@ -0,0 +1,92 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
import avian.Utf8;
public class InputStreamReader extends Reader {
private static final int MultibytePadding = 4;
private final InputStream in;
public InputStreamReader(InputStream in) {
this.in = in;
}
public InputStreamReader(InputStream in, String encoding)
throws UnsupportedEncodingException
{
this(in);
if (! encoding.equals("UTF-8")) {
throw new UnsupportedEncodingException(encoding);
}
}
public int read(char[] b, int offset, int length) throws IOException {
if (length == 0) {
return 0;
}
byte[] buffer = new byte[length + MultibytePadding];
int bufferLength = length;
int bufferOffset = 0;
while (true) {
int c = in.read(buffer, bufferOffset, bufferLength);
if (c <= 0) {
if (bufferOffset > 0) {
// if we've reached the end of the stream while trying to
// read a multibyte character, we still need to return any
// competely-decoded characters, plus \ufffd to indicate an
// unknown character
c = 1;
while (bufferOffset > 0) {
char[] buffer16 = Utf8.decode16(buffer, 0, bufferOffset);
if (buffer16 != null) {
System.arraycopy(buffer16, 0, b, offset, buffer16.length);
c = buffer16.length + 1;
break;
} else {
-- bufferOffset;
}
}
b[offset + c - 1] = '\ufffd';
}
return c;
}
bufferOffset += c;
char[] buffer16 = Utf8.decode16(buffer, 0, bufferOffset);
if (buffer16 != null) {
bufferOffset = 0;
System.arraycopy(buffer16, 0, b, offset, buffer16.length);
return buffer16.length;
} else {
// the buffer ended in an incomplete multibyte character, so
// we try to read a another byte at a time until it's complete
bufferLength = 1;
}
}
}
public void close() throws IOException {
in.close();
}
}

View File

@ -0,0 +1,41 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class LineNumberReader extends BufferedReader {
private int line;
public LineNumberReader(Reader in, int bufferSize) {
super(in, bufferSize);
}
public LineNumberReader(Reader in) {
super(in);
}
public int getLineNumber() {
return line;
}
public void setLineNumber(int v) {
line = v;
}
public int read(char[] b, int offset, int length) throws IOException {
int c = super.read(b, offset, length);
for (int i = 0; i < c; ++i) {
if (b[i] == '\n') {
++ line;
}
}
return c;
}
}

View File

@ -0,0 +1,21 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class NotSerializableException extends ObjectStreamException {
public NotSerializableException(String message) {
super(message);
}
public NotSerializableException() {
this(null);
}
}

View File

@ -0,0 +1,21 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public interface ObjectInput {
public int available();
public void close();
public void read();
public void read(byte[] b);
public void read(byte[] b, int off, int len);
public Object readObject();
public long skip(long n);
}

View File

@ -0,0 +1,443 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
import static java.io.ObjectOutputStream.STREAM_MAGIC;
import static java.io.ObjectOutputStream.STREAM_VERSION;
import static java.io.ObjectOutputStream.TC_NULL;
import static java.io.ObjectOutputStream.TC_REFERENCE;
import static java.io.ObjectOutputStream.TC_CLASSDESC;
import static java.io.ObjectOutputStream.TC_OBJECT;
import static java.io.ObjectOutputStream.TC_STRING;
import static java.io.ObjectOutputStream.TC_ARRAY;
import static java.io.ObjectOutputStream.TC_CLASS;
import static java.io.ObjectOutputStream.TC_BLOCKDATA;
import static java.io.ObjectOutputStream.TC_ENDBLOCKDATA;
import static java.io.ObjectOutputStream.TC_RESET;
import static java.io.ObjectOutputStream.TC_BLOCKDATALONG;
import static java.io.ObjectOutputStream.TC_EXCEPTION;
import static java.io.ObjectOutputStream.TC_LONGSTRING;
import static java.io.ObjectOutputStream.TC_PROXYCLASSDESC;
import static java.io.ObjectOutputStream.TC_ENUM;
import static java.io.ObjectOutputStream.SC_WRITE_METHOD;
import static java.io.ObjectOutputStream.SC_BLOCK_DATA;
import static java.io.ObjectOutputStream.SC_SERIALIZABLE;
import static java.io.ObjectOutputStream.SC_EXTERNALIZABLE;
import static java.io.ObjectOutputStream.SC_ENUM;
import static java.io.ObjectOutputStream.getReadOrWriteMethod;
import avian.VMClass;
import java.util.ArrayList;
import java.util.HashMap;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class ObjectInputStream extends InputStream implements DataInput {
private final static int HANDLE_OFFSET = 0x7e0000;
private final InputStream in;
private final ArrayList references;
public ObjectInputStream(InputStream in) throws IOException {
this.in = in;
short signature = (short)rawShort();
if (signature != STREAM_MAGIC) {
throw new IOException("Unrecognized signature: 0x"
+ Integer.toHexString(signature));
}
int version = rawShort();
if (version != STREAM_VERSION) {
throw new IOException("Unsupported version: " + version);
}
references = new ArrayList();
}
public int read() throws IOException {
return in.read();
}
private int rawByte() throws IOException {
int c = read();
if (c < 0) {
throw new EOFException();
}
return c;
}
private int rawShort() throws IOException {
return (rawByte() << 8) | rawByte();
}
private int rawInt() throws IOException {
return (rawShort() << 16) | rawShort();
}
private long rawLong() throws IOException {
return ((rawInt() & 0xffffffffl) << 32) | rawInt();
}
private String rawString() throws IOException {
int length = rawShort();
byte[] array = new byte[length];
readFully(array);
return new String(array);
}
public int read(byte[] b, int offset, int length) throws IOException {
return in.read(b, offset, length);
}
public void readFully(byte[] b) throws IOException {
readFully(b, 0, b.length);
}
public void readFully(byte[] b, int offset, int length) throws IOException {
while (length > 0) {
int count = read(b, offset, length);
if (count < 0) {
throw new EOFException("Reached EOF " + length + " bytes too early");
}
offset += count;
length -= count;
}
}
public String readLine() throws IOException {
int c = read();
if (c < 0) {
return null;
} else if (c == '\n') {
return "";
}
StringBuilder builder = new StringBuilder();
for (;;) {
builder.append((char)c);
c = read();
if (c < 0 || c == '\n') {
return builder.toString();
}
}
}
public void close() throws IOException {
in.close();
}
private int remainingBlockData;
private int rawBlockDataByte() throws IOException {
while (remainingBlockData <= 0) {
int b = rawByte();
if (b == TC_BLOCKDATA) {
remainingBlockData = rawByte();
} else {
throw new UnsupportedOperationException("Unknown token: 0x"
+ Integer.toHexString(b));
}
}
--remainingBlockData;
return rawByte();
}
private int rawBlockDataShort() throws IOException {
return (rawBlockDataByte() << 8) | rawBlockDataByte();
}
private int rawBlockDataInt() throws IOException {
return (rawBlockDataShort() << 16) | rawBlockDataShort();
}
private long rawBlockDataLong() throws IOException {
return ((rawBlockDataInt() & 0xffffffffl) << 32) | rawBlockDataInt();
}
public boolean readBoolean() throws IOException {
return rawBlockDataByte() != 0;
}
public byte readByte() throws IOException {
return (byte)rawBlockDataByte();
}
public char readChar() throws IOException {
return (char)rawBlockDataShort();
}
public short readShort() throws IOException {
return (short)rawBlockDataShort();
}
public int readInt() throws IOException {
return rawBlockDataInt();
}
public long readLong() throws IOException {
return rawBlockDataLong();
}
public float readFloat() throws IOException {
return Float.intBitsToFloat(rawBlockDataInt());
}
public double readDouble() throws IOException {
return Double.longBitsToDouble(rawBlockDataLong());
}
public int readUnsignedByte() throws IOException {
return rawBlockDataByte();
}
public int readUnsignedShort() throws IOException {
return rawBlockDataShort();
}
public String readUTF() throws IOException {
int length = rawBlockDataShort();
if (remainingBlockData < length) {
throw new IOException("Short block data: "
+ remainingBlockData + " < " + length);
}
byte[] bytes = new byte[length];
readFully(bytes);
remainingBlockData -= length;
return new String(bytes, "UTF-8");
}
public int skipBytes(int count) throws IOException {
int i = 0;
while (i < count) {
if (read() < 0) {
return i;
}
++i;
}
return count;
}
private static Class charToPrimitiveType(int c) {
if (c == 'B') {
return Byte.TYPE;
} else if (c == 'C') {
return Character.TYPE;
} else if (c == 'D') {
return Double.TYPE;
} else if (c == 'F') {
return Float.TYPE;
} else if (c == 'I') {
return Integer.TYPE;
} else if (c == 'J') {
return Long.TYPE;
} else if (c == 'S') {
return Short.TYPE;
} else if (c == 'Z') {
return Boolean.TYPE;
}
throw new RuntimeException("Unhandled char: " + (char)c);
}
private void expectToken(int token) throws IOException {
int c = rawByte();
if (c != token) {
throw new UnsupportedOperationException("Unexpected token: 0x"
+ Integer.toHexString(c));
}
}
private void field(Field field, Object o)
throws IOException, IllegalArgumentException, IllegalAccessException,
ClassNotFoundException
{
Class type = field.getType();
if (!type.isPrimitive()) {
field.set(o, readObject());
} else {
if (type == Byte.TYPE) {
field.setByte(o, (byte)rawByte());
} else if (type == Character.TYPE) {
field.setChar(o, (char)rawShort());
} else if (type == Double.TYPE) {
field.setDouble(o, Double.longBitsToDouble(rawLong()));
} else if (type == Float.TYPE) {
field.setFloat(o, Float.intBitsToFloat(rawInt()));
} else if (type == Integer.TYPE) {
field.setInt(o, rawInt());
} else if (type == Long.TYPE) {
field.setLong(o, rawLong());
} else if (type == Short.TYPE) {
field.setShort(o, (short)rawShort());
} else if (type == Boolean.TYPE) {
field.setBoolean(o, rawByte() != 0);
} else {
throw new IOException("Unhandled type: " + type);
}
}
}
public Object readObject() throws IOException, ClassNotFoundException {
int c = rawByte();
if (c == TC_NULL) {
return null;
}
if (c == TC_STRING) {
int length = rawShort();
byte[] bytes = new byte[length];
readFully(bytes);
String s = new String(bytes, "UTF-8");
references.add(s);
return s;
}
if (c == TC_REFERENCE) {
int handle = rawInt();
return references.get(handle - HANDLE_OFFSET);
}
if (c != TC_OBJECT) {
throw new IOException("Unexpected token: 0x"
+ Integer.toHexString(c));
}
// class desc
c = rawByte();
ClassDesc classDesc;
if (c == TC_REFERENCE) {
int handle = rawInt() - HANDLE_OFFSET;
classDesc = (ClassDesc)references.get(handle);
} else if (c == TC_CLASSDESC) {
classDesc = classDesc();
} else {
throw new UnsupportedOperationException("Unexpected token: 0x"
+ Integer.toHexString(c));
}
try {
Object o = makeInstance(classDesc.clazz.vmClass);
references.add(o);
do {
Object o1 = classDesc.clazz.cast(o);
boolean customized = (classDesc.flags & SC_WRITE_METHOD) != 0;
Method readMethod = customized ?
getReadOrWriteMethod(o, "readObject") : null;
if (readMethod == null) {
if (customized) {
throw new IOException("Could not find required readObject method "
+ "in " + classDesc.clazz);
}
defaultReadObject(o, classDesc.fields);
} else {
current = o1;
currentFields = classDesc.fields;
readMethod.invoke(o, this);
current = null;
currentFields = null;
expectToken(TC_ENDBLOCKDATA);
}
} while ((classDesc = classDesc.superClassDesc) != null);
return o;
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new IOException(e);
}
}
private static class ClassDesc {
Class clazz;
int flags;
Field[] fields;
ClassDesc superClassDesc;
}
private ClassDesc classDesc() throws ClassNotFoundException, IOException {
ClassDesc result = new ClassDesc();
String className = rawString();
ClassLoader loader = Thread.currentThread().getContextClassLoader();
result.clazz = loader.loadClass(className);
long serialVersionUID = rawLong();
try {
Field field = result.clazz.getField("serialVersionUID");
long expected = field.getLong(null);
if (expected != serialVersionUID) {
throw new IOException("Incompatible serial version UID: 0x"
+ Long.toHexString(serialVersionUID) + " != 0x"
+ Long.toHexString(expected));
}
} catch (Exception ignored) { }
references.add(result);
result.flags = rawByte();
if ((result.flags & ~(SC_SERIALIZABLE | SC_WRITE_METHOD)) != 0) {
throw new UnsupportedOperationException("Cannot handle flags: 0x"
+ Integer.toHexString(result.flags));
}
int fieldCount = rawShort();
result.fields = new Field[fieldCount];
for (int i = 0; i < result.fields.length; i++) {
int typeChar = rawByte();
String fieldName = rawString();
try {
result.fields[i] = result.clazz.getDeclaredField(fieldName);
} catch (Exception e) {
throw new IOException(e);
}
Class type;
if (typeChar == '[' || typeChar == 'L') {
String typeName = (String)readObject();
if (typeName.startsWith("L") && typeName.endsWith(";")) {
typeName = typeName.substring(1, typeName.length() - 1)
.replace('/', '.');
}
type = loader.loadClass(typeName);
} else {
type = charToPrimitiveType(typeChar);
}
if (result.fields[i].getType() != type) {
throw new IOException("Unexpected type of field " + fieldName
+ ": expected " + result.fields[i].getType() + " but got " + type);
}
}
expectToken(TC_ENDBLOCKDATA);
int c = rawByte();
if (c == TC_CLASSDESC) {
result.superClassDesc = classDesc();
} else if (c != TC_NULL) {
throw new UnsupportedOperationException("Unexpected token: 0x"
+ Integer.toHexString(c));
}
return result;
}
private Object current;
private Field[] currentFields;
public void defaultReadObject() throws IOException {
defaultReadObject(current, currentFields);
}
private void defaultReadObject(Object o, Field[] fields) throws IOException {
try {
for (Field field : fields) {
field(field, o);
}
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new IOException(e);
}
}
private static native Object makeInstance(VMClass c);
}

View File

@ -0,0 +1,20 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public interface ObjectOutput {
public void close();
public void flush();
public void write(byte[] b);
public void write(byte[] b, int off, int len);
public void write(int b);
public void writeObject(Object obj);
}

View File

@ -0,0 +1,337 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
import java.util.ArrayList;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class ObjectOutputStream extends OutputStream implements DataOutput {
final static short STREAM_MAGIC = (short)0xaced;
final static short STREAM_VERSION = 5;
final static byte TC_NULL = (byte)0x70;
final static byte TC_REFERENCE = (byte)0x71;
final static byte TC_CLASSDESC = (byte)0x72;
final static byte TC_OBJECT = (byte)0x73;
final static byte TC_STRING = (byte)0x74;
final static byte TC_ARRAY = (byte)0x75;
final static byte TC_CLASS = (byte)0x76;
final static byte TC_BLOCKDATA = (byte)0x77;
final static byte TC_ENDBLOCKDATA = (byte)0x78;
final static byte TC_RESET = (byte)0x79;
final static byte TC_BLOCKDATALONG = (byte)0x7a;
final static byte TC_EXCEPTION = (byte)0x7b;
final static byte TC_LONGSTRING = (byte)0x7c;
final static byte TC_PROXYCLASSDESC = (byte)0x7d;
final static byte TC_ENUM = (byte)0x7e;
final static byte SC_WRITE_METHOD = 0x01; //if SC_SERIALIZABLE
final static byte SC_BLOCK_DATA = 0x08; //if SC_EXTERNALIZABLE
final static byte SC_SERIALIZABLE = 0x02;
final static byte SC_EXTERNALIZABLE = 0x04;
final static byte SC_ENUM = 0x10;
private final OutputStream out;
public ObjectOutputStream(OutputStream out) throws IOException {
this.out = out;
rawShort(STREAM_MAGIC);
rawShort(STREAM_VERSION);
}
public void write(int c) throws IOException {
out.write(c);
}
public void write(byte[] b, int offset, int length) throws IOException {
out.write(b, offset, length);
}
public void flush() throws IOException {
out.flush();
}
public void close() throws IOException {
out.close();
}
private void rawByte(int v) throws IOException {
out.write((byte)(v & 0xff));
}
private void rawShort(int v) throws IOException {
rawByte(v >> 8);
rawByte(v);
}
private void rawInt(int v) throws IOException {
rawShort(v >> 16);
rawShort(v);
}
private void rawLong(long v) throws IOException {
rawInt((int)(v >> 32));
rawInt((int)(v & 0xffffffffl));
}
private void blockData(int... bytes) throws IOException {
blockData(bytes, null, null);
}
private void blockData(int[] bytes, byte[] bytes2, char[] chars) throws IOException {
int count = (bytes == null ? 0 : bytes.length)
+ (bytes2 == null ? 0 : bytes2.length)
+ (chars == null ? 0 : chars.length * 2);
if (count < 0x100) {
rawByte(TC_BLOCKDATA);
rawByte(count);
} else {
rawByte(TC_BLOCKDATALONG);
rawInt(count);
}
if (bytes != null) {
for (int b : bytes) {
rawByte(b);
}
}
if (bytes2 != null) {
for (byte b : bytes2) {
rawByte(b & 0xff);
}
}
if (chars != null) {
for (char c : chars) {
rawShort((short)c);
}
}
}
public void writeBoolean(boolean v) throws IOException {
blockData(v ? 1 : 0);
}
public void writeByte(int v) throws IOException {
blockData(v);
}
public void writeShort(int v) throws IOException {
blockData(v >> 8, v);
}
public void writeChar(int v) throws IOException {
blockData(v >> 8, v);
}
public void writeInt(int v) throws IOException {
blockData(v >> 24, v >> 16, v >> 8, v);
}
public void writeLong(long v) throws IOException {
int u = (int)(v >> 32), l = (int)(v & 0xffffffff);
blockData(u >> 24, u >> 16, u >> 8, u, l >> 24, l >> 16, l >> 8, l);
}
public void writeFloat(float v) throws IOException {
writeInt(Float.floatToIntBits(v));
}
public void writeDouble(double v) throws IOException {
writeLong(Double.doubleToLongBits(v));
}
public void writeBytes(String s) throws IOException {
blockData(null, s.getBytes(), null);
}
public void writeChars(String s) throws IOException {
blockData(null, null, s.toCharArray());
}
public void writeUTF(String s) throws IOException {
byte[] bytes = s.getBytes();
int length = bytes.length;
blockData(new int[] { length >> 8, length }, bytes, null);
}
private int classHandle;
private void string(String s) throws IOException {
int length = s.length();
rawShort(length);
for (byte b : s.getBytes()) {
rawByte(b);
}
}
private static char primitiveTypeChar(Class type) {
if (type == Byte.TYPE) {
return 'B';
} else if (type == Character.TYPE) {
return 'C';
} else if (type == Double.TYPE) {
return 'D';
} else if (type == Float.TYPE) {
return 'F';
} else if (type == Integer.TYPE) {
return 'I';
} else if (type == Long.TYPE) {
return 'J';
} else if (type == Short.TYPE) {
return 'S';
} else if (type == Boolean.TYPE) {
return 'Z';
}
throw new RuntimeException("Unhandled primitive type: " + type);
}
private void classDesc(Class clazz, int scFlags) throws IOException {
rawByte(TC_CLASSDESC);
// class name
string(clazz.getName());
// serial version UID
long serialVersionUID = 1l;
try {
Field field = clazz.getField("serialVersionUID");
serialVersionUID = field.getLong(null);
} catch (Exception ignored) {}
rawLong(serialVersionUID);
// handle
rawByte(SC_SERIALIZABLE | scFlags);
Field[] fields = getFields(clazz);
rawShort(fields.length);
for (Field field : fields) {
Class fieldType = field.getType();
if (fieldType.isPrimitive()) {
rawByte(primitiveTypeChar(fieldType));
string(field.getName());
} else {
rawByte(fieldType.isArray() ? '[' : 'L');
string(field.getName());
rawByte(TC_STRING);
string("L" + fieldType.getName().replace('.', '/') + ";");
}
}
rawByte(TC_ENDBLOCKDATA); // TODO: write annotation
rawByte(TC_NULL); // super class desc
}
private void field(Object o, Field field) throws IOException {
try {
field.setAccessible(true);
Class type = field.getType();
if (!type.isPrimitive()) {
writeObject(field.get(o));
} else if (type == Byte.TYPE) {
rawByte(field.getByte(o));
} else if (type == Character.TYPE) {
char c = field.getChar(o);
rawShort((short)c);
} else if (type == Double.TYPE) {
double d = field.getDouble(o);
rawLong(Double.doubleToLongBits(d));
} else if (type == Float.TYPE) {
float f = field.getFloat(o);
rawInt(Float.floatToIntBits(f));
} else if (type == Integer.TYPE) {
int i = field.getInt(o);
rawInt(i);
} else if (type == Long.TYPE) {
long l = field.getLong(o);
rawLong(l);
} else if (type == Short.TYPE) {
short s = field.getShort(o);
rawShort(s);
} else if (type == Boolean.TYPE) {
boolean b = field.getBoolean(o);
rawByte(b ? 1 : 0);
} else {
throw new UnsupportedOperationException("Field '" + field.getName()
+ "' has unsupported type: " + type);
}
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new IOException(e);
}
}
private static Field[] getFields(Class clazz) {
ArrayList<Field> list = new ArrayList<Field>();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (0 == (field.getModifiers() &
(Modifier.STATIC | Modifier.TRANSIENT))) {
list.add(field);
}
}
return list.toArray(new Field[list.size()]);
}
public void writeObject(Object o) throws IOException {
if (o == null) {
rawByte(TC_NULL);
return;
}
if (o instanceof String) {
byte[] bytes = ((String)o).getBytes("UTF-8");
rawByte(TC_STRING);
rawShort(bytes.length);
write(bytes);
return;
}
rawByte(TC_OBJECT);
Method writeObject = getReadOrWriteMethod(o, "writeObject");
if (writeObject == null) {
classDesc(o.getClass(), 0);
defaultWriteObject(o);
} else try {
classDesc(o.getClass(), SC_WRITE_METHOD);
current = o;
writeObject.invoke(o, this);
current = null;
rawByte(TC_ENDBLOCKDATA);
} catch (Exception e) {
throw new IOException(e);
}
}
static Method getReadOrWriteMethod(Object o, String methodName) {
try {
Method method = o.getClass().getDeclaredMethod(methodName,
new Class[] { methodName.startsWith("write") ?
ObjectOutputStream.class : ObjectInputStream.class });
method.setAccessible(true);
int modifiers = method.getModifiers();
if ((modifiers & Modifier.STATIC) == 0 ||
(modifiers & Modifier.PRIVATE) != 0) {
return method;
}
} catch (NoSuchMethodException ignored) { }
return null;
}
private Object current;
public void defaultWriteObject() throws IOException {
defaultWriteObject(current);
}
private void defaultWriteObject(Object o) throws IOException {
for (Field field : getFields(o.getClass())) {
field(o, field);
}
}
}

View File

@ -0,0 +1,21 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class ObjectStreamException extends IOException {
public ObjectStreamException(String message) {
super(message);
}
public ObjectStreamException() {
this(null);
}
}

View File

@ -0,0 +1,29 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public abstract class OutputStream implements Closeable, Flushable {
public abstract void write(int c) throws IOException;
public void write(byte[] buffer) throws IOException {
write(buffer, 0, buffer.length);
}
public void write(byte[] buffer, int offset, int length) throws IOException {
for (int i = 0; i < length; ++i) {
write(buffer[offset + i]);
}
}
public void flush() throws IOException { }
public void close() throws IOException { }
}

View File

@ -0,0 +1,33 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
import avian.Utf8;
public class OutputStreamWriter extends Writer {
private final OutputStream out;
public OutputStreamWriter(OutputStream out) {
this.out = out;
}
public void write(char[] b, int offset, int length) throws IOException {
out.write(Utf8.encode(b, offset, length));
}
public void flush() throws IOException {
out.flush();
}
public void close() throws IOException {
out.close();
}
}

View File

@ -0,0 +1,170 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class PrintStream extends OutputStream {
private final OutputStream out;
private final boolean autoFlush;
private static class Static {
private static final byte[] newline
= System.getProperty("line.separator").getBytes();
}
public PrintStream(OutputStream out, boolean autoFlush) {
this.out = out;
this.autoFlush = autoFlush;
}
public PrintStream(OutputStream out, boolean autoFlush, String encoding)
throws UnsupportedEncodingException
{
this.out = out;
this.autoFlush = autoFlush;
if (! (encoding.equals("UTF-8") || encoding.equals("ISO-8859-1"))) {
throw new UnsupportedEncodingException(encoding);
}
}
public PrintStream(OutputStream out) {
this(out, false);
}
public synchronized void print(String s) {
try {
out.write(s.getBytes());
if (autoFlush) flush();
} catch (IOException e) { }
}
public void print(Object o) {
print(String.valueOf(o));
}
public void print(boolean v) {
print(String.valueOf(v));
}
public void print(char c) {
print(String.valueOf(c));
}
public void print(int v) {
print(String.valueOf(v));
}
public void print(long v) {
print(String.valueOf(v));
}
public void print(float v) {
print(String.valueOf(v));
}
public void print(double v) {
print(String.valueOf(v));
}
public void print(char[] s) {
print(String.valueOf(s));
}
public synchronized PrintStream printf(java.util.Locale locale, String format, Object... args) {
// should this be cached in an instance variable??
final java.util.Formatter formatter = new java.util.Formatter(this);
formatter.format(locale, format, args);
return this;
}
public synchronized PrintStream printf(String format, Object... args) {
final java.util.Formatter formatter = new java.util.Formatter(this);
formatter.format(format, args);
return this;
}
public PrintStream format(String format, Object... args) {
return printf(format, args);
}
public PrintStream format(java.util.Locale locale, String format, Object... args) {
return printf(locale, format, args);
}
public synchronized void println(String s) {
try {
out.write(s.getBytes());
out.write(Static.newline);
if (autoFlush) flush();
} catch (IOException e) { }
}
public synchronized void println() {
try {
out.write(Static.newline);
if (autoFlush) flush();
} catch (IOException e) { }
}
public void println(Object o) {
println(String.valueOf(o));
}
public void println(boolean v) {
println(String.valueOf(v));
}
public void println(char c) {
println(String.valueOf(c));
}
public void println(int v) {
println(String.valueOf(v));
}
public void println(long v) {
println(String.valueOf(v));
}
public void println(float v) {
println(String.valueOf(v));
}
public void println(double v) {
println(String.valueOf(v));
}
public void println(char[] s) {
println(String.valueOf(s));
}
public void write(int c) throws IOException {
out.write(c);
if (autoFlush && c == '\n') flush();
}
public void write(byte[] buffer, int offset, int length) throws IOException {
out.write(buffer, offset, length);
if (autoFlush) flush();
}
public void flush() {
try {
out.flush();
} catch (IOException e) { }
}
public void close() {
try {
out.close();
} catch (IOException e) { }
}
}

View File

@ -0,0 +1,90 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class PrintWriter extends Writer {
private static final char[] newline
= System.getProperty("line.separator").toCharArray();
private final Writer out;
private final boolean autoFlush;
public PrintWriter(Writer out, boolean autoFlush) {
this.out = out;
this.autoFlush = autoFlush;
}
public PrintWriter(Writer out) {
this(out, false);
}
public PrintWriter(OutputStream out, boolean autoFlush) {
this(new OutputStreamWriter(out), autoFlush);
}
public PrintWriter(OutputStream out) {
this(out, false);
}
public synchronized void print(String s) {
try {
out.write(s.toCharArray());
} catch (IOException e) { }
}
public void print(Object o) {
print(o.toString());
}
public void print(char c) {
print(String.valueOf(c));
}
public synchronized void println(String s) {
try {
out.write(s.toCharArray());
out.write(newline);
if (autoFlush) flush();
} catch (IOException e) { }
}
public synchronized void println() {
try {
out.write(newline);
if (autoFlush) flush();
} catch (IOException e) { }
}
public void println(Object o) {
println(o.toString());
}
public void println(char c) {
println(String.valueOf(c));
}
public void write(char[] buffer, int offset, int length) throws IOException {
out.write(buffer, offset, length);
if (autoFlush) flush();
}
public void flush() {
try {
out.flush();
} catch (IOException e) { }
}
public void close() {
try {
out.close();
} catch (IOException e) { }
}
}

View File

@ -0,0 +1,74 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class PushbackReader extends Reader {
private final Reader in;
private char savedChar;
private boolean hasSavedChar;
public PushbackReader(Reader in, int bufferSize) {
if (bufferSize > 1) {
throw new IllegalArgumentException(bufferSize + " > 1");
}
this.in = in;
this.hasSavedChar = false;
}
public PushbackReader(Reader in) {
this(in, 1);
}
public int read(char[] b, int offset, int length) throws IOException {
int count = 0;
if (hasSavedChar && length > 0) {
length--;
b[offset++] = savedChar;
hasSavedChar = false;
count = 1;
}
if (length > 0) {
int c = in.read(b, offset, length);
if (c == -1) {
if (count == 0) {
count = -1;
}
} else {
count += c;
}
}
return count;
}
public void unread(char[] b, int offset, int length) throws IOException {
if (length != 1) {
throw new IOException("Can only push back 1 char, not " + length);
} else if (hasSavedChar) {
throw new IOException("Already have a saved char");
} else {
hasSavedChar = true;
savedChar = b[offset];
}
}
public void unread(char[] b) throws IOException {
unread(b, 0, b.length);
}
public void unread(int c) throws IOException {
unread(new char[] { (char) c });
}
public void close() throws IOException {
in.close();
}
}

View File

@ -0,0 +1,282 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
import java.lang.IllegalArgumentException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class RandomAccessFile implements DataInput, Closeable {
private long peer;
private File file;
private long position = 0;
private long length;
private boolean allowWrite;
public RandomAccessFile(String name, String mode)
throws FileNotFoundException
{
this(new File(name), mode);
}
public RandomAccessFile(File file, String mode)
throws FileNotFoundException
{
if (file == null) throw new NullPointerException();
if (mode.equals("rw")) allowWrite = true;
else if (! mode.equals("r")) throw new IllegalArgumentException();
this.file = file;
open();
}
private void open() throws FileNotFoundException {
long[] result = new long[2];
open(file.getPath(), allowWrite, result);
peer = result[0];
length = result[1];
}
private static native void open(String name, boolean allowWrite, long[] result)
throws FileNotFoundException;
private void refresh() throws IOException {
if (file.length() != length) {
close();
open();
}
}
public long length() throws IOException {
refresh();
return length;
}
public long getFilePointer() throws IOException {
return position;
}
public void seek(long position) throws IOException {
if (position < 0 || (!allowWrite && position > length())) throw new IOException();
this.position = position;
}
public int skipBytes(int count) throws IOException {
if (position + count > length()) throw new IOException();
this.position = position + count;
return count;
}
public int read(byte b[], int off, int len) throws IOException {
if(b == null)
throw new IllegalArgumentException();
if (peer == 0)
throw new IOException();
if(len == 0)
return 0;
if (position + len > this.length)
throw new EOFException();
if (off < 0 || off + len > b.length)
throw new ArrayIndexOutOfBoundsException();
int bytesRead = readBytes(peer, position, b, off, len);
position += bytesRead;
return bytesRead;
}
public int read(byte b[]) throws IOException {
if(b == null)
throw new IllegalArgumentException();
if (peer == 0)
throw new IOException();
if(b.length == 0)
return 0;
if (position + b.length > this.length)
throw new EOFException();
int bytesRead = readBytes(peer, position, b, 0, b.length);
position += bytesRead;
return bytesRead;
}
public void readFully(byte b[], int off, int len) throws IOException {
if (b == null)
throw new IllegalArgumentException();
if (peer == 0)
throw new IOException();
if(len == 0)
return;
if (position + len > this.length)
throw new EOFException();
if (off < 0 || off + len > b.length)
throw new ArrayIndexOutOfBoundsException();
int n = 0;
do {
int count = readBytes(peer, position, b, off + n, len - n);
position += count;
if (count == 0)
throw new EOFException();
n += count;
} while (n < len);
}
public void readFully(byte b[]) throws IOException {
readFully(b, 0, b.length);
}
private static native int readBytes(long peer, long position, byte[] buffer,
int offset, int length);
public boolean readBoolean() throws IOException {
return readByte() != 0;
}
public int read() throws IOException {
try {
return readByte() & 0xff;
} catch (final EOFException e) {
return -1;
}
}
public byte readByte() throws IOException {
final byte[] buffer = new byte[1];
readFully(buffer);
return buffer[0];
}
public short readShort() throws IOException {
final byte[] buffer = new byte[2];
readFully(buffer);
return (short)((buffer[0] << 8) | buffer[1]);
}
public int readInt() throws IOException {
byte[] buf = new byte[4];
readFully(buf);
return ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);
}
public float readFloat() throws IOException {
return Float.floatToIntBits(readInt());
}
public double readDouble() throws IOException {
return Double.doubleToLongBits(readLong());
}
public long readLong() throws IOException {
return ((readInt() & 0xffffffffl) << 32) | (readInt() & 0xffffffffl);
}
public char readChar() throws IOException {
return (char)readShort();
}
public int readUnsignedByte() throws IOException {
return readByte() & 0xff;
}
public int readUnsignedShort() throws IOException {
return readShort() & 0xffff;
}
public String readUTF() throws IOException {
int length = readUnsignedShort();
byte[] bytes = new byte[length];
readFully(bytes);
return new String(bytes, "UTF-8");
}
@Deprecated
public String readLine() throws IOException {
int c = read();
if (c < 0) {
return null;
} else if (c == '\n') {
return "";
}
StringBuilder builder = new StringBuilder();
for (;;) {
builder.append((char)c);
c = read();
if (c < 0 || c == '\n') {
return builder.toString();
}
}
}
public void write(int b) throws IOException {
int count = writeBytes(peer, position, new byte[] { (byte)b }, 0, 1);
if (count > 0) position += count;
}
private static native int writeBytes(long peer, long position, byte[] buffer,
int offset, int length);
public void close() throws IOException {
if (peer != 0) {
close(peer);
peer = 0;
}
}
private static native void close(long peer);
public FileChannel getChannel() {
return new FileChannel() {
public void close() {
if (peer != 0) RandomAccessFile.close(peer);
}
public boolean isOpen() {
return peer != 0;
}
public int read(ByteBuffer dst, long position) throws IOException {
if (!dst.hasArray()) throw new IOException("Cannot handle " + dst.getClass());
// TODO: this needs to be synchronized on the Buffer, no?
byte[] array = dst.array();
return readBytes(peer, position, array, dst.position(), dst.remaining());
}
public int read(ByteBuffer dst) throws IOException {
int count = read(dst, position);
if (count > 0) position += count;
return count;
}
public int write(ByteBuffer src, long position) throws IOException {
if (!src.hasArray()) throw new IOException("Cannot handle " + src.getClass());
byte[] array = src.array();
return writeBytes(peer, position, array, src.position(), src.remaining());
}
public int write(ByteBuffer src) throws IOException {
int count = write(src, position);
if (count > 0) position += count;
return count;
}
public long position() throws IOException {
return getFilePointer();
}
public FileChannel position(long position) throws IOException {
seek(position);
return this;
}
public long size() throws IOException {
return length();
}
};
}
}

View File

@ -0,0 +1,58 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
import java.nio.CharBuffer;
public abstract class Reader implements Closeable, Readable {
public int read(CharBuffer buffer) throws IOException {
int c = read(buffer.array(),
buffer.arrayOffset() + buffer.position(),
buffer.remaining());
if (c > 0) {
buffer.position(buffer.position() + c);
}
return c;
}
public int read() throws IOException {
char[] buffer = new char[1];
int c = read(buffer);
if (c <= 0) {
return -1;
} else {
return (int) buffer[0];
}
}
public int read(char[] buffer) throws IOException {
return read(buffer, 0, buffer.length);
}
public abstract int read(char[] buffer, int offset, int length)
throws IOException;
public boolean markSupported() {
return false;
}
public void mark(int readAheadLimit) throws IOException {
throw new IOException("mark not supported");
}
public void reset() throws IOException {
throw new IOException("reset not supported");
}
public abstract void close() throws IOException;
}

View File

@ -0,0 +1,13 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public interface Serializable { }

View File

@ -0,0 +1,21 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class StreamCorruptedException extends IOException {
public StreamCorruptedException(String message) {
super(message);
}
public StreamCorruptedException() {
this(null);
}
}

View File

@ -0,0 +1,34 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class StringReader extends Reader {
private final String in;
private int position = 0;
public StringReader(String in) {
this.in = in;
}
public int read(char[] b, int offset, int length) throws IOException {
if (length > in.length() - position) {
length = in.length() - position;
if (length <= 0) {
return -1;
}
}
in.getChars(position, position+length, b, offset);
position += length;
return length;
}
public void close() throws IOException { }
}

View File

@ -0,0 +1,31 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class StringWriter extends Writer {
private final StringBuffer out = new StringBuffer();
public void write(char[] b, int offset, int length) throws IOException {
out.append(b, offset, length);
}
public String toString() {
return out.toString();
}
public void flush() throws IOException { }
public void close() throws IOException { }
public StringBuffer getBuffer() {
return out;
}
}

View File

@ -0,0 +1,21 @@
/* Copyright (c) 2008-2015, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class UTFDataFormatException extends IOException {
public UTFDataFormatException(String s) {
super(s);
}
public UTFDataFormatException() {
super();
}
}

Some files were not shown because too many files have changed in this diff Show More