8187443: Forest Consolidation: Move files to unified layout

Reviewed-by: darcy, ihse
This commit is contained in:
Erik Joelsson 2017-09-12 19:03:39 +02:00
parent 270fe13182
commit 3789983e89
56923 changed files with 3 additions and 15727 deletions

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio;
import java.nio.ByteBuffer;
import java.io.IOException;
/** This is an interface to adapt existing APIs to use {@link java.nio.ByteBuffer
* ByteBuffers} as the underlying
* data format. Only the initial producer and final consumer have to be changed.<p>
*
* For example, the Zip/Jar code supports {@link java.io.InputStream InputStreams}.
* To make the Zip code use {@link java.nio.MappedByteBuffer MappedByteBuffers} as
* the underlying data structure, it can create a class of InputStream that wraps the ByteBuffer,
* and implements the ByteBuffered interface. A co-operating class several layers
* away can ask the InputStream if it is an instance of ByteBuffered, then
* call the {@link #getByteBuffer()} method.
*/
public interface ByteBuffered {
/**
* Returns the {@code ByteBuffer} behind this object, if this particular
* instance has one. An implementation of {@code getByteBuffer()} is allowed
* to return {@code null} for any reason.
*
* @return The {@code ByteBuffer}, if this particular instance has one,
* or {@code null} otherwise.
*
* @throws IOException
* If the ByteBuffer is no longer valid.
*
* @since 1.5
*/
public ByteBuffer getByteBuffer() throws IOException;
}

View file

@ -0,0 +1,84 @@
/*
* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
/**
* Manipulates a native array of pollfd structs.
*
* @author Mike McCloskey
* @since 1.4
*/
public abstract class AbstractPollArrayWrapper {
// Miscellaneous constants
static final short SIZE_POLLFD = 8;
static final short FD_OFFSET = 0;
static final short EVENT_OFFSET = 4;
static final short REVENT_OFFSET = 6;
// The poll fd array
protected AllocatedNativeObject pollArray;
// Number of valid entries in the pollArray
protected int totalChannels = 0;
// Base address of the native pollArray
protected long pollArrayAddress;
// Access methods for fd structures
int getEventOps(int i) {
int offset = SIZE_POLLFD * i + EVENT_OFFSET;
return pollArray.getShort(offset);
}
int getReventOps(int i) {
int offset = SIZE_POLLFD * i + REVENT_OFFSET;
return pollArray.getShort(offset);
}
int getDescriptor(int i) {
int offset = SIZE_POLLFD * i + FD_OFFSET;
return pollArray.getInt(offset);
}
void putEventOps(int i, int event) {
int offset = SIZE_POLLFD * i + EVENT_OFFSET;
pollArray.putShort(offset, (short)event);
}
void putReventOps(int i, int revent) {
int offset = SIZE_POLLFD * i + REVENT_OFFSET;
pollArray.putShort(offset, (short)revent);
}
void putDescriptor(int i, int fd) {
int offset = SIZE_POLLFD * i + FD_OFFSET;
pollArray.putInt(offset, fd);
}
}

View file

@ -0,0 +1,195 @@
/*
* Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.io.IOException;
import java.nio.channels.*;
import java.nio.channels.spi.*;
import java.util.*;
/**
* An abstract selector impl.
*/
abstract class AbstractPollSelectorImpl
extends SelectorImpl
{
// The poll fd array
PollArrayWrapper pollWrapper;
// Initial capacity of the pollfd array
protected final int INIT_CAP = 10;
// The list of SelectableChannels serviced by this Selector
protected SelectionKeyImpl[] channelArray;
// In some impls the first entry of channelArray is bogus
protected int channelOffset = 0;
// The number of valid channels in this Selector's poll array
protected int totalChannels;
// True if this Selector has been closed
private boolean closed = false;
// Lock for close and cleanup
private Object closeLock = new Object();
AbstractPollSelectorImpl(SelectorProvider sp, int channels, int offset) {
super(sp);
this.totalChannels = channels;
this.channelOffset = offset;
}
public void putEventOps(SelectionKeyImpl sk, int ops) {
synchronized (closeLock) {
if (closed)
throw new ClosedSelectorException();
pollWrapper.putEventOps(sk.getIndex(), ops);
}
}
public Selector wakeup() {
pollWrapper.interrupt();
return this;
}
protected abstract int doSelect(long timeout) throws IOException;
protected void implClose() throws IOException {
synchronized (closeLock) {
if (closed)
return;
closed = true;
// Deregister channels
for(int i=channelOffset; i<totalChannels; i++) {
SelectionKeyImpl ski = channelArray[i];
assert(ski.getIndex() != -1);
ski.setIndex(-1);
deregister(ski);
SelectableChannel selch = channelArray[i].channel();
if (!selch.isOpen() && !selch.isRegistered())
((SelChImpl)selch).kill();
}
implCloseInterrupt();
pollWrapper.free();
pollWrapper = null;
selectedKeys = null;
channelArray = null;
totalChannels = 0;
}
}
protected abstract void implCloseInterrupt() throws IOException;
/**
* Copy the information in the pollfd structs into the opss
* of the corresponding Channels. Add the ready keys to the
* ready queue.
*/
protected int updateSelectedKeys() {
int numKeysUpdated = 0;
// Skip zeroth entry; it is for interrupts only
for (int i=channelOffset; i<totalChannels; i++) {
int rOps = pollWrapper.getReventOps(i);
if (rOps != 0) {
SelectionKeyImpl sk = channelArray[i];
pollWrapper.putReventOps(i, 0);
if (selectedKeys.contains(sk)) {
if (sk.channel.translateAndSetReadyOps(rOps, sk)) {
numKeysUpdated++;
}
} else {
sk.channel.translateAndSetReadyOps(rOps, sk);
if ((sk.nioReadyOps() & sk.nioInterestOps()) != 0) {
selectedKeys.add(sk);
numKeysUpdated++;
}
}
}
}
return numKeysUpdated;
}
protected void implRegister(SelectionKeyImpl ski) {
synchronized (closeLock) {
if (closed)
throw new ClosedSelectorException();
// Check to see if the array is large enough
if (channelArray.length == totalChannels) {
// Make a larger array
int newSize = pollWrapper.totalChannels * 2;
SelectionKeyImpl temp[] = new SelectionKeyImpl[newSize];
// Copy over
for (int i=channelOffset; i<totalChannels; i++)
temp[i] = channelArray[i];
channelArray = temp;
// Grow the NativeObject poll array
pollWrapper.grow(newSize);
}
channelArray[totalChannels] = ski;
ski.setIndex(totalChannels);
pollWrapper.addEntry(ski.channel);
totalChannels++;
keys.add(ski);
}
}
protected void implDereg(SelectionKeyImpl ski) throws IOException {
// Algorithm: Copy the sc from the end of the list and put it into
// the location of the sc to be removed (since order doesn't
// matter). Decrement the sc count. Update the index of the sc
// that is moved.
int i = ski.getIndex();
assert (i >= 0);
if (i != totalChannels - 1) {
// Copy end one over it
SelectionKeyImpl endChannel = channelArray[totalChannels-1];
channelArray[i] = endChannel;
endChannel.setIndex(i);
pollWrapper.release(i);
PollArrayWrapper.replaceEntry(pollWrapper, totalChannels - 1,
pollWrapper, i);
} else {
pollWrapper.release(i);
}
// Destroy the last one
channelArray[totalChannels-1] = null;
totalChannels--;
pollWrapper.totalChannels--;
ski.setIndex(-1);
// Remove the key from keys and selectedKeys
keys.remove(ski);
selectedKeys.remove(ski);
deregister((AbstractSelectionKey)ski);
SelectableChannel selch = ski.channel();
if (!selch.isOpen() && !selch.isRegistered())
((SelChImpl)selch).kill();
}
}

View file

@ -0,0 +1,66 @@
/*
* Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*/
package sun.nio.ch; // Formerly in sun.misc
// ## In the fullness of time, this class will be eliminated
class AllocatedNativeObject // package-private
extends NativeObject
{
/**
* Allocates a memory area of at least {@code size} bytes outside of the
* Java heap and creates a native object for that area.
*
* @param size
* Number of bytes to allocate
*
* @param pageAligned
* If {@code true} then the area will be aligned on a hardware
* page boundary
*
* @throws OutOfMemoryError
* If the request cannot be satisfied
*/
AllocatedNativeObject(int size, boolean pageAligned) {
super(size, pageAligned);
}
/**
* Frees the native memory area associated with this object.
*/
synchronized void free() {
if (allocationAddress != 0) {
unsafe.freeMemory(allocationAddress);
allocationAddress = 0;
}
}
}

View file

@ -0,0 +1,341 @@
/*
* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.nio.channels.Channel;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.channels.spi.AsynchronousChannelProvider;
import java.io.IOException;
import java.io.FileDescriptor;
import java.util.Queue;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicBoolean;
import java.security.PrivilegedAction;
import java.security.AccessController;
import java.security.AccessControlContext;
import sun.security.action.GetIntegerAction;
/**
* Base implementation of AsynchronousChannelGroup
*/
abstract class AsynchronousChannelGroupImpl
extends AsynchronousChannelGroup implements Executor
{
// number of internal threads handling I/O events when using an unbounded
// thread pool. Internal threads do not dispatch to completion handlers.
private static final int internalThreadCount = AccessController.doPrivileged(
new GetIntegerAction("sun.nio.ch.internalThreadPoolSize", 1));
// associated thread pool
private final ThreadPool pool;
// number of tasks running (including internal)
private final AtomicInteger threadCount = new AtomicInteger();
// associated Executor for timeouts
private ScheduledThreadPoolExecutor timeoutExecutor;
// task queue for when using a fixed thread pool. In that case, thread
// waiting on I/O events must be awokon to poll tasks from this queue.
private final Queue<Runnable> taskQueue;
// group shutdown
private final AtomicBoolean shutdown = new AtomicBoolean();
private final Object shutdownNowLock = new Object();
private volatile boolean terminateInitiated;
AsynchronousChannelGroupImpl(AsynchronousChannelProvider provider,
ThreadPool pool)
{
super(provider);
this.pool = pool;
if (pool.isFixedThreadPool()) {
taskQueue = new ConcurrentLinkedQueue<>();
} else {
taskQueue = null; // not used
}
// use default thread factory as thread should not be visible to
// application (it doesn't execute completion handlers).
this.timeoutExecutor = (ScheduledThreadPoolExecutor)
Executors.newScheduledThreadPool(1, ThreadPool.defaultThreadFactory());
this.timeoutExecutor.setRemoveOnCancelPolicy(true);
}
final ExecutorService executor() {
return pool.executor();
}
final boolean isFixedThreadPool() {
return pool.isFixedThreadPool();
}
final int fixedThreadCount() {
if (isFixedThreadPool()) {
return pool.poolSize();
} else {
return pool.poolSize() + internalThreadCount;
}
}
private Runnable bindToGroup(final Runnable task) {
final AsynchronousChannelGroupImpl thisGroup = this;
return new Runnable() {
public void run() {
Invoker.bindToGroup(thisGroup);
task.run();
}
};
}
private void startInternalThread(final Runnable task) {
AccessController.doPrivileged(new PrivilegedAction<>() {
@Override
public Void run() {
// internal threads should not be visible to application so
// cannot use user-supplied thread factory
ThreadPool.defaultThreadFactory().newThread(task).start();
return null;
}
});
}
protected final void startThreads(Runnable task) {
if (!isFixedThreadPool()) {
for (int i=0; i<internalThreadCount; i++) {
startInternalThread(task);
threadCount.incrementAndGet();
}
}
if (pool.poolSize() > 0) {
task = bindToGroup(task);
try {
for (int i=0; i<pool.poolSize(); i++) {
pool.executor().execute(task);
threadCount.incrementAndGet();
}
} catch (RejectedExecutionException x) {
// nothing we can do
}
}
}
final int threadCount() {
return threadCount.get();
}
/**
* Invoked by tasks as they terminate
*/
final int threadExit(Runnable task, boolean replaceMe) {
if (replaceMe) {
try {
if (Invoker.isBoundToAnyGroup()) {
// submit new task to replace this thread
pool.executor().execute(bindToGroup(task));
} else {
// replace internal thread
startInternalThread(task);
}
return threadCount.get();
} catch (RejectedExecutionException x) {
// unable to replace
}
}
return threadCount.decrementAndGet();
}
/**
* Wakes up a thread waiting for I/O events to execute the given task.
*/
abstract void executeOnHandlerTask(Runnable task);
/**
* For a fixed thread pool the task is queued to a thread waiting on I/O
* events. For other thread pools we simply submit the task to the thread
* pool.
*/
final void executeOnPooledThread(Runnable task) {
if (isFixedThreadPool()) {
executeOnHandlerTask(task);
} else {
pool.executor().execute(bindToGroup(task));
}
}
final void offerTask(Runnable task) {
taskQueue.offer(task);
}
final Runnable pollTask() {
return (taskQueue == null) ? null : taskQueue.poll();
}
final Future<?> schedule(Runnable task, long timeout, TimeUnit unit) {
try {
return timeoutExecutor.schedule(task, timeout, unit);
} catch (RejectedExecutionException rej) {
if (terminateInitiated) {
// no timeout scheduled as group is terminating
return null;
}
throw new AssertionError(rej);
}
}
@Override
public final boolean isShutdown() {
return shutdown.get();
}
@Override
public final boolean isTerminated() {
return pool.executor().isTerminated();
}
/**
* Returns true if there are no channels in the group
*/
abstract boolean isEmpty();
/**
* Attaches a foreign channel to this group.
*/
abstract Object attachForeignChannel(Channel channel, FileDescriptor fdo)
throws IOException;
/**
* Detaches a foreign channel from this group.
*/
abstract void detachForeignChannel(Object key);
/**
* Closes all channels in the group
*/
abstract void closeAllChannels() throws IOException;
/**
* Shutdown all tasks waiting for I/O events.
*/
abstract void shutdownHandlerTasks();
private void shutdownExecutors() {
AccessController.doPrivileged(
new PrivilegedAction<>() {
public Void run() {
pool.executor().shutdown();
timeoutExecutor.shutdown();
return null;
}
},
null,
new RuntimePermission("modifyThread"));
}
@Override
public final void shutdown() {
if (shutdown.getAndSet(true)) {
// already shutdown
return;
}
// if there are channels in the group then shutdown will continue
// when the last channel is closed
if (!isEmpty()) {
return;
}
// initiate termination (acquire shutdownNowLock to ensure that other
// threads invoking shutdownNow will block).
synchronized (shutdownNowLock) {
if (!terminateInitiated) {
terminateInitiated = true;
shutdownHandlerTasks();
shutdownExecutors();
}
}
}
@Override
public final void shutdownNow() throws IOException {
shutdown.set(true);
synchronized (shutdownNowLock) {
if (!terminateInitiated) {
terminateInitiated = true;
closeAllChannels();
shutdownHandlerTasks();
shutdownExecutors();
}
}
}
/**
* For use by AsynchronousFileChannel to release resources without shutting
* down the thread pool.
*/
final void detachFromThreadPool() {
if (shutdown.getAndSet(true))
throw new AssertionError("Already shutdown");
if (!isEmpty())
throw new AssertionError("Group not empty");
shutdownHandlerTasks();
}
@Override
public final boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException
{
return pool.executor().awaitTermination(timeout, unit);
}
/**
* Executes the given command on one of the channel group's pooled threads.
*/
@Override
public final void execute(Runnable task) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
// when a security manager is installed then the user's task
// must be run with the current calling context
final AccessControlContext acc = AccessController.getContext();
final Runnable delegate = task;
task = new Runnable() {
@Override
public void run() {
AccessController.doPrivileged(new PrivilegedAction<>() {
@Override
public Void run() {
delegate.run();
return null;
}
}, acc);
}
};
}
executeOnPooledThread(task);
}
}

View file

@ -0,0 +1,253 @@
/*
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.locks.*;
import java.io.FileDescriptor;
import java.io.IOException;
/**
* Base implementation of AsynchronousFileChannel.
*/
abstract class AsynchronousFileChannelImpl
extends AsynchronousFileChannel
{
// close support
protected final ReadWriteLock closeLock = new ReentrantReadWriteLock();
protected volatile boolean closed;
// file descriptor
protected final FileDescriptor fdObj;
// indicates if open for reading/writing
protected final boolean reading;
protected final boolean writing;
// associated Executor
protected final ExecutorService executor;
protected AsynchronousFileChannelImpl(FileDescriptor fdObj,
boolean reading,
boolean writing,
ExecutorService executor)
{
this.fdObj = fdObj;
this.reading = reading;
this.writing = writing;
this.executor = executor;
}
final ExecutorService executor() {
return executor;
}
@Override
public final boolean isOpen() {
return !closed;
}
/**
* Marks the beginning of an I/O operation.
*
* @throws ClosedChannelException If channel is closed
*/
protected final void begin() throws IOException {
closeLock.readLock().lock();
if (closed)
throw new ClosedChannelException();
}
/**
* Marks the end of an I/O operation.
*/
protected final void end() {
closeLock.readLock().unlock();
}
/**
* Marks end of I/O operation
*/
protected final void end(boolean completed) throws IOException {
end();
if (!completed && !isOpen())
throw new AsynchronousCloseException();
}
// -- file locking --
abstract <A> Future<FileLock> implLock(long position,
long size,
boolean shared,
A attachment,
CompletionHandler<FileLock,? super A> handler);
@Override
public final Future<FileLock> lock(long position,
long size,
boolean shared)
{
return implLock(position, size, shared, null, null);
}
@Override
public final <A> void lock(long position,
long size,
boolean shared,
A attachment,
CompletionHandler<FileLock,? super A> handler)
{
if (handler == null)
throw new NullPointerException("'handler' is null");
implLock(position, size, shared, attachment, handler);
}
private volatile FileLockTable fileLockTable;
final void ensureFileLockTableInitialized() throws IOException {
if (fileLockTable == null) {
synchronized (this) {
if (fileLockTable == null) {
fileLockTable = FileLockTable.newSharedFileLockTable(this, fdObj);
}
}
}
}
final void invalidateAllLocks() throws IOException {
if (fileLockTable != null) {
for (FileLock fl: fileLockTable.removeAll()) {
synchronized (fl) {
if (fl.isValid()) {
FileLockImpl fli = (FileLockImpl)fl;
implRelease(fli);
fli.invalidate();
}
}
}
}
}
/**
* Adds region to lock table
*/
protected final FileLockImpl addToFileLockTable(long position, long size, boolean shared) {
final FileLockImpl fli;
try {
// like begin() but returns null instead of exception
closeLock.readLock().lock();
if (closed)
return null;
try {
ensureFileLockTableInitialized();
} catch (IOException x) {
// should not happen
throw new AssertionError(x);
}
fli = new FileLockImpl(this, position, size, shared);
// may throw OverlappedFileLockException
fileLockTable.add(fli);
} finally {
end();
}
return fli;
}
protected final void removeFromFileLockTable(FileLockImpl fli) {
fileLockTable.remove(fli);
}
/**
* Releases the given file lock.
*/
protected abstract void implRelease(FileLockImpl fli) throws IOException;
/**
* Invoked by FileLockImpl to release the given file lock and remove it
* from the lock table.
*/
final void release(FileLockImpl fli) throws IOException {
try {
begin();
implRelease(fli);
removeFromFileLockTable(fli);
} finally {
end();
}
}
// -- reading and writing --
abstract <A> Future<Integer> implRead(ByteBuffer dst,
long position,
A attachment,
CompletionHandler<Integer,? super A> handler);
@Override
public final Future<Integer> read(ByteBuffer dst, long position) {
return implRead(dst, position, null, null);
}
@Override
public final <A> void read(ByteBuffer dst,
long position,
A attachment,
CompletionHandler<Integer,? super A> handler)
{
if (handler == null)
throw new NullPointerException("'handler' is null");
implRead(dst, position, attachment, handler);
}
abstract <A> Future<Integer> implWrite(ByteBuffer src,
long position,
A attachment,
CompletionHandler<Integer,? super A> handler);
@Override
public final Future<Integer> write(ByteBuffer src, long position) {
return implWrite(src, position, null, null);
}
@Override
public final <A> void write(ByteBuffer src,
long position,
A attachment,
CompletionHandler<Integer,? super A> handler)
{
if (handler == null)
throw new NullPointerException("'handler' is null");
implWrite(src, position, attachment, handler);
}
}

View file

@ -0,0 +1,263 @@
/*
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.nio.channels.*;
import java.net.SocketAddress;
import java.net.SocketOption;
import java.net.StandardSocketOptions;
import java.net.InetSocketAddress;
import java.io.FileDescriptor;
import java.io.IOException;
import java.util.Set;
import java.util.HashSet;
import java.util.Collections;
import java.util.concurrent.Future;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import sun.net.NetHooks;
/**
* Base implementation of AsynchronousServerSocketChannel.
*/
abstract class AsynchronousServerSocketChannelImpl
extends AsynchronousServerSocketChannel
implements Cancellable, Groupable
{
protected final FileDescriptor fd;
// the local address to which the channel's socket is bound
protected volatile InetSocketAddress localAddress;
// need this lock to set local address
private final Object stateLock = new Object();
// close support
private ReadWriteLock closeLock = new ReentrantReadWriteLock();
private volatile boolean closed;
// set true when accept operation is cancelled
private volatile boolean acceptKilled;
// set true when exclusive binding is on and SO_REUSEADDR is emulated
private boolean isReuseAddress;
AsynchronousServerSocketChannelImpl(AsynchronousChannelGroupImpl group) {
super(group.provider());
this.fd = Net.serverSocket(true);
}
@Override
public final boolean isOpen() {
return !closed;
}
/**
* Marks beginning of access to file descriptor/handle
*/
final void begin() throws IOException {
closeLock.readLock().lock();
if (!isOpen())
throw new ClosedChannelException();
}
/**
* Marks end of access to file descriptor/handle
*/
final void end() {
closeLock.readLock().unlock();
}
/**
* Invoked to close file descriptor/handle.
*/
abstract void implClose() throws IOException;
@Override
public final void close() throws IOException {
// synchronize with any threads using file descriptor/handle
closeLock.writeLock().lock();
try {
if (closed)
return; // already closed
closed = true;
} finally {
closeLock.writeLock().unlock();
}
implClose();
}
/**
* Invoked by accept to accept connection
*/
abstract Future<AsynchronousSocketChannel>
implAccept(Object attachment,
CompletionHandler<AsynchronousSocketChannel,Object> handler);
@Override
public final Future<AsynchronousSocketChannel> accept() {
return implAccept(null, null);
}
@Override
@SuppressWarnings("unchecked")
public final <A> void accept(A attachment,
CompletionHandler<AsynchronousSocketChannel,? super A> handler)
{
if (handler == null)
throw new NullPointerException("'handler' is null");
implAccept(attachment, (CompletionHandler<AsynchronousSocketChannel,Object>)handler);
}
final boolean isAcceptKilled() {
return acceptKilled;
}
@Override
public final void onCancel(PendingFuture<?,?> task) {
acceptKilled = true;
}
@Override
public final AsynchronousServerSocketChannel bind(SocketAddress local, int backlog)
throws IOException
{
InetSocketAddress isa = (local == null) ? new InetSocketAddress(0) :
Net.checkAddress(local);
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkListen(isa.getPort());
try {
begin();
synchronized (stateLock) {
if (localAddress != null)
throw new AlreadyBoundException();
NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
Net.bind(fd, isa.getAddress(), isa.getPort());
Net.listen(fd, backlog < 1 ? 50 : backlog);
localAddress = Net.localAddress(fd);
}
} finally {
end();
}
return this;
}
@Override
public final SocketAddress getLocalAddress() throws IOException {
if (!isOpen())
throw new ClosedChannelException();
return Net.getRevealedLocalAddress(localAddress);
}
@Override
public final <T> AsynchronousServerSocketChannel setOption(SocketOption<T> name,
T value)
throws IOException
{
if (name == null)
throw new NullPointerException();
if (!supportedOptions().contains(name))
throw new UnsupportedOperationException("'" + name + "' not supported");
try {
begin();
if (name == StandardSocketOptions.SO_REUSEADDR &&
Net.useExclusiveBind())
{
// SO_REUSEADDR emulated when using exclusive bind
isReuseAddress = (Boolean)value;
} else {
Net.setSocketOption(fd, Net.UNSPEC, name, value);
}
return this;
} finally {
end();
}
}
@Override
@SuppressWarnings("unchecked")
public final <T> T getOption(SocketOption<T> name) throws IOException {
if (name == null)
throw new NullPointerException();
if (!supportedOptions().contains(name))
throw new UnsupportedOperationException("'" + name + "' not supported");
try {
begin();
if (name == StandardSocketOptions.SO_REUSEADDR &&
Net.useExclusiveBind())
{
// SO_REUSEADDR emulated when using exclusive bind
return (T)Boolean.valueOf(isReuseAddress);
}
return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
} finally {
end();
}
}
private static class DefaultOptionsHolder {
static final Set<SocketOption<?>> defaultOptions = defaultOptions();
private static Set<SocketOption<?>> defaultOptions() {
HashSet<SocketOption<?>> set = new HashSet<>(2);
set.add(StandardSocketOptions.SO_RCVBUF);
set.add(StandardSocketOptions.SO_REUSEADDR);
if (Net.isReusePortAvailable()) {
set.add(StandardSocketOptions.SO_REUSEPORT);
}
return Collections.unmodifiableSet(set);
}
}
@Override
public final Set<SocketOption<?>> supportedOptions() {
return DefaultOptionsHolder.defaultOptions;
}
@Override
public final String toString() {
StringBuilder sb = new StringBuilder();
sb.append(this.getClass().getName());
sb.append('[');
if (!isOpen())
sb.append("closed");
else {
if (localAddress == null) {
sb.append("unbound");
} else {
sb.append(Net.getRevealedLocalAddressAsString(localAddress));
}
}
sb.append(']');
return sb.toString();
}
}

View file

@ -0,0 +1,608 @@
/*
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.net.SocketOption;
import java.net.StandardSocketOptions;
import java.net.SocketAddress;
import java.net.InetSocketAddress;
import java.io.IOException;
import java.io.FileDescriptor;
import java.util.Set;
import java.util.HashSet;
import java.util.Collections;
import java.util.concurrent.*;
import java.util.concurrent.locks.*;
import sun.net.NetHooks;
import sun.net.ext.ExtendedSocketOptions;
/**
* Base implementation of AsynchronousSocketChannel
*/
abstract class AsynchronousSocketChannelImpl
extends AsynchronousSocketChannel
implements Cancellable, Groupable
{
protected final FileDescriptor fd;
// protects state, localAddress, and remoteAddress
protected final Object stateLock = new Object();
protected volatile InetSocketAddress localAddress;
protected volatile InetSocketAddress remoteAddress;
// State, increases monotonically
static final int ST_UNINITIALIZED = -1;
static final int ST_UNCONNECTED = 0;
static final int ST_PENDING = 1;
static final int ST_CONNECTED = 2;
protected volatile int state = ST_UNINITIALIZED;
// reading state
private final Object readLock = new Object();
private boolean reading;
private boolean readShutdown;
private boolean readKilled; // further reading disallowed due to timeout
// writing state
private final Object writeLock = new Object();
private boolean writing;
private boolean writeShutdown;
private boolean writeKilled; // further writing disallowed due to timeout
// close support
private final ReadWriteLock closeLock = new ReentrantReadWriteLock();
private volatile boolean closed;
// set true when exclusive binding is on and SO_REUSEADDR is emulated
private boolean isReuseAddress;
AsynchronousSocketChannelImpl(AsynchronousChannelGroupImpl group)
throws IOException
{
super(group.provider());
this.fd = Net.socket(true);
this.state = ST_UNCONNECTED;
}
// Constructor for sockets obtained from AsynchronousServerSocketChannelImpl
AsynchronousSocketChannelImpl(AsynchronousChannelGroupImpl group,
FileDescriptor fd,
InetSocketAddress remote)
throws IOException
{
super(group.provider());
this.fd = fd;
this.state = ST_CONNECTED;
this.localAddress = Net.localAddress(fd);
this.remoteAddress = remote;
}
@Override
public final boolean isOpen() {
return !closed;
}
/**
* Marks beginning of access to file descriptor/handle
*/
final void begin() throws IOException {
closeLock.readLock().lock();
if (!isOpen())
throw new ClosedChannelException();
}
/**
* Marks end of access to file descriptor/handle
*/
final void end() {
closeLock.readLock().unlock();
}
/**
* Invoked to close socket and release other resources.
*/
abstract void implClose() throws IOException;
@Override
public final void close() throws IOException {
// synchronize with any threads initiating asynchronous operations
closeLock.writeLock().lock();
try {
if (closed)
return; // already closed
closed = true;
} finally {
closeLock.writeLock().unlock();
}
implClose();
}
final void enableReading(boolean killed) {
synchronized (readLock) {
reading = false;
if (killed)
readKilled = true;
}
}
final void enableReading() {
enableReading(false);
}
final void enableWriting(boolean killed) {
synchronized (writeLock) {
writing = false;
if (killed)
writeKilled = true;
}
}
final void enableWriting() {
enableWriting(false);
}
final void killReading() {
synchronized (readLock) {
readKilled = true;
}
}
final void killWriting() {
synchronized (writeLock) {
writeKilled = true;
}
}
final void killConnect() {
// when a connect is cancelled then the connection may have been
// established so prevent reading or writing.
killReading();
killWriting();
}
/**
* Invoked by connect to initiate the connect operation.
*/
abstract <A> Future<Void> implConnect(SocketAddress remote,
A attachment,
CompletionHandler<Void,? super A> handler);
@Override
public final Future<Void> connect(SocketAddress remote) {
return implConnect(remote, null, null);
}
@Override
public final <A> void connect(SocketAddress remote,
A attachment,
CompletionHandler<Void,? super A> handler)
{
if (handler == null)
throw new NullPointerException("'handler' is null");
implConnect(remote, attachment, handler);
}
/**
* Invoked by read to initiate the I/O operation.
*/
abstract <V extends Number,A> Future<V> implRead(boolean isScatteringRead,
ByteBuffer dst,
ByteBuffer[] dsts,
long timeout,
TimeUnit unit,
A attachment,
CompletionHandler<V,? super A> handler);
@SuppressWarnings("unchecked")
private <V extends Number,A> Future<V> read(boolean isScatteringRead,
ByteBuffer dst,
ByteBuffer[] dsts,
long timeout,
TimeUnit unit,
A att,
CompletionHandler<V,? super A> handler)
{
if (!isOpen()) {
Throwable e = new ClosedChannelException();
if (handler == null)
return CompletedFuture.withFailure(e);
Invoker.invoke(this, handler, att, null, e);
return null;
}
if (remoteAddress == null)
throw new NotYetConnectedException();
boolean hasSpaceToRead = isScatteringRead || dst.hasRemaining();
boolean shutdown = false;
// check and update state
synchronized (readLock) {
if (readKilled)
throw new IllegalStateException("Reading not allowed due to timeout or cancellation");
if (reading)
throw new ReadPendingException();
if (readShutdown) {
shutdown = true;
} else {
if (hasSpaceToRead) {
reading = true;
}
}
}
// immediately complete with -1 if shutdown for read
// immediately complete with 0 if no space remaining
if (shutdown || !hasSpaceToRead) {
Number result;
if (isScatteringRead) {
result = (shutdown) ? Long.valueOf(-1L) : Long.valueOf(0L);
} else {
result = (shutdown) ? -1 : 0;
}
if (handler == null)
return CompletedFuture.withResult((V)result);
Invoker.invoke(this, handler, att, (V)result, null);
return null;
}
return implRead(isScatteringRead, dst, dsts, timeout, unit, att, handler);
}
@Override
public final Future<Integer> read(ByteBuffer dst) {
if (dst.isReadOnly())
throw new IllegalArgumentException("Read-only buffer");
return read(false, dst, null, 0L, TimeUnit.MILLISECONDS, null, null);
}
@Override
public final <A> void read(ByteBuffer dst,
long timeout,
TimeUnit unit,
A attachment,
CompletionHandler<Integer,? super A> handler)
{
if (handler == null)
throw new NullPointerException("'handler' is null");
if (dst.isReadOnly())
throw new IllegalArgumentException("Read-only buffer");
read(false, dst, null, timeout, unit, attachment, handler);
}
@Override
public final <A> void read(ByteBuffer[] dsts,
int offset,
int length,
long timeout,
TimeUnit unit,
A attachment,
CompletionHandler<Long,? super A> handler)
{
if (handler == null)
throw new NullPointerException("'handler' is null");
if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
throw new IndexOutOfBoundsException();
ByteBuffer[] bufs = Util.subsequence(dsts, offset, length);
for (int i=0; i<bufs.length; i++) {
if (bufs[i].isReadOnly())
throw new IllegalArgumentException("Read-only buffer");
}
read(true, null, bufs, timeout, unit, attachment, handler);
}
/**
* Invoked by write to initiate the I/O operation.
*/
abstract <V extends Number,A> Future<V> implWrite(boolean isGatheringWrite,
ByteBuffer src,
ByteBuffer[] srcs,
long timeout,
TimeUnit unit,
A attachment,
CompletionHandler<V,? super A> handler);
@SuppressWarnings("unchecked")
private <V extends Number,A> Future<V> write(boolean isGatheringWrite,
ByteBuffer src,
ByteBuffer[] srcs,
long timeout,
TimeUnit unit,
A att,
CompletionHandler<V,? super A> handler)
{
boolean hasDataToWrite = isGatheringWrite || src.hasRemaining();
boolean closed = false;
if (isOpen()) {
if (remoteAddress == null)
throw new NotYetConnectedException();
// check and update state
synchronized (writeLock) {
if (writeKilled)
throw new IllegalStateException("Writing not allowed due to timeout or cancellation");
if (writing)
throw new WritePendingException();
if (writeShutdown) {
closed = true;
} else {
if (hasDataToWrite)
writing = true;
}
}
} else {
closed = true;
}
// channel is closed or shutdown for write
if (closed) {
Throwable e = new ClosedChannelException();
if (handler == null)
return CompletedFuture.withFailure(e);
Invoker.invoke(this, handler, att, null, e);
return null;
}
// nothing to write so complete immediately
if (!hasDataToWrite) {
Number result = (isGatheringWrite) ? (Number)0L : (Number)0;
if (handler == null)
return CompletedFuture.withResult((V)result);
Invoker.invoke(this, handler, att, (V)result, null);
return null;
}
return implWrite(isGatheringWrite, src, srcs, timeout, unit, att, handler);
}
@Override
public final Future<Integer> write(ByteBuffer src) {
return write(false, src, null, 0L, TimeUnit.MILLISECONDS, null, null);
}
@Override
public final <A> void write(ByteBuffer src,
long timeout,
TimeUnit unit,
A attachment,
CompletionHandler<Integer,? super A> handler)
{
if (handler == null)
throw new NullPointerException("'handler' is null");
write(false, src, null, timeout, unit, attachment, handler);
}
@Override
public final <A> void write(ByteBuffer[] srcs,
int offset,
int length,
long timeout,
TimeUnit unit,
A attachment,
CompletionHandler<Long,? super A> handler)
{
if (handler == null)
throw new NullPointerException("'handler' is null");
if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
throw new IndexOutOfBoundsException();
srcs = Util.subsequence(srcs, offset, length);
write(true, null, srcs, timeout, unit, attachment, handler);
}
@Override
public final AsynchronousSocketChannel bind(SocketAddress local)
throws IOException
{
try {
begin();
synchronized (stateLock) {
if (state == ST_PENDING)
throw new ConnectionPendingException();
if (localAddress != null)
throw new AlreadyBoundException();
InetSocketAddress isa = (local == null) ?
new InetSocketAddress(0) : Net.checkAddress(local);
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkListen(isa.getPort());
}
NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
Net.bind(fd, isa.getAddress(), isa.getPort());
localAddress = Net.localAddress(fd);
}
} finally {
end();
}
return this;
}
@Override
public final SocketAddress getLocalAddress() throws IOException {
if (!isOpen())
throw new ClosedChannelException();
return Net.getRevealedLocalAddress(localAddress);
}
@Override
public final <T> AsynchronousSocketChannel setOption(SocketOption<T> name, T value)
throws IOException
{
if (name == null)
throw new NullPointerException();
if (!supportedOptions().contains(name))
throw new UnsupportedOperationException("'" + name + "' not supported");
try {
begin();
if (writeShutdown)
throw new IOException("Connection has been shutdown for writing");
if (name == StandardSocketOptions.SO_REUSEADDR &&
Net.useExclusiveBind())
{
// SO_REUSEADDR emulated when using exclusive bind
isReuseAddress = (Boolean)value;
} else {
Net.setSocketOption(fd, Net.UNSPEC, name, value);
}
return this;
} finally {
end();
}
}
@Override
@SuppressWarnings("unchecked")
public final <T> T getOption(SocketOption<T> name) throws IOException {
if (name == null)
throw new NullPointerException();
if (!supportedOptions().contains(name))
throw new UnsupportedOperationException("'" + name + "' not supported");
try {
begin();
if (name == StandardSocketOptions.SO_REUSEADDR &&
Net.useExclusiveBind())
{
// SO_REUSEADDR emulated when using exclusive bind
return (T)Boolean.valueOf(isReuseAddress);
}
return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
} finally {
end();
}
}
private static class DefaultOptionsHolder {
static final Set<SocketOption<?>> defaultOptions = defaultOptions();
private static Set<SocketOption<?>> defaultOptions() {
HashSet<SocketOption<?>> set = new HashSet<>(5);
set.add(StandardSocketOptions.SO_SNDBUF);
set.add(StandardSocketOptions.SO_RCVBUF);
set.add(StandardSocketOptions.SO_KEEPALIVE);
set.add(StandardSocketOptions.SO_REUSEADDR);
if (Net.isReusePortAvailable()) {
set.add(StandardSocketOptions.SO_REUSEPORT);
}
set.add(StandardSocketOptions.TCP_NODELAY);
ExtendedSocketOptions extendedOptions =
ExtendedSocketOptions.getInstance();
set.addAll(extendedOptions.options());
return Collections.unmodifiableSet(set);
}
}
@Override
public final Set<SocketOption<?>> supportedOptions() {
return DefaultOptionsHolder.defaultOptions;
}
@Override
public final SocketAddress getRemoteAddress() throws IOException {
if (!isOpen())
throw new ClosedChannelException();
return remoteAddress;
}
@Override
public final AsynchronousSocketChannel shutdownInput() throws IOException {
try {
begin();
if (remoteAddress == null)
throw new NotYetConnectedException();
synchronized (readLock) {
if (!readShutdown) {
Net.shutdown(fd, Net.SHUT_RD);
readShutdown = true;
}
}
} finally {
end();
}
return this;
}
@Override
public final AsynchronousSocketChannel shutdownOutput() throws IOException {
try {
begin();
if (remoteAddress == null)
throw new NotYetConnectedException();
synchronized (writeLock) {
if (!writeShutdown) {
Net.shutdown(fd, Net.SHUT_WR);
writeShutdown = true;
}
}
} finally {
end();
}
return this;
}
@Override
public final String toString() {
StringBuilder sb = new StringBuilder();
sb.append(this.getClass().getName());
sb.append('[');
synchronized (stateLock) {
if (!isOpen()) {
sb.append("closed");
} else {
switch (state) {
case ST_UNCONNECTED:
sb.append("unconnected");
break;
case ST_PENDING:
sb.append("connection-pending");
break;
case ST_CONNECTED:
sb.append("connected");
if (readShutdown)
sb.append(" ishut");
if (writeShutdown)
sb.append(" oshut");
break;
}
if (localAddress != null) {
sb.append(" local=");
sb.append(
Net.getRevealedLocalAddressAsString(localAddress));
}
if (remoteAddress != null) {
sb.append(" remote=");
sb.append(remoteAddress.toString());
}
}
}
sb.append(']');
return sb.toString();
}
}

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
/**
* Implemented by asynchronous channels that require notification when an I/O
* operation is cancelled.
*/
interface Cancellable {
/**
* Invoked to notify channel that cancel has been invoked while holding
* the Future's lock.
*/
void onCancel(PendingFuture<?,?> task);
}

View file

@ -0,0 +1,126 @@
/*
* Copyright (c) 2001, 2002, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.channels.spi.*;
/**
* This class is defined here rather than in java.nio.channels.Channels
* so that code can be shared with SocketAdaptor.
*
* @author Mike McCloskey
* @author Mark Reinhold
* @since 1.4
*/
public class ChannelInputStream
extends InputStream
{
public static int read(ReadableByteChannel ch, ByteBuffer bb,
boolean block)
throws IOException
{
if (ch instanceof SelectableChannel) {
SelectableChannel sc = (SelectableChannel)ch;
synchronized (sc.blockingLock()) {
boolean bm = sc.isBlocking();
if (!bm)
throw new IllegalBlockingModeException();
if (bm != block)
sc.configureBlocking(block);
int n = ch.read(bb);
if (bm != block)
sc.configureBlocking(bm);
return n;
}
} else {
return ch.read(bb);
}
}
protected final ReadableByteChannel ch;
private ByteBuffer bb = null;
private byte[] bs = null; // Invoker's previous array
private byte[] b1 = null;
public ChannelInputStream(ReadableByteChannel ch) {
this.ch = ch;
}
public synchronized int read() throws IOException {
if (b1 == null)
b1 = new byte[1];
int n = this.read(b1);
if (n == 1)
return b1[0] & 0xff;
return -1;
}
public synchronized int read(byte[] bs, int off, int len)
throws IOException
{
if ((off < 0) || (off > bs.length) || (len < 0) ||
((off + len) > bs.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0)
return 0;
ByteBuffer bb = ((this.bs == bs)
? this.bb
: ByteBuffer.wrap(bs));
bb.limit(Math.min(off + len, bb.capacity()));
bb.position(off);
this.bb = bb;
this.bs = bs;
return read(bb);
}
protected int read(ByteBuffer bb)
throws IOException
{
return ChannelInputStream.read(ch, bb, true);
}
public int available() throws IOException {
// special case where the channel is to a file
if (ch instanceof SeekableByteChannel) {
SeekableByteChannel sbc = (SeekableByteChannel)ch;
long rem = Math.max(0, sbc.size() - sbc.position());
return (rem > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int)rem;
}
return 0;
}
public void close() throws IOException {
ch.close();
}
}

View file

@ -0,0 +1,96 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ExecutionException;
import java.io.IOException;
/**
* A Future representing the result of an I/O operation that has already
* completed.
*/
final class CompletedFuture<V> implements Future<V> {
private final V result;
private final Throwable exc;
private CompletedFuture(V result, Throwable exc) {
this.result = result;
this.exc = exc;
}
static <V> CompletedFuture<V> withResult(V result) {
return new CompletedFuture<V>(result, null);
}
static <V> CompletedFuture<V> withFailure(Throwable exc) {
// exception must be IOException or SecurityException
if (!(exc instanceof IOException) && !(exc instanceof SecurityException))
exc = new IOException(exc);
return new CompletedFuture<V>(null, exc);
}
static <V> CompletedFuture<V> withResult(V result, Throwable exc) {
if (exc == null) {
return withResult(result);
} else {
return withFailure(exc);
}
}
@Override
public V get() throws ExecutionException {
if (exc != null)
throw new ExecutionException(exc);
return result;
}
@Override
public V get(long timeout, TimeUnit unit) throws ExecutionException {
if (unit == null)
throw new NullPointerException();
if (exc != null)
throw new ExecutionException(exc);
return result;
}
@Override
public boolean isCancelled() {
return false;
}
@Override
public boolean isDone() {
return true;
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
return false;
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,410 @@
/*
* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.io.*;
import java.net.*;
import java.nio.*;
import java.nio.channels.*;
// Make a datagram-socket channel look like a datagram socket.
//
// The methods in this class are defined in exactly the same order as in
// java.net.DatagramSocket so as to simplify tracking future changes to that
// class.
//
public class DatagramSocketAdaptor
extends DatagramSocket
{
// The channel being adapted
private final DatagramChannelImpl dc;
// Timeout "option" value for receives
private volatile int timeout;
// ## super will create a useless impl
private DatagramSocketAdaptor(DatagramChannelImpl dc) throws IOException {
// Invoke the DatagramSocketAdaptor(SocketAddress) constructor,
// passing a dummy DatagramSocketImpl object to aovid any native
// resource allocation in super class and invoking our bind method
// before the dc field is initialized.
super(dummyDatagramSocket);
this.dc = dc;
}
public static DatagramSocket create(DatagramChannelImpl dc) {
try {
return new DatagramSocketAdaptor(dc);
} catch (IOException x) {
throw new Error(x);
}
}
private void connectInternal(SocketAddress remote)
throws SocketException
{
InetSocketAddress isa = Net.asInetSocketAddress(remote);
int port = isa.getPort();
if (port < 0 || port > 0xFFFF)
throw new IllegalArgumentException("connect: " + port);
if (remote == null)
throw new IllegalArgumentException("connect: null address");
if (isClosed())
return;
try {
dc.connect(remote);
} catch (Exception x) {
Net.translateToSocketException(x);
}
}
public void bind(SocketAddress local) throws SocketException {
try {
if (local == null)
local = new InetSocketAddress(0);
dc.bind(local);
} catch (Exception x) {
Net.translateToSocketException(x);
}
}
public void connect(InetAddress address, int port) {
try {
connectInternal(new InetSocketAddress(address, port));
} catch (SocketException x) {
// Yes, j.n.DatagramSocket really does this
}
}
public void connect(SocketAddress remote) throws SocketException {
if (remote == null)
throw new IllegalArgumentException("Address can't be null");
connectInternal(remote);
}
public void disconnect() {
try {
dc.disconnect();
} catch (IOException x) {
throw new Error(x);
}
}
public boolean isBound() {
return dc.localAddress() != null;
}
public boolean isConnected() {
return dc.remoteAddress() != null;
}
public InetAddress getInetAddress() {
return (isConnected()
? Net.asInetSocketAddress(dc.remoteAddress()).getAddress()
: null);
}
public int getPort() {
return (isConnected()
? Net.asInetSocketAddress(dc.remoteAddress()).getPort()
: -1);
}
public void send(DatagramPacket p) throws IOException {
synchronized (dc.blockingLock()) {
if (!dc.isBlocking())
throw new IllegalBlockingModeException();
try {
synchronized (p) {
ByteBuffer bb = ByteBuffer.wrap(p.getData(),
p.getOffset(),
p.getLength());
if (dc.isConnected()) {
if (p.getAddress() == null) {
// Legacy DatagramSocket will send in this case
// and set address and port of the packet
InetSocketAddress isa = (InetSocketAddress)
dc.remoteAddress();
p.setPort(isa.getPort());
p.setAddress(isa.getAddress());
dc.write(bb);
} else {
// Target address may not match connected address
dc.send(bb, p.getSocketAddress());
}
} else {
// Not connected so address must be valid or throw
dc.send(bb, p.getSocketAddress());
}
}
} catch (IOException x) {
Net.translateException(x);
}
}
}
// Must hold dc.blockingLock()
//
private SocketAddress receive(ByteBuffer bb) throws IOException {
if (timeout == 0) {
return dc.receive(bb);
}
dc.configureBlocking(false);
try {
int n;
SocketAddress sender;
if ((sender = dc.receive(bb)) != null)
return sender;
long to = timeout;
for (;;) {
if (!dc.isOpen())
throw new ClosedChannelException();
long st = System.currentTimeMillis();
int result = dc.poll(Net.POLLIN, to);
if (result > 0 &&
((result & Net.POLLIN) != 0)) {
if ((sender = dc.receive(bb)) != null)
return sender;
}
to -= System.currentTimeMillis() - st;
if (to <= 0)
throw new SocketTimeoutException();
}
} finally {
if (dc.isOpen())
dc.configureBlocking(true);
}
}
public void receive(DatagramPacket p) throws IOException {
synchronized (dc.blockingLock()) {
if (!dc.isBlocking())
throw new IllegalBlockingModeException();
try {
synchronized (p) {
ByteBuffer bb = ByteBuffer.wrap(p.getData(),
p.getOffset(),
p.getLength());
SocketAddress sender = receive(bb);
p.setSocketAddress(sender);
p.setLength(bb.position() - p.getOffset());
}
} catch (IOException x) {
Net.translateException(x);
}
}
}
public InetAddress getLocalAddress() {
if (isClosed())
return null;
SocketAddress local = dc.localAddress();
if (local == null)
local = new InetSocketAddress(0);
InetAddress result = ((InetSocketAddress)local).getAddress();
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
try {
sm.checkConnect(result.getHostAddress(), -1);
} catch (SecurityException x) {
return new InetSocketAddress(0).getAddress();
}
}
return result;
}
public int getLocalPort() {
if (isClosed())
return -1;
try {
SocketAddress local = dc.getLocalAddress();
if (local != null) {
return ((InetSocketAddress)local).getPort();
}
} catch (Exception x) {
}
return 0;
}
public void setSoTimeout(int timeout) throws SocketException {
this.timeout = timeout;
}
public int getSoTimeout() throws SocketException {
return timeout;
}
private void setBooleanOption(SocketOption<Boolean> name, boolean value)
throws SocketException
{
try {
dc.setOption(name, value);
} catch (IOException x) {
Net.translateToSocketException(x);
}
}
private void setIntOption(SocketOption<Integer> name, int value)
throws SocketException
{
try {
dc.setOption(name, value);
} catch (IOException x) {
Net.translateToSocketException(x);
}
}
private boolean getBooleanOption(SocketOption<Boolean> name) throws SocketException {
try {
return dc.getOption(name).booleanValue();
} catch (IOException x) {
Net.translateToSocketException(x);
return false; // keep compiler happy
}
}
private int getIntOption(SocketOption<Integer> name) throws SocketException {
try {
return dc.getOption(name).intValue();
} catch (IOException x) {
Net.translateToSocketException(x);
return -1; // keep compiler happy
}
}
public void setSendBufferSize(int size) throws SocketException {
if (size <= 0)
throw new IllegalArgumentException("Invalid send size");
setIntOption(StandardSocketOptions.SO_SNDBUF, size);
}
public int getSendBufferSize() throws SocketException {
return getIntOption(StandardSocketOptions.SO_SNDBUF);
}
public void setReceiveBufferSize(int size) throws SocketException {
if (size <= 0)
throw new IllegalArgumentException("Invalid receive size");
setIntOption(StandardSocketOptions.SO_RCVBUF, size);
}
public int getReceiveBufferSize() throws SocketException {
return getIntOption(StandardSocketOptions.SO_RCVBUF);
}
public void setReuseAddress(boolean on) throws SocketException {
setBooleanOption(StandardSocketOptions.SO_REUSEADDR, on);
}
public boolean getReuseAddress() throws SocketException {
return getBooleanOption(StandardSocketOptions.SO_REUSEADDR);
}
public void setBroadcast(boolean on) throws SocketException {
setBooleanOption(StandardSocketOptions.SO_BROADCAST, on);
}
public boolean getBroadcast() throws SocketException {
return getBooleanOption(StandardSocketOptions.SO_BROADCAST);
}
public void setTrafficClass(int tc) throws SocketException {
setIntOption(StandardSocketOptions.IP_TOS, tc);
}
public int getTrafficClass() throws SocketException {
return getIntOption(StandardSocketOptions.IP_TOS);
}
public void close() {
try {
dc.close();
} catch (IOException x) {
throw new Error(x);
}
}
public boolean isClosed() {
return !dc.isOpen();
}
public DatagramChannel getChannel() {
return dc;
}
/*
* A dummy implementation of DatagramSocketImpl that can be passed to the
* DatagramSocket constructor so that no native resources are allocated in
* super class.
*/
private static final DatagramSocketImpl dummyDatagramSocket
= new DatagramSocketImpl()
{
protected void create() throws SocketException {}
protected void bind(int lport, InetAddress laddr) throws SocketException {}
protected void send(DatagramPacket p) throws IOException {}
protected int peek(InetAddress i) throws IOException { return 0; }
protected int peekData(DatagramPacket p) throws IOException { return 0; }
protected void receive(DatagramPacket p) throws IOException {}
@Deprecated
protected void setTTL(byte ttl) throws IOException {}
@Deprecated
protected byte getTTL() throws IOException { return 0; }
protected void setTimeToLive(int ttl) throws IOException {}
protected int getTimeToLive() throws IOException { return 0;}
protected void join(InetAddress inetaddr) throws IOException {}
protected void leave(InetAddress inetaddr) throws IOException {}
protected void joinGroup(SocketAddress mcastaddr,
NetworkInterface netIf) throws IOException {}
protected void leaveGroup(SocketAddress mcastaddr,
NetworkInterface netIf) throws IOException {}
protected void close() {}
public Object getOption(int optID) throws SocketException { return null;}
public void setOption(int optID, Object value) throws SocketException {}
};
}

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import jdk.internal.ref.Cleaner;
public interface DirectBuffer {
public long address();
public Object attachment();
public Cleaner cleaner();
}

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.net.SocketOption;
/**
* Defines socket options that are supported by the implementation
* but not defined in StandardSocketOptions.
*/
class ExtendedSocketOption {
private ExtendedSocketOption() { }
static final SocketOption<Boolean> SO_OOBINLINE =
new SocketOption<Boolean>() {
public String name() { return "SO_OOBINLINE"; }
public Class<Boolean> type() { return Boolean.class; }
public String toString() { return name(); }
};
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.io.FileDescriptor;
import java.io.IOException;
import java.nio.channels.SelectableChannel;
abstract class FileDispatcher extends NativeDispatcher {
public static final int NO_LOCK = -1; // Failed to lock
public static final int LOCKED = 0; // Obtained requested lock
public static final int RET_EX_LOCK = 1; // Obtained exclusive lock
public static final int INTERRUPTED = 2; // Request interrupted
abstract int force(FileDescriptor fd, boolean metaData) throws IOException;
abstract int truncate(FileDescriptor fd, long size) throws IOException;
abstract int allocate(FileDescriptor fd, long size) throws IOException;
abstract long size(FileDescriptor fd) throws IOException;
abstract int lock(FileDescriptor fd, boolean blocking, long pos, long size,
boolean shared) throws IOException;
abstract void release(FileDescriptor fd, long pos, long size)
throws IOException;
/**
* Returns a dup of fd if a file descriptor is required for
* memory-mapping operations, otherwise returns an invalid
* FileDescriptor (meaning a newly allocated FileDescriptor)
*/
abstract FileDescriptor duplicateForMapping(FileDescriptor fd)
throws IOException;
abstract boolean canTransferToDirectly(SelectableChannel sc);
abstract boolean transferToDirectlyNeedsPositionLock();
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.io.IOException;
import java.nio.channels.*;
public class FileLockImpl
extends FileLock
{
private volatile boolean invalid;
FileLockImpl(FileChannel channel, long position, long size, boolean shared)
{
super(channel, position, size, shared);
}
FileLockImpl(AsynchronousFileChannel channel, long position, long size, boolean shared)
{
super(channel, position, size, shared);
}
public boolean isValid() {
return !invalid;
}
void invalidate() {
assert Thread.holdsLock(this);
invalid = true;
}
public synchronized void release() throws IOException {
Channel ch = acquiredBy();
if (!ch.isOpen())
throw new ClosedChannelException();
if (isValid()) {
if (ch instanceof FileChannelImpl)
((FileChannelImpl)ch).release(this);
else if (ch instanceof AsynchronousFileChannelImpl)
((AsynchronousFileChannelImpl)ch).release(this);
else throw new AssertionError();
invalidate();
}
}
}

View file

@ -0,0 +1,273 @@
/*
* Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.nio.channels.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.lang.ref.*;
import java.io.FileDescriptor;
import java.io.IOException;
abstract class FileLockTable {
protected FileLockTable() {
}
/**
* Creates and returns a file lock table for a channel that is connected to
* the a system-wide map of all file locks for the Java virtual machine.
*/
public static FileLockTable newSharedFileLockTable(Channel channel,
FileDescriptor fd)
throws IOException
{
return new SharedFileLockTable(channel, fd);
}
/**
* Adds a file lock to the table.
*
* @throws OverlappingFileLockException if the file lock overlaps
* with an existing file lock in the table
*/
public abstract void add(FileLock fl) throws OverlappingFileLockException;
/**
* Remove an existing file lock from the table.
*/
public abstract void remove(FileLock fl);
/**
* Removes all file locks from the table.
*
* @return The list of file locks removed
*/
public abstract List<FileLock> removeAll();
/**
* Replaces an existing file lock in the table.
*/
public abstract void replace(FileLock fl1, FileLock fl2);
}
/**
* A file lock table that is over a system-wide map of all file locks.
*/
class SharedFileLockTable extends FileLockTable {
/**
* A weak reference to a FileLock.
* <p>
* SharedFileLockTable uses a list of file lock references to avoid keeping the
* FileLock (and FileChannel) alive.
*/
private static class FileLockReference extends WeakReference<FileLock> {
private FileKey fileKey;
FileLockReference(FileLock referent,
ReferenceQueue<FileLock> queue,
FileKey key) {
super(referent, queue);
this.fileKey = key;
}
FileKey fileKey() {
return fileKey;
}
}
// The system-wide map is a ConcurrentHashMap that is keyed on the FileKey.
// The map value is a list of file locks represented by FileLockReferences.
// All access to the list must be synchronized on the list.
private static ConcurrentHashMap<FileKey, List<FileLockReference>> lockMap =
new ConcurrentHashMap<FileKey, List<FileLockReference>>();
// reference queue for cleared refs
private static ReferenceQueue<FileLock> queue = new ReferenceQueue<FileLock>();
// The connection to which this table is connected
private final Channel channel;
// File key for the file that this channel is connected to
private final FileKey fileKey;
SharedFileLockTable(Channel channel, FileDescriptor fd) throws IOException {
this.channel = channel;
this.fileKey = FileKey.create(fd);
}
@Override
public void add(FileLock fl) throws OverlappingFileLockException {
List<FileLockReference> list = lockMap.get(fileKey);
for (;;) {
// The key isn't in the map so we try to create it atomically
if (list == null) {
list = new ArrayList<FileLockReference>(2);
List<FileLockReference> prev;
synchronized (list) {
prev = lockMap.putIfAbsent(fileKey, list);
if (prev == null) {
// we successfully created the key so we add the file lock
list.add(new FileLockReference(fl, queue, fileKey));
break;
}
}
// someone else got there first
list = prev;
}
// There is already a key. It is possible that some other thread
// is removing it so we re-fetch the value from the map. If it
// hasn't changed then we check the list for overlapping locks
// and add the new lock to the list.
synchronized (list) {
List<FileLockReference> current = lockMap.get(fileKey);
if (list == current) {
checkList(list, fl.position(), fl.size());
list.add(new FileLockReference(fl, queue, fileKey));
break;
}
list = current;
}
}
// process any stale entries pending in the reference queue
removeStaleEntries();
}
private void removeKeyIfEmpty(FileKey fk, List<FileLockReference> list) {
assert Thread.holdsLock(list);
assert lockMap.get(fk) == list;
if (list.isEmpty()) {
lockMap.remove(fk);
}
}
@Override
public void remove(FileLock fl) {
assert fl != null;
// the lock must exist so the list of locks must be present
List<FileLockReference> list = lockMap.get(fileKey);
if (list == null) return;
synchronized (list) {
int index = 0;
while (index < list.size()) {
FileLockReference ref = list.get(index);
FileLock lock = ref.get();
if (lock == fl) {
assert (lock != null) && (lock.acquiredBy() == channel);
ref.clear();
list.remove(index);
break;
}
index++;
}
}
}
@Override
public List<FileLock> removeAll() {
List<FileLock> result = new ArrayList<FileLock>();
List<FileLockReference> list = lockMap.get(fileKey);
if (list != null) {
synchronized (list) {
int index = 0;
while (index < list.size()) {
FileLockReference ref = list.get(index);
FileLock lock = ref.get();
// remove locks obtained by this channel
if (lock != null && lock.acquiredBy() == channel) {
// remove the lock from the list
ref.clear();
list.remove(index);
// add to result
result.add(lock);
} else {
index++;
}
}
// once the lock list is empty we remove it from the map
removeKeyIfEmpty(fileKey, list);
}
}
return result;
}
@Override
public void replace(FileLock fromLock, FileLock toLock) {
// the lock must exist so there must be a list
List<FileLockReference> list = lockMap.get(fileKey);
assert list != null;
synchronized (list) {
for (int index=0; index<list.size(); index++) {
FileLockReference ref = list.get(index);
FileLock lock = ref.get();
if (lock == fromLock) {
ref.clear();
list.set(index, new FileLockReference(toLock, queue, fileKey));
break;
}
}
}
}
// Check for overlapping file locks
private void checkList(List<FileLockReference> list, long position, long size)
throws OverlappingFileLockException
{
assert Thread.holdsLock(list);
for (FileLockReference ref: list) {
FileLock fl = ref.get();
if (fl != null && fl.overlaps(position, size))
throw new OverlappingFileLockException();
}
}
// Process the reference queue
private void removeStaleEntries() {
FileLockReference ref;
while ((ref = (FileLockReference)queue.poll()) != null) {
FileKey fk = ref.fileKey();
List<FileLockReference> list = lockMap.get(fk);
if (list != null) {
synchronized (list) {
list.remove(ref);
removeKeyIfEmpty(fk, list);
}
}
}
}
}

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
/**
* Implemented by asynchronous channels that can be associated with an
* asynchronous channel group.
*/
interface Groupable {
AsynchronousChannelGroupImpl group();
}

View file

@ -0,0 +1,84 @@
/*
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.lang.annotation.Native;
// Constants for reporting I/O status
public final class IOStatus {
private IOStatus() { }
@Native public static final int EOF = -1; // End of file
@Native public static final int UNAVAILABLE = -2; // Nothing available (non-blocking)
@Native public static final int INTERRUPTED = -3; // System call interrupted
@Native public static final int UNSUPPORTED = -4; // Operation not supported
@Native public static final int THROWN = -5; // Exception thrown in JNI code
@Native public static final int UNSUPPORTED_CASE = -6; // This case not supported
// The following two methods are for use in try/finally blocks where a
// status value needs to be normalized before being returned to the invoker
// but also checked for illegal negative values before the return
// completes, like so:
//
// int n = 0;
// try {
// begin();
// n = op(fd, buf, ...);
// return IOStatus.normalize(n); // Converts UNAVAILABLE to zero
// } finally {
// end(n > 0);
// assert IOStatus.check(n); // Checks other negative values
// }
//
public static int normalize(int n) {
if (n == UNAVAILABLE)
return 0;
return n;
}
public static boolean check(int n) {
return (n >= UNAVAILABLE);
}
public static long normalize(long n) {
if (n == UNAVAILABLE)
return 0;
return n;
}
public static boolean check(long n) {
return (n >= UNAVAILABLE);
}
// Return true iff n is not one of the IOStatus values
public static boolean checkAll(long n) {
return ((n > EOF) || (n < UNSUPPORTED_CASE));
}
}

View file

@ -0,0 +1,370 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.io.FileDescriptor;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
* File-descriptor based I/O utilities that are shared by NIO classes.
*/
public class IOUtil {
/**
* Max number of iovec structures that readv/writev supports
*/
static final int IOV_MAX;
private IOUtil() { } // No instantiation
static int write(FileDescriptor fd, ByteBuffer src, long position,
NativeDispatcher nd)
throws IOException
{
if (src instanceof DirectBuffer)
return writeFromNativeBuffer(fd, src, position, nd);
// Substitute a native buffer
int pos = src.position();
int lim = src.limit();
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
ByteBuffer bb = Util.getTemporaryDirectBuffer(rem);
try {
bb.put(src);
bb.flip();
// Do not update src until we see how many bytes were written
src.position(pos);
int n = writeFromNativeBuffer(fd, bb, position, nd);
if (n > 0) {
// now update src
src.position(pos + n);
}
return n;
} finally {
Util.offerFirstTemporaryDirectBuffer(bb);
}
}
private static int writeFromNativeBuffer(FileDescriptor fd, ByteBuffer bb,
long position, NativeDispatcher nd)
throws IOException
{
int pos = bb.position();
int lim = bb.limit();
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
int written = 0;
if (rem == 0)
return 0;
if (position != -1) {
written = nd.pwrite(fd,
((DirectBuffer)bb).address() + pos,
rem, position);
} else {
written = nd.write(fd, ((DirectBuffer)bb).address() + pos, rem);
}
if (written > 0)
bb.position(pos + written);
return written;
}
static long write(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd)
throws IOException
{
return write(fd, bufs, 0, bufs.length, nd);
}
static long write(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
NativeDispatcher nd)
throws IOException
{
IOVecWrapper vec = IOVecWrapper.get(length);
boolean completed = false;
int iov_len = 0;
try {
// Iterate over buffers to populate native iovec array.
int count = offset + length;
int i = offset;
while (i < count && iov_len < IOV_MAX) {
ByteBuffer buf = bufs[i];
int pos = buf.position();
int lim = buf.limit();
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
if (rem > 0) {
vec.setBuffer(iov_len, buf, pos, rem);
// allocate shadow buffer to ensure I/O is done with direct buffer
if (!(buf instanceof DirectBuffer)) {
ByteBuffer shadow = Util.getTemporaryDirectBuffer(rem);
shadow.put(buf);
shadow.flip();
vec.setShadow(iov_len, shadow);
buf.position(pos); // temporarily restore position in user buffer
buf = shadow;
pos = shadow.position();
}
vec.putBase(iov_len, ((DirectBuffer)buf).address() + pos);
vec.putLen(iov_len, rem);
iov_len++;
}
i++;
}
if (iov_len == 0)
return 0L;
long bytesWritten = nd.writev(fd, vec.address, iov_len);
// Notify the buffers how many bytes were taken
long left = bytesWritten;
for (int j=0; j<iov_len; j++) {
if (left > 0) {
ByteBuffer buf = vec.getBuffer(j);
int pos = vec.getPosition(j);
int rem = vec.getRemaining(j);
int n = (left > rem) ? rem : (int)left;
buf.position(pos + n);
left -= n;
}
// return shadow buffers to buffer pool
ByteBuffer shadow = vec.getShadow(j);
if (shadow != null)
Util.offerLastTemporaryDirectBuffer(shadow);
vec.clearRefs(j);
}
completed = true;
return bytesWritten;
} finally {
// if an error occurred then clear refs to buffers and return any shadow
// buffers to cache
if (!completed) {
for (int j=0; j<iov_len; j++) {
ByteBuffer shadow = vec.getShadow(j);
if (shadow != null)
Util.offerLastTemporaryDirectBuffer(shadow);
vec.clearRefs(j);
}
}
}
}
static int read(FileDescriptor fd, ByteBuffer dst, long position,
NativeDispatcher nd)
throws IOException
{
if (dst.isReadOnly())
throw new IllegalArgumentException("Read-only buffer");
if (dst instanceof DirectBuffer)
return readIntoNativeBuffer(fd, dst, position, nd);
// Substitute a native buffer
ByteBuffer bb = Util.getTemporaryDirectBuffer(dst.remaining());
try {
int n = readIntoNativeBuffer(fd, bb, position, nd);
bb.flip();
if (n > 0)
dst.put(bb);
return n;
} finally {
Util.offerFirstTemporaryDirectBuffer(bb);
}
}
private static int readIntoNativeBuffer(FileDescriptor fd, ByteBuffer bb,
long position, NativeDispatcher nd)
throws IOException
{
int pos = bb.position();
int lim = bb.limit();
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
if (rem == 0)
return 0;
int n = 0;
if (position != -1) {
n = nd.pread(fd, ((DirectBuffer)bb).address() + pos,
rem, position);
} else {
n = nd.read(fd, ((DirectBuffer)bb).address() + pos, rem);
}
if (n > 0)
bb.position(pos + n);
return n;
}
static long read(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd)
throws IOException
{
return read(fd, bufs, 0, bufs.length, nd);
}
static long read(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
NativeDispatcher nd)
throws IOException
{
IOVecWrapper vec = IOVecWrapper.get(length);
boolean completed = false;
int iov_len = 0;
try {
// Iterate over buffers to populate native iovec array.
int count = offset + length;
int i = offset;
while (i < count && iov_len < IOV_MAX) {
ByteBuffer buf = bufs[i];
if (buf.isReadOnly())
throw new IllegalArgumentException("Read-only buffer");
int pos = buf.position();
int lim = buf.limit();
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
if (rem > 0) {
vec.setBuffer(iov_len, buf, pos, rem);
// allocate shadow buffer to ensure I/O is done with direct buffer
if (!(buf instanceof DirectBuffer)) {
ByteBuffer shadow = Util.getTemporaryDirectBuffer(rem);
vec.setShadow(iov_len, shadow);
buf = shadow;
pos = shadow.position();
}
vec.putBase(iov_len, ((DirectBuffer)buf).address() + pos);
vec.putLen(iov_len, rem);
iov_len++;
}
i++;
}
if (iov_len == 0)
return 0L;
long bytesRead = nd.readv(fd, vec.address, iov_len);
// Notify the buffers how many bytes were read
long left = bytesRead;
for (int j=0; j<iov_len; j++) {
ByteBuffer shadow = vec.getShadow(j);
if (left > 0) {
ByteBuffer buf = vec.getBuffer(j);
int rem = vec.getRemaining(j);
int n = (left > rem) ? rem : (int)left;
if (shadow == null) {
int pos = vec.getPosition(j);
buf.position(pos + n);
} else {
shadow.limit(shadow.position() + n);
buf.put(shadow);
}
left -= n;
}
if (shadow != null)
Util.offerLastTemporaryDirectBuffer(shadow);
vec.clearRefs(j);
}
completed = true;
return bytesRead;
} finally {
// if an error occurred then clear refs to buffers and return any shadow
// buffers to cache
if (!completed) {
for (int j=0; j<iov_len; j++) {
ByteBuffer shadow = vec.getShadow(j);
if (shadow != null)
Util.offerLastTemporaryDirectBuffer(shadow);
vec.clearRefs(j);
}
}
}
}
public static FileDescriptor newFD(int i) {
FileDescriptor fd = new FileDescriptor();
setfdVal(fd, i);
return fd;
}
static native boolean randomBytes(byte[] someBytes);
/**
* Returns two file descriptors for a pipe encoded in a long.
* The read end of the pipe is returned in the high 32 bits,
* while the write end is returned in the low 32 bits.
*/
static native long makePipe(boolean blocking);
static native boolean drain(int fd) throws IOException;
public static native void configureBlocking(FileDescriptor fd,
boolean blocking)
throws IOException;
public static native int fdVal(FileDescriptor fd);
static native void setfdVal(FileDescriptor fd, int value);
static native int fdLimit();
static native int iovMax();
static native void initIDs();
/**
* Used to trigger loading of native libraries
*/
public static void load() { }
static {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() {
System.loadLibrary("net");
System.loadLibrary("nio");
return null;
}
});
initIDs();
IOV_MAX = iovMax();
}
}

View file

@ -0,0 +1,162 @@
/*
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.nio.ByteBuffer;
import jdk.internal.ref.CleanerFactory;
/**
* Manipulates a native array of iovec structs on Solaris:
*
* typedef struct iovec {
* caddr_t iov_base;
int iov_len;
* } iovec_t;
*
* @author Mike McCloskey
* @since 1.4
*/
class IOVecWrapper {
// Miscellaneous constants
private static final int BASE_OFFSET = 0;
private static final int LEN_OFFSET;
private static final int SIZE_IOVEC;
// The iovec array
private final AllocatedNativeObject vecArray;
// Number of elements in iovec array
private final int size;
// Buffers and position/remaining corresponding to elements in iovec array
private final ByteBuffer[] buf;
private final int[] position;
private final int[] remaining;
// Shadow buffers for cases when original buffer is substituted
private final ByteBuffer[] shadow;
// Base address of this array
final long address;
// Address size in bytes
static int addressSize;
private static class Deallocator implements Runnable {
private final AllocatedNativeObject obj;
Deallocator(AllocatedNativeObject obj) {
this.obj = obj;
}
public void run() {
obj.free();
}
}
// per thread IOVecWrapper
private static final ThreadLocal<IOVecWrapper> cached =
new ThreadLocal<IOVecWrapper>();
private IOVecWrapper(int size) {
this.size = size;
this.buf = new ByteBuffer[size];
this.position = new int[size];
this.remaining = new int[size];
this.shadow = new ByteBuffer[size];
this.vecArray = new AllocatedNativeObject(size * SIZE_IOVEC, false);
this.address = vecArray.address();
}
static IOVecWrapper get(int size) {
IOVecWrapper wrapper = cached.get();
if (wrapper != null && wrapper.size < size) {
// not big enough; eagerly release memory
wrapper.vecArray.free();
wrapper = null;
}
if (wrapper == null) {
wrapper = new IOVecWrapper(size);
CleanerFactory.cleaner().register(wrapper, new Deallocator(wrapper.vecArray));
cached.set(wrapper);
}
return wrapper;
}
void setBuffer(int i, ByteBuffer buf, int pos, int rem) {
this.buf[i] = buf;
this.position[i] = pos;
this.remaining[i] = rem;
}
void setShadow(int i, ByteBuffer buf) {
shadow[i] = buf;
}
ByteBuffer getBuffer(int i) {
return buf[i];
}
int getPosition(int i) {
return position[i];
}
int getRemaining(int i) {
return remaining[i];
}
ByteBuffer getShadow(int i) {
return shadow[i];
}
void clearRefs(int i) {
buf[i] = null;
shadow[i] = null;
}
void putBase(int i, long base) {
int offset = SIZE_IOVEC * i + BASE_OFFSET;
if (addressSize == 4)
vecArray.putInt(offset, (int)base);
else
vecArray.putLong(offset, base);
}
void putLen(int i, long len) {
int offset = SIZE_IOVEC * i + LEN_OFFSET;
if (addressSize == 4)
vecArray.putInt(offset, (int)len);
else
vecArray.putLong(offset, len);
}
static {
addressSize = Util.unsafe().addressSize();
LEN_OFFSET = addressSize;
SIZE_IOVEC = (short) (addressSize * 2);
}
}

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* An object that interrupts a thread blocked in an I/O operation.
*/
package sun.nio.ch;
public interface Interruptible {
public void interrupt(Thread t);
}

View file

@ -0,0 +1,321 @@
/*
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.nio.channels.*;
import java.util.concurrent.*;
import java.security.AccessController;
import sun.security.action.GetIntegerAction;
import jdk.internal.misc.InnocuousThread;
/**
* Defines static methods to invoke a completion handler or arbitrary task.
*/
class Invoker {
private Invoker() { }
// maximum number of completion handlers that may be invoked on the current
// thread before it re-directs invocations to the thread pool. This helps
// avoid stack overflow and lessens the risk of starvation.
private static final int maxHandlerInvokeCount = AccessController.doPrivileged(
new GetIntegerAction("sun.nio.ch.maxCompletionHandlersOnStack", 16));
// Per-thread object with reference to channel group and a counter for
// the number of completion handlers invoked. This should be reset to 0
// when all completion handlers have completed.
static class GroupAndInvokeCount {
private final AsynchronousChannelGroupImpl group;
private int handlerInvokeCount;
GroupAndInvokeCount(AsynchronousChannelGroupImpl group) {
this.group = group;
}
AsynchronousChannelGroupImpl group() {
return group;
}
int invokeCount() {
return handlerInvokeCount;
}
void setInvokeCount(int value) {
handlerInvokeCount = value;
}
void resetInvokeCount() {
handlerInvokeCount = 0;
}
void incrementInvokeCount() {
handlerInvokeCount++;
}
}
private static final ThreadLocal<GroupAndInvokeCount> myGroupAndInvokeCount =
new ThreadLocal<GroupAndInvokeCount>() {
@Override protected GroupAndInvokeCount initialValue() {
return null;
}
};
/**
* Binds this thread to the given group
*/
static void bindToGroup(AsynchronousChannelGroupImpl group) {
myGroupAndInvokeCount.set(new GroupAndInvokeCount(group));
}
/**
* Returns the GroupAndInvokeCount object for this thread.
*/
static GroupAndInvokeCount getGroupAndInvokeCount() {
return myGroupAndInvokeCount.get();
}
/**
* Returns true if the current thread is in a channel group's thread pool
*/
static boolean isBoundToAnyGroup() {
return myGroupAndInvokeCount.get() != null;
}
/**
* Returns true if the current thread is in the given channel's thread
* pool and we haven't exceeded the maximum number of handler frames on
* the stack.
*/
static boolean mayInvokeDirect(GroupAndInvokeCount myGroupAndInvokeCount,
AsynchronousChannelGroupImpl group)
{
if ((myGroupAndInvokeCount != null) &&
(myGroupAndInvokeCount.group() == group) &&
(myGroupAndInvokeCount.invokeCount() < maxHandlerInvokeCount))
{
return true;
}
return false;
}
/**
* Invoke handler without checking the thread identity or number of handlers
* on the thread stack.
*/
static <V,A> void invokeUnchecked(CompletionHandler<V,? super A> handler,
A attachment,
V value,
Throwable exc)
{
if (exc == null) {
handler.completed(value, attachment);
} else {
handler.failed(exc, attachment);
}
// clear interrupt
Thread.interrupted();
// clear thread locals when in default thread pool
if (System.getSecurityManager() != null) {
Thread me = Thread.currentThread();
if (me instanceof InnocuousThread) {
GroupAndInvokeCount thisGroupAndInvokeCount = myGroupAndInvokeCount.get();
((InnocuousThread)me).eraseThreadLocals();
if (thisGroupAndInvokeCount != null) {
myGroupAndInvokeCount.set(thisGroupAndInvokeCount);
}
}
}
}
/**
* Invoke handler assuming thread identity already checked
*/
static <V,A> void invokeDirect(GroupAndInvokeCount myGroupAndInvokeCount,
CompletionHandler<V,? super A> handler,
A attachment,
V result,
Throwable exc)
{
myGroupAndInvokeCount.incrementInvokeCount();
Invoker.invokeUnchecked(handler, attachment, result, exc);
}
/**
* Invokes the handler. If the current thread is in the channel group's
* thread pool then the handler is invoked directly, otherwise it is
* invoked indirectly.
*/
static <V,A> void invoke(AsynchronousChannel channel,
CompletionHandler<V,? super A> handler,
A attachment,
V result,
Throwable exc)
{
boolean invokeDirect = false;
boolean identityOkay = false;
GroupAndInvokeCount thisGroupAndInvokeCount = myGroupAndInvokeCount.get();
if (thisGroupAndInvokeCount != null) {
if ((thisGroupAndInvokeCount.group() == ((Groupable)channel).group()))
identityOkay = true;
if (identityOkay &&
(thisGroupAndInvokeCount.invokeCount() < maxHandlerInvokeCount))
{
// group match
invokeDirect = true;
}
}
if (invokeDirect) {
invokeDirect(thisGroupAndInvokeCount, handler, attachment, result, exc);
} else {
try {
invokeIndirectly(channel, handler, attachment, result, exc);
} catch (RejectedExecutionException ree) {
// channel group shutdown; fallback to invoking directly
// if the current thread has the right identity.
if (identityOkay) {
invokeDirect(thisGroupAndInvokeCount,
handler, attachment, result, exc);
} else {
throw new ShutdownChannelGroupException();
}
}
}
}
/**
* Invokes the handler indirectly via the channel group's thread pool.
*/
static <V,A> void invokeIndirectly(AsynchronousChannel channel,
final CompletionHandler<V,? super A> handler,
final A attachment,
final V result,
final Throwable exc)
{
try {
((Groupable)channel).group().executeOnPooledThread(new Runnable() {
public void run() {
GroupAndInvokeCount thisGroupAndInvokeCount =
myGroupAndInvokeCount.get();
if (thisGroupAndInvokeCount != null)
thisGroupAndInvokeCount.setInvokeCount(1);
invokeUnchecked(handler, attachment, result, exc);
}
});
} catch (RejectedExecutionException ree) {
throw new ShutdownChannelGroupException();
}
}
/**
* Invokes the handler "indirectly" in the given Executor
*/
static <V,A> void invokeIndirectly(final CompletionHandler<V,? super A> handler,
final A attachment,
final V value,
final Throwable exc,
Executor executor)
{
try {
executor.execute(new Runnable() {
public void run() {
invokeUnchecked(handler, attachment, value, exc);
}
});
} catch (RejectedExecutionException ree) {
throw new ShutdownChannelGroupException();
}
}
/**
* Invokes the given task on the thread pool associated with the given
* channel. If the current thread is in the thread pool then the task is
* invoked directly.
*/
static void invokeOnThreadInThreadPool(Groupable channel,
Runnable task)
{
boolean invokeDirect;
GroupAndInvokeCount thisGroupAndInvokeCount = myGroupAndInvokeCount.get();
AsynchronousChannelGroupImpl targetGroup = channel.group();
if (thisGroupAndInvokeCount == null) {
invokeDirect = false;
} else {
invokeDirect = (thisGroupAndInvokeCount.group == targetGroup);
}
try {
if (invokeDirect) {
task.run();
} else {
targetGroup.executeOnPooledThread(task);
}
} catch (RejectedExecutionException ree) {
throw new ShutdownChannelGroupException();
}
}
/**
* Invoke handler with completed result. This method does not check the
* thread identity or the number of handlers on the thread stack.
*/
static <V,A> void invokeUnchecked(PendingFuture<V,A> future) {
assert future.isDone();
CompletionHandler<V,? super A> handler = future.handler();
if (handler != null) {
invokeUnchecked(handler,
future.attachment(),
future.value(),
future.exception());
}
}
/**
* Invoke handler with completed result. If the current thread is in the
* channel group's thread pool then the handler is invoked directly,
* otherwise it is invoked indirectly.
*/
static <V,A> void invoke(PendingFuture<V,A> future) {
assert future.isDone();
CompletionHandler<V,? super A> handler = future.handler();
if (handler != null) {
invoke(future.channel(),
handler,
future.attachment(),
future.value(),
future.exception());
}
}
/**
* Invoke handler with completed result. The handler is invoked indirectly,
* via the channel group's thread pool.
*/
static <V,A> void invokeIndirectly(PendingFuture<V,A> future) {
assert future.isDone();
CompletionHandler<V,? super A> handler = future.handler();
if (handler != null) {
invokeIndirectly(future.channel(),
handler,
future.attachment(),
future.value(),
future.exception());
}
}
}

View file

@ -0,0 +1,219 @@
/*
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.nio.channels.*;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.io.IOException;
import java.util.HashSet;
/**
* MembershipKey implementation.
*/
class MembershipKeyImpl
extends MembershipKey
{
private final MulticastChannel ch;
private final InetAddress group;
private final NetworkInterface interf;
private final InetAddress source;
private volatile boolean invalid;
// lock used when creating or accessing blockedSet
private Object stateLock = new Object();
// set of source addresses that are blocked
private HashSet<InetAddress> blockedSet;
private MembershipKeyImpl(MulticastChannel ch,
InetAddress group,
NetworkInterface interf,
InetAddress source)
{
this.ch = ch;
this.group = group;
this.interf = interf;
this.source = source;
}
/**
* MembershipKey will additional context for IPv4 membership
*/
static class Type4 extends MembershipKeyImpl {
private final int groupAddress;
private final int interfAddress;
private final int sourceAddress;
Type4(MulticastChannel ch,
InetAddress group,
NetworkInterface interf,
InetAddress source,
int groupAddress,
int interfAddress,
int sourceAddress)
{
super(ch, group, interf, source);
this.groupAddress = groupAddress;
this.interfAddress = interfAddress;
this.sourceAddress = sourceAddress;
}
int groupAddress() {
return groupAddress;
}
int interfaceAddress() {
return interfAddress;
}
int source() {
return sourceAddress;
}
}
/**
* MembershipKey will additional context for IPv6 membership
*/
static class Type6 extends MembershipKeyImpl {
private final byte[] groupAddress;
private final int index;
private final byte[] sourceAddress;
Type6(MulticastChannel ch,
InetAddress group,
NetworkInterface interf,
InetAddress source,
byte[] groupAddress,
int index,
byte[] sourceAddress)
{
super(ch, group, interf, source);
this.groupAddress = groupAddress;
this.index = index;
this.sourceAddress = sourceAddress;
}
byte[] groupAddress() {
return groupAddress;
}
int index() {
return index;
}
byte[] source() {
return sourceAddress;
}
}
public boolean isValid() {
return !invalid;
}
// package-private
void invalidate() {
invalid = true;
}
public void drop() {
// delegate to channel
((DatagramChannelImpl)ch).drop(this);
}
@Override
public MulticastChannel channel() {
return ch;
}
@Override
public InetAddress group() {
return group;
}
@Override
public NetworkInterface networkInterface() {
return interf;
}
@Override
public InetAddress sourceAddress() {
return source;
}
@Override
public MembershipKey block(InetAddress toBlock)
throws IOException
{
if (source != null)
throw new IllegalStateException("key is source-specific");
synchronized (stateLock) {
if ((blockedSet != null) && blockedSet.contains(toBlock)) {
// already blocked, nothing to do
return this;
}
((DatagramChannelImpl)ch).block(this, toBlock);
// created blocked set if required and add source address
if (blockedSet == null)
blockedSet = new HashSet<>();
blockedSet.add(toBlock);
}
return this;
}
@Override
public MembershipKey unblock(InetAddress toUnblock) {
synchronized (stateLock) {
if ((blockedSet == null) || !blockedSet.contains(toUnblock))
throw new IllegalStateException("not blocked");
((DatagramChannelImpl)ch).unblock(this, toUnblock);
blockedSet.remove(toUnblock);
}
return this;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(64);
sb.append('<');
sb.append(group.getHostAddress());
sb.append(',');
sb.append(interf.getName());
if (source != null) {
sb.append(',');
sb.append(source.getHostAddress());
}
sb.append('>');
return sb.toString();
}
}

View file

@ -0,0 +1,131 @@
/*
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.nio.channels.*;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.*;
/**
* Simple registry of membership keys for a MulticastChannel.
*
* Instances of this object are not safe by multiple concurrent threads.
*/
class MembershipRegistry {
// map multicast group to keys
private Map<InetAddress,List<MembershipKeyImpl>> groups = null;
MembershipRegistry() {
}
/**
* Checks registry for membership of the group on the given
* network interface.
*/
MembershipKey checkMembership(InetAddress group, NetworkInterface interf,
InetAddress source)
{
if (groups != null) {
List<MembershipKeyImpl> keys = groups.get(group);
if (keys != null) {
for (MembershipKeyImpl key: keys) {
if (key.networkInterface().equals(interf)) {
// already a member to receive all packets so return
// existing key or detect conflict
if (source == null) {
if (key.sourceAddress() == null)
return key;
throw new IllegalStateException("Already a member to receive all packets");
}
// already have source-specific membership so return key
// or detect conflict
if (key.sourceAddress() == null)
throw new IllegalStateException("Already have source-specific membership");
if (source.equals(key.sourceAddress()))
return key;
}
}
}
}
return null;
}
/**
* Add membership to the registry, returning a new membership key.
*/
void add(MembershipKeyImpl key) {
InetAddress group = key.group();
List<MembershipKeyImpl> keys;
if (groups == null) {
groups = new HashMap<>();
keys = null;
} else {
keys = groups.get(group);
}
if (keys == null) {
keys = new LinkedList<>();
groups.put(group, keys);
}
keys.add(key);
}
/**
* Remove a key from the registry
*/
void remove(MembershipKeyImpl key) {
InetAddress group = key.group();
List<MembershipKeyImpl> keys = groups.get(group);
if (keys != null) {
Iterator<MembershipKeyImpl> i = keys.iterator();
while (i.hasNext()) {
if (i.next() == key) {
i.remove();
break;
}
}
if (keys.isEmpty()) {
groups.remove(group);
}
}
}
/**
* Invalidate all keys in the registry
*/
void invalidateAll() {
if (groups != null) {
for (InetAddress group: groups.keySet()) {
for (MembershipKeyImpl key: groups.get(group)) {
key.invalidate();
}
}
}
}
}

View file

@ -0,0 +1,80 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.io.*;
/**
* Allows different platforms to call different native methods
* for read and write operations.
*/
abstract class NativeDispatcher
{
abstract int read(FileDescriptor fd, long address, int len)
throws IOException;
/**
* Returns {@code true} if pread/pwrite needs to be synchronized with
* position sensitive methods.
*/
boolean needsPositionLock() {
return false;
}
int pread(FileDescriptor fd, long address, int len, long position)
throws IOException
{
throw new IOException("Operation Unsupported");
}
abstract long readv(FileDescriptor fd, long address, int len)
throws IOException;
abstract int write(FileDescriptor fd, long address, int len)
throws IOException;
int pwrite(FileDescriptor fd, long address, int len, long position)
throws IOException
{
throw new IOException("Operation Unsupported");
}
abstract long writev(FileDescriptor fd, long address, int len)
throws IOException;
abstract void close(FileDescriptor fd) throws IOException;
// Prepare the given fd for closing by duping it to a known internal fd
// that's already closed. This is necessary on some operating systems
// (Solaris and Linux) to prevent fd recycling.
//
void preClose(FileDescriptor fd) throws IOException {
// Do nothing by default; this is only needed on Unix
}
}

View file

@ -0,0 +1,405 @@
/*
* Copyright (c) 2000, 2002, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*/
package sun.nio.ch; // Formerly in sun.misc
import java.nio.ByteOrder;
import jdk.internal.misc.Unsafe;
// ## In the fullness of time, this class will be eliminated
/**
* Proxies for objects that reside in native memory.
*/
class NativeObject { // package-private
protected static final Unsafe unsafe = Unsafe.getUnsafe();
// Native allocation address;
// may be smaller than the base address due to page-size rounding
//
protected long allocationAddress;
// Native base address
//
private final long address;
/**
* Creates a new native object that is based at the given native address.
*/
NativeObject(long address) {
this.allocationAddress = address;
this.address = address;
}
/**
* Creates a new native object allocated at the given native address but
* whose base is at the additional offset.
*/
NativeObject(long address, long offset) {
this.allocationAddress = address;
this.address = address + offset;
}
// Invoked only by AllocatedNativeObject
//
protected NativeObject(int size, boolean pageAligned) {
if (!pageAligned) {
this.allocationAddress = unsafe.allocateMemory(size);
this.address = this.allocationAddress;
} else {
int ps = pageSize();
long a = unsafe.allocateMemory(size + ps);
this.allocationAddress = a;
this.address = a + ps - (a & (ps - 1));
}
}
/**
* Returns the native base address of this native object.
*
* @return The native base address
*/
long address() {
return address;
}
long allocationAddress() {
return allocationAddress;
}
/**
* Creates a new native object starting at the given offset from the base
* of this native object.
*
* @param offset
* The offset from the base of this native object that is to be
* the base of the new native object
*
* @return The newly created native object
*/
NativeObject subObject(int offset) {
return new NativeObject(offset + address);
}
/**
* Reads an address from this native object at the given offset and
* constructs a native object using that address.
*
* @param offset
* The offset of the address to be read. Note that the size of an
* address is implementation-dependent.
*
* @return The native object created using the address read from the
* given offset
*/
NativeObject getObject(int offset) {
long newAddress = 0L;
switch (addressSize()) {
case 8:
newAddress = unsafe.getLong(offset + address);
break;
case 4:
newAddress = unsafe.getInt(offset + address) & 0x00000000FFFFFFFF;
break;
default:
throw new InternalError("Address size not supported");
}
return new NativeObject(newAddress);
}
/**
* Writes the base address of the given native object at the given offset
* of this native object.
*
* @param offset
* The offset at which the address is to be written. Note that the
* size of an address is implementation-dependent.
*
* @param ob
* The native object whose address is to be written
*/
void putObject(int offset, NativeObject ob) {
switch (addressSize()) {
case 8:
putLong(offset, ob.address);
break;
case 4:
putInt(offset, (int)(ob.address & 0x00000000FFFFFFFF));
break;
default:
throw new InternalError("Address size not supported");
}
}
/* -- Value accessors: No range checking! -- */
/**
* Reads a byte starting at the given offset from base of this native
* object.
*
* @param offset
* The offset at which to read the byte
*
* @return The byte value read
*/
final byte getByte(int offset) {
return unsafe.getByte(offset + address);
}
/**
* Writes a byte at the specified offset from this native object's
* base address.
*
* @param offset
* The offset at which to write the byte
*
* @param value
* The byte value to be written
*/
final void putByte(int offset, byte value) {
unsafe.putByte(offset + address, value);
}
/**
* Reads a short starting at the given offset from base of this native
* object.
*
* @param offset
* The offset at which to read the short
*
* @return The short value read
*/
final short getShort(int offset) {
return unsafe.getShort(offset + address);
}
/**
* Writes a short at the specified offset from this native object's
* base address.
*
* @param offset
* The offset at which to write the short
*
* @param value
* The short value to be written
*/
final void putShort(int offset, short value) {
unsafe.putShort(offset + address, value);
}
/**
* Reads a char starting at the given offset from base of this native
* object.
*
* @param offset
* The offset at which to read the char
*
* @return The char value read
*/
final char getChar(int offset) {
return unsafe.getChar(offset + address);
}
/**
* Writes a char at the specified offset from this native object's
* base address.
*
* @param offset
* The offset at which to write the char
*
* @param value
* The char value to be written
*/
final void putChar(int offset, char value) {
unsafe.putChar(offset + address, value);
}
/**
* Reads an int starting at the given offset from base of this native
* object.
*
* @param offset
* The offset at which to read the int
*
* @return The int value read
*/
final int getInt(int offset) {
return unsafe.getInt(offset + address);
}
/**
* Writes an int at the specified offset from this native object's
* base address.
*
* @param offset
* The offset at which to write the int
*
* @param value
* The int value to be written
*/
final void putInt(int offset, int value) {
unsafe.putInt(offset + address, value);
}
/**
* Reads a long starting at the given offset from base of this native
* object.
*
* @param offset
* The offset at which to read the long
*
* @return The long value read
*/
final long getLong(int offset) {
return unsafe.getLong(offset + address);
}
/**
* Writes a long at the specified offset from this native object's
* base address.
*
* @param offset
* The offset at which to write the long
*
* @param value
* The long value to be written
*/
final void putLong(int offset, long value) {
unsafe.putLong(offset + address, value);
}
/**
* Reads a float starting at the given offset from base of this native
* object.
*
* @param offset
* The offset at which to read the float
*
* @return The float value read
*/
final float getFloat(int offset) {
return unsafe.getFloat(offset + address);
}
/**
* Writes a float at the specified offset from this native object's
* base address.
*
* @param offset
* The offset at which to write the float
*
* @param value
* The float value to be written
*/
final void putFloat(int offset, float value) {
unsafe.putFloat(offset + address, value);
}
/**
* Reads a double starting at the given offset from base of this native
* object.
*
* @param offset
* The offset at which to read the double
*
* @return The double value read
*/
final double getDouble(int offset) {
return unsafe.getDouble(offset + address);
}
/**
* Writes a double at the specified offset from this native object's
* base address.
*
* @param offset
* The offset at which to write the double
*
* @param value
* The double value to be written
*/
final void putDouble(int offset, double value) {
unsafe.putDouble(offset + address, value);
}
/**
* Returns the native architecture's address size in bytes.
*
* @return The address size of the native architecture
*/
static int addressSize() {
return unsafe.addressSize();
}
// Cache for byte order
private static ByteOrder byteOrder = null;
/**
* Returns the byte order of the underlying hardware.
*
* @return An instance of {@link java.nio.ByteOrder}
*/
static ByteOrder byteOrder() {
if (byteOrder != null)
return byteOrder;
long a = unsafe.allocateMemory(8);
try {
unsafe.putLong(a, 0x0102030405060708L);
byte b = unsafe.getByte(a);
switch (b) {
case 0x01: byteOrder = ByteOrder.BIG_ENDIAN; break;
case 0x08: byteOrder = ByteOrder.LITTLE_ENDIAN; break;
default:
assert false;
}
} finally {
unsafe.freeMemory(a);
}
return byteOrder;
}
// Cache for page size
private static int pageSize = -1;
/**
* Returns the page size of the underlying hardware.
*
* @return The page size, in bytes
*/
static int pageSize() {
if (pageSize == -1)
pageSize = unsafe.pageSize();
return pageSize;
}
}

View file

@ -0,0 +1,111 @@
/*
* Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
// Special-purpose data structure for sets of native threads
class NativeThreadSet {
private long[] elts;
private int used = 0;
private boolean waitingToEmpty;
NativeThreadSet(int n) {
elts = new long[n];
}
// Adds the current native thread to this set, returning its index so that
// it can efficiently be removed later.
//
int add() {
long th = NativeThread.current();
// 0 and -1 are treated as placeholders, not real thread handles
if (th == 0)
th = -1;
synchronized (this) {
int start = 0;
if (used >= elts.length) {
int on = elts.length;
int nn = on * 2;
long[] nelts = new long[nn];
System.arraycopy(elts, 0, nelts, 0, on);
elts = nelts;
start = on;
}
for (int i = start; i < elts.length; i++) {
if (elts[i] == 0) {
elts[i] = th;
used++;
return i;
}
}
assert false;
return -1;
}
}
// Removes the thread at the given index.
//
void remove(int i) {
synchronized (this) {
elts[i] = 0;
used--;
if (used == 0 && waitingToEmpty)
notifyAll();
}
}
// Signals all threads in this set.
//
synchronized void signalAndWait() {
boolean interrupted = false;
while (used > 0) {
int u = used;
int n = elts.length;
for (int i = 0; i < n; i++) {
long th = elts[i];
if (th == 0)
continue;
if (th != -1)
NativeThread.signal(th);
if (--u == 0)
break;
}
waitingToEmpty = true;
try {
wait(50);
} catch (InterruptedException e) {
interrupted = true;
} finally {
waitingToEmpty = false;
}
}
if (interrupted)
Thread.currentThread().interrupt();
}
}

View file

@ -0,0 +1,652 @@
/*
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.io.*;
import java.net.*;
import java.nio.channels.*;
import java.util.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
import sun.net.ext.ExtendedSocketOptions;
import sun.security.action.GetPropertyAction;
public class Net {
private Net() { }
// unspecified protocol family
static final ProtocolFamily UNSPEC = new ProtocolFamily() {
public String name() {
return "UNSPEC";
}
};
// set to true if exclusive binding is on for Windows
private static final boolean exclusiveBind;
// set to true if the fast tcp loopback should be enabled on Windows
private static final boolean fastLoopback;
// -- Miscellaneous utilities --
private static volatile boolean checkedIPv6;
private static volatile boolean isIPv6Available;
private static volatile boolean checkedReusePort;
private static volatile boolean isReusePortAvailable;
/**
* Tells whether dual-IPv4/IPv6 sockets should be used.
*/
static boolean isIPv6Available() {
if (!checkedIPv6) {
isIPv6Available = isIPv6Available0();
checkedIPv6 = true;
}
return isIPv6Available;
}
/**
* Tells whether SO_REUSEPORT is supported.
*/
static boolean isReusePortAvailable() {
if (!checkedReusePort) {
isReusePortAvailable = isReusePortAvailable0();
checkedReusePort = true;
}
return isReusePortAvailable;
}
/**
* Returns true if exclusive binding is on
*/
static boolean useExclusiveBind() {
return exclusiveBind;
}
/**
* Tells whether IPv6 sockets can join IPv4 multicast groups
*/
static boolean canIPv6SocketJoinIPv4Group() {
return canIPv6SocketJoinIPv4Group0();
}
/**
* Tells whether {@link #join6} can be used to join an IPv4
* multicast group (IPv4 group as IPv4-mapped IPv6 address)
*/
static boolean canJoin6WithIPv4Group() {
return canJoin6WithIPv4Group0();
}
public static InetSocketAddress checkAddress(SocketAddress sa) {
if (sa == null)
throw new NullPointerException();
if (!(sa instanceof InetSocketAddress))
throw new UnsupportedAddressTypeException(); // ## needs arg
InetSocketAddress isa = (InetSocketAddress)sa;
if (isa.isUnresolved())
throw new UnresolvedAddressException(); // ## needs arg
InetAddress addr = isa.getAddress();
if (!(addr instanceof Inet4Address || addr instanceof Inet6Address))
throw new IllegalArgumentException("Invalid address type");
return isa;
}
static InetSocketAddress asInetSocketAddress(SocketAddress sa) {
if (!(sa instanceof InetSocketAddress))
throw new UnsupportedAddressTypeException();
return (InetSocketAddress)sa;
}
static void translateToSocketException(Exception x)
throws SocketException
{
if (x instanceof SocketException)
throw (SocketException)x;
Exception nx = x;
if (x instanceof ClosedChannelException)
nx = new SocketException("Socket is closed");
else if (x instanceof NotYetConnectedException)
nx = new SocketException("Socket is not connected");
else if (x instanceof AlreadyBoundException)
nx = new SocketException("Already bound");
else if (x instanceof NotYetBoundException)
nx = new SocketException("Socket is not bound yet");
else if (x instanceof UnsupportedAddressTypeException)
nx = new SocketException("Unsupported address type");
else if (x instanceof UnresolvedAddressException) {
nx = new SocketException("Unresolved address");
}
if (nx != x)
nx.initCause(x);
if (nx instanceof SocketException)
throw (SocketException)nx;
else if (nx instanceof RuntimeException)
throw (RuntimeException)nx;
else
throw new Error("Untranslated exception", nx);
}
static void translateException(Exception x,
boolean unknownHostForUnresolved)
throws IOException
{
if (x instanceof IOException)
throw (IOException)x;
// Throw UnknownHostException from here since it cannot
// be thrown as a SocketException
if (unknownHostForUnresolved &&
(x instanceof UnresolvedAddressException))
{
throw new UnknownHostException();
}
translateToSocketException(x);
}
static void translateException(Exception x)
throws IOException
{
translateException(x, false);
}
/**
* Returns the local address after performing a SecurityManager#checkConnect.
*/
static InetSocketAddress getRevealedLocalAddress(InetSocketAddress addr) {
SecurityManager sm = System.getSecurityManager();
if (addr == null || sm == null)
return addr;
try{
sm.checkConnect(addr.getAddress().getHostAddress(), -1);
// Security check passed
} catch (SecurityException e) {
// Return loopback address only if security check fails
addr = getLoopbackAddress(addr.getPort());
}
return addr;
}
static String getRevealedLocalAddressAsString(InetSocketAddress addr) {
return System.getSecurityManager() == null ? addr.toString() :
getLoopbackAddress(addr.getPort()).toString();
}
private static InetSocketAddress getLoopbackAddress(int port) {
return new InetSocketAddress(InetAddress.getLoopbackAddress(),
port);
}
/**
* Returns any IPv4 address of the given network interface, or
* null if the interface does not have any IPv4 addresses.
*/
static Inet4Address anyInet4Address(final NetworkInterface interf) {
return AccessController.doPrivileged(new PrivilegedAction<Inet4Address>() {
public Inet4Address run() {
Enumeration<InetAddress> addrs = interf.getInetAddresses();
while (addrs.hasMoreElements()) {
InetAddress addr = addrs.nextElement();
if (addr instanceof Inet4Address) {
return (Inet4Address)addr;
}
}
return null;
}
});
}
/**
* Returns an IPv4 address as an int.
*/
static int inet4AsInt(InetAddress ia) {
if (ia instanceof Inet4Address) {
byte[] addr = ia.getAddress();
int address = addr[3] & 0xFF;
address |= ((addr[2] << 8) & 0xFF00);
address |= ((addr[1] << 16) & 0xFF0000);
address |= ((addr[0] << 24) & 0xFF000000);
return address;
}
throw new AssertionError("Should not reach here");
}
/**
* Returns an InetAddress from the given IPv4 address
* represented as an int.
*/
static InetAddress inet4FromInt(int address) {
byte[] addr = new byte[4];
addr[0] = (byte) ((address >>> 24) & 0xFF);
addr[1] = (byte) ((address >>> 16) & 0xFF);
addr[2] = (byte) ((address >>> 8) & 0xFF);
addr[3] = (byte) (address & 0xFF);
try {
return InetAddress.getByAddress(addr);
} catch (UnknownHostException uhe) {
throw new AssertionError("Should not reach here");
}
}
/**
* Returns an IPv6 address as a byte array
*/
static byte[] inet6AsByteArray(InetAddress ia) {
if (ia instanceof Inet6Address) {
return ia.getAddress();
}
// need to construct IPv4-mapped address
if (ia instanceof Inet4Address) {
byte[] ip4address = ia.getAddress();
byte[] address = new byte[16];
address[10] = (byte)0xff;
address[11] = (byte)0xff;
address[12] = ip4address[0];
address[13] = ip4address[1];
address[14] = ip4address[2];
address[15] = ip4address[3];
return address;
}
throw new AssertionError("Should not reach here");
}
// -- Socket options
static final ExtendedSocketOptions extendedOptions =
ExtendedSocketOptions.getInstance();
static void setSocketOption(FileDescriptor fd, ProtocolFamily family,
SocketOption<?> name, Object value)
throws IOException
{
if (value == null)
throw new IllegalArgumentException("Invalid option value");
// only simple values supported by this method
Class<?> type = name.type();
if (extendedOptions.isOptionSupported(name)) {
extendedOptions.setOption(fd, name, value);
return;
}
if (type != Integer.class && type != Boolean.class)
throw new AssertionError("Should not reach here");
// special handling
if (name == StandardSocketOptions.SO_RCVBUF ||
name == StandardSocketOptions.SO_SNDBUF)
{
int i = ((Integer)value).intValue();
if (i < 0)
throw new IllegalArgumentException("Invalid send/receive buffer size");
}
if (name == StandardSocketOptions.SO_LINGER) {
int i = ((Integer)value).intValue();
if (i < 0)
value = Integer.valueOf(-1);
if (i > 65535)
value = Integer.valueOf(65535);
}
if (name == StandardSocketOptions.IP_TOS) {
int i = ((Integer)value).intValue();
if (i < 0 || i > 255)
throw new IllegalArgumentException("Invalid IP_TOS value");
}
if (name == StandardSocketOptions.IP_MULTICAST_TTL) {
int i = ((Integer)value).intValue();
if (i < 0 || i > 255)
throw new IllegalArgumentException("Invalid TTL/hop value");
}
// map option name to platform level/name
OptionKey key = SocketOptionRegistry.findOption(name, family);
if (key == null)
throw new AssertionError("Option not found");
int arg;
if (type == Integer.class) {
arg = ((Integer)value).intValue();
} else {
boolean b = ((Boolean)value).booleanValue();
arg = (b) ? 1 : 0;
}
boolean mayNeedConversion = (family == UNSPEC);
boolean isIPv6 = (family == StandardProtocolFamily.INET6);
setIntOption0(fd, mayNeedConversion, key.level(), key.name(), arg, isIPv6);
}
static Object getSocketOption(FileDescriptor fd, ProtocolFamily family,
SocketOption<?> name)
throws IOException
{
Class<?> type = name.type();
if (extendedOptions.isOptionSupported(name)) {
return extendedOptions.getOption(fd, name);
}
// only simple values supported by this method
if (type != Integer.class && type != Boolean.class)
throw new AssertionError("Should not reach here");
// map option name to platform level/name
OptionKey key = SocketOptionRegistry.findOption(name, family);
if (key == null)
throw new AssertionError("Option not found");
boolean mayNeedConversion = (family == UNSPEC);
int value = getIntOption0(fd, mayNeedConversion, key.level(), key.name());
if (type == Integer.class) {
return Integer.valueOf(value);
} else {
return (value == 0) ? Boolean.FALSE : Boolean.TRUE;
}
}
public static boolean isFastTcpLoopbackRequested() {
String loopbackProp = GetPropertyAction
.privilegedGetProperty("jdk.net.useFastTcpLoopback");
boolean enable;
if ("".equals(loopbackProp)) {
enable = true;
} else {
enable = Boolean.parseBoolean(loopbackProp);
}
return enable;
}
// -- Socket operations --
private static native boolean isIPv6Available0();
private static native boolean isReusePortAvailable0();
/*
* Returns 1 for Windows and -1 for Solaris/Linux/Mac OS
*/
private static native int isExclusiveBindAvailable();
private static native boolean canIPv6SocketJoinIPv4Group0();
private static native boolean canJoin6WithIPv4Group0();
static FileDescriptor socket(boolean stream) throws IOException {
return socket(UNSPEC, stream);
}
static FileDescriptor socket(ProtocolFamily family, boolean stream)
throws IOException {
boolean preferIPv6 = isIPv6Available() &&
(family != StandardProtocolFamily.INET);
return IOUtil.newFD(socket0(preferIPv6, stream, false, fastLoopback));
}
static FileDescriptor serverSocket(boolean stream) {
return IOUtil.newFD(socket0(isIPv6Available(), stream, true, fastLoopback));
}
// Due to oddities SO_REUSEADDR on windows reuse is ignored
private static native int socket0(boolean preferIPv6, boolean stream, boolean reuse,
boolean fastLoopback);
public static void bind(FileDescriptor fd, InetAddress addr, int port)
throws IOException
{
bind(UNSPEC, fd, addr, port);
}
static void bind(ProtocolFamily family, FileDescriptor fd,
InetAddress addr, int port) throws IOException
{
boolean preferIPv6 = isIPv6Available() &&
(family != StandardProtocolFamily.INET);
bind0(fd, preferIPv6, exclusiveBind, addr, port);
}
private static native void bind0(FileDescriptor fd, boolean preferIPv6,
boolean useExclBind, InetAddress addr,
int port)
throws IOException;
static native void listen(FileDescriptor fd, int backlog) throws IOException;
static int connect(FileDescriptor fd, InetAddress remote, int remotePort)
throws IOException
{
return connect(UNSPEC, fd, remote, remotePort);
}
static int connect(ProtocolFamily family, FileDescriptor fd, InetAddress remote, int remotePort)
throws IOException
{
boolean preferIPv6 = isIPv6Available() &&
(family != StandardProtocolFamily.INET);
return connect0(preferIPv6, fd, remote, remotePort);
}
private static native int connect0(boolean preferIPv6,
FileDescriptor fd,
InetAddress remote,
int remotePort)
throws IOException;
public static final int SHUT_RD = 0;
public static final int SHUT_WR = 1;
public static final int SHUT_RDWR = 2;
static native void shutdown(FileDescriptor fd, int how) throws IOException;
private static native int localPort(FileDescriptor fd)
throws IOException;
private static native InetAddress localInetAddress(FileDescriptor fd)
throws IOException;
public static InetSocketAddress localAddress(FileDescriptor fd)
throws IOException
{
return new InetSocketAddress(localInetAddress(fd), localPort(fd));
}
private static native int remotePort(FileDescriptor fd)
throws IOException;
private static native InetAddress remoteInetAddress(FileDescriptor fd)
throws IOException;
static InetSocketAddress remoteAddress(FileDescriptor fd)
throws IOException
{
return new InetSocketAddress(remoteInetAddress(fd), remotePort(fd));
}
private static native int getIntOption0(FileDescriptor fd, boolean mayNeedConversion,
int level, int opt)
throws IOException;
private static native void setIntOption0(FileDescriptor fd, boolean mayNeedConversion,
int level, int opt, int arg, boolean isIPv6)
throws IOException;
static native int poll(FileDescriptor fd, int events, long timeout)
throws IOException;
// -- Multicast support --
/**
* Join IPv4 multicast group
*/
static int join4(FileDescriptor fd, int group, int interf, int source)
throws IOException
{
return joinOrDrop4(true, fd, group, interf, source);
}
/**
* Drop membership of IPv4 multicast group
*/
static void drop4(FileDescriptor fd, int group, int interf, int source)
throws IOException
{
joinOrDrop4(false, fd, group, interf, source);
}
private static native int joinOrDrop4(boolean join, FileDescriptor fd, int group, int interf, int source)
throws IOException;
/**
* Block IPv4 source
*/
static int block4(FileDescriptor fd, int group, int interf, int source)
throws IOException
{
return blockOrUnblock4(true, fd, group, interf, source);
}
/**
* Unblock IPv6 source
*/
static void unblock4(FileDescriptor fd, int group, int interf, int source)
throws IOException
{
blockOrUnblock4(false, fd, group, interf, source);
}
private static native int blockOrUnblock4(boolean block, FileDescriptor fd, int group,
int interf, int source)
throws IOException;
/**
* Join IPv6 multicast group
*/
static int join6(FileDescriptor fd, byte[] group, int index, byte[] source)
throws IOException
{
return joinOrDrop6(true, fd, group, index, source);
}
/**
* Drop membership of IPv6 multicast group
*/
static void drop6(FileDescriptor fd, byte[] group, int index, byte[] source)
throws IOException
{
joinOrDrop6(false, fd, group, index, source);
}
private static native int joinOrDrop6(boolean join, FileDescriptor fd, byte[] group, int index, byte[] source)
throws IOException;
/**
* Block IPv6 source
*/
static int block6(FileDescriptor fd, byte[] group, int index, byte[] source)
throws IOException
{
return blockOrUnblock6(true, fd, group, index, source);
}
/**
* Unblock IPv6 source
*/
static void unblock6(FileDescriptor fd, byte[] group, int index, byte[] source)
throws IOException
{
blockOrUnblock6(false, fd, group, index, source);
}
static native int blockOrUnblock6(boolean block, FileDescriptor fd, byte[] group, int index, byte[] source)
throws IOException;
static native void setInterface4(FileDescriptor fd, int interf) throws IOException;
static native int getInterface4(FileDescriptor fd) throws IOException;
static native void setInterface6(FileDescriptor fd, int index) throws IOException;
static native int getInterface6(FileDescriptor fd) throws IOException;
private static native void initIDs();
/**
* Event masks for the various poll system calls.
* They will be set platform dependent in the static initializer below.
*/
public static final short POLLIN;
public static final short POLLOUT;
public static final short POLLERR;
public static final short POLLHUP;
public static final short POLLNVAL;
public static final short POLLCONN;
static native short pollinValue();
static native short polloutValue();
static native short pollerrValue();
static native short pollhupValue();
static native short pollnvalValue();
static native short pollconnValue();
static {
IOUtil.load();
initIDs();
POLLIN = pollinValue();
POLLOUT = polloutValue();
POLLERR = pollerrValue();
POLLHUP = pollhupValue();
POLLNVAL = pollnvalValue();
POLLCONN = pollconnValue();
}
static {
int availLevel = isExclusiveBindAvailable();
if (availLevel >= 0) {
String exclBindProp = GetPropertyAction
.privilegedGetProperty("sun.net.useExclusiveBind");
if (exclBindProp != null) {
exclusiveBind = exclBindProp.isEmpty() ?
true : Boolean.parseBoolean(exclBindProp);
} else if (availLevel == 1) {
exclusiveBind = true;
} else {
exclusiveBind = false;
}
} else {
exclusiveBind = false;
}
fastLoopback = isFastTcpLoopbackRequested();
}
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
/**
* Represents the level/name of a socket option
*/
class OptionKey {
private int level;
private int name;
OptionKey(int level, int name) {
this.level = level;
this.name = name;
}
int level() {
return level;
}
int name() {
return name;
}
}

View file

@ -0,0 +1,252 @@
/*
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.nio.channels.*;
import java.util.concurrent.*;
import java.io.IOException;
/**
* A Future for a pending I/O operation. A PendingFuture allows for the
* attachment of an additional arbitrary context object and a timer task.
*/
final class PendingFuture<V,A> implements Future<V> {
private final AsynchronousChannel channel;
private final CompletionHandler<V,? super A> handler;
private final A attachment;
// true if result (or exception) is available
private volatile boolean haveResult;
private volatile V result;
private volatile Throwable exc;
// latch for waiting (created lazily if needed)
private CountDownLatch latch;
// optional timer task that is cancelled when result becomes available
private Future<?> timeoutTask;
// optional context object
private volatile Object context;
PendingFuture(AsynchronousChannel channel,
CompletionHandler<V,? super A> handler,
A attachment,
Object context)
{
this.channel = channel;
this.handler = handler;
this.attachment = attachment;
this.context = context;
}
PendingFuture(AsynchronousChannel channel,
CompletionHandler<V,? super A> handler,
A attachment)
{
this.channel = channel;
this.handler = handler;
this.attachment = attachment;
}
PendingFuture(AsynchronousChannel channel) {
this(channel, null, null);
}
PendingFuture(AsynchronousChannel channel, Object context) {
this(channel, null, null, context);
}
AsynchronousChannel channel() {
return channel;
}
CompletionHandler<V,? super A> handler() {
return handler;
}
A attachment() {
return attachment;
}
void setContext(Object context) {
this.context = context;
}
Object getContext() {
return context;
}
void setTimeoutTask(Future<?> task) {
synchronized (this) {
if (haveResult) {
task.cancel(false);
} else {
this.timeoutTask = task;
}
}
}
// creates latch if required; return true if caller needs to wait
private boolean prepareForWait() {
synchronized (this) {
if (haveResult) {
return false;
} else {
if (latch == null)
latch = new CountDownLatch(1);
return true;
}
}
}
/**
* Sets the result, or a no-op if the result or exception is already set.
*/
void setResult(V res) {
synchronized (this) {
if (haveResult)
return;
result = res;
haveResult = true;
if (timeoutTask != null)
timeoutTask.cancel(false);
if (latch != null)
latch.countDown();
}
}
/**
* Sets the result, or a no-op if the result or exception is already set.
*/
void setFailure(Throwable x) {
if (!(x instanceof IOException) && !(x instanceof SecurityException))
x = new IOException(x);
synchronized (this) {
if (haveResult)
return;
exc = x;
haveResult = true;
if (timeoutTask != null)
timeoutTask.cancel(false);
if (latch != null)
latch.countDown();
}
}
/**
* Sets the result
*/
void setResult(V res, Throwable x) {
if (x == null) {
setResult(res);
} else {
setFailure(x);
}
}
@Override
public V get() throws ExecutionException, InterruptedException {
if (!haveResult) {
boolean needToWait = prepareForWait();
if (needToWait)
latch.await();
}
if (exc != null) {
if (exc instanceof CancellationException)
throw new CancellationException();
throw new ExecutionException(exc);
}
return result;
}
@Override
public V get(long timeout, TimeUnit unit)
throws ExecutionException, InterruptedException, TimeoutException
{
if (!haveResult) {
boolean needToWait = prepareForWait();
if (needToWait)
if (!latch.await(timeout, unit)) throw new TimeoutException();
}
if (exc != null) {
if (exc instanceof CancellationException)
throw new CancellationException();
throw new ExecutionException(exc);
}
return result;
}
Throwable exception() {
return (exc instanceof CancellationException) ? null : exc;
}
V value() {
return result;
}
@Override
public boolean isCancelled() {
return (exc instanceof CancellationException);
}
@Override
public boolean isDone() {
return haveResult;
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
synchronized (this) {
if (haveResult)
return false; // already completed
// notify channel
if (channel() instanceof Cancellable)
((Cancellable)channel()).onCancel(this);
// set result and cancel timer
exc = new CancellationException();
haveResult = true;
if (timeoutTask != null)
timeoutTask.cancel(false);
}
// close channel if forceful cancel
if (mayInterruptIfRunning) {
try {
channel().close();
} catch (IOException ignore) { }
}
// release waiters
if (latch != null)
latch.countDown();
return true;
}
}

View file

@ -0,0 +1,42 @@
/*
* Copyright (c) 2001, 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.io.IOException;
import java.nio.channels.*;
import java.nio.channels.spi.*;
public class PollSelectorProvider
extends SelectorProviderImpl
{
public AbstractSelector openSelector() throws IOException {
return new PollSelectorImpl(this);
}
public Channel inheritedChannel() throws IOException {
return InheritedChannel.getChannel();
}
}

View file

@ -0,0 +1,159 @@
/*
* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.io.*;
import java.lang.reflect.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
class Reflect { // package-private
private Reflect() { }
private static class ReflectionError extends Error {
private static final long serialVersionUID = -8659519328078164097L;
ReflectionError(Throwable x) {
super(x);
}
}
private static void setAccessible(final AccessibleObject ao) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
ao.setAccessible(true);
return null;
}});
}
static Constructor<?> lookupConstructor(String className,
Class<?>[] paramTypes)
{
try {
Class<?> cl = Class.forName(className);
Constructor<?> c = cl.getDeclaredConstructor(paramTypes);
setAccessible(c);
return c;
} catch (ClassNotFoundException | NoSuchMethodException x) {
throw new ReflectionError(x);
}
}
static Object invoke(Constructor<?> c, Object[] args) {
try {
return c.newInstance(args);
} catch (InstantiationException |
IllegalAccessException |
InvocationTargetException x) {
throw new ReflectionError(x);
}
}
static Method lookupMethod(String className,
String methodName,
Class<?>... paramTypes)
{
try {
Class<?> cl = Class.forName(className);
Method m = cl.getDeclaredMethod(methodName, paramTypes);
setAccessible(m);
return m;
} catch (ClassNotFoundException | NoSuchMethodException x) {
throw new ReflectionError(x);
}
}
static Object invoke(Method m, Object ob, Object[] args) {
try {
return m.invoke(ob, args);
} catch (IllegalAccessException | InvocationTargetException x) {
throw new ReflectionError(x);
}
}
static Object invokeIO(Method m, Object ob, Object[] args)
throws IOException
{
try {
return m.invoke(ob, args);
} catch (IllegalAccessException x) {
throw new ReflectionError(x);
} catch (InvocationTargetException x) {
if (IOException.class.isInstance(x.getCause()))
throw (IOException)x.getCause();
throw new ReflectionError(x);
}
}
static Field lookupField(String className, String fieldName) {
try {
Class<?> cl = Class.forName(className);
Field f = cl.getDeclaredField(fieldName);
setAccessible(f);
return f;
} catch (ClassNotFoundException | NoSuchFieldException x) {
throw new ReflectionError(x);
}
}
static Object get(Object ob, Field f) {
try {
return f.get(ob);
} catch (IllegalAccessException x) {
throw new ReflectionError(x);
}
}
static Object get(Field f) {
return get(null, f);
}
static void set(Object ob, Field f, Object val) {
try {
f.set(ob, val);
} catch (IllegalAccessException x) {
throw new ReflectionError(x);
}
}
static void setInt(Object ob, Field f, int val) {
try {
f.setInt(ob, val);
} catch (IllegalAccessException x) {
throw new ReflectionError(x);
}
}
static void setBoolean(Object ob, Field f, boolean val) {
try {
f.setBoolean(ob, val);
} catch (IllegalAccessException x) {
throw new ReflectionError(x);
}
}
}

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.nio.channels.SocketChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.io.FileDescriptor;
import java.io.IOException;
/**
* Provides access to implementation private constructors and methods.
*/
public final class Secrets {
private Secrets() { }
private static SelectorProvider provider() {
SelectorProvider p = SelectorProvider.provider();
if (!(p instanceof SelectorProviderImpl))
throw new UnsupportedOperationException();
return p;
}
public static SocketChannel newSocketChannel(FileDescriptor fd) {
try {
return new SocketChannelImpl(provider(), fd, false);
} catch (IOException ioe) {
throw new AssertionError(ioe);
}
}
public static ServerSocketChannel newServerSocketChannel(FileDescriptor fd) {
try {
return new ServerSocketChannelImpl(provider(), fd, false);
} catch (IOException ioe) {
throw new AssertionError(ioe);
}
}
}

View file

@ -0,0 +1,71 @@
/*
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.nio.channels.Channel;
import java.io.FileDescriptor;
import java.io.IOException;
/**
* An interface that allows translation (and more!).
*
* @since 1.4
*/
public interface SelChImpl extends Channel {
FileDescriptor getFD();
int getFDVal();
/**
* Adds the specified ops if present in interestOps. The specified
* ops are turned on without affecting the other ops.
*
* @return true iff the new value of sk.readyOps() set by this method
* contains at least one bit that the previous value did not
* contain
*/
public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk);
/**
* Sets the specified ops if present in interestOps. The specified
* ops are turned on, and all other ops are turned off.
*
* @return true iff the new value of sk.readyOps() set by this method
* contains at least one bit that the previous value did not
* contain
*/
public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk);
void translateAndSetInterestOps(int ops, SelectionKeyImpl sk);
int validOps();
void kill() throws IOException;
}

View file

@ -0,0 +1,114 @@
/*
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.io.IOException;
import java.nio.channels.*;
import java.nio.channels.spi.*;
/**
* An implementation of SelectionKey for Solaris.
*/
public class SelectionKeyImpl
extends AbstractSelectionKey
{
final SelChImpl channel; // package-private
public final SelectorImpl selector;
// Index for a pollfd array in Selector that this key is registered with
private int index;
private volatile int interestOps;
private int readyOps;
SelectionKeyImpl(SelChImpl ch, SelectorImpl sel) {
channel = ch;
selector = sel;
}
public SelectableChannel channel() {
return (SelectableChannel)channel;
}
public Selector selector() {
return selector;
}
int getIndex() { // package-private
return index;
}
void setIndex(int i) { // package-private
index = i;
}
private void ensureValid() {
if (!isValid())
throw new CancelledKeyException();
}
public int interestOps() {
ensureValid();
return interestOps;
}
public SelectionKey interestOps(int ops) {
ensureValid();
return nioInterestOps(ops);
}
public int readyOps() {
ensureValid();
return readyOps;
}
// The nio versions of these operations do not care if a key
// has been invalidated. They are for internal use by nio code.
public void nioReadyOps(int ops) {
readyOps = ops;
}
public int nioReadyOps() {
return readyOps;
}
public SelectionKey nioInterestOps(int ops) {
if ((ops & ~channel().validOps()) != 0)
throw new IllegalArgumentException();
channel.translateAndSetInterestOps(ops, this);
interestOps = ops;
return this;
}
public int nioInterestOps() {
return interestOps;
}
}

View file

@ -0,0 +1,167 @@
/*
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.io.IOException;
import java.net.SocketException;
import java.nio.channels.ClosedSelectorException;
import java.nio.channels.IllegalSelectorException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.spi.AbstractSelectableChannel;
import java.nio.channels.spi.AbstractSelector;
import java.nio.channels.spi.SelectorProvider;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* Base Selector implementation class.
*/
public abstract class SelectorImpl
extends AbstractSelector
{
// The set of keys with data ready for an operation
protected Set<SelectionKey> selectedKeys;
// The set of keys registered with this Selector
protected HashSet<SelectionKey> keys;
// Public views of the key sets
private Set<SelectionKey> publicKeys; // Immutable
private Set<SelectionKey> publicSelectedKeys; // Removal allowed, but not addition
protected SelectorImpl(SelectorProvider sp) {
super(sp);
keys = new HashSet<>();
selectedKeys = new HashSet<>();
publicKeys = Collections.unmodifiableSet(keys);
publicSelectedKeys = Util.ungrowableSet(selectedKeys);
}
public Set<SelectionKey> keys() {
if (!isOpen())
throw new ClosedSelectorException();
return publicKeys;
}
public Set<SelectionKey> selectedKeys() {
if (!isOpen())
throw new ClosedSelectorException();
return publicSelectedKeys;
}
protected abstract int doSelect(long timeout) throws IOException;
private int lockAndDoSelect(long timeout) throws IOException {
synchronized (this) {
if (!isOpen())
throw new ClosedSelectorException();
synchronized (publicKeys) {
synchronized (publicSelectedKeys) {
return doSelect(timeout);
}
}
}
}
public int select(long timeout)
throws IOException
{
if (timeout < 0)
throw new IllegalArgumentException("Negative timeout");
return lockAndDoSelect((timeout == 0) ? -1 : timeout);
}
public int select() throws IOException {
return select(0);
}
public int selectNow() throws IOException {
return lockAndDoSelect(0);
}
public void implCloseSelector() throws IOException {
wakeup();
synchronized (this) {
synchronized (publicKeys) {
synchronized (publicSelectedKeys) {
implClose();
}
}
}
}
protected abstract void implClose() throws IOException;
public void putEventOps(SelectionKeyImpl sk, int ops) { }
protected final SelectionKey register(AbstractSelectableChannel ch,
int ops,
Object attachment)
{
if (!(ch instanceof SelChImpl))
throw new IllegalSelectorException();
SelectionKeyImpl k = new SelectionKeyImpl((SelChImpl)ch, this);
k.attach(attachment);
synchronized (publicKeys) {
implRegister(k);
}
k.interestOps(ops);
return k;
}
protected abstract void implRegister(SelectionKeyImpl ski);
void processDeregisterQueue() throws IOException {
// Precondition: Synchronized on this, keys, and selectedKeys
Set<SelectionKey> cks = cancelledKeys();
synchronized (cks) {
if (!cks.isEmpty()) {
Iterator<SelectionKey> i = cks.iterator();
while (i.hasNext()) {
SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
try {
implDereg(ski);
} catch (SocketException se) {
throw new IOException("Error deregistering key", se);
} finally {
i.remove();
}
}
}
}
}
protected abstract void implDereg(SelectionKeyImpl ski) throws IOException;
public abstract Selector wakeup();
}

View file

@ -0,0 +1,62 @@
/*
* Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.io.FileDescriptor;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.ProtocolFamily;
import java.nio.channels.*;
import java.nio.channels.spi.*;
public abstract class SelectorProviderImpl
extends SelectorProvider
{
public DatagramChannel openDatagramChannel() throws IOException {
return new DatagramChannelImpl(this);
}
public DatagramChannel openDatagramChannel(ProtocolFamily family) throws IOException {
return new DatagramChannelImpl(this, family);
}
public Pipe openPipe() throws IOException {
return new PipeImpl(this);
}
public abstract AbstractSelector openSelector() throws IOException;
public ServerSocketChannel openServerSocketChannel() throws IOException {
return new ServerSocketChannelImpl(this);
}
public SocketChannel openSocketChannel() throws IOException {
return new SocketChannelImpl(this);
}
}

View file

@ -0,0 +1,205 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.io.*;
import java.net.*;
import java.nio.channels.*;
// Make a server-socket channel look like a server socket.
//
// The methods in this class are defined in exactly the same order as in
// java.net.ServerSocket so as to simplify tracking future changes to that
// class.
//
public class ServerSocketAdaptor // package-private
extends ServerSocket
{
// The channel being adapted
private final ServerSocketChannelImpl ssc;
// Timeout "option" value for accepts
private volatile int timeout;
public static ServerSocket create(ServerSocketChannelImpl ssc) {
try {
return new ServerSocketAdaptor(ssc);
} catch (IOException x) {
throw new Error(x);
}
}
// ## super will create a useless impl
private ServerSocketAdaptor(ServerSocketChannelImpl ssc)
throws IOException
{
this.ssc = ssc;
}
public void bind(SocketAddress local) throws IOException {
bind(local, 50);
}
public void bind(SocketAddress local, int backlog) throws IOException {
if (local == null)
local = new InetSocketAddress(0);
try {
ssc.bind(local, backlog);
} catch (Exception x) {
Net.translateException(x);
}
}
public InetAddress getInetAddress() {
if (!ssc.isBound())
return null;
return Net.getRevealedLocalAddress(ssc.localAddress()).getAddress();
}
public int getLocalPort() {
if (!ssc.isBound())
return -1;
return Net.asInetSocketAddress(ssc.localAddress()).getPort();
}
public Socket accept() throws IOException {
synchronized (ssc.blockingLock()) {
try {
if (!ssc.isBound())
throw new NotYetBoundException();
if (timeout == 0) {
SocketChannel sc = ssc.accept();
if (sc == null && !ssc.isBlocking())
throw new IllegalBlockingModeException();
return sc.socket();
}
ssc.configureBlocking(false);
try {
SocketChannel sc;
if ((sc = ssc.accept()) != null)
return sc.socket();
long to = timeout;
for (;;) {
if (!ssc.isOpen())
throw new ClosedChannelException();
long st = System.currentTimeMillis();
int result = ssc.poll(Net.POLLIN, to);
if (result > 0 && ((sc = ssc.accept()) != null))
return sc.socket();
to -= System.currentTimeMillis() - st;
if (to <= 0)
throw new SocketTimeoutException();
}
} finally {
if (ssc.isOpen())
ssc.configureBlocking(true);
}
} catch (Exception x) {
Net.translateException(x);
assert false;
return null; // Never happens
}
}
}
public void close() throws IOException {
ssc.close();
}
public ServerSocketChannel getChannel() {
return ssc;
}
public boolean isBound() {
return ssc.isBound();
}
public boolean isClosed() {
return !ssc.isOpen();
}
public void setSoTimeout(int timeout) throws SocketException {
this.timeout = timeout;
}
public int getSoTimeout() throws SocketException {
return timeout;
}
public void setReuseAddress(boolean on) throws SocketException {
try {
ssc.setOption(StandardSocketOptions.SO_REUSEADDR, on);
} catch (IOException x) {
Net.translateToSocketException(x);
}
}
public boolean getReuseAddress() throws SocketException {
try {
return ssc.getOption(StandardSocketOptions.SO_REUSEADDR).booleanValue();
} catch (IOException x) {
Net.translateToSocketException(x);
return false; // Never happens
}
}
public String toString() {
if (!isBound())
return "ServerSocket[unbound]";
return "ServerSocket[addr=" + getInetAddress() +
// ",port=" + getPort() +
",localport=" + getLocalPort() + "]";
}
public void setReceiveBufferSize(int size) throws SocketException {
// size 0 valid for ServerSocketChannel, invalid for ServerSocket
if (size <= 0)
throw new IllegalArgumentException("size cannot be 0 or negative");
try {
ssc.setOption(StandardSocketOptions.SO_RCVBUF, size);
} catch (IOException x) {
Net.translateToSocketException(x);
}
}
public int getReceiveBufferSize() throws SocketException {
try {
return ssc.getOption(StandardSocketOptions.SO_RCVBUF).intValue();
} catch (IOException x) {
Net.translateToSocketException(x);
return -1; // Never happens
}
}
}

View file

@ -0,0 +1,446 @@
/*
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.io.FileDescriptor;
import java.io.IOException;
import java.net.*;
import java.nio.channels.*;
import java.nio.channels.spi.*;
import java.util.*;
import sun.net.NetHooks;
/**
* An implementation of ServerSocketChannels
*/
class ServerSocketChannelImpl
extends ServerSocketChannel
implements SelChImpl
{
// Used to make native close and configure calls
private static NativeDispatcher nd;
// Our file descriptor
private final FileDescriptor fd;
// fd value needed for dev/poll. This value will remain valid
// even after the value in the file descriptor object has been set to -1
private int fdVal;
// ID of native thread currently blocked in this channel, for signalling
private volatile long thread;
// Lock held by thread currently blocked in this channel
private final Object lock = new Object();
// Lock held by any thread that modifies the state fields declared below
// DO NOT invoke a blocking I/O operation while holding this lock!
private final Object stateLock = new Object();
// -- The following fields are protected by stateLock
// Channel state, increases monotonically
private static final int ST_UNINITIALIZED = -1;
private static final int ST_INUSE = 0;
private static final int ST_KILLED = 1;
private int state = ST_UNINITIALIZED;
// Binding
private InetSocketAddress localAddress; // null => unbound
// set true when exclusive binding is on and SO_REUSEADDR is emulated
private boolean isReuseAddress;
// Our socket adaptor, if any
ServerSocket socket;
// -- End of fields protected by stateLock
ServerSocketChannelImpl(SelectorProvider sp) throws IOException {
super(sp);
this.fd = Net.serverSocket(true);
this.fdVal = IOUtil.fdVal(fd);
this.state = ST_INUSE;
}
ServerSocketChannelImpl(SelectorProvider sp,
FileDescriptor fd,
boolean bound)
throws IOException
{
super(sp);
this.fd = fd;
this.fdVal = IOUtil.fdVal(fd);
this.state = ST_INUSE;
if (bound)
localAddress = Net.localAddress(fd);
}
public ServerSocket socket() {
synchronized (stateLock) {
if (socket == null)
socket = ServerSocketAdaptor.create(this);
return socket;
}
}
@Override
public SocketAddress getLocalAddress() throws IOException {
synchronized (stateLock) {
if (!isOpen())
throw new ClosedChannelException();
return localAddress == null ? localAddress
: Net.getRevealedLocalAddress(
Net.asInetSocketAddress(localAddress));
}
}
@Override
public <T> ServerSocketChannel setOption(SocketOption<T> name, T value)
throws IOException
{
if (name == null)
throw new NullPointerException();
if (!supportedOptions().contains(name))
throw new UnsupportedOperationException("'" + name + "' not supported");
synchronized (stateLock) {
if (!isOpen())
throw new ClosedChannelException();
if (name == StandardSocketOptions.IP_TOS) {
ProtocolFamily family = Net.isIPv6Available() ?
StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
Net.setSocketOption(fd, family, name, value);
return this;
}
if (name == StandardSocketOptions.SO_REUSEADDR &&
Net.useExclusiveBind())
{
// SO_REUSEADDR emulated when using exclusive bind
isReuseAddress = (Boolean)value;
} else {
// no options that require special handling
Net.setSocketOption(fd, Net.UNSPEC, name, value);
}
return this;
}
}
@Override
@SuppressWarnings("unchecked")
public <T> T getOption(SocketOption<T> name)
throws IOException
{
if (name == null)
throw new NullPointerException();
if (!supportedOptions().contains(name))
throw new UnsupportedOperationException("'" + name + "' not supported");
synchronized (stateLock) {
if (!isOpen())
throw new ClosedChannelException();
if (name == StandardSocketOptions.SO_REUSEADDR &&
Net.useExclusiveBind())
{
// SO_REUSEADDR emulated when using exclusive bind
return (T)Boolean.valueOf(isReuseAddress);
}
// no options that require special handling
return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
}
}
private static class DefaultOptionsHolder {
static final Set<SocketOption<?>> defaultOptions = defaultOptions();
private static Set<SocketOption<?>> defaultOptions() {
HashSet<SocketOption<?>> set = new HashSet<>(2);
set.add(StandardSocketOptions.SO_RCVBUF);
set.add(StandardSocketOptions.SO_REUSEADDR);
if (Net.isReusePortAvailable()) {
set.add(StandardSocketOptions.SO_REUSEPORT);
}
set.add(StandardSocketOptions.IP_TOS);
return Collections.unmodifiableSet(set);
}
}
@Override
public final Set<SocketOption<?>> supportedOptions() {
return DefaultOptionsHolder.defaultOptions;
}
public boolean isBound() {
synchronized (stateLock) {
return localAddress != null;
}
}
public InetSocketAddress localAddress() {
synchronized (stateLock) {
return localAddress;
}
}
@Override
public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException {
synchronized (lock) {
if (!isOpen())
throw new ClosedChannelException();
if (isBound())
throw new AlreadyBoundException();
InetSocketAddress isa = (local == null) ? new InetSocketAddress(0) :
Net.checkAddress(local);
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkListen(isa.getPort());
NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
Net.bind(fd, isa.getAddress(), isa.getPort());
Net.listen(fd, backlog < 1 ? 50 : backlog);
synchronized (stateLock) {
localAddress = Net.localAddress(fd);
}
}
return this;
}
public SocketChannel accept() throws IOException {
synchronized (lock) {
if (!isOpen())
throw new ClosedChannelException();
if (!isBound())
throw new NotYetBoundException();
SocketChannel sc = null;
int n = 0;
FileDescriptor newfd = new FileDescriptor();
InetSocketAddress[] isaa = new InetSocketAddress[1];
try {
begin();
if (!isOpen())
return null;
thread = NativeThread.current();
for (;;) {
n = accept(this.fd, newfd, isaa);
if ((n == IOStatus.INTERRUPTED) && isOpen())
continue;
break;
}
} finally {
thread = 0;
end(n > 0);
assert IOStatus.check(n);
}
if (n < 1)
return null;
IOUtil.configureBlocking(newfd, true);
InetSocketAddress isa = isaa[0];
sc = new SocketChannelImpl(provider(), newfd, isa);
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
try {
sm.checkAccept(isa.getAddress().getHostAddress(),
isa.getPort());
} catch (SecurityException x) {
sc.close();
throw x;
}
}
return sc;
}
}
protected void implConfigureBlocking(boolean block) throws IOException {
IOUtil.configureBlocking(fd, block);
}
protected void implCloseSelectableChannel() throws IOException {
synchronized (stateLock) {
if (state != ST_KILLED)
nd.preClose(fd);
long th = thread;
if (th != 0)
NativeThread.signal(th);
if (!isRegistered())
kill();
}
}
public void kill() throws IOException {
synchronized (stateLock) {
if (state == ST_KILLED)
return;
if (state == ST_UNINITIALIZED) {
state = ST_KILLED;
return;
}
assert !isOpen() && !isRegistered();
nd.close(fd);
state = ST_KILLED;
}
}
/**
* Translates native poll revent set into a ready operation set
*/
public boolean translateReadyOps(int ops, int initialOps,
SelectionKeyImpl sk) {
int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes
int oldOps = sk.nioReadyOps();
int newOps = initialOps;
if ((ops & Net.POLLNVAL) != 0) {
// This should only happen if this channel is pre-closed while a
// selection operation is in progress
// ## Throw an error if this channel has not been pre-closed
return false;
}
if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
newOps = intOps;
sk.nioReadyOps(newOps);
return (newOps & ~oldOps) != 0;
}
if (((ops & Net.POLLIN) != 0) &&
((intOps & SelectionKey.OP_ACCEPT) != 0))
newOps |= SelectionKey.OP_ACCEPT;
sk.nioReadyOps(newOps);
return (newOps & ~oldOps) != 0;
}
public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
return translateReadyOps(ops, sk.nioReadyOps(), sk);
}
public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
return translateReadyOps(ops, 0, sk);
}
// package-private
int poll(int events, long timeout) throws IOException {
assert Thread.holdsLock(blockingLock()) && !isBlocking();
synchronized (lock) {
int n = 0;
try {
begin();
synchronized (stateLock) {
if (!isOpen())
return 0;
thread = NativeThread.current();
}
n = Net.poll(fd, events, timeout);
} finally {
thread = 0;
end(n > 0);
}
return n;
}
}
/**
* Translates an interest operation set into a native poll event set
*/
public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
int newOps = 0;
// Translate ops
if ((ops & SelectionKey.OP_ACCEPT) != 0)
newOps |= Net.POLLIN;
// Place ops into pollfd array
sk.selector.putEventOps(sk, newOps);
}
public FileDescriptor getFD() {
return fd;
}
public int getFDVal() {
return fdVal;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(this.getClass().getName());
sb.append('[');
if (!isOpen()) {
sb.append("closed");
} else {
synchronized (stateLock) {
InetSocketAddress addr = localAddress();
if (addr == null) {
sb.append("unbound");
} else {
sb.append(Net.getRevealedLocalAddressAsString(addr));
}
}
}
sb.append(']');
return sb.toString();
}
/**
* Accept a connection on a socket.
*
* @implNote Wrap native call to allow instrumentation.
*/
private int accept(FileDescriptor ssfd, FileDescriptor newfd,
InetSocketAddress[] isaa)
throws IOException
{
return accept0(ssfd, newfd, isaa);
}
// -- Native methods --
// Accepts a new connection, setting the given file descriptor to refer to
// the new socket and setting isaa[0] to the socket's remote address.
// Returns 1 on success, or IOStatus.UNAVAILABLE (if non-blocking and no
// connections are pending) or IOStatus.INTERRUPTED.
//
private native int accept0(FileDescriptor ssfd, FileDescriptor newfd,
InetSocketAddress[] isaa)
throws IOException;
private static native void initIDs();
static {
IOUtil.load();
initIDs();
nd = new SocketDispatcher();
}
}

View file

@ -0,0 +1,396 @@
/*
* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.nio.channels.*;
import java.util.concurrent.*;
import java.nio.ByteBuffer;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.io.FileDescriptor;
import java.io.IOException;
/**
* "Portable" implementation of AsynchronousFileChannel for use on operating
* systems that don't support asynchronous file I/O.
*/
public class SimpleAsynchronousFileChannelImpl
extends AsynchronousFileChannelImpl
{
// lazy initialization of default thread pool for file I/O
private static class DefaultExecutorHolder {
static final ExecutorService defaultExecutor =
ThreadPool.createDefault().executor();
}
// Used to make native read and write calls
private static final FileDispatcher nd = new FileDispatcherImpl();
// Thread-safe set of IDs of native threads, for signalling
private final NativeThreadSet threads = new NativeThreadSet(2);
SimpleAsynchronousFileChannelImpl(FileDescriptor fdObj,
boolean reading,
boolean writing,
ExecutorService executor)
{
super(fdObj, reading, writing, executor);
}
public static AsynchronousFileChannel open(FileDescriptor fdo,
boolean reading,
boolean writing,
ThreadPool pool)
{
// Executor is either default or based on pool parameters
ExecutorService executor = (pool == null) ?
DefaultExecutorHolder.defaultExecutor : pool.executor();
return new SimpleAsynchronousFileChannelImpl(fdo, reading, writing, executor);
}
@Override
public void close() throws IOException {
// mark channel as closed
synchronized (fdObj) {
if (closed)
return; // already closed
closed = true;
// from this point on, if another thread invokes the begin() method
// then it will throw ClosedChannelException
}
// Invalidate and release any locks that we still hold
invalidateAllLocks();
// signal any threads blocked on this channel
threads.signalAndWait();
// wait until all async I/O operations have completely gracefully
closeLock.writeLock().lock();
try {
// do nothing
} finally {
closeLock.writeLock().unlock();
}
// close file
nd.close(fdObj);
}
@Override
public long size() throws IOException {
int ti = threads.add();
try {
long n = 0L;
try {
begin();
do {
n = nd.size(fdObj);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
return n;
} finally {
end(n >= 0L);
}
} finally {
threads.remove(ti);
}
}
@Override
public AsynchronousFileChannel truncate(long size) throws IOException {
if (size < 0L)
throw new IllegalArgumentException("Negative size");
if (!writing)
throw new NonWritableChannelException();
int ti = threads.add();
try {
long n = 0L;
try {
begin();
do {
n = nd.size(fdObj);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
// truncate file if 'size' less than current size
if (size < n && isOpen()) {
do {
n = nd.truncate(fdObj, size);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
}
return this;
} finally {
end(n > 0);
}
} finally {
threads.remove(ti);
}
}
@Override
public void force(boolean metaData) throws IOException {
int ti = threads.add();
try {
int n = 0;
try {
begin();
do {
n = nd.force(fdObj, metaData);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
} finally {
end(n >= 0);
}
} finally {
threads.remove(ti);
}
}
@Override
<A> Future<FileLock> implLock(final long position,
final long size,
final boolean shared,
final A attachment,
final CompletionHandler<FileLock,? super A> handler)
{
if (shared && !reading)
throw new NonReadableChannelException();
if (!shared && !writing)
throw new NonWritableChannelException();
// add to lock table
final FileLockImpl fli = addToFileLockTable(position, size, shared);
if (fli == null) {
Throwable exc = new ClosedChannelException();
if (handler == null)
return CompletedFuture.withFailure(exc);
Invoker.invokeIndirectly(handler, attachment, null, exc, executor);
return null;
}
final PendingFuture<FileLock,A> result = (handler == null) ?
new PendingFuture<FileLock,A>(this) : null;
Runnable task = new Runnable() {
public void run() {
Throwable exc = null;
int ti = threads.add();
try {
int n;
try {
begin();
do {
n = nd.lock(fdObj, true, position, size, shared);
} while ((n == FileDispatcher.INTERRUPTED) && isOpen());
if (n != FileDispatcher.LOCKED || !isOpen()) {
throw new AsynchronousCloseException();
}
} catch (IOException x) {
removeFromFileLockTable(fli);
if (!isOpen())
x = new AsynchronousCloseException();
exc = x;
} finally {
end();
}
} finally {
threads.remove(ti);
}
if (handler == null) {
result.setResult(fli, exc);
} else {
Invoker.invokeUnchecked(handler, attachment, fli, exc);
}
}
};
boolean executed = false;
try {
executor.execute(task);
executed = true;
} finally {
if (!executed) {
// rollback
removeFromFileLockTable(fli);
}
}
return result;
}
@Override
public FileLock tryLock(long position, long size, boolean shared)
throws IOException
{
if (shared && !reading)
throw new NonReadableChannelException();
if (!shared && !writing)
throw new NonWritableChannelException();
// add to lock table
FileLockImpl fli = addToFileLockTable(position, size, shared);
if (fli == null)
throw new ClosedChannelException();
int ti = threads.add();
boolean gotLock = false;
try {
begin();
int n;
do {
n = nd.lock(fdObj, false, position, size, shared);
} while ((n == FileDispatcher.INTERRUPTED) && isOpen());
if (n == FileDispatcher.LOCKED && isOpen()) {
gotLock = true;
return fli; // lock acquired
}
if (n == FileDispatcher.NO_LOCK)
return null; // locked by someone else
if (n == FileDispatcher.INTERRUPTED)
throw new AsynchronousCloseException();
// should not get here
throw new AssertionError();
} finally {
if (!gotLock)
removeFromFileLockTable(fli);
end();
threads.remove(ti);
}
}
@Override
protected void implRelease(FileLockImpl fli) throws IOException {
nd.release(fdObj, fli.position(), fli.size());
}
@Override
<A> Future<Integer> implRead(final ByteBuffer dst,
final long position,
final A attachment,
final CompletionHandler<Integer,? super A> handler)
{
if (position < 0)
throw new IllegalArgumentException("Negative position");
if (!reading)
throw new NonReadableChannelException();
if (dst.isReadOnly())
throw new IllegalArgumentException("Read-only buffer");
// complete immediately if channel closed or no space remaining
if (!isOpen() || (dst.remaining() == 0)) {
Throwable exc = (isOpen()) ? null : new ClosedChannelException();
if (handler == null)
return CompletedFuture.withResult(0, exc);
Invoker.invokeIndirectly(handler, attachment, 0, exc, executor);
return null;
}
final PendingFuture<Integer,A> result = (handler == null) ?
new PendingFuture<Integer,A>(this) : null;
Runnable task = new Runnable() {
public void run() {
int n = 0;
Throwable exc = null;
int ti = threads.add();
try {
begin();
do {
n = IOUtil.read(fdObj, dst, position, nd);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
if (n < 0 && !isOpen())
throw new AsynchronousCloseException();
} catch (IOException x) {
if (!isOpen())
x = new AsynchronousCloseException();
exc = x;
} finally {
end();
threads.remove(ti);
}
if (handler == null) {
result.setResult(n, exc);
} else {
Invoker.invokeUnchecked(handler, attachment, n, exc);
}
}
};
executor.execute(task);
return result;
}
@Override
<A> Future<Integer> implWrite(final ByteBuffer src,
final long position,
final A attachment,
final CompletionHandler<Integer,? super A> handler)
{
if (position < 0)
throw new IllegalArgumentException("Negative position");
if (!writing)
throw new NonWritableChannelException();
// complete immediately if channel is closed or no bytes remaining
if (!isOpen() || (src.remaining() == 0)) {
Throwable exc = (isOpen()) ? null : new ClosedChannelException();
if (handler == null)
return CompletedFuture.withResult(0, exc);
Invoker.invokeIndirectly(handler, attachment, 0, exc, executor);
return null;
}
final PendingFuture<Integer,A> result = (handler == null) ?
new PendingFuture<Integer,A>(this) : null;
Runnable task = new Runnable() {
public void run() {
int n = 0;
Throwable exc = null;
int ti = threads.add();
try {
begin();
do {
n = IOUtil.write(fdObj, src, position, nd);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
if (n < 0 && !isOpen())
throw new AsynchronousCloseException();
} catch (IOException x) {
if (!isOpen())
x = new AsynchronousCloseException();
exc = x;
} finally {
end();
threads.remove(ti);
}
if (handler == null) {
result.setResult(n, exc);
} else {
Invoker.invokeUnchecked(handler, attachment, n, exc);
}
}
};
executor.execute(task);
return result;
}
}

View file

@ -0,0 +1,443 @@
/*
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.io.*;
import java.net.*;
import java.nio.*;
import java.nio.channels.*;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
import java.util.concurrent.TimeUnit;
// Make a socket channel look like a socket.
//
// The only aspects of java.net.Socket-hood that we don't attempt to emulate
// here are the interrupted-I/O exceptions (which our Solaris implementations
// attempt to support) and the sending of urgent data. Otherwise an adapted
// socket should look enough like a real java.net.Socket to fool most of the
// developers most of the time, right down to the exception message strings.
//
// The methods in this class are defined in exactly the same order as in
// java.net.Socket so as to simplify tracking future changes to that class.
//
public class SocketAdaptor
extends Socket
{
// The channel being adapted
private final SocketChannelImpl sc;
// Timeout "option" value for reads
private volatile int timeout;
private SocketAdaptor(SocketChannelImpl sc) throws SocketException {
super((SocketImpl) null);
this.sc = sc;
}
public static Socket create(SocketChannelImpl sc) {
try {
return new SocketAdaptor(sc);
} catch (SocketException e) {
throw new InternalError("Should not reach here");
}
}
public SocketChannel getChannel() {
return sc;
}
// Override this method just to protect against changes in the superclass
//
public void connect(SocketAddress remote) throws IOException {
connect(remote, 0);
}
public void connect(SocketAddress remote, int timeout) throws IOException {
if (remote == null)
throw new IllegalArgumentException("connect: The address can't be null");
if (timeout < 0)
throw new IllegalArgumentException("connect: timeout can't be negative");
synchronized (sc.blockingLock()) {
if (!sc.isBlocking())
throw new IllegalBlockingModeException();
try {
if (timeout == 0) {
sc.connect(remote);
return;
}
sc.configureBlocking(false);
try {
if (sc.connect(remote))
return;
long timeoutNanos =
TimeUnit.NANOSECONDS.convert(timeout,
TimeUnit.MILLISECONDS);
for (;;) {
if (!sc.isOpen())
throw new ClosedChannelException();
long startTime = System.nanoTime();
int result = sc.poll(Net.POLLCONN, timeout);
if (result > 0 && sc.finishConnect())
break;
timeoutNanos -= System.nanoTime() - startTime;
if (timeoutNanos <= 0) {
try {
sc.close();
} catch (IOException x) { }
throw new SocketTimeoutException();
}
}
} finally {
if (sc.isOpen())
sc.configureBlocking(true);
}
} catch (Exception x) {
Net.translateException(x, true);
}
}
}
public void bind(SocketAddress local) throws IOException {
try {
sc.bind(local);
} catch (Exception x) {
Net.translateException(x);
}
}
public InetAddress getInetAddress() {
SocketAddress remote = sc.remoteAddress();
if (remote == null) {
return null;
} else {
return ((InetSocketAddress)remote).getAddress();
}
}
public InetAddress getLocalAddress() {
if (sc.isOpen()) {
InetSocketAddress local = sc.localAddress();
if (local != null) {
return Net.getRevealedLocalAddress(local).getAddress();
}
}
return new InetSocketAddress(0).getAddress();
}
public int getPort() {
SocketAddress remote = sc.remoteAddress();
if (remote == null) {
return 0;
} else {
return ((InetSocketAddress)remote).getPort();
}
}
public int getLocalPort() {
SocketAddress local = sc.localAddress();
if (local == null) {
return -1;
} else {
return ((InetSocketAddress)local).getPort();
}
}
private class SocketInputStream
extends ChannelInputStream
{
private SocketInputStream() {
super(sc);
}
protected int read(ByteBuffer bb)
throws IOException
{
synchronized (sc.blockingLock()) {
if (!sc.isBlocking())
throw new IllegalBlockingModeException();
if (timeout == 0)
return sc.read(bb);
sc.configureBlocking(false);
try {
int n;
if ((n = sc.read(bb)) != 0)
return n;
long timeoutNanos =
TimeUnit.NANOSECONDS.convert(timeout,
TimeUnit.MILLISECONDS);
for (;;) {
if (!sc.isOpen())
throw new ClosedChannelException();
long startTime = System.nanoTime();
int result = sc.poll(Net.POLLIN, timeout);
if (result > 0) {
if ((n = sc.read(bb)) != 0)
return n;
}
timeoutNanos -= System.nanoTime() - startTime;
if (timeoutNanos <= 0)
throw new SocketTimeoutException();
}
} finally {
if (sc.isOpen())
sc.configureBlocking(true);
}
}
}
}
private InputStream socketInputStream = null;
public InputStream getInputStream() throws IOException {
if (!sc.isOpen())
throw new SocketException("Socket is closed");
if (!sc.isConnected())
throw new SocketException("Socket is not connected");
if (!sc.isInputOpen())
throw new SocketException("Socket input is shutdown");
if (socketInputStream == null) {
try {
socketInputStream = AccessController.doPrivileged(
new PrivilegedExceptionAction<InputStream>() {
public InputStream run() throws IOException {
return new SocketInputStream();
}
});
} catch (java.security.PrivilegedActionException e) {
throw (IOException)e.getException();
}
}
return socketInputStream;
}
public OutputStream getOutputStream() throws IOException {
if (!sc.isOpen())
throw new SocketException("Socket is closed");
if (!sc.isConnected())
throw new SocketException("Socket is not connected");
if (!sc.isOutputOpen())
throw new SocketException("Socket output is shutdown");
OutputStream os = null;
try {
os = AccessController.doPrivileged(
new PrivilegedExceptionAction<OutputStream>() {
public OutputStream run() throws IOException {
return Channels.newOutputStream(sc);
}
});
} catch (java.security.PrivilegedActionException e) {
throw (IOException)e.getException();
}
return os;
}
private void setBooleanOption(SocketOption<Boolean> name, boolean value)
throws SocketException
{
try {
sc.setOption(name, value);
} catch (IOException x) {
Net.translateToSocketException(x);
}
}
private void setIntOption(SocketOption<Integer> name, int value)
throws SocketException
{
try {
sc.setOption(name, value);
} catch (IOException x) {
Net.translateToSocketException(x);
}
}
private boolean getBooleanOption(SocketOption<Boolean> name) throws SocketException {
try {
return sc.getOption(name).booleanValue();
} catch (IOException x) {
Net.translateToSocketException(x);
return false; // keep compiler happy
}
}
private int getIntOption(SocketOption<Integer> name) throws SocketException {
try {
return sc.getOption(name).intValue();
} catch (IOException x) {
Net.translateToSocketException(x);
return -1; // keep compiler happy
}
}
public void setTcpNoDelay(boolean on) throws SocketException {
setBooleanOption(StandardSocketOptions.TCP_NODELAY, on);
}
public boolean getTcpNoDelay() throws SocketException {
return getBooleanOption(StandardSocketOptions.TCP_NODELAY);
}
public void setSoLinger(boolean on, int linger) throws SocketException {
if (!on)
linger = -1;
setIntOption(StandardSocketOptions.SO_LINGER, linger);
}
public int getSoLinger() throws SocketException {
return getIntOption(StandardSocketOptions.SO_LINGER);
}
public void sendUrgentData(int data) throws IOException {
int n = sc.sendOutOfBandData((byte) data);
if (n == 0)
throw new IOException("Socket buffer full");
}
public void setOOBInline(boolean on) throws SocketException {
setBooleanOption(ExtendedSocketOption.SO_OOBINLINE, on);
}
public boolean getOOBInline() throws SocketException {
return getBooleanOption(ExtendedSocketOption.SO_OOBINLINE);
}
public void setSoTimeout(int timeout) throws SocketException {
if (timeout < 0)
throw new IllegalArgumentException("timeout can't be negative");
this.timeout = timeout;
}
public int getSoTimeout() throws SocketException {
return timeout;
}
public void setSendBufferSize(int size) throws SocketException {
// size 0 valid for SocketChannel, invalid for Socket
if (size <= 0)
throw new IllegalArgumentException("Invalid send size");
setIntOption(StandardSocketOptions.SO_SNDBUF, size);
}
public int getSendBufferSize() throws SocketException {
return getIntOption(StandardSocketOptions.SO_SNDBUF);
}
public void setReceiveBufferSize(int size) throws SocketException {
// size 0 valid for SocketChannel, invalid for Socket
if (size <= 0)
throw new IllegalArgumentException("Invalid receive size");
setIntOption(StandardSocketOptions.SO_RCVBUF, size);
}
public int getReceiveBufferSize() throws SocketException {
return getIntOption(StandardSocketOptions.SO_RCVBUF);
}
public void setKeepAlive(boolean on) throws SocketException {
setBooleanOption(StandardSocketOptions.SO_KEEPALIVE, on);
}
public boolean getKeepAlive() throws SocketException {
return getBooleanOption(StandardSocketOptions.SO_KEEPALIVE);
}
public void setTrafficClass(int tc) throws SocketException {
setIntOption(StandardSocketOptions.IP_TOS, tc);
}
public int getTrafficClass() throws SocketException {
return getIntOption(StandardSocketOptions.IP_TOS);
}
public void setReuseAddress(boolean on) throws SocketException {
setBooleanOption(StandardSocketOptions.SO_REUSEADDR, on);
}
public boolean getReuseAddress() throws SocketException {
return getBooleanOption(StandardSocketOptions.SO_REUSEADDR);
}
public void close() throws IOException {
sc.close();
}
public void shutdownInput() throws IOException {
try {
sc.shutdownInput();
} catch (Exception x) {
Net.translateException(x);
}
}
public void shutdownOutput() throws IOException {
try {
sc.shutdownOutput();
} catch (Exception x) {
Net.translateException(x);
}
}
public String toString() {
if (sc.isConnected())
return "Socket[addr=" + getInetAddress() +
",port=" + getPort() +
",localport=" + getLocalPort() + "]";
return "Socket[unconnected]";
}
public boolean isConnected() {
return sc.isConnected();
}
public boolean isBound() {
return sc.localAddress() != null;
}
public boolean isClosed() {
return !sc.isOpen();
}
public boolean isInputShutdown() {
return !sc.isInputOpen();
}
public boolean isOutputShutdown() {
return !sc.isOutputOpen();
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,154 @@
/*
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
@@END_COPYRIGHT@@
#include <stdio.h>
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#endif
/* Defines SO_REUSEPORT */
#if !defined(SO_REUSEPORT)
#ifdef _WIN32
#define SO_REUSEPORT 0
#elif __linux__
#define SO_REUSEPORT 15
#elif __solaris__
#define SO_REUSEPORT 0x100e
#elif defined(AIX) || defined(MACOSX)
#define SO_REUSEPORT 0x0200
#else
#define SO_REUSEPORT 0
#endif
#endif
/* On Solaris, "sun" is defined as a macro. Undefine to make package
declaration valid */
#undef sun
/* To be able to name the Java constants the same as the C constants without
having the preprocessor rewrite those identifiers, add PREFIX_ to all
identifiers matching a C constant. The PREFIX_ is filtered out in the
makefile. */
@@START_HERE@@
package sun.nio.ch;
import java.net.SocketOption;
import java.net.StandardSocketOptions;
import java.net.ProtocolFamily;
import java.net.StandardProtocolFamily;
import java.util.Map;
import java.util.HashMap;
class SocketOptionRegistry {
private SocketOptionRegistry() { }
private static class RegistryKey {
private final SocketOption<?> name;
private final ProtocolFamily family;
RegistryKey(SocketOption<?> name, ProtocolFamily family) {
this.name = name;
this.family = family;
}
public int hashCode() {
return name.hashCode() + family.hashCode();
}
public boolean equals(Object ob) {
if (ob == null) return false;
if (!(ob instanceof RegistryKey)) return false;
RegistryKey other = (RegistryKey)ob;
if (this.name != other.name) return false;
if (this.family != other.family) return false;
return true;
}
}
private static class LazyInitialization {
static final Map<RegistryKey,OptionKey> options = options();
private static Map<RegistryKey,OptionKey> options() {
Map<RegistryKey,OptionKey> map =
new HashMap<RegistryKey,OptionKey>();
map.put(new RegistryKey(StandardSocketOptions.PREFIX_SO_BROADCAST,
Net.UNSPEC), new OptionKey(SOL_SOCKET, SO_BROADCAST));
map.put(new RegistryKey(StandardSocketOptions.PREFIX_SO_KEEPALIVE,
Net.UNSPEC), new OptionKey(SOL_SOCKET, SO_KEEPALIVE));
map.put(new RegistryKey(StandardSocketOptions.PREFIX_SO_LINGER,
Net.UNSPEC), new OptionKey(SOL_SOCKET, SO_LINGER));
map.put(new RegistryKey(StandardSocketOptions.PREFIX_SO_SNDBUF,
Net.UNSPEC), new OptionKey(SOL_SOCKET, SO_SNDBUF));
map.put(new RegistryKey(StandardSocketOptions.PREFIX_SO_RCVBUF,
Net.UNSPEC), new OptionKey(SOL_SOCKET, SO_RCVBUF));
map.put(new RegistryKey(StandardSocketOptions.PREFIX_SO_REUSEADDR,
Net.UNSPEC), new OptionKey(SOL_SOCKET, SO_REUSEADDR));
map.put(new RegistryKey(StandardSocketOptions.PREFIX_SO_REUSEPORT,
Net.UNSPEC), new OptionKey(SOL_SOCKET, SO_REUSEPORT));
// IPPROTO_TCP is 6
map.put(new RegistryKey(StandardSocketOptions.PREFIX_TCP_NODELAY,
Net.UNSPEC), new OptionKey(6, TCP_NODELAY));
// IPPROTO_IP is 0
map.put(new RegistryKey(StandardSocketOptions.PREFIX_IP_TOS,
StandardProtocolFamily.INET), new OptionKey(0, IP_TOS));
map.put(new RegistryKey(StandardSocketOptions.PREFIX_IP_MULTICAST_IF,
StandardProtocolFamily.INET), new OptionKey(0, IP_MULTICAST_IF));
map.put(new RegistryKey(StandardSocketOptions.PREFIX_IP_MULTICAST_TTL,
StandardProtocolFamily.INET), new OptionKey(0, IP_MULTICAST_TTL));
map.put(new RegistryKey(StandardSocketOptions.PREFIX_IP_MULTICAST_LOOP,
StandardProtocolFamily.INET), new OptionKey(0, IP_MULTICAST_LOOP));
#ifdef AF_INET6
// IPPROTO_IPV6 is 41
map.put(new RegistryKey(StandardSocketOptions.PREFIX_IP_TOS,
StandardProtocolFamily.INET6), new OptionKey(41, IPV6_TCLASS));
map.put(new RegistryKey(StandardSocketOptions.PREFIX_IP_MULTICAST_IF,
StandardProtocolFamily.INET6), new OptionKey(41, IPV6_MULTICAST_IF));
map.put(new RegistryKey(StandardSocketOptions.PREFIX_IP_MULTICAST_TTL,
StandardProtocolFamily.INET6), new OptionKey(41, IPV6_MULTICAST_HOPS));
map.put(new RegistryKey(StandardSocketOptions.PREFIX_IP_MULTICAST_LOOP,
StandardProtocolFamily.INET6), new OptionKey(41, IPV6_MULTICAST_LOOP));
#endif
map.put(new RegistryKey(ExtendedSocketOption.PREFIX_SO_OOBINLINE,
Net.UNSPEC), new OptionKey(SOL_SOCKET, SO_OOBINLINE));
return map;
}
}
public static OptionKey findOption(SocketOption<?> name, ProtocolFamily family) {
RegistryKey key = new RegistryKey(name, family);
return LazyInitialization.options.get(key);
}
}

View file

@ -0,0 +1,178 @@
/*
* Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.util.concurrent.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
import sun.security.action.GetPropertyAction;
import sun.security.action.GetIntegerAction;
import jdk.internal.misc.InnocuousThread;
/**
* Encapsulates a thread pool associated with a channel group.
*/
public class ThreadPool {
private static final String DEFAULT_THREAD_POOL_THREAD_FACTORY =
"java.nio.channels.DefaultThreadPool.threadFactory";
private static final String DEFAULT_THREAD_POOL_INITIAL_SIZE =
"java.nio.channels.DefaultThreadPool.initialSize";
private final ExecutorService executor;
// indicates if thread pool is fixed size
private final boolean isFixed;
// indicates the pool size (for a fixed thread pool configuratin this is
// the maximum pool size; for other thread pools it is the initial size)
private final int poolSize;
private ThreadPool(ExecutorService executor,
boolean isFixed,
int poolSize)
{
this.executor = executor;
this.isFixed = isFixed;
this.poolSize = poolSize;
}
ExecutorService executor() {
return executor;
}
boolean isFixedThreadPool() {
return isFixed;
}
int poolSize() {
return poolSize;
}
static ThreadFactory defaultThreadFactory() {
if (System.getSecurityManager() == null) {
return (Runnable r) -> {
Thread t = new Thread(r);
t.setDaemon(true);
return t;
};
} else {
return (Runnable r) -> {
PrivilegedAction<Thread> action = () -> {
Thread t = InnocuousThread.newThread(r);
t.setDaemon(true);
return t;
};
return AccessController.doPrivileged(action);
};
}
}
private static class DefaultThreadPoolHolder {
static final ThreadPool defaultThreadPool = createDefault();
}
// return the default (system-wide) thread pool
static ThreadPool getDefault() {
return DefaultThreadPoolHolder.defaultThreadPool;
}
// create thread using default settings (configured by system properties)
static ThreadPool createDefault() {
// default the number of fixed threads to the hardware core count
int initialSize = getDefaultThreadPoolInitialSize();
if (initialSize < 0)
initialSize = Runtime.getRuntime().availableProcessors();
// default to thread factory that creates daemon threads
ThreadFactory threadFactory = getDefaultThreadPoolThreadFactory();
if (threadFactory == null)
threadFactory = defaultThreadFactory();
// create thread pool
ExecutorService executor = Executors.newCachedThreadPool(threadFactory);
return new ThreadPool(executor, false, initialSize);
}
// create using given parameters
static ThreadPool create(int nThreads, ThreadFactory factory) {
if (nThreads <= 0)
throw new IllegalArgumentException("'nThreads' must be > 0");
ExecutorService executor = Executors.newFixedThreadPool(nThreads, factory);
return new ThreadPool(executor, true, nThreads);
}
// wrap a user-supplied executor
public static ThreadPool wrap(ExecutorService executor, int initialSize) {
if (executor == null)
throw new NullPointerException("'executor' is null");
// attempt to check if cached thread pool
if (executor instanceof ThreadPoolExecutor) {
int max = ((ThreadPoolExecutor)executor).getMaximumPoolSize();
if (max == Integer.MAX_VALUE) {
if (initialSize < 0) {
initialSize = Runtime.getRuntime().availableProcessors();
} else {
// not a cached thread pool so ignore initial size
initialSize = 0;
}
}
} else {
// some other type of thread pool
if (initialSize < 0)
initialSize = 0;
}
return new ThreadPool(executor, false, initialSize);
}
private static int getDefaultThreadPoolInitialSize() {
String propValue = AccessController.doPrivileged(new
GetPropertyAction(DEFAULT_THREAD_POOL_INITIAL_SIZE));
if (propValue != null) {
try {
return Integer.parseInt(propValue);
} catch (NumberFormatException x) {
throw new Error("Value of property '" + DEFAULT_THREAD_POOL_INITIAL_SIZE +
"' is invalid: " + x);
}
}
return -1;
}
private static ThreadFactory getDefaultThreadPoolThreadFactory() {
String propValue = AccessController.doPrivileged(new
GetPropertyAction(DEFAULT_THREAD_POOL_THREAD_FACTORY));
if (propValue != null) {
try {
@SuppressWarnings("deprecation")
Object tmp = Class
.forName(propValue, true, ClassLoader.getSystemClassLoader()).newInstance();
return (ThreadFactory)tmp;
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException x) {
throw new Error(x);
}
}
return null;
}
}

View file

@ -0,0 +1,462 @@
/*
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.io.FileDescriptor;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import jdk.internal.misc.Unsafe;
import sun.security.action.GetPropertyAction;
public class Util {
// -- Caches --
// The number of temp buffers in our pool
private static final int TEMP_BUF_POOL_SIZE = IOUtil.IOV_MAX;
// The max size allowed for a cached temp buffer, in bytes
private static final long MAX_CACHED_BUFFER_SIZE = getMaxCachedBufferSize();
// Per-thread cache of temporary direct buffers
private static ThreadLocal<BufferCache> bufferCache =
new ThreadLocal<BufferCache>()
{
@Override
protected BufferCache initialValue() {
return new BufferCache();
}
};
/**
* Returns the max size allowed for a cached temp buffers, in
* bytes. It defaults to Long.MAX_VALUE. It can be set with the
* jdk.nio.maxCachedBufferSize property. Even though
* ByteBuffer.capacity() returns an int, we're using a long here
* for potential future-proofing.
*/
private static long getMaxCachedBufferSize() {
String s = GetPropertyAction
.privilegedGetProperty("jdk.nio.maxCachedBufferSize");
if (s != null) {
try {
long m = Long.parseLong(s);
if (m >= 0) {
return m;
} else {
// if it's negative, ignore the system property
}
} catch (NumberFormatException e) {
// if the string is not well formed, ignore the system property
}
}
return Long.MAX_VALUE;
}
/**
* Returns true if a buffer of this size is too large to be
* added to the buffer cache, false otherwise.
*/
private static boolean isBufferTooLarge(int size) {
return size > MAX_CACHED_BUFFER_SIZE;
}
/**
* Returns true if the buffer is too large to be added to the
* buffer cache, false otherwise.
*/
private static boolean isBufferTooLarge(ByteBuffer buf) {
return isBufferTooLarge(buf.capacity());
}
/**
* A simple cache of direct buffers.
*/
private static class BufferCache {
// the array of buffers
private ByteBuffer[] buffers;
// the number of buffers in the cache
private int count;
// the index of the first valid buffer (undefined if count == 0)
private int start;
private int next(int i) {
return (i + 1) % TEMP_BUF_POOL_SIZE;
}
BufferCache() {
buffers = new ByteBuffer[TEMP_BUF_POOL_SIZE];
}
/**
* Removes and returns a buffer from the cache of at least the given
* size (or null if no suitable buffer is found).
*/
ByteBuffer get(int size) {
// Don't call this if the buffer would be too large.
assert !isBufferTooLarge(size);
if (count == 0)
return null; // cache is empty
ByteBuffer[] buffers = this.buffers;
// search for suitable buffer (often the first buffer will do)
ByteBuffer buf = buffers[start];
if (buf.capacity() < size) {
buf = null;
int i = start;
while ((i = next(i)) != start) {
ByteBuffer bb = buffers[i];
if (bb == null)
break;
if (bb.capacity() >= size) {
buf = bb;
break;
}
}
if (buf == null)
return null;
// move first element to here to avoid re-packing
buffers[i] = buffers[start];
}
// remove first element
buffers[start] = null;
start = next(start);
count--;
// prepare the buffer and return it
buf.rewind();
buf.limit(size);
return buf;
}
boolean offerFirst(ByteBuffer buf) {
// Don't call this if the buffer is too large.
assert !isBufferTooLarge(buf);
if (count >= TEMP_BUF_POOL_SIZE) {
return false;
} else {
start = (start + TEMP_BUF_POOL_SIZE - 1) % TEMP_BUF_POOL_SIZE;
buffers[start] = buf;
count++;
return true;
}
}
boolean offerLast(ByteBuffer buf) {
// Don't call this if the buffer is too large.
assert !isBufferTooLarge(buf);
if (count >= TEMP_BUF_POOL_SIZE) {
return false;
} else {
int next = (start + count) % TEMP_BUF_POOL_SIZE;
buffers[next] = buf;
count++;
return true;
}
}
boolean isEmpty() {
return count == 0;
}
ByteBuffer removeFirst() {
assert count > 0;
ByteBuffer buf = buffers[start];
buffers[start] = null;
start = next(start);
count--;
return buf;
}
}
/**
* Returns a temporary buffer of at least the given size
*/
public static ByteBuffer getTemporaryDirectBuffer(int size) {
// If a buffer of this size is too large for the cache, there
// should not be a buffer in the cache that is at least as
// large. So we'll just create a new one. Also, we don't have
// to remove the buffer from the cache (as this method does
// below) given that we won't put the new buffer in the cache.
if (isBufferTooLarge(size)) {
return ByteBuffer.allocateDirect(size);
}
BufferCache cache = bufferCache.get();
ByteBuffer buf = cache.get(size);
if (buf != null) {
return buf;
} else {
// No suitable buffer in the cache so we need to allocate a new
// one. To avoid the cache growing then we remove the first
// buffer from the cache and free it.
if (!cache.isEmpty()) {
buf = cache.removeFirst();
free(buf);
}
return ByteBuffer.allocateDirect(size);
}
}
/**
* Releases a temporary buffer by returning to the cache or freeing it.
*/
public static void releaseTemporaryDirectBuffer(ByteBuffer buf) {
offerFirstTemporaryDirectBuffer(buf);
}
/**
* Releases a temporary buffer by returning to the cache or freeing it. If
* returning to the cache then insert it at the start so that it is
* likely to be returned by a subsequent call to getTemporaryDirectBuffer.
*/
static void offerFirstTemporaryDirectBuffer(ByteBuffer buf) {
// If the buffer is too large for the cache we don't have to
// check the cache. We'll just free it.
if (isBufferTooLarge(buf)) {
free(buf);
return;
}
assert buf != null;
BufferCache cache = bufferCache.get();
if (!cache.offerFirst(buf)) {
// cache is full
free(buf);
}
}
/**
* Releases a temporary buffer by returning to the cache or freeing it. If
* returning to the cache then insert it at the end. This makes it
* suitable for scatter/gather operations where the buffers are returned to
* cache in same order that they were obtained.
*/
static void offerLastTemporaryDirectBuffer(ByteBuffer buf) {
// If the buffer is too large for the cache we don't have to
// check the cache. We'll just free it.
if (isBufferTooLarge(buf)) {
free(buf);
return;
}
assert buf != null;
BufferCache cache = bufferCache.get();
if (!cache.offerLast(buf)) {
// cache is full
free(buf);
}
}
/**
* Frees the memory for the given direct buffer
*/
private static void free(ByteBuffer buf) {
((DirectBuffer)buf).cleaner().clean();
}
// -- Random stuff --
static ByteBuffer[] subsequence(ByteBuffer[] bs, int offset, int length) {
if ((offset == 0) && (length == bs.length))
return bs;
int n = length;
ByteBuffer[] bs2 = new ByteBuffer[n];
for (int i = 0; i < n; i++)
bs2[i] = bs[offset + i];
return bs2;
}
static <E> Set<E> ungrowableSet(final Set<E> s) {
return new Set<E>() {
public int size() { return s.size(); }
public boolean isEmpty() { return s.isEmpty(); }
public boolean contains(Object o) { return s.contains(o); }
public Object[] toArray() { return s.toArray(); }
public <T> T[] toArray(T[] a) { return s.toArray(a); }
public String toString() { return s.toString(); }
public Iterator<E> iterator() { return s.iterator(); }
public boolean equals(Object o) { return s.equals(o); }
public int hashCode() { return s.hashCode(); }
public void clear() { s.clear(); }
public boolean remove(Object o) { return s.remove(o); }
public boolean containsAll(Collection<?> coll) {
return s.containsAll(coll);
}
public boolean removeAll(Collection<?> coll) {
return s.removeAll(coll);
}
public boolean retainAll(Collection<?> coll) {
return s.retainAll(coll);
}
public boolean add(E o){
throw new UnsupportedOperationException();
}
public boolean addAll(Collection<? extends E> coll) {
throw new UnsupportedOperationException();
}
};
}
// -- Unsafe access --
private static Unsafe unsafe = Unsafe.getUnsafe();
private static byte _get(long a) {
return unsafe.getByte(a);
}
private static void _put(long a, byte b) {
unsafe.putByte(a, b);
}
static void erase(ByteBuffer bb) {
unsafe.setMemory(((DirectBuffer)bb).address(), bb.capacity(), (byte)0);
}
static Unsafe unsafe() {
return unsafe;
}
private static int pageSize = -1;
static int pageSize() {
if (pageSize == -1)
pageSize = unsafe().pageSize();
return pageSize;
}
private static volatile Constructor<?> directByteBufferConstructor;
private static void initDBBConstructor() {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
try {
Class<?> cl = Class.forName("java.nio.DirectByteBuffer");
Constructor<?> ctor = cl.getDeclaredConstructor(
new Class<?>[] { int.class,
long.class,
FileDescriptor.class,
Runnable.class });
ctor.setAccessible(true);
directByteBufferConstructor = ctor;
} catch (ClassNotFoundException |
NoSuchMethodException |
IllegalArgumentException |
ClassCastException x) {
throw new InternalError(x);
}
return null;
}});
}
static MappedByteBuffer newMappedByteBuffer(int size, long addr,
FileDescriptor fd,
Runnable unmapper)
{
MappedByteBuffer dbb;
if (directByteBufferConstructor == null)
initDBBConstructor();
try {
dbb = (MappedByteBuffer)directByteBufferConstructor.newInstance(
new Object[] { size,
addr,
fd,
unmapper });
} catch (InstantiationException |
IllegalAccessException |
InvocationTargetException e) {
throw new InternalError(e);
}
return dbb;
}
private static volatile Constructor<?> directByteBufferRConstructor;
private static void initDBBRConstructor() {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
try {
Class<?> cl = Class.forName("java.nio.DirectByteBufferR");
Constructor<?> ctor = cl.getDeclaredConstructor(
new Class<?>[] { int.class,
long.class,
FileDescriptor.class,
Runnable.class });
ctor.setAccessible(true);
directByteBufferRConstructor = ctor;
} catch (ClassNotFoundException |
NoSuchMethodException |
IllegalArgumentException |
ClassCastException x) {
throw new InternalError(x);
}
return null;
}});
}
static MappedByteBuffer newMappedByteBufferR(int size, long addr,
FileDescriptor fd,
Runnable unmapper)
{
MappedByteBuffer dbb;
if (directByteBufferRConstructor == null)
initDBBRConstructor();
try {
dbb = (MappedByteBuffer)directByteBufferRConstructor.newInstance(
new Object[] { size,
addr,
fd,
unmapper });
} catch (InstantiationException |
IllegalAccessException |
InvocationTargetException e) {
throw new InternalError(e);
}
return dbb;
}
}

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
/*
* FastPath byte[]->char[] decoder, REPLACE on malformed or
* unmappable input.
*/
public interface ArrayDecoder {
int decode(byte[] src, int off, int len, char[] dst);
default boolean isASCIICompatible() {
return false;
}
}

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
/*
* FastPath char[]/byte[] -> byte[] encoder, REPLACE on malformed input or
* unmappable input.
*/
public interface ArrayEncoder {
// is only used by j.u.zip.ZipCoder for utf8
int encode(char[] src, int off, int len, byte[] dst);
default int encodeFromLatin1(byte[] src, int sp, int len, byte[] dst) {
return -1;
}
default int encodeFromUTF16(byte[] src, int sp, int len, byte[] dst) {
return -1;
}
default boolean isASCIICompatible() {
return false;
}
}

View file

@ -0,0 +1,604 @@
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
/* Legal CESU-8 Byte Sequences
*
* # Code Points Bits Bit/Byte pattern
* 1 7 0xxxxxxx
* U+0000..U+007F 00..7F
*
* 2 11 110xxxxx 10xxxxxx
* U+0080..U+07FF C2..DF 80..BF
*
* 3 16 1110xxxx 10xxxxxx 10xxxxxx
* U+0800..U+0FFF E0 A0..BF 80..BF
* U+1000..U+FFFF E1..EF 80..BF 80..BF
*
*/
class CESU_8 extends Unicode
{
public CESU_8() {
super("CESU-8", StandardCharsets.aliases_CESU_8());
}
public String historicalName() {
return "CESU8";
}
public CharsetDecoder newDecoder() {
return new Decoder(this);
}
public CharsetEncoder newEncoder() {
return new Encoder(this);
}
private static final void updatePositions(Buffer src, int sp,
Buffer dst, int dp) {
src.position(sp - src.arrayOffset());
dst.position(dp - dst.arrayOffset());
}
private static class Decoder extends CharsetDecoder
implements ArrayDecoder {
private Decoder(Charset cs) {
super(cs, 1.0f, 1.0f);
}
private static boolean isNotContinuation(int b) {
return (b & 0xc0) != 0x80;
}
// [E0] [A0..BF] [80..BF]
// [E1..EF] [80..BF] [80..BF]
private static boolean isMalformed3(int b1, int b2, int b3) {
return (b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) ||
(b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80;
}
// only used when there is only one byte left in src buffer
private static boolean isMalformed3_2(int b1, int b2) {
return (b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) ||
(b2 & 0xc0) != 0x80;
}
// [F0] [90..BF] [80..BF] [80..BF]
// [F1..F3] [80..BF] [80..BF] [80..BF]
// [F4] [80..8F] [80..BF] [80..BF]
// only check 80-be range here, the [0xf0,0x80...] and [0xf4,0x90-...]
// will be checked by Character.isSupplementaryCodePoint(uc)
private static boolean isMalformed4(int b2, int b3, int b4) {
return (b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80 ||
(b4 & 0xc0) != 0x80;
}
// only used when there is less than 4 bytes left in src buffer
private static boolean isMalformed4_2(int b1, int b2) {
return (b1 == 0xf0 && b2 == 0x90) ||
(b2 & 0xc0) != 0x80;
}
private static boolean isMalformed4_3(int b3) {
return (b3 & 0xc0) != 0x80;
}
private static CoderResult malformedN(ByteBuffer src, int nb) {
switch (nb) {
case 1:
case 2: // always 1
return CoderResult.malformedForLength(1);
case 3:
int b1 = src.get();
int b2 = src.get(); // no need to lookup b3
return CoderResult.malformedForLength(
((b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) ||
isNotContinuation(b2)) ? 1 : 2);
case 4: // we don't care the speed here
b1 = src.get() & 0xff;
b2 = src.get() & 0xff;
if (b1 > 0xf4 ||
(b1 == 0xf0 && (b2 < 0x90 || b2 > 0xbf)) ||
(b1 == 0xf4 && (b2 & 0xf0) != 0x80) ||
isNotContinuation(b2))
return CoderResult.malformedForLength(1);
if (isNotContinuation(src.get()))
return CoderResult.malformedForLength(2);
return CoderResult.malformedForLength(3);
default:
assert false;
return null;
}
}
private static CoderResult malformed(ByteBuffer src, int sp,
CharBuffer dst, int dp,
int nb)
{
src.position(sp - src.arrayOffset());
CoderResult cr = malformedN(src, nb);
updatePositions(src, sp, dst, dp);
return cr;
}
private static CoderResult malformed(ByteBuffer src,
int mark, int nb)
{
src.position(mark);
CoderResult cr = malformedN(src, nb);
src.position(mark);
return cr;
}
private static CoderResult malformedForLength(ByteBuffer src,
int sp,
CharBuffer dst,
int dp,
int malformedNB)
{
updatePositions(src, sp, dst, dp);
return CoderResult.malformedForLength(malformedNB);
}
private static CoderResult malformedForLength(ByteBuffer src,
int mark,
int malformedNB)
{
src.position(mark);
return CoderResult.malformedForLength(malformedNB);
}
private static CoderResult xflow(Buffer src, int sp, int sl,
Buffer dst, int dp, int nb) {
updatePositions(src, sp, dst, dp);
return (nb == 0 || sl - sp < nb)
? CoderResult.UNDERFLOW : CoderResult.OVERFLOW;
}
private static CoderResult xflow(Buffer src, int mark, int nb) {
src.position(mark);
return (nb == 0 || src.remaining() < nb)
? CoderResult.UNDERFLOW : CoderResult.OVERFLOW;
}
private CoderResult decodeArrayLoop(ByteBuffer src,
CharBuffer dst)
{
// This method is optimized for ASCII input.
byte[] sa = src.array();
int sp = src.arrayOffset() + src.position();
int sl = src.arrayOffset() + src.limit();
char[] da = dst.array();
int dp = dst.arrayOffset() + dst.position();
int dl = dst.arrayOffset() + dst.limit();
int dlASCII = dp + Math.min(sl - sp, dl - dp);
// ASCII only loop
while (dp < dlASCII && sa[sp] >= 0)
da[dp++] = (char) sa[sp++];
while (sp < sl) {
int b1 = sa[sp];
if (b1 >= 0) {
// 1 byte, 7 bits: 0xxxxxxx
if (dp >= dl)
return xflow(src, sp, sl, dst, dp, 1);
da[dp++] = (char) b1;
sp++;
} else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) {
// 2 bytes, 11 bits: 110xxxxx 10xxxxxx
if (sl - sp < 2 || dp >= dl)
return xflow(src, sp, sl, dst, dp, 2);
int b2 = sa[sp + 1];
if (isNotContinuation(b2))
return malformedForLength(src, sp, dst, dp, 1);
da[dp++] = (char) (((b1 << 6) ^ b2)
^
(((byte) 0xC0 << 6) ^
((byte) 0x80 << 0)));
sp += 2;
} else if ((b1 >> 4) == -2) {
// 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx
int srcRemaining = sl - sp;
if (srcRemaining < 3 || dp >= dl) {
if (srcRemaining > 1 && isMalformed3_2(b1, sa[sp + 1]))
return malformedForLength(src, sp, dst, dp, 1);
return xflow(src, sp, sl, dst, dp, 3);
}
int b2 = sa[sp + 1];
int b3 = sa[sp + 2];
if (isMalformed3(b1, b2, b3))
return malformed(src, sp, dst, dp, 3);
da[dp++] = (char)
((b1 << 12) ^
(b2 << 6) ^
(b3 ^
(((byte) 0xE0 << 12) ^
((byte) 0x80 << 6) ^
((byte) 0x80 << 0))));
sp += 3;
} else {
return malformed(src, sp, dst, dp, 1);
}
}
return xflow(src, sp, sl, dst, dp, 0);
}
private CoderResult decodeBufferLoop(ByteBuffer src,
CharBuffer dst)
{
int mark = src.position();
int limit = src.limit();
while (mark < limit) {
int b1 = src.get();
if (b1 >= 0) {
// 1 byte, 7 bits: 0xxxxxxx
if (dst.remaining() < 1)
return xflow(src, mark, 1); // overflow
dst.put((char) b1);
mark++;
} else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) {
// 2 bytes, 11 bits: 110xxxxx 10xxxxxx
if (limit - mark < 2|| dst.remaining() < 1)
return xflow(src, mark, 2);
int b2 = src.get();
if (isNotContinuation(b2))
return malformedForLength(src, mark, 1);
dst.put((char) (((b1 << 6) ^ b2)
^
(((byte) 0xC0 << 6) ^
((byte) 0x80 << 0))));
mark += 2;
} else if ((b1 >> 4) == -2) {
// 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx
int srcRemaining = limit - mark;
if (srcRemaining < 3 || dst.remaining() < 1) {
if (srcRemaining > 1 && isMalformed3_2(b1, src.get()))
return malformedForLength(src, mark, 1);
return xflow(src, mark, 3);
}
int b2 = src.get();
int b3 = src.get();
if (isMalformed3(b1, b2, b3))
return malformed(src, mark, 3);
dst.put((char)
((b1 << 12) ^
(b2 << 6) ^
(b3 ^
(((byte) 0xE0 << 12) ^
((byte) 0x80 << 6) ^
((byte) 0x80 << 0)))));
mark += 3;
} else {
return malformed(src, mark, 1);
}
}
return xflow(src, mark, 0);
}
protected CoderResult decodeLoop(ByteBuffer src,
CharBuffer dst)
{
if (src.hasArray() && dst.hasArray())
return decodeArrayLoop(src, dst);
else
return decodeBufferLoop(src, dst);
}
private static ByteBuffer getByteBuffer(ByteBuffer bb, byte[] ba, int sp)
{
if (bb == null)
bb = ByteBuffer.wrap(ba);
bb.position(sp);
return bb;
}
// returns -1 if there is/are malformed byte(s) and the
// "action" for malformed input is not REPLACE.
public int decode(byte[] sa, int sp, int len, char[] da) {
final int sl = sp + len;
int dp = 0;
int dlASCII = Math.min(len, da.length);
ByteBuffer bb = null; // only necessary if malformed
// ASCII only optimized loop
while (dp < dlASCII && sa[sp] >= 0)
da[dp++] = (char) sa[sp++];
while (sp < sl) {
int b1 = sa[sp++];
if (b1 >= 0) {
// 1 byte, 7 bits: 0xxxxxxx
da[dp++] = (char) b1;
} else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) {
// 2 bytes, 11 bits: 110xxxxx 10xxxxxx
if (sp < sl) {
int b2 = sa[sp++];
if (isNotContinuation(b2)) {
if (malformedInputAction() != CodingErrorAction.REPLACE)
return -1;
da[dp++] = replacement().charAt(0);
sp--; // malformedN(bb, 2) always returns 1
} else {
da[dp++] = (char) (((b1 << 6) ^ b2)^
(((byte) 0xC0 << 6) ^
((byte) 0x80 << 0)));
}
continue;
}
if (malformedInputAction() != CodingErrorAction.REPLACE)
return -1;
da[dp++] = replacement().charAt(0);
return dp;
} else if ((b1 >> 4) == -2) {
// 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx
if (sp + 1 < sl) {
int b2 = sa[sp++];
int b3 = sa[sp++];
if (isMalformed3(b1, b2, b3)) {
if (malformedInputAction() != CodingErrorAction.REPLACE)
return -1;
da[dp++] = replacement().charAt(0);
sp -=3;
bb = getByteBuffer(bb, sa, sp);
sp += malformedN(bb, 3).length();
} else {
da[dp++] = (char)((b1 << 12) ^
(b2 << 6) ^
(b3 ^
(((byte) 0xE0 << 12) ^
((byte) 0x80 << 6) ^
((byte) 0x80 << 0))));
}
continue;
}
if (malformedInputAction() != CodingErrorAction.REPLACE)
return -1;
if (sp < sl && isMalformed3_2(b1, sa[sp])) {
da[dp++] = replacement().charAt(0);
continue;
}
da[dp++] = replacement().charAt(0);
return dp;
} else {
if (malformedInputAction() != CodingErrorAction.REPLACE)
return -1;
da[dp++] = replacement().charAt(0);
}
}
return dp;
}
}
private static class Encoder extends CharsetEncoder
implements ArrayEncoder {
private Encoder(Charset cs) {
super(cs, 1.1f, 3.0f);
}
public boolean canEncode(char c) {
return !Character.isSurrogate(c);
}
public boolean isLegalReplacement(byte[] repl) {
return ((repl.length == 1 && repl[0] >= 0) ||
super.isLegalReplacement(repl));
}
private static CoderResult overflow(CharBuffer src, int sp,
ByteBuffer dst, int dp) {
updatePositions(src, sp, dst, dp);
return CoderResult.OVERFLOW;
}
private static CoderResult overflow(CharBuffer src, int mark) {
src.position(mark);
return CoderResult.OVERFLOW;
}
private static void to3Bytes(byte[] da, int dp, char c) {
da[dp] = (byte)(0xe0 | ((c >> 12)));
da[dp + 1] = (byte)(0x80 | ((c >> 6) & 0x3f));
da[dp + 2] = (byte)(0x80 | (c & 0x3f));
}
private static void to3Bytes(ByteBuffer dst, char c) {
dst.put((byte)(0xe0 | ((c >> 12))));
dst.put((byte)(0x80 | ((c >> 6) & 0x3f)));
dst.put((byte)(0x80 | (c & 0x3f)));
}
private Surrogate.Parser sgp;
private char[] c2;
private CoderResult encodeArrayLoop(CharBuffer src,
ByteBuffer dst)
{
char[] sa = src.array();
int sp = src.arrayOffset() + src.position();
int sl = src.arrayOffset() + src.limit();
byte[] da = dst.array();
int dp = dst.arrayOffset() + dst.position();
int dl = dst.arrayOffset() + dst.limit();
int dlASCII = dp + Math.min(sl - sp, dl - dp);
// ASCII only loop
while (dp < dlASCII && sa[sp] < '\u0080')
da[dp++] = (byte) sa[sp++];
while (sp < sl) {
char c = sa[sp];
if (c < 0x80) {
// Have at most seven bits
if (dp >= dl)
return overflow(src, sp, dst, dp);
da[dp++] = (byte)c;
} else if (c < 0x800) {
// 2 bytes, 11 bits
if (dl - dp < 2)
return overflow(src, sp, dst, dp);
da[dp++] = (byte)(0xc0 | (c >> 6));
da[dp++] = (byte)(0x80 | (c & 0x3f));
} else if (Character.isSurrogate(c)) {
// Have a surrogate pair
if (sgp == null)
sgp = new Surrogate.Parser();
int uc = sgp.parse(c, sa, sp, sl);
if (uc < 0) {
updatePositions(src, sp, dst, dp);
return sgp.error();
}
if (dl - dp < 6)
return overflow(src, sp, dst, dp);
to3Bytes(da, dp, Character.highSurrogate(uc));
dp += 3;
to3Bytes(da, dp, Character.lowSurrogate(uc));
dp += 3;
sp++; // 2 chars
} else {
// 3 bytes, 16 bits
if (dl - dp < 3)
return overflow(src, sp, dst, dp);
to3Bytes(da, dp, c);
dp += 3;
}
sp++;
}
updatePositions(src, sp, dst, dp);
return CoderResult.UNDERFLOW;
}
private CoderResult encodeBufferLoop(CharBuffer src,
ByteBuffer dst)
{
int mark = src.position();
while (src.hasRemaining()) {
char c = src.get();
if (c < 0x80) {
// Have at most seven bits
if (!dst.hasRemaining())
return overflow(src, mark);
dst.put((byte)c);
} else if (c < 0x800) {
// 2 bytes, 11 bits
if (dst.remaining() < 2)
return overflow(src, mark);
dst.put((byte)(0xc0 | (c >> 6)));
dst.put((byte)(0x80 | (c & 0x3f)));
} else if (Character.isSurrogate(c)) {
// Have a surrogate pair
if (sgp == null)
sgp = new Surrogate.Parser();
int uc = sgp.parse(c, src);
if (uc < 0) {
src.position(mark);
return sgp.error();
}
if (dst.remaining() < 6)
return overflow(src, mark);
to3Bytes(dst, Character.highSurrogate(uc));
to3Bytes(dst, Character.lowSurrogate(uc));
mark++; // 2 chars
} else {
// 3 bytes, 16 bits
if (dst.remaining() < 3)
return overflow(src, mark);
to3Bytes(dst, c);
}
mark++;
}
src.position(mark);
return CoderResult.UNDERFLOW;
}
protected final CoderResult encodeLoop(CharBuffer src,
ByteBuffer dst)
{
if (src.hasArray() && dst.hasArray())
return encodeArrayLoop(src, dst);
else
return encodeBufferLoop(src, dst);
}
// returns -1 if there is malformed char(s) and the
// "action" for malformed input is not REPLACE.
public int encode(char[] sa, int sp, int len, byte[] da) {
int sl = sp + len;
int dp = 0;
int dlASCII = dp + Math.min(len, da.length);
// ASCII only optimized loop
while (dp < dlASCII && sa[sp] < '\u0080')
da[dp++] = (byte) sa[sp++];
while (sp < sl) {
char c = sa[sp++];
if (c < 0x80) {
// Have at most seven bits
da[dp++] = (byte)c;
} else if (c < 0x800) {
// 2 bytes, 11 bits
da[dp++] = (byte)(0xc0 | (c >> 6));
da[dp++] = (byte)(0x80 | (c & 0x3f));
} else if (Character.isSurrogate(c)) {
if (sgp == null)
sgp = new Surrogate.Parser();
int uc = sgp.parse(c, sa, sp - 1, sl);
if (uc < 0) {
if (malformedInputAction() != CodingErrorAction.REPLACE)
return -1;
da[dp++] = replacement()[0];
} else {
to3Bytes(da, dp, Character.highSurrogate(uc));
dp += 3;
to3Bytes(da, dp, Character.lowSurrogate(uc));
dp += 3;
sp++; // 2 chars
}
} else {
// 3 bytes, 16 bits
to3Bytes(da, dp, c);
dp += 3;
}
}
return dp;
}
}
}

View file

@ -0,0 +1,353 @@
/*
* Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.*;
import java.security.*;
public class CharsetMapping {
public static final char UNMAPPABLE_DECODING = '\uFFFD';
public static final int UNMAPPABLE_ENCODING = 0xFFFD;
char[] b2cSB; //singlebyte b->c
char[] b2cDB1; //dobulebyte b->c /db1
char[] b2cDB2; //dobulebyte b->c /db2
int b2Min, b2Max; //min/max(start/end) value of 2nd byte
int b1MinDB1, b1MaxDB1; //min/Max(start/end) value of 1st byte/db1
int b1MinDB2, b1MaxDB2; //min/Max(start/end) value of 1st byte/db2
int dbSegSize;
char[] c2b;
char[] c2bIndex;
// Supplementary
char[] b2cSupp;
char[] c2bSupp;
// Composite
Entry[] b2cComp;
Entry[] c2bComp;
public char decodeSingle(int b) {
return b2cSB[b];
}
public char decodeDouble(int b1, int b2) {
if (b2 >= b2Min && b2 < b2Max) {
b2 -= b2Min;
if (b1 >= b1MinDB1 && b1 <= b1MaxDB1) {
b1 -= b1MinDB1;
return b2cDB1[b1 * dbSegSize + b2];
}
if (b1 >= b1MinDB2 && b1 <= b1MaxDB2) {
b1 -= b1MinDB2;
return b2cDB2[b1 * dbSegSize + b2];
}
}
return UNMAPPABLE_DECODING;
}
// for jis0213 all supplementary characters are in 0x2xxxx range,
// so only the xxxx part is now stored, should actually store the
// codepoint value instead.
public char[] decodeSurrogate(int db, char[] cc) {
int end = b2cSupp.length / 2;
int i = Arrays.binarySearch(b2cSupp, 0, end, (char)db);
if (i >= 0) {
Character.toChars(b2cSupp[end + i] + 0x20000, cc, 0);
return cc;
}
return null;
}
public char[] decodeComposite(Entry comp, char[] cc) {
int i = findBytes(b2cComp, comp);
if (i >= 0) {
cc[0] = (char)b2cComp[i].cp;
cc[1] = (char)b2cComp[i].cp2;
return cc;
}
return null;
}
public int encodeChar(char ch) {
int index = c2bIndex[ch >> 8];
if (index == 0xffff)
return UNMAPPABLE_ENCODING;
return c2b[index + (ch & 0xff)];
}
public int encodeSurrogate(char hi, char lo) {
int cp = Character.toCodePoint(hi, lo);
if (cp < 0x20000 || cp >= 0x30000)
return UNMAPPABLE_ENCODING;
int end = c2bSupp.length / 2;
int i = Arrays.binarySearch(c2bSupp, 0, end, (char)cp);
if (i >= 0)
return c2bSupp[end + i];
return UNMAPPABLE_ENCODING;
}
public boolean isCompositeBase(Entry comp) {
if (comp.cp <= 0x31f7 && comp.cp >= 0xe6) {
return (findCP(c2bComp, comp) >= 0);
}
return false;
}
public int encodeComposite(Entry comp) {
int i = findComp(c2bComp, comp);
if (i >= 0)
return c2bComp[i].bs;
return UNMAPPABLE_ENCODING;
}
// init the CharsetMapping object from the .dat binary file
public static CharsetMapping get(final InputStream is) {
return AccessController.doPrivileged(new PrivilegedAction<>() {
public CharsetMapping run() {
return new CharsetMapping().load(is);
}
});
}
public static class Entry {
public int bs; //byte sequence reps
public int cp; //Unicode codepoint
public int cp2; //CC of composite
}
static Comparator<Entry> comparatorBytes =
new Comparator<Entry>() {
public int compare(Entry m1, Entry m2) {
return m1.bs - m2.bs;
}
public boolean equals(Object obj) {
return this == obj;
}
};
static Comparator<Entry> comparatorCP =
new Comparator<Entry>() {
public int compare(Entry m1, Entry m2) {
return m1.cp - m2.cp;
}
public boolean equals(Object obj) {
return this == obj;
}
};
static Comparator<Entry> comparatorComp =
new Comparator<Entry>() {
public int compare(Entry m1, Entry m2) {
int v = m1.cp - m2.cp;
if (v == 0)
v = m1.cp2 - m2.cp2;
return v;
}
public boolean equals(Object obj) {
return this == obj;
}
};
static int findBytes(Entry[] a, Entry k) {
return Arrays.binarySearch(a, 0, a.length, k, comparatorBytes);
}
static int findCP(Entry[] a, Entry k) {
return Arrays.binarySearch(a, 0, a.length, k, comparatorCP);
}
static int findComp(Entry[] a, Entry k) {
return Arrays.binarySearch(a, 0, a.length, k, comparatorComp);
}
/*****************************************************************************/
// tags of different charset mapping tables
private static final int MAP_SINGLEBYTE = 0x1; // 0..256 : c
private static final int MAP_DOUBLEBYTE1 = 0x2; // min..max: c
private static final int MAP_DOUBLEBYTE2 = 0x3; // min..max: c [DB2]
private static final int MAP_SUPPLEMENT = 0x5; // db,c
private static final int MAP_SUPPLEMENT_C2B = 0x6; // c,db
private static final int MAP_COMPOSITE = 0x7; // db,base,cc
private static final int MAP_INDEXC2B = 0x8; // index table of c->bb
private static final boolean readNBytes(InputStream in, byte[] bb, int N)
throws IOException
{
int off = 0;
while (N > 0) {
int n = in.read(bb, off, N);
if (n == -1)
return false;
N = N - n;
off += n;
}
return true;
}
int off = 0;
byte[] bb;
private char[] readCharArray() {
// first 2 bytes are the number of "chars" stored in this table
int size = ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);
char [] cc = new char[size];
for (int i = 0; i < size; i++) {
cc[i] = (char)(((bb[off++]&0xff)<<8) | (bb[off++]&0xff));
}
return cc;
}
void readSINGLEBYTE() {
char[] map = readCharArray();
for (int i = 0; i < map.length; i++) {
char c = map[i];
if (c != UNMAPPABLE_DECODING) {
c2b[c2bIndex[c >> 8] + (c&0xff)] = (char)i;
}
}
b2cSB = map;
}
void readINDEXC2B() {
char[] map = readCharArray();
for (int i = map.length - 1; i >= 0; i--) {
if (c2b == null && map[i] != -1) {
c2b = new char[map[i] + 256];
Arrays.fill(c2b, (char)UNMAPPABLE_ENCODING);
break;
}
}
c2bIndex = map;
}
char[] readDB(int b1Min, int b2Min, int segSize) {
char[] map = readCharArray();
for (int i = 0; i < map.length; i++) {
char c = map[i];
if (c != UNMAPPABLE_DECODING) {
int b1 = i / segSize;
int b2 = i % segSize;
int b = (b1 + b1Min)* 256 + (b2 + b2Min);
//System.out.printf(" DB %x\t%x%n", b, c & 0xffff);
c2b[c2bIndex[c >> 8] + (c&0xff)] = (char)(b);
}
}
return map;
}
void readDOUBLEBYTE1() {
b1MinDB1 = ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);
b1MaxDB1 = ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);
b2Min = ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);
b2Max = ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);
dbSegSize = b2Max - b2Min + 1;
b2cDB1 = readDB(b1MinDB1, b2Min, dbSegSize);
}
void readDOUBLEBYTE2() {
b1MinDB2 = ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);
b1MaxDB2 = ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);
b2Min = ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);
b2Max = ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);
dbSegSize = b2Max - b2Min + 1;
b2cDB2 = readDB(b1MinDB2, b2Min, dbSegSize);
}
void readCOMPOSITE() {
char[] map = readCharArray();
int mLen = map.length/3;
b2cComp = new Entry[mLen];
c2bComp = new Entry[mLen];
for (int i = 0, j= 0; i < mLen; i++) {
Entry m = new Entry();
m.bs = map[j++];
m.cp = map[j++];
m.cp2 = map[j++];
b2cComp[i] = m;
c2bComp[i] = m;
}
Arrays.sort(c2bComp, 0, c2bComp.length, comparatorComp);
}
CharsetMapping load(InputStream in) {
try {
// The first 4 bytes are the size of the total data followed in
// this .dat file.
int len = ((in.read()&0xff) << 24) | ((in.read()&0xff) << 16) |
((in.read()&0xff) << 8) | (in.read()&0xff);
bb = new byte[len];
off = 0;
//System.out.printf("In : Total=%d%n", len);
// Read in all bytes
if (!readNBytes(in, bb, len))
throw new RuntimeException("Corrupted data file");
in.close();
while (off < len) {
int type = ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);
switch(type) {
case MAP_INDEXC2B:
readINDEXC2B();
break;
case MAP_SINGLEBYTE:
readSINGLEBYTE();
break;
case MAP_DOUBLEBYTE1:
readDOUBLEBYTE1();
break;
case MAP_DOUBLEBYTE2:
readDOUBLEBYTE2();
break;
case MAP_SUPPLEMENT:
b2cSupp = readCharArray();
break;
case MAP_SUPPLEMENT_C2B:
c2bSupp = readCharArray();
break;
case MAP_COMPOSITE:
readCOMPOSITE();
break;
default:
throw new RuntimeException("Corrupted data file");
}
}
bb = null;
return this;
} catch (IOException x) {
x.printStackTrace();
return null;
}
}
}

View file

@ -0,0 +1,41 @@
/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CoderResult;
/**
* A decoder that can be delegated to by another decoder
* when normal inheritance cannot be used.
* Used by autodecting decoders.
*/
public interface DelegatableDecoder {
CoderResult decodeLoop(ByteBuffer src, CharBuffer dst);
void implReset();
CoderResult implFlush(CharBuffer out);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,161 @@
/*
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
import java.nio.charset.Charset;
import java.nio.charset.spi.CharsetProvider;
import java.util.Iterator;
import java.util.Map;
/**
* Abstract base class for fast charset providers.
*
* @author Mark Reinhold
*/
public class FastCharsetProvider
extends CharsetProvider
{
// Maps canonical names to class names
private Map<String,String> classMap;
// Maps alias names to canonical names
private Map<String,String> aliasMap;
// Maps canonical names to cached instances
private Map<String,Charset> cache;
private String packagePrefix;
protected FastCharsetProvider(String pp,
Map<String,String> am,
Map<String,String> cm,
Map<String,Charset> c)
{
packagePrefix = pp;
aliasMap = am;
classMap = cm;
cache = c;
}
private String canonicalize(String csn) {
String acn = aliasMap.get(csn);
return (acn != null) ? acn : csn;
}
// Private ASCII-only version, optimized for interpretation during startup
//
private static String toLower(String s) {
int n = s.length();
boolean allLower = true;
for (int i = 0; i < n; i++) {
int c = s.charAt(i);
if (((c - 'A') | ('Z' - c)) >= 0) {
allLower = false;
break;
}
}
if (allLower)
return s;
char[] ca = new char[n];
for (int i = 0; i < n; i++) {
int c = s.charAt(i);
if (((c - 'A') | ('Z' - c)) >= 0)
ca[i] = (char)(c + 0x20);
else
ca[i] = (char)c;
}
return new String(ca);
}
private Charset lookup(String charsetName) {
String csn = canonicalize(toLower(charsetName));
// Check cache first
Charset cs = cache.get(csn);
if (cs != null)
return cs;
// Do we even support this charset?
String cln = classMap.get(csn);
if (cln == null)
return null;
if (cln.equals("US_ASCII")) {
cs = new US_ASCII();
cache.put(csn, cs);
return cs;
}
// Instantiate the charset and cache it
try {
@SuppressWarnings("deprecation")
Object o= Class.forName(packagePrefix + "." + cln,
true,
this.getClass().getClassLoader()).newInstance();
cs = (Charset)o;
cache.put(csn, cs);
return cs;
} catch (ClassNotFoundException |
IllegalAccessException |
InstantiationException x) {
return null;
}
}
public final Charset charsetForName(String charsetName) {
synchronized (this) {
return lookup(canonicalize(charsetName));
}
}
public final Iterator<Charset> charsets() {
return new Iterator<Charset>() {
Iterator<String> i = classMap.keySet().iterator();
public boolean hasNext() {
return i.hasNext();
}
public Charset next() {
String csn = i.next();
return lookup(csn);
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}

View file

@ -0,0 +1,462 @@
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.util.Arrays;
import sun.nio.cs.DoubleByte;
import sun.nio.cs.Surrogate;
import static sun.nio.cs.CharsetMapping.*;
public class HKSCS {
public static class Decoder extends DoubleByte.Decoder {
static int b2Min = 0x40;
static int b2Max = 0xfe;
private char[][] b2cBmp;
private char[][] b2cSupp;
private DoubleByte.Decoder big5Dec;
protected Decoder(Charset cs,
DoubleByte.Decoder big5Dec,
char[][] b2cBmp, char[][] b2cSupp)
{
// super(cs, 0.5f, 1.0f);
// need to extends DoubleByte.Decoder so the
// sun.io can use it. this implementation
super(cs, 0.5f, 1.0f, null, null, 0, 0, true);
this.big5Dec = big5Dec;
this.b2cBmp = b2cBmp;
this.b2cSupp = b2cSupp;
}
public char decodeSingle(int b) {
return big5Dec.decodeSingle(b);
}
public char decodeBig5(int b1, int b2) {
return big5Dec.decodeDouble(b1, b2);
}
public char decodeDouble(int b1, int b2) {
return b2cBmp[b1][b2 - b2Min];
}
public char decodeDoubleEx(int b1, int b2) {
/* if the b2cSupp is null, the subclass need
to override the methold
if (b2cSupp == null)
return UNMAPPABLE_DECODING;
*/
return b2cSupp[b1][b2 - b2Min];
}
protected CoderResult decodeArrayLoop(ByteBuffer src, CharBuffer dst) {
byte[] sa = src.array();
int sp = src.arrayOffset() + src.position();
int sl = src.arrayOffset() + src.limit();
char[] da = dst.array();
int dp = dst.arrayOffset() + dst.position();
int dl = dst.arrayOffset() + dst.limit();
try {
while (sp < sl) {
int b1 = sa[sp] & 0xff;
char c = decodeSingle(b1);
int inSize = 1, outSize = 1;
char[] cc = null;
if (c == UNMAPPABLE_DECODING) {
if (sl - sp < 2)
return CoderResult.UNDERFLOW;
int b2 = sa[sp + 1] & 0xff;
inSize++;
if (b2 < b2Min || b2 > b2Max)
return CoderResult.unmappableForLength(2);
c = decodeDouble(b1, b2); //bmp
if (c == UNMAPPABLE_DECODING) {
c = decodeDoubleEx(b1, b2); //supp
if (c == UNMAPPABLE_DECODING) {
c = decodeBig5(b1, b2); //big5
if (c == UNMAPPABLE_DECODING)
return CoderResult.unmappableForLength(2);
} else {
// supplementary character in u+2xxxx area
outSize = 2;
}
}
}
if (dl - dp < outSize)
return CoderResult.OVERFLOW;
if (outSize == 2) {
// supplementary characters
da[dp++] = Surrogate.high(0x20000 + c);
da[dp++] = Surrogate.low(0x20000 + c);
} else {
da[dp++] = c;
}
sp += inSize;
}
return CoderResult.UNDERFLOW;
} finally {
src.position(sp - src.arrayOffset());
dst.position(dp - dst.arrayOffset());
}
}
protected CoderResult decodeBufferLoop(ByteBuffer src, CharBuffer dst) {
int mark = src.position();
try {
while (src.hasRemaining()) {
char[] cc = null;
int b1 = src.get() & 0xff;
int inSize = 1, outSize = 1;
char c = decodeSingle(b1);
if (c == UNMAPPABLE_DECODING) {
if (src.remaining() < 1)
return CoderResult.UNDERFLOW;
int b2 = src.get() & 0xff;
inSize++;
if (b2 < b2Min || b2 > b2Max)
return CoderResult.unmappableForLength(2);
c = decodeDouble(b1, b2); //bmp
if (c == UNMAPPABLE_DECODING) {
c = decodeDoubleEx(b1, b2); //supp
if (c == UNMAPPABLE_DECODING) {
c = decodeBig5(b1, b2); //big5
if (c == UNMAPPABLE_DECODING)
return CoderResult.unmappableForLength(2);
} else {
outSize = 2;
}
}
}
if (dst.remaining() < outSize)
return CoderResult.OVERFLOW;
if (outSize == 2) {
dst.put(Surrogate.high(0x20000 + c));
dst.put(Surrogate.low(0x20000 + c));
} else {
dst.put(c);
}
mark += inSize;
}
return CoderResult.UNDERFLOW;
} finally {
src.position(mark);
}
}
public int decode(byte[] src, int sp, int len, char[] dst) {
int dp = 0;
int sl = sp + len;
char repl = replacement().charAt(0);
while (sp < sl) {
int b1 = src[sp++] & 0xff;
char c = decodeSingle(b1);
if (c == UNMAPPABLE_DECODING) {
if (sl == sp) {
c = repl;
} else {
int b2 = src[sp++] & 0xff;
if (b2 < b2Min || b2 > b2Max) {
c = repl;
} else if ((c = decodeDouble(b1, b2)) == UNMAPPABLE_DECODING) {
c = decodeDoubleEx(b1, b2); //supp
if (c == UNMAPPABLE_DECODING) {
c = decodeBig5(b1, b2); //big5
if (c == UNMAPPABLE_DECODING)
c = repl;
} else {
// supplementary character in u+2xxxx area
dst[dp++] = Surrogate.high(0x20000 + c);
dst[dp++] = Surrogate.low(0x20000 + c);
continue;
}
}
}
}
dst[dp++] = c;
}
return dp;
}
public CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) {
if (src.hasArray() && dst.hasArray())
return decodeArrayLoop(src, dst);
else
return decodeBufferLoop(src, dst);
}
public static void initb2c(char[][]b2c, String[] b2cStr)
{
for (int i = 0; i < b2cStr.length; i++) {
if (b2cStr[i] == null)
b2c[i] = DoubleByte.B2C_UNMAPPABLE;
else
b2c[i] = b2cStr[i].toCharArray();
}
}
}
public static class Encoder extends DoubleByte.Encoder {
private DoubleByte.Encoder big5Enc;
private char[][] c2bBmp;
private char[][] c2bSupp;
protected Encoder(Charset cs,
DoubleByte.Encoder big5Enc,
char[][] c2bBmp,
char[][] c2bSupp)
{
super(cs, null, null, true);
this.big5Enc = big5Enc;
this.c2bBmp = c2bBmp;
this.c2bSupp = c2bSupp;
}
public int encodeBig5(char ch) {
return big5Enc.encodeChar(ch);
}
public int encodeChar(char ch) {
int bb = c2bBmp[ch >> 8][ch & 0xff];
if (bb == UNMAPPABLE_ENCODING)
return encodeBig5(ch);
return bb;
}
public int encodeSupp(int cp) {
if ((cp & 0xf0000) != 0x20000)
return UNMAPPABLE_ENCODING;
return c2bSupp[(cp >> 8) & 0xff][cp & 0xff];
}
public boolean canEncode(char c) {
return encodeChar(c) != UNMAPPABLE_ENCODING;
}
protected CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) {
char[] sa = src.array();
int sp = src.arrayOffset() + src.position();
int sl = src.arrayOffset() + src.limit();
byte[] da = dst.array();
int dp = dst.arrayOffset() + dst.position();
int dl = dst.arrayOffset() + dst.limit();
try {
while (sp < sl) {
char c = sa[sp];
int inSize = 1;
int bb = encodeChar(c);
if (bb == UNMAPPABLE_ENCODING) {
if (Character.isSurrogate(c)) {
int cp;
if ((cp = sgp().parse(c, sa, sp, sl)) < 0)
return sgp.error();
bb = encodeSupp(cp);
if (bb == UNMAPPABLE_ENCODING)
return CoderResult.unmappableForLength(2);
inSize = 2;
} else {
return CoderResult.unmappableForLength(1);
}
}
if (bb > MAX_SINGLEBYTE) { // DoubleByte
if (dl - dp < 2)
return CoderResult.OVERFLOW;
da[dp++] = (byte)(bb >> 8);
da[dp++] = (byte)bb;
} else { // SingleByte
if (dl - dp < 1)
return CoderResult.OVERFLOW;
da[dp++] = (byte)bb;
}
sp += inSize;
}
return CoderResult.UNDERFLOW;
} finally {
src.position(sp - src.arrayOffset());
dst.position(dp - dst.arrayOffset());
}
}
protected CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) {
int mark = src.position();
try {
while (src.hasRemaining()) {
int inSize = 1;
char c = src.get();
int bb = encodeChar(c);
if (bb == UNMAPPABLE_ENCODING) {
if (Character.isSurrogate(c)) {
int cp;
if ((cp = sgp().parse(c, src)) < 0)
return sgp.error();
bb = encodeSupp(cp);
if (bb == UNMAPPABLE_ENCODING)
return CoderResult.unmappableForLength(2);
inSize = 2;
} else {
return CoderResult.unmappableForLength(1);
}
}
if (bb > MAX_SINGLEBYTE) { // DoubleByte
if (dst.remaining() < 2)
return CoderResult.OVERFLOW;
dst.put((byte)(bb >> 8));
dst.put((byte)(bb));
} else {
if (dst.remaining() < 1)
return CoderResult.OVERFLOW;
dst.put((byte)bb);
}
mark += inSize;
}
return CoderResult.UNDERFLOW;
} finally {
src.position(mark);
}
}
protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) {
if (src.hasArray() && dst.hasArray())
return encodeArrayLoop(src, dst);
else
return encodeBufferLoop(src, dst);
}
private byte[] repl = replacement();
protected void implReplaceWith(byte[] newReplacement) {
repl = newReplacement;
}
public int encode(char[] src, int sp, int len, byte[] dst) {
int dp = 0;
int sl = sp + len;
while (sp < sl) {
char c = src[sp++];
int bb = encodeChar(c);
if (bb == UNMAPPABLE_ENCODING) {
if (!Character.isHighSurrogate(c) || sp == sl ||
!Character.isLowSurrogate(src[sp]) ||
(bb = encodeSupp(Character.toCodePoint(c, src[sp++])))
== UNMAPPABLE_ENCODING) {
dst[dp++] = repl[0];
if (repl.length > 1)
dst[dp++] = repl[1];
continue;
}
}
if (bb > MAX_SINGLEBYTE) { // DoubleByte
dst[dp++] = (byte)(bb >> 8);
dst[dp++] = (byte)bb;
} else { // SingleByte
dst[dp++] = (byte)bb;
}
}
return dp;
}
public int encodeFromUTF16(byte[] src, int sp, int len, byte[] dst) {
int dp = 0;
int sl = sp + len;
int dl = dst.length;
while (sp < sl) {
char c = StringUTF16.getChar(src, sp++);
int bb = encodeChar(c);
if (bb == UNMAPPABLE_ENCODING) {
if (!Character.isHighSurrogate(c) || sp == sl ||
!Character.isLowSurrogate(StringUTF16.getChar(src,sp)) ||
(bb = encodeSupp(Character.toCodePoint(c, StringUTF16.getChar(src, sp++))))
== UNMAPPABLE_ENCODING) {
dst[dp++] = repl[0];
if (repl.length > 1)
dst[dp++] = repl[1];
continue;
}
}
if (bb > MAX_SINGLEBYTE) { // DoubleByte
dst[dp++] = (byte)(bb >> 8);
dst[dp++] = (byte)bb;
} else { // SingleByte
dst[dp++] = (byte)bb;
}
}
return dp;
}
static char[] C2B_UNMAPPABLE = new char[0x100];
static {
Arrays.fill(C2B_UNMAPPABLE, (char)UNMAPPABLE_ENCODING);
}
public static void initc2b(char[][] c2b, String[] b2cStr, String pua) {
// init c2b/c2bSupp from b2cStr and supp
int b2Min = 0x40;
Arrays.fill(c2b, C2B_UNMAPPABLE);
for (int b1 = 0; b1 < 0x100; b1++) {
String s = b2cStr[b1];
if (s == null)
continue;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == UNMAPPABLE_DECODING)
continue;
int hi = c >> 8;
if (c2b[hi] == C2B_UNMAPPABLE) {
c2b[hi] = new char[0x100];
Arrays.fill(c2b[hi], (char)UNMAPPABLE_ENCODING);
}
c2b[hi][c & 0xff] = (char)((b1 << 8) | (i + b2Min));
}
}
if (pua != null) { // add the compatibility pua entries
char c = '\ue000'; //first pua character
for (int i = 0; i < pua.length(); i++) {
char bb = pua.charAt(i);
if (bb != UNMAPPABLE_DECODING) {
int hi = c >> 8;
if (c2b[hi] == C2B_UNMAPPABLE) {
c2b[hi] = new char[0x100];
Arrays.fill(c2b[hi], (char)UNMAPPABLE_ENCODING);
}
c2b[hi][c & 0xff] = bb;
}
c++;
}
}
}
}
}

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
public interface HistoricallyNamedCharset {
public String historicalName();
}

View file

@ -0,0 +1,309 @@
/*
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.util.Objects;
import jdk.internal.HotSpotIntrinsicCandidate;
public class ISO_8859_1
extends Charset
implements HistoricallyNamedCharset
{
public static final ISO_8859_1 INSTANCE = new ISO_8859_1();
public ISO_8859_1() {
super("ISO-8859-1", StandardCharsets.aliases_ISO_8859_1());
}
public String historicalName() {
return "ISO8859_1";
}
public boolean contains(Charset cs) {
return ((cs instanceof US_ASCII)
|| (cs instanceof ISO_8859_1));
}
public CharsetDecoder newDecoder() {
return new Decoder(this);
}
public CharsetEncoder newEncoder() {
return new Encoder(this);
}
private static class Decoder extends CharsetDecoder
implements ArrayDecoder {
private Decoder(Charset cs) {
super(cs, 1.0f, 1.0f);
}
private CoderResult decodeArrayLoop(ByteBuffer src,
CharBuffer dst)
{
byte[] sa = src.array();
int sp = src.arrayOffset() + src.position();
int sl = src.arrayOffset() + src.limit();
assert (sp <= sl);
sp = (sp <= sl ? sp : sl);
char[] da = dst.array();
int dp = dst.arrayOffset() + dst.position();
int dl = dst.arrayOffset() + dst.limit();
assert (dp <= dl);
dp = (dp <= dl ? dp : dl);
try {
while (sp < sl) {
byte b = sa[sp];
if (dp >= dl)
return CoderResult.OVERFLOW;
da[dp++] = (char)(b & 0xff);
sp++;
}
return CoderResult.UNDERFLOW;
} finally {
src.position(sp - src.arrayOffset());
dst.position(dp - dst.arrayOffset());
}
}
private CoderResult decodeBufferLoop(ByteBuffer src,
CharBuffer dst)
{
int mark = src.position();
try {
while (src.hasRemaining()) {
byte b = src.get();
if (!dst.hasRemaining())
return CoderResult.OVERFLOW;
dst.put((char)(b & 0xff));
mark++;
}
return CoderResult.UNDERFLOW;
} finally {
src.position(mark);
}
}
protected CoderResult decodeLoop(ByteBuffer src,
CharBuffer dst)
{
if (src.hasArray() && dst.hasArray())
return decodeArrayLoop(src, dst);
else
return decodeBufferLoop(src, dst);
}
public int decode(byte[] src, int sp, int len, char[] dst) {
if (len > dst.length)
len = dst.length;
int dp = 0;
while (dp < len)
dst[dp++] = (char)(src[sp++] & 0xff);
return dp;
}
public boolean isASCIICompatible() {
return true;
}
}
private static class Encoder extends CharsetEncoder
implements ArrayEncoder {
private Encoder(Charset cs) {
super(cs, 1.0f, 1.0f);
}
public boolean canEncode(char c) {
return c <= '\u00FF';
}
public boolean isLegalReplacement(byte[] repl) {
return true; // we accept any byte value
}
private final Surrogate.Parser sgp = new Surrogate.Parser();
// Method possible replaced with a compiler intrinsic.
private static int encodeISOArray(char[] sa, int sp,
byte[] da, int dp, int len) {
if (len <= 0) {
return 0;
}
encodeISOArrayCheck(sa, sp, da, dp, len);
return implEncodeISOArray(sa, sp, da, dp, len);
}
@HotSpotIntrinsicCandidate
private static int implEncodeISOArray(char[] sa, int sp,
byte[] da, int dp, int len)
{
int i = 0;
for (; i < len; i++) {
char c = sa[sp++];
if (c > '\u00FF')
break;
da[dp++] = (byte)c;
}
return i;
}
private static void encodeISOArrayCheck(char[] sa, int sp,
byte[] da, int dp, int len) {
Objects.requireNonNull(sa);
Objects.requireNonNull(da);
if (sp < 0 || sp >= sa.length) {
throw new ArrayIndexOutOfBoundsException(sp);
}
if (dp < 0 || dp >= da.length) {
throw new ArrayIndexOutOfBoundsException(dp);
}
int endIndexSP = sp + len - 1;
if (endIndexSP < 0 || endIndexSP >= sa.length) {
throw new ArrayIndexOutOfBoundsException(endIndexSP);
}
int endIndexDP = dp + len - 1;
if (endIndexDP < 0 || endIndexDP >= da.length) {
throw new ArrayIndexOutOfBoundsException(endIndexDP);
}
}
private CoderResult encodeArrayLoop(CharBuffer src,
ByteBuffer dst)
{
char[] sa = src.array();
int soff = src.arrayOffset();
int sp = soff + src.position();
int sl = soff + src.limit();
assert (sp <= sl);
sp = (sp <= sl ? sp : sl);
byte[] da = dst.array();
int doff = dst.arrayOffset();
int dp = doff + dst.position();
int dl = doff + dst.limit();
assert (dp <= dl);
dp = (dp <= dl ? dp : dl);
int dlen = dl - dp;
int slen = sl - sp;
int len = (dlen < slen) ? dlen : slen;
try {
int ret = encodeISOArray(sa, sp, da, dp, len);
sp = sp + ret;
dp = dp + ret;
if (ret != len) {
if (sgp.parse(sa[sp], sa, sp, sl) < 0)
return sgp.error();
return sgp.unmappableResult();
}
if (len < slen)
return CoderResult.OVERFLOW;
return CoderResult.UNDERFLOW;
} finally {
src.position(sp - soff);
dst.position(dp - doff);
}
}
private CoderResult encodeBufferLoop(CharBuffer src,
ByteBuffer dst)
{
int mark = src.position();
try {
while (src.hasRemaining()) {
char c = src.get();
if (c <= '\u00FF') {
if (!dst.hasRemaining())
return CoderResult.OVERFLOW;
dst.put((byte)c);
mark++;
continue;
}
if (sgp.parse(c, src) < 0)
return sgp.error();
return sgp.unmappableResult();
}
return CoderResult.UNDERFLOW;
} finally {
src.position(mark);
}
}
protected CoderResult encodeLoop(CharBuffer src,
ByteBuffer dst)
{
if (src.hasArray() && dst.hasArray())
return encodeArrayLoop(src, dst);
else
return encodeBufferLoop(src, dst);
}
private byte repl = (byte)'?';
protected void implReplaceWith(byte[] newReplacement) {
repl = newReplacement[0];
}
public int encode(char[] src, int sp, int len, byte[] dst) {
int dp = 0;
int slen = Math.min(len, dst.length);
int sl = sp + slen;
while (sp < sl) {
int ret = encodeISOArray(src, sp, dst, dp, slen);
sp = sp + ret;
dp = dp + ret;
if (ret != slen) {
char c = src[sp++];
if (Character.isHighSurrogate(c) && sp < sl &&
Character.isLowSurrogate(src[sp])) {
if (len > dst.length) {
sl++;
len--;
}
sp++;
}
dst[dp++] = repl;
slen = Math.min((sl - sp), (dst.length - dp));
}
}
return dp;
}
public boolean isASCIICompatible() {
return true;
}
}
}

View file

@ -0,0 +1,354 @@
/*
* Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.util.Arrays;
import static sun.nio.cs.CharsetMapping.*;
public class SingleByte
{
private static final CoderResult withResult(CoderResult cr,
Buffer src, int sp,
Buffer dst, int dp)
{
src.position(sp - src.arrayOffset());
dst.position(dp - dst.arrayOffset());
return cr;
}
public static final class Decoder extends CharsetDecoder
implements ArrayDecoder {
private final char[] b2c;
private final boolean isASCIICompatible;
public Decoder(Charset cs, char[] b2c) {
super(cs, 1.0f, 1.0f);
this.b2c = b2c;
this.isASCIICompatible = false;
}
public Decoder(Charset cs, char[] b2c, boolean isASCIICompatible) {
super(cs, 1.0f, 1.0f);
this.b2c = b2c;
this.isASCIICompatible = isASCIICompatible;
}
private CoderResult decodeArrayLoop(ByteBuffer src, CharBuffer dst) {
byte[] sa = src.array();
int sp = src.arrayOffset() + src.position();
int sl = src.arrayOffset() + src.limit();
char[] da = dst.array();
int dp = dst.arrayOffset() + dst.position();
int dl = dst.arrayOffset() + dst.limit();
CoderResult cr = CoderResult.UNDERFLOW;
if ((dl - dp) < (sl - sp)) {
sl = sp + (dl - dp);
cr = CoderResult.OVERFLOW;
}
while (sp < sl) {
char c = decode(sa[sp]);
if (c == UNMAPPABLE_DECODING) {
return withResult(CoderResult.unmappableForLength(1),
src, sp, dst, dp);
}
da[dp++] = c;
sp++;
}
return withResult(cr, src, sp, dst, dp);
}
private CoderResult decodeBufferLoop(ByteBuffer src, CharBuffer dst) {
int mark = src.position();
try {
while (src.hasRemaining()) {
char c = decode(src.get());
if (c == UNMAPPABLE_DECODING)
return CoderResult.unmappableForLength(1);
if (!dst.hasRemaining())
return CoderResult.OVERFLOW;
dst.put(c);
mark++;
}
return CoderResult.UNDERFLOW;
} finally {
src.position(mark);
}
}
protected CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) {
if (src.hasArray() && dst.hasArray())
return decodeArrayLoop(src, dst);
else
return decodeBufferLoop(src, dst);
}
public final char decode(int b) {
return b2c[b + 128];
}
private char repl = '\uFFFD';
protected void implReplaceWith(String newReplacement) {
repl = newReplacement.charAt(0);
}
@Override
public int decode(byte[] src, int sp, int len, char[] dst) {
if (len > dst.length)
len = dst.length;
int dp = 0;
while (dp < len) {
dst[dp] = decode(src[sp++]);
if (dst[dp] == UNMAPPABLE_DECODING) {
dst[dp] = repl;
}
dp++;
}
return dp;
}
@Override
public boolean isASCIICompatible() {
return isASCIICompatible;
}
}
public static final class Encoder extends CharsetEncoder
implements ArrayEncoder {
private Surrogate.Parser sgp;
private final char[] c2b;
private final char[] c2bIndex;
private final boolean isASCIICompatible;
public Encoder(Charset cs, char[] c2b, char[] c2bIndex, boolean isASCIICompatible) {
super(cs, 1.0f, 1.0f);
this.c2b = c2b;
this.c2bIndex = c2bIndex;
this.isASCIICompatible = isASCIICompatible;
}
public boolean canEncode(char c) {
return encode(c) != UNMAPPABLE_ENCODING;
}
public boolean isLegalReplacement(byte[] repl) {
return ((repl.length == 1 && repl[0] == (byte)'?') ||
super.isLegalReplacement(repl));
}
private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) {
char[] sa = src.array();
int sp = src.arrayOffset() + src.position();
int sl = src.arrayOffset() + src.limit();
byte[] da = dst.array();
int dp = dst.arrayOffset() + dst.position();
int dl = dst.arrayOffset() + dst.limit();
int len = Math.min(dl - dp, sl - sp);
while (len-- > 0) {
char c = sa[sp];
int b = encode(c);
if (b == UNMAPPABLE_ENCODING) {
if (Character.isSurrogate(c)) {
if (sgp == null)
sgp = new Surrogate.Parser();
if (sgp.parse(c, sa, sp, sl) < 0) {
return withResult(sgp.error(), src, sp, dst, dp);
}
return withResult(sgp.unmappableResult(), src, sp, dst, dp);
}
return withResult(CoderResult.unmappableForLength(1),
src, sp, dst, dp);
}
da[dp++] = (byte)b;
sp++;
}
return withResult(sp < sl ? CoderResult.OVERFLOW : CoderResult.UNDERFLOW,
src, sp, dst, dp);
}
private CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) {
int mark = src.position();
try {
while (src.hasRemaining()) {
char c = src.get();
int b = encode(c);
if (b == UNMAPPABLE_ENCODING) {
if (Character.isSurrogate(c)) {
if (sgp == null)
sgp = new Surrogate.Parser();
if (sgp.parse(c, src) < 0)
return sgp.error();
return sgp.unmappableResult();
}
return CoderResult.unmappableForLength(1);
}
if (!dst.hasRemaining())
return CoderResult.OVERFLOW;
dst.put((byte)b);
mark++;
}
return CoderResult.UNDERFLOW;
} finally {
src.position(mark);
}
}
protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) {
if (src.hasArray() && dst.hasArray())
return encodeArrayLoop(src, dst);
else
return encodeBufferLoop(src, dst);
}
public final int encode(char ch) {
char index = c2bIndex[ch >> 8];
if (index == UNMAPPABLE_ENCODING)
return UNMAPPABLE_ENCODING;
return c2b[index + (ch & 0xff)];
}
private byte repl = (byte)'?';
protected void implReplaceWith(byte[] newReplacement) {
repl = newReplacement[0];
}
public int encode(char[] src, int sp, int len, byte[] dst) {
int dp = 0;
int sl = sp + Math.min(len, dst.length);
while (sp < sl) {
char c = src[sp++];
int b = encode(c);
if (b != UNMAPPABLE_ENCODING) {
dst[dp++] = (byte)b;
continue;
}
if (Character.isHighSurrogate(c) && sp < sl &&
Character.isLowSurrogate(src[sp])) {
if (len > dst.length) {
sl++;
len--;
}
sp++;
}
dst[dp++] = repl;
}
return dp;
}
@Override
public int encodeFromLatin1(byte[] src, int sp, int len, byte[] dst) {
int dp = 0;
int sl = sp + Math.min(len, dst.length);
while (sp < sl) {
char c = (char)(src[sp++] & 0xff);
int b = encode(c);
if (b == UNMAPPABLE_ENCODING) {
dst[dp++] = repl;
} else {
dst[dp++] = (byte)b;
}
}
return dp;
}
@Override
public int encodeFromUTF16(byte[] src, int sp, int len, byte[] dst) {
int dp = 0;
int sl = sp + Math.min(len, dst.length);
while (sp < sl) {
char c = StringUTF16.getChar(src, sp++);
int b = encode(c);
if (b != UNMAPPABLE_ENCODING) {
dst[dp++] = (byte)b;
continue;
}
if (Character.isHighSurrogate(c) && sp < sl &&
Character.isLowSurrogate(StringUTF16.getChar(src, sp))) {
if (len > dst.length) {
sl++;
len--;
}
sp++;
}
dst[dp++] = repl;
}
return dp;
}
@Override
public boolean isASCIICompatible() {
return isASCIICompatible;
}
}
// init the c2b and c2bIndex tables from b2c.
public static void initC2B(char[] b2c, char[] c2bNR,
char[] c2b, char[] c2bIndex) {
for (int i = 0; i < c2bIndex.length; i++)
c2bIndex[i] = UNMAPPABLE_ENCODING;
for (int i = 0; i < c2b.length; i++)
c2b[i] = UNMAPPABLE_ENCODING;
int off = 0;
for (int i = 0; i < b2c.length; i++) {
char c = b2c[i];
if (c == UNMAPPABLE_DECODING)
continue;
int index = (c >> 8);
if (c2bIndex[index] == UNMAPPABLE_ENCODING) {
c2bIndex[index] = (char)off;
off += 0x100;
}
index = c2bIndex[index] + (c & 0xff);
c2b[index] = (char)((i>=0x80)?(i-0x80):(i+0x80));
}
if (c2bNR != null) {
// c-->b nr entries
int i = 0;
while (i < c2bNR.length) {
char b = c2bNR[i++];
char c = c2bNR[i++];
int index = (c >> 8);
if (c2bIndex[index] == UNMAPPABLE_ENCODING) {
c2bIndex[index] = (char)off;
off += 0x100;
}
index = c2bIndex[index] + (c & 0xff);
c2b[index] = b;
}
}
}
}

View file

@ -0,0 +1,247 @@
/*
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
// -- This file was mechanically generated: Do not edit! -- //
package sun.nio.cs;
import java.nio.charset.Charset;
import java.nio.charset.spi.CharsetProvider;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import jdk.internal.vm.annotation.Stable;
import sun.security.action.GetPropertyAction;
public class StandardCharsets extends CharsetProvider {
_INCLUDE_ALIASES_TABLES_
_INCLUDE_ALIASES_MAP_
_INCLUDE_CLASSES_MAP_
_INCLUDE_CACHE_MAP_
// Maps canonical names to class names
private @Stable Map<String,String> classMap;
// Maps alias names to canonical names
private @Stable Map<String,String> aliasMap;
// Maps canonical names to cached instances
private @Stable Map<String,Charset> cache;
private static final String packagePrefix = "sun.nio.cs.";
public StandardCharsets() {
}
private String canonicalize(String csn) {
String acn = aliasMap().get(csn);
return (acn != null) ? acn : csn;
}
private Map<String,String> aliasMap() {
Map<String,String> map = aliasMap;
if (map == null) {
aliasMap = map = new Aliases();
}
return map;
}
private Map<String,String> classMap() {
Map<String,String> map = classMap;
if (map == null) {
classMap = map = new Classes();
}
return map;
}
private Map<String,Charset> cache() {
Map<String,Charset> map = cache;
if (map == null) {
map = new Cache();
map.put("utf-8", UTF_8.INSTANCE);
map.put("iso-8859-1", ISO_8859_1.INSTANCE);
map.put("us-ascii", US_ASCII.INSTANCE);
cache = map;
}
return map;
}
// Private ASCII-only version, optimized for interpretation during startup
//
private static String toLower(String s) {
int n = s.length();
boolean allLower = true;
for (int i = 0; i < n; i++) {
int c = s.charAt(i);
if (((c - 'A') | ('Z' - c)) >= 0) {
allLower = false;
break;
}
}
if (allLower)
return s;
StringBuilder sb = new StringBuilder(n);
for (int i = 0; i < n; i++) {
int c = s.charAt(i);
if (((c - 'A') | ('Z' - c)) >= 0)
sb.append((char)(c + 0x20));
else
sb.append((char)c);
}
return sb.toString();
}
private Charset lookup(String charsetName) {
init();
// By checking these built-ins we can avoid initializing Aliases and
// Classes eagerly during bootstrap
String csn;
if (charsetName.equals("UTF-8")) {
return UTF_8.INSTANCE;
} else if (charsetName.equals("US-ASCII")) {
return US_ASCII.INSTANCE;
} else if (charsetName.equals("ISO-8859-1")) {
return ISO_8859_1.INSTANCE;
} else {
csn = canonicalize(toLower(charsetName));
}
// Check cache first
Charset cs = cache().get(csn);
if (cs != null)
return cs;
// Do we even support this charset?
String cln = classMap().get(csn);
if (cln == null)
return null;
// Instantiate the charset and cache it
try {
@SuppressWarnings("deprecation")
Object o = Class.forName(packagePrefix + cln,
true,
this.getClass().getClassLoader()).newInstance();
return cache(csn, (Charset)o);
} catch (ClassNotFoundException |
IllegalAccessException |
InstantiationException x) {
return null;
}
}
private Charset cache(String csn, Charset cs) {
cache().put(csn, cs);
return cs;
}
public final Charset charsetForName(String charsetName) {
synchronized (this) {
return lookup(charsetName);
}
}
public final Iterator<Charset> charsets() {
Set<String> charsetNames;
synchronized (this) {
init();
// Ensure initialized in synchronized block
charsetNames = classMap().keySet();
aliasMap();
cache();
}
return new Iterator<Charset>() {
Iterator<String> i = charsetNames.iterator();
public boolean hasNext() {
return i.hasNext();
}
public Charset next() {
String csn = i.next();
return lookup(csn);
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
private boolean initialized = false;
/* provider the sun.nio.cs.map property fir sjis/ms932 mapping hack
*/
private void init() {
if (initialized)
return;
if (!jdk.internal.misc.VM.isBooted())
return;
initialized = true;
String map = GetPropertyAction.privilegedGetProperty("sun.nio.cs.map");
if (map != null) {
Map<String,String> aliasMap = aliasMap();
Map<String,String> classMap = classMap();
String[] maps = map.split(",");
for (int i = 0; i < maps.length; i++) {
if (maps[i].equalsIgnoreCase("Windows-31J/Shift_JIS")) {
// if we dont have both sjis and ms932, do nothing
if (classMap.get("shift_jis") == null ||
classMap.get("windows-31j") == null) {
break;
}
aliases_MS932 = new String[] {
"MS932", // JDK historical
"windows-932",
"csWindows31J",
"shift-jis",
"ms_kanji",
"x-sjis",
"csShiftJIS",
// This alias takes precedence over the actual
// Shift_JIS charset itself since aliases are always
// resolved first, before looking up canonical names.
"shift_jis"
};
aliases_SJIS = new String[] { "sjis" };
for (String alias : aliases_MS932) {
aliasMap.put(toLower(alias), "windows-31j");
}
cache().put("shift_jis", null);
break;
}
}
}
}
}

View file

@ -0,0 +1,381 @@
/*
* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*/
package sun.nio.cs;
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;
public class StreamDecoder extends Reader
{
private static final int MIN_BYTE_BUFFER_SIZE = 32;
private static final int DEFAULT_BYTE_BUFFER_SIZE = 8192;
private volatile boolean closed;
private void ensureOpen() throws IOException {
if (closed)
throw new IOException("Stream closed");
}
// In order to handle surrogates properly we must never try to produce
// fewer than two characters at a time. If we're only asked to return one
// character then the other is saved here to be returned later.
//
private boolean haveLeftoverChar = false;
private char leftoverChar;
// Factories for java.io.InputStreamReader
public static StreamDecoder forInputStreamReader(InputStream in,
Object lock,
String charsetName)
throws UnsupportedEncodingException
{
String csn = charsetName;
if (csn == null)
csn = Charset.defaultCharset().name();
try {
if (Charset.isSupported(csn))
return new StreamDecoder(in, lock, Charset.forName(csn));
} catch (IllegalCharsetNameException x) { }
throw new UnsupportedEncodingException (csn);
}
public static StreamDecoder forInputStreamReader(InputStream in,
Object lock,
Charset cs)
{
return new StreamDecoder(in, lock, cs);
}
public static StreamDecoder forInputStreamReader(InputStream in,
Object lock,
CharsetDecoder dec)
{
return new StreamDecoder(in, lock, dec);
}
// Factory for java.nio.channels.Channels.newReader
public static StreamDecoder forDecoder(ReadableByteChannel ch,
CharsetDecoder dec,
int minBufferCap)
{
return new StreamDecoder(ch, dec, minBufferCap);
}
// -- Public methods corresponding to those in InputStreamReader --
// All synchronization and state/argument checking is done in these public
// methods; the concrete stream-decoder subclasses defined below need not
// do any such checking.
public String getEncoding() {
if (isOpen())
return encodingName();
return null;
}
public int read() throws IOException {
return read0();
}
@SuppressWarnings("fallthrough")
private int read0() throws IOException {
synchronized (lock) {
// Return the leftover char, if there is one
if (haveLeftoverChar) {
haveLeftoverChar = false;
return leftoverChar;
}
// Convert more bytes
char cb[] = new char[2];
int n = read(cb, 0, 2);
switch (n) {
case -1:
return -1;
case 2:
leftoverChar = cb[1];
haveLeftoverChar = true;
// FALL THROUGH
case 1:
return cb[0];
default:
assert false : n;
return -1;
}
}
}
public int read(char cbuf[], int offset, int length) throws IOException {
int off = offset;
int len = length;
synchronized (lock) {
ensureOpen();
if ((off < 0) || (off > cbuf.length) || (len < 0) ||
((off + len) > cbuf.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
}
if (len == 0)
return 0;
int n = 0;
if (haveLeftoverChar) {
// Copy the leftover char into the buffer
cbuf[off] = leftoverChar;
off++; len--;
haveLeftoverChar = false;
n = 1;
if ((len == 0) || !implReady())
// Return now if this is all we can produce w/o blocking
return n;
}
if (len == 1) {
// Treat single-character array reads just like read()
int c = read0();
if (c == -1)
return (n == 0) ? -1 : n;
cbuf[off] = (char)c;
return n + 1;
}
return n + implRead(cbuf, off, off + len);
}
}
public boolean ready() throws IOException {
synchronized (lock) {
ensureOpen();
return haveLeftoverChar || implReady();
}
}
public void close() throws IOException {
synchronized (lock) {
if (closed)
return;
implClose();
closed = true;
}
}
private boolean isOpen() {
return !closed;
}
// -- Charset-based stream decoder impl --
// In the early stages of the build we haven't yet built the NIO native
// code, so guard against that by catching the first UnsatisfiedLinkError
// and setting this flag so that later attempts fail quickly.
//
private static volatile boolean channelsAvailable = true;
private static FileChannel getChannel(FileInputStream in) {
if (!channelsAvailable)
return null;
try {
return in.getChannel();
} catch (UnsatisfiedLinkError x) {
channelsAvailable = false;
return null;
}
}
private Charset cs;
private CharsetDecoder decoder;
private ByteBuffer bb;
// Exactly one of these is non-null
private InputStream in;
private ReadableByteChannel ch;
StreamDecoder(InputStream in, Object lock, Charset cs) {
this(in, lock,
cs.newDecoder()
.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE));
}
StreamDecoder(InputStream in, Object lock, CharsetDecoder dec) {
super(lock);
this.cs = dec.charset();
this.decoder = dec;
// This path disabled until direct buffers are faster
if (false && in instanceof FileInputStream) {
ch = getChannel((FileInputStream)in);
if (ch != null)
bb = ByteBuffer.allocateDirect(DEFAULT_BYTE_BUFFER_SIZE);
}
if (ch == null) {
this.in = in;
this.ch = null;
bb = ByteBuffer.allocate(DEFAULT_BYTE_BUFFER_SIZE);
}
bb.flip(); // So that bb is initially empty
}
StreamDecoder(ReadableByteChannel ch, CharsetDecoder dec, int mbc) {
this.in = null;
this.ch = ch;
this.decoder = dec;
this.cs = dec.charset();
this.bb = ByteBuffer.allocate(mbc < 0
? DEFAULT_BYTE_BUFFER_SIZE
: (mbc < MIN_BYTE_BUFFER_SIZE
? MIN_BYTE_BUFFER_SIZE
: mbc));
bb.flip();
}
private int readBytes() throws IOException {
bb.compact();
try {
if (ch != null) {
// Read from the channel
int n = ch.read(bb);
if (n < 0)
return n;
} else {
// Read from the input stream, and then update the buffer
int lim = bb.limit();
int pos = bb.position();
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
assert rem > 0;
int n = in.read(bb.array(), bb.arrayOffset() + pos, rem);
if (n < 0)
return n;
if (n == 0)
throw new IOException("Underlying input stream returned zero bytes");
assert (n <= rem) : "n = " + n + ", rem = " + rem;
bb.position(pos + n);
}
} finally {
// Flip even when an IOException is thrown,
// otherwise the stream will stutter
bb.flip();
}
int rem = bb.remaining();
assert (rem != 0) : rem;
return rem;
}
int implRead(char[] cbuf, int off, int end) throws IOException {
// In order to handle surrogate pairs, this method requires that
// the invoker attempt to read at least two characters. Saving the
// extra character, if any, at a higher level is easier than trying
// to deal with it here.
assert (end - off > 1);
CharBuffer cb = CharBuffer.wrap(cbuf, off, end - off);
if (cb.position() != 0)
// Ensure that cb[0] == cbuf[off]
cb = cb.slice();
boolean eof = false;
for (;;) {
CoderResult cr = decoder.decode(bb, cb, eof);
if (cr.isUnderflow()) {
if (eof)
break;
if (!cb.hasRemaining())
break;
if ((cb.position() > 0) && !inReady())
break; // Block at most once
int n = readBytes();
if (n < 0) {
eof = true;
if ((cb.position() == 0) && (!bb.hasRemaining()))
break;
decoder.reset();
}
continue;
}
if (cr.isOverflow()) {
assert cb.position() > 0;
break;
}
cr.throwException();
}
if (eof) {
// ## Need to flush decoder
decoder.reset();
}
if (cb.position() == 0) {
if (eof)
return -1;
assert false;
}
return cb.position();
}
String encodingName() {
return ((cs instanceof HistoricallyNamedCharset)
? ((HistoricallyNamedCharset)cs).historicalName()
: cs.name());
}
private boolean inReady() {
try {
return (((in != null) && (in.available() > 0))
|| (ch instanceof FileChannel)); // ## RBC.available()?
} catch (IOException x) {
return false;
}
}
boolean implReady() {
return bb.hasRemaining() || inReady();
}
void implClose() throws IOException {
if (ch != null)
ch.close();
else
in.close();
}
}

View file

@ -0,0 +1,353 @@
/*
* Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*/
package sun.nio.cs;
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;
public class StreamEncoder extends Writer
{
private static final int DEFAULT_BYTE_BUFFER_SIZE = 8192;
private volatile boolean closed;
private void ensureOpen() throws IOException {
if (closed)
throw new IOException("Stream closed");
}
// Factories for java.io.OutputStreamWriter
public static StreamEncoder forOutputStreamWriter(OutputStream out,
Object lock,
String charsetName)
throws UnsupportedEncodingException
{
String csn = charsetName;
if (csn == null)
csn = Charset.defaultCharset().name();
try {
if (Charset.isSupported(csn))
return new StreamEncoder(out, lock, Charset.forName(csn));
} catch (IllegalCharsetNameException x) { }
throw new UnsupportedEncodingException (csn);
}
public static StreamEncoder forOutputStreamWriter(OutputStream out,
Object lock,
Charset cs)
{
return new StreamEncoder(out, lock, cs);
}
public static StreamEncoder forOutputStreamWriter(OutputStream out,
Object lock,
CharsetEncoder enc)
{
return new StreamEncoder(out, lock, enc);
}
// Factory for java.nio.channels.Channels.newWriter
public static StreamEncoder forEncoder(WritableByteChannel ch,
CharsetEncoder enc,
int minBufferCap)
{
return new StreamEncoder(ch, enc, minBufferCap);
}
// -- Public methods corresponding to those in OutputStreamWriter --
// All synchronization and state/argument checking is done in these public
// methods; the concrete stream-encoder subclasses defined below need not
// do any such checking.
public String getEncoding() {
if (isOpen())
return encodingName();
return null;
}
public void flushBuffer() throws IOException {
synchronized (lock) {
if (isOpen())
implFlushBuffer();
else
throw new IOException("Stream closed");
}
}
public void write(int c) throws IOException {
char cbuf[] = new char[1];
cbuf[0] = (char) c;
write(cbuf, 0, 1);
}
public void write(char cbuf[], int off, int len) throws IOException {
synchronized (lock) {
ensureOpen();
if ((off < 0) || (off > cbuf.length) || (len < 0) ||
((off + len) > cbuf.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
implWrite(cbuf, off, len);
}
}
public void write(String str, int off, int len) throws IOException {
/* Check the len before creating a char buffer */
if (len < 0)
throw new IndexOutOfBoundsException();
char cbuf[] = new char[len];
str.getChars(off, off + len, cbuf, 0);
write(cbuf, 0, len);
}
public void write(CharBuffer cb) throws IOException {
int position = cb.position();
try {
synchronized (lock) {
ensureOpen();
implWrite(cb);
}
} finally {
cb.position(position);
}
}
public void flush() throws IOException {
synchronized (lock) {
ensureOpen();
implFlush();
}
}
public void close() throws IOException {
synchronized (lock) {
if (closed)
return;
implClose();
closed = true;
}
}
private boolean isOpen() {
return !closed;
}
// -- Charset-based stream encoder impl --
private Charset cs;
private CharsetEncoder encoder;
private ByteBuffer bb;
// Exactly one of these is non-null
private final OutputStream out;
private WritableByteChannel ch;
// Leftover first char in a surrogate pair
private boolean haveLeftoverChar = false;
private char leftoverChar;
private CharBuffer lcb = null;
private StreamEncoder(OutputStream out, Object lock, Charset cs) {
this(out, lock,
cs.newEncoder()
.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE));
}
private StreamEncoder(OutputStream out, Object lock, CharsetEncoder enc) {
super(lock);
this.out = out;
this.ch = null;
this.cs = enc.charset();
this.encoder = enc;
// This path disabled until direct buffers are faster
if (false && out instanceof FileOutputStream) {
ch = ((FileOutputStream)out).getChannel();
if (ch != null)
bb = ByteBuffer.allocateDirect(DEFAULT_BYTE_BUFFER_SIZE);
}
if (ch == null) {
bb = ByteBuffer.allocate(DEFAULT_BYTE_BUFFER_SIZE);
}
}
private StreamEncoder(WritableByteChannel ch, CharsetEncoder enc, int mbc) {
this.out = null;
this.ch = ch;
this.cs = enc.charset();
this.encoder = enc;
this.bb = ByteBuffer.allocate(mbc < 0
? DEFAULT_BYTE_BUFFER_SIZE
: mbc);
}
private void writeBytes() throws IOException {
bb.flip();
int lim = bb.limit();
int pos = bb.position();
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
if (rem > 0) {
if (ch != null) {
if (ch.write(bb) != rem)
assert false : rem;
} else {
out.write(bb.array(), bb.arrayOffset() + pos, rem);
}
}
bb.clear();
}
private void flushLeftoverChar(CharBuffer cb, boolean endOfInput)
throws IOException
{
if (!haveLeftoverChar && !endOfInput)
return;
if (lcb == null)
lcb = CharBuffer.allocate(2);
else
lcb.clear();
if (haveLeftoverChar)
lcb.put(leftoverChar);
if ((cb != null) && cb.hasRemaining())
lcb.put(cb.get());
lcb.flip();
while (lcb.hasRemaining() || endOfInput) {
CoderResult cr = encoder.encode(lcb, bb, endOfInput);
if (cr.isUnderflow()) {
if (lcb.hasRemaining()) {
leftoverChar = lcb.get();
if (cb != null && cb.hasRemaining()) {
lcb.clear();
lcb.put(leftoverChar).put(cb.get()).flip();
continue;
}
return;
}
break;
}
if (cr.isOverflow()) {
assert bb.position() > 0;
writeBytes();
continue;
}
cr.throwException();
}
haveLeftoverChar = false;
}
void implWrite(char cbuf[], int off, int len)
throws IOException
{
CharBuffer cb = CharBuffer.wrap(cbuf, off, len);
implWrite(cb);
}
void implWrite(CharBuffer cb)
throws IOException
{
if (haveLeftoverChar) {
flushLeftoverChar(cb, false);
}
while (cb.hasRemaining()) {
CoderResult cr = encoder.encode(cb, bb, false);
if (cr.isUnderflow()) {
assert (cb.remaining() <= 1) : cb.remaining();
if (cb.remaining() == 1) {
haveLeftoverChar = true;
leftoverChar = cb.get();
}
break;
}
if (cr.isOverflow()) {
assert bb.position() > 0;
writeBytes();
continue;
}
cr.throwException();
}
}
void implFlushBuffer() throws IOException {
if (bb.position() > 0)
writeBytes();
}
void implFlush() throws IOException {
implFlushBuffer();
if (out != null)
out.flush();
}
void implClose() throws IOException {
flushLeftoverChar(null, true);
try {
for (;;) {
CoderResult cr = encoder.flush(bb);
if (cr.isUnderflow())
break;
if (cr.isOverflow()) {
assert bb.position() > 0;
writeBytes();
continue;
}
cr.throwException();
}
if (bb.position() > 0)
writeBytes();
if (ch != null)
ch.close();
else
out.close();
} catch (IOException x) {
encoder.reset();
throw x;
}
}
String encodingName() {
return ((cs instanceof HistoricallyNamedCharset)
? ((HistoricallyNamedCharset)cs).historicalName()
: cs.name());
}
}

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
import static jdk.internal.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET;
import static jdk.internal.misc.Unsafe.ARRAY_BYTE_INDEX_SCALE;
class StringUTF16 {
public static char getChar(byte[] val, int index) {
return unsafe.getChar(val,
ARRAY_BYTE_BASE_OFFSET + ARRAY_BYTE_INDEX_SCALE * index * 2L);
}
private static final jdk.internal.misc.Unsafe unsafe = jdk.internal.misc.Unsafe.getUnsafe();
}

View file

@ -0,0 +1,362 @@
/*
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
import java.nio.CharBuffer;
import java.nio.charset.CoderResult;
import java.nio.charset.MalformedInputException;
import java.nio.charset.UnmappableCharacterException;
/**
* Utility class for dealing with surrogates.
*
* @author Mark Reinhold
* @author Martin Buchholz
* @author Ulf Zibis
*/
public class Surrogate {
private Surrogate() { }
// TODO: Deprecate/remove the following redundant definitions
public static final char MIN_HIGH = Character.MIN_HIGH_SURROGATE;
public static final char MAX_HIGH = Character.MAX_HIGH_SURROGATE;
public static final char MIN_LOW = Character.MIN_LOW_SURROGATE;
public static final char MAX_LOW = Character.MAX_LOW_SURROGATE;
public static final char MIN = Character.MIN_SURROGATE;
public static final char MAX = Character.MAX_SURROGATE;
public static final int UCS4_MIN = Character.MIN_SUPPLEMENTARY_CODE_POINT;
public static final int UCS4_MAX = Character.MAX_CODE_POINT;
/**
* Tells whether or not the given value is in the high surrogate range.
* Use of {@link Character#isHighSurrogate} is generally preferred.
*/
public static boolean isHigh(int c) {
return (MIN_HIGH <= c) && (c <= MAX_HIGH);
}
/**
* Tells whether or not the given value is in the low surrogate range.
* Use of {@link Character#isLowSurrogate} is generally preferred.
*/
public static boolean isLow(int c) {
return (MIN_LOW <= c) && (c <= MAX_LOW);
}
/**
* Tells whether or not the given value is in the surrogate range.
* Use of {@link Character#isSurrogate} is generally preferred.
*/
public static boolean is(int c) {
return (MIN <= c) && (c <= MAX);
}
/**
* Tells whether or not the given UCS-4 character must be represented as a
* surrogate pair in UTF-16.
* Use of {@link Character#isSupplementaryCodePoint} is generally preferred.
*/
public static boolean neededFor(int uc) {
return Character.isSupplementaryCodePoint(uc);
}
/**
* Returns the high UTF-16 surrogate for the given supplementary UCS-4 character.
* Use of {@link Character#highSurrogate} is generally preferred.
*/
public static char high(int uc) {
assert Character.isSupplementaryCodePoint(uc);
return Character.highSurrogate(uc);
}
/**
* Returns the low UTF-16 surrogate for the given supplementary UCS-4 character.
* Use of {@link Character#lowSurrogate} is generally preferred.
*/
public static char low(int uc) {
assert Character.isSupplementaryCodePoint(uc);
return Character.lowSurrogate(uc);
}
/**
* Converts the given surrogate pair into a 32-bit UCS-4 character.
* Use of {@link Character#toCodePoint} is generally preferred.
*/
public static int toUCS4(char c, char d) {
assert Character.isHighSurrogate(c) && Character.isLowSurrogate(d);
return Character.toCodePoint(c, d);
}
/**
* Surrogate parsing support. Charset implementations may use instances of
* this class to handle the details of parsing UTF-16 surrogate pairs.
*/
public static class Parser {
public Parser() { }
private int character; // UCS-4
private CoderResult error = CoderResult.UNDERFLOW;
private boolean isPair;
/**
* Returns the UCS-4 character previously parsed.
*/
public int character() {
assert (error == null);
return character;
}
/**
* Tells whether or not the previously-parsed UCS-4 character was
* originally represented by a surrogate pair.
*/
public boolean isPair() {
assert (error == null);
return isPair;
}
/**
* Returns the number of UTF-16 characters consumed by the previous
* parse.
*/
public int increment() {
assert (error == null);
return isPair ? 2 : 1;
}
/**
* If the previous parse operation detected an error, return the object
* describing that error.
*/
public CoderResult error() {
assert (error != null);
return error;
}
/**
* Returns an unmappable-input result object, with the appropriate
* input length, for the previously-parsed character.
*/
public CoderResult unmappableResult() {
assert (error == null);
return CoderResult.unmappableForLength(isPair ? 2 : 1);
}
/**
* Parses a UCS-4 character from the given source buffer, handling
* surrogates.
*
* @param c The first character
* @param in The source buffer, from which one more character
* will be consumed if c is a high surrogate
*
* @return Either a parsed UCS-4 character, in which case the isPair()
* and increment() methods will return meaningful values, or
* -1, in which case error() will return a descriptive result
* object
*/
public int parse(char c, CharBuffer in) {
if (Character.isHighSurrogate(c)) {
if (!in.hasRemaining()) {
error = CoderResult.UNDERFLOW;
return -1;
}
char d = in.get();
if (Character.isLowSurrogate(d)) {
character = Character.toCodePoint(c, d);
isPair = true;
error = null;
return character;
}
error = CoderResult.malformedForLength(1);
return -1;
}
if (Character.isLowSurrogate(c)) {
error = CoderResult.malformedForLength(1);
return -1;
}
character = c;
isPair = false;
error = null;
return character;
}
/**
* Parses a UCS-4 character from the given source buffer, handling
* surrogates.
*
* @param c The first character
* @param ia The input array, from which one more character
* will be consumed if c is a high surrogate
* @param ip The input index
* @param il The input limit
*
* @return Either a parsed UCS-4 character, in which case the isPair()
* and increment() methods will return meaningful values, or
* -1, in which case error() will return a descriptive result
* object
*/
public int parse(char c, char[] ia, int ip, int il) {
assert (ia[ip] == c);
if (Character.isHighSurrogate(c)) {
if (il - ip < 2) {
error = CoderResult.UNDERFLOW;
return -1;
}
char d = ia[ip + 1];
if (Character.isLowSurrogate(d)) {
character = Character.toCodePoint(c, d);
isPair = true;
error = null;
return character;
}
error = CoderResult.malformedForLength(1);
return -1;
}
if (Character.isLowSurrogate(c)) {
error = CoderResult.malformedForLength(1);
return -1;
}
character = c;
isPair = false;
error = null;
return character;
}
}
/**
* Surrogate generation support. Charset implementations may use instances
* of this class to handle the details of generating UTF-16 surrogate
* pairs.
*/
public static class Generator {
public Generator() { }
private CoderResult error = CoderResult.OVERFLOW;
/**
* If the previous generation operation detected an error, return the
* object describing that error.
*/
public CoderResult error() {
assert error != null;
return error;
}
/**
* Generates one or two UTF-16 characters to represent the given UCS-4
* character.
*
* @param uc The UCS-4 character
* @param len The number of input bytes from which the UCS-4 value
* was constructed (used when creating result objects)
* @param dst The destination buffer, to which one or two UTF-16
* characters will be written
*
* @return Either a positive count of the number of UTF-16 characters
* written to the destination buffer, or -1, in which case
* error() will return a descriptive result object
*/
public int generate(int uc, int len, CharBuffer dst) {
if (Character.isBmpCodePoint(uc)) {
char c = (char) uc;
if (Character.isSurrogate(c)) {
error = CoderResult.malformedForLength(len);
return -1;
}
if (dst.remaining() < 1) {
error = CoderResult.OVERFLOW;
return -1;
}
dst.put(c);
error = null;
return 1;
} else if (Character.isValidCodePoint(uc)) {
if (dst.remaining() < 2) {
error = CoderResult.OVERFLOW;
return -1;
}
dst.put(Character.highSurrogate(uc));
dst.put(Character.lowSurrogate(uc));
error = null;
return 2;
} else {
error = CoderResult.unmappableForLength(len);
return -1;
}
}
/**
* Generates one or two UTF-16 characters to represent the given UCS-4
* character.
*
* @param uc The UCS-4 character
* @param len The number of input bytes from which the UCS-4 value
* was constructed (used when creating result objects)
* @param da The destination array, to which one or two UTF-16
* characters will be written
* @param dp The destination position
* @param dl The destination limit
*
* @return Either a positive count of the number of UTF-16 characters
* written to the destination buffer, or -1, in which case
* error() will return a descriptive result object
*/
public int generate(int uc, int len, char[] da, int dp, int dl) {
if (Character.isBmpCodePoint(uc)) {
char c = (char) uc;
if (Character.isSurrogate(c)) {
error = CoderResult.malformedForLength(len);
return -1;
}
if (dl - dp < 1) {
error = CoderResult.OVERFLOW;
return -1;
}
da[dp] = c;
error = null;
return 1;
} else if (Character.isValidCodePoint(uc)) {
if (dl - dp < 2) {
error = CoderResult.OVERFLOW;
return -1;
}
da[dp] = Character.highSurrogate(uc);
da[dp + 1] = Character.lowSurrogate(uc);
error = null;
return 2;
} else {
error = CoderResult.unmappableForLength(len);
return -1;
}
}
}
}

View file

@ -0,0 +1,136 @@
/*
* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
import java.nio.charset.*;
/**
* Utility class for caching per-thread decoders and encoders.
*/
public class ThreadLocalCoders {
private static final int CACHE_SIZE = 3;
private abstract static class Cache {
// Thread-local reference to array of cached objects, in LRU order
private ThreadLocal<Object[]> cache = new ThreadLocal<>();
private final int size;
Cache(int size) {
this.size = size;
}
abstract Object create(Object name);
private void moveToFront(Object[] oa, int i) {
Object ob = oa[i];
for (int j = i; j > 0; j--)
oa[j] = oa[j - 1];
oa[0] = ob;
}
abstract boolean hasName(Object ob, Object name);
Object forName(Object name) {
Object[] oa = cache.get();
if (oa == null) {
oa = new Object[size];
cache.set(oa);
} else {
for (int i = 0; i < oa.length; i++) {
Object ob = oa[i];
if (ob == null)
continue;
if (hasName(ob, name)) {
if (i > 0)
moveToFront(oa, i);
return ob;
}
}
}
// Create a new object
Object ob = create(name);
oa[oa.length - 1] = ob;
moveToFront(oa, oa.length - 1);
return ob;
}
}
private static Cache decoderCache = new Cache(CACHE_SIZE) {
boolean hasName(Object ob, Object name) {
if (name instanceof String)
return (((CharsetDecoder)ob).charset().name().equals(name));
if (name instanceof Charset)
return ((CharsetDecoder)ob).charset().equals(name);
return false;
}
Object create(Object name) {
if (name instanceof String)
return Charset.forName((String)name).newDecoder();
if (name instanceof Charset)
return ((Charset)name).newDecoder();
assert false;
return null;
}
};
public static CharsetDecoder decoderFor(Object name) {
CharsetDecoder cd = (CharsetDecoder)decoderCache.forName(name);
cd.reset();
return cd;
}
private static Cache encoderCache = new Cache(CACHE_SIZE) {
boolean hasName(Object ob, Object name) {
if (name instanceof String)
return (((CharsetEncoder)ob).charset().name().equals(name));
if (name instanceof Charset)
return ((CharsetEncoder)ob).charset().equals(name);
return false;
}
Object create(Object name) {
if (name instanceof String)
return Charset.forName((String)name).newEncoder();
if (name instanceof Charset)
return ((Charset)name).newEncoder();
assert false;
return null;
}
};
public static CharsetEncoder encoderFor(Object name) {
CharsetEncoder ce = (CharsetEncoder)encoderCache.forName(name);
ce.reset();
return ce;
}
}

View file

@ -0,0 +1,272 @@
/*
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
public class US_ASCII
extends Charset
implements HistoricallyNamedCharset
{
public static final US_ASCII INSTANCE = new US_ASCII();
public US_ASCII() {
super("US-ASCII", StandardCharsets.aliases_US_ASCII());
}
public String historicalName() {
return "ASCII";
}
public boolean contains(Charset cs) {
return (cs instanceof US_ASCII);
}
public CharsetDecoder newDecoder() {
return new Decoder(this);
}
public CharsetEncoder newEncoder() {
return new Encoder(this);
}
private static class Decoder extends CharsetDecoder
implements ArrayDecoder {
private Decoder(Charset cs) {
super(cs, 1.0f, 1.0f);
}
private CoderResult decodeArrayLoop(ByteBuffer src,
CharBuffer dst)
{
byte[] sa = src.array();
int sp = src.arrayOffset() + src.position();
int sl = src.arrayOffset() + src.limit();
assert (sp <= sl);
sp = (sp <= sl ? sp : sl);
char[] da = dst.array();
int dp = dst.arrayOffset() + dst.position();
int dl = dst.arrayOffset() + dst.limit();
assert (dp <= dl);
dp = (dp <= dl ? dp : dl);
try {
while (sp < sl) {
byte b = sa[sp];
if (b >= 0) {
if (dp >= dl)
return CoderResult.OVERFLOW;
da[dp++] = (char)b;
sp++;
continue;
}
return CoderResult.malformedForLength(1);
}
return CoderResult.UNDERFLOW;
} finally {
src.position(sp - src.arrayOffset());
dst.position(dp - dst.arrayOffset());
}
}
private CoderResult decodeBufferLoop(ByteBuffer src,
CharBuffer dst)
{
int mark = src.position();
try {
while (src.hasRemaining()) {
byte b = src.get();
if (b >= 0) {
if (!dst.hasRemaining())
return CoderResult.OVERFLOW;
dst.put((char)b);
mark++;
continue;
}
return CoderResult.malformedForLength(1);
}
return CoderResult.UNDERFLOW;
} finally {
src.position(mark);
}
}
protected CoderResult decodeLoop(ByteBuffer src,
CharBuffer dst)
{
if (src.hasArray() && dst.hasArray())
return decodeArrayLoop(src, dst);
else
return decodeBufferLoop(src, dst);
}
private char repl = '\uFFFD';
protected void implReplaceWith(String newReplacement) {
repl = newReplacement.charAt(0);
}
public int decode(byte[] src, int sp, int len, char[] dst) {
int dp = 0;
len = Math.min(len, dst.length);
while (dp < len) {
byte b = src[sp++];
if (b >= 0)
dst[dp++] = (char)b;
else
dst[dp++] = repl;
}
return dp;
}
public boolean isASCIICompatible() {
return true;
}
}
private static class Encoder extends CharsetEncoder
implements ArrayEncoder {
private Encoder(Charset cs) {
super(cs, 1.0f, 1.0f);
}
public boolean canEncode(char c) {
return c < 0x80;
}
public boolean isLegalReplacement(byte[] repl) {
return (repl.length == 1 && repl[0] >= 0) ||
super.isLegalReplacement(repl);
}
private final Surrogate.Parser sgp = new Surrogate.Parser();
private CoderResult encodeArrayLoop(CharBuffer src,
ByteBuffer dst)
{
char[] sa = src.array();
int sp = src.arrayOffset() + src.position();
int sl = src.arrayOffset() + src.limit();
assert (sp <= sl);
sp = (sp <= sl ? sp : sl);
byte[] da = dst.array();
int dp = dst.arrayOffset() + dst.position();
int dl = dst.arrayOffset() + dst.limit();
assert (dp <= dl);
dp = (dp <= dl ? dp : dl);
try {
while (sp < sl) {
char c = sa[sp];
if (c < 0x80) {
if (dp >= dl)
return CoderResult.OVERFLOW;
da[dp] = (byte)c;
sp++; dp++;
continue;
}
if (sgp.parse(c, sa, sp, sl) < 0)
return sgp.error();
return sgp.unmappableResult();
}
return CoderResult.UNDERFLOW;
} finally {
src.position(sp - src.arrayOffset());
dst.position(dp - dst.arrayOffset());
}
}
private CoderResult encodeBufferLoop(CharBuffer src,
ByteBuffer dst)
{
int mark = src.position();
try {
while (src.hasRemaining()) {
char c = src.get();
if (c < 0x80) {
if (!dst.hasRemaining())
return CoderResult.OVERFLOW;
dst.put((byte)c);
mark++;
continue;
}
if (sgp.parse(c, src) < 0)
return sgp.error();
return sgp.unmappableResult();
}
return CoderResult.UNDERFLOW;
} finally {
src.position(mark);
}
}
protected CoderResult encodeLoop(CharBuffer src,
ByteBuffer dst)
{
if (src.hasArray() && dst.hasArray())
return encodeArrayLoop(src, dst);
else
return encodeBufferLoop(src, dst);
}
private byte repl = (byte)'?';
protected void implReplaceWith(byte[] newReplacement) {
repl = newReplacement[0];
}
public int encode(char[] src, int sp, int len, byte[] dst) {
int dp = 0;
int sl = sp + Math.min(len, dst.length);
while (sp < sl) {
char c = src[sp++];
if (c < 0x80) {
dst[dp++] = (byte)c;
continue;
}
if (Character.isHighSurrogate(c) && sp < sl &&
Character.isLowSurrogate(src[sp])) {
if (len > dst.length) {
sl++;
len--;
}
sp++;
}
dst[dp++] = repl;
}
return dp;
}
public boolean isASCIICompatible() {
return true;
}
}
}

View file

@ -0,0 +1,65 @@
/*
* Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
class UTF_16 extends Unicode
{
public UTF_16() {
super("UTF-16", StandardCharsets.aliases_UTF_16());
}
public String historicalName() {
return "UTF-16";
}
public CharsetDecoder newDecoder() {
return new Decoder(this);
}
public CharsetEncoder newEncoder() {
return new Encoder(this);
}
private static class Decoder extends UnicodeDecoder {
public Decoder(Charset cs) {
super(cs, NONE);
}
}
private static class Encoder extends UnicodeEncoder {
public Encoder(Charset cs) {
super(cs, BIG, true);
}
}
}

View file

@ -0,0 +1,65 @@
/*
* Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
class UTF_16BE extends Unicode
{
public UTF_16BE() {
super("UTF-16BE", StandardCharsets.aliases_UTF_16BE());
}
public String historicalName() {
return "UnicodeBigUnmarked";
}
public CharsetDecoder newDecoder() {
return new Decoder(this);
}
public CharsetEncoder newEncoder() {
return new Encoder(this);
}
private static class Decoder extends UnicodeDecoder {
public Decoder(Charset cs) {
super(cs, BIG);
}
}
private static class Encoder extends UnicodeEncoder {
public Encoder(Charset cs) {
super(cs, BIG, false);
}
}
}

View file

@ -0,0 +1,65 @@
/*
* Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
class UTF_16LE extends Unicode
{
public UTF_16LE() {
super("UTF-16LE", StandardCharsets.aliases_UTF_16LE());
}
public String historicalName() {
return "UnicodeLittleUnmarked";
}
public CharsetDecoder newDecoder() {
return new Decoder(this);
}
public CharsetEncoder newEncoder() {
return new Encoder(this);
}
private static class Decoder extends UnicodeDecoder {
public Decoder(Charset cs) {
super(cs, LITTLE);
}
}
private static class Encoder extends UnicodeEncoder {
public Encoder(Charset cs) {
super(cs, LITTLE, false);
}
}
}

View file

@ -0,0 +1,65 @@
/*
* Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
class UTF_16LE_BOM extends Unicode
{
public UTF_16LE_BOM() {
super("x-UTF-16LE-BOM", StandardCharsets.aliases_UTF_16LE_BOM());
}
public String historicalName() {
return "UnicodeLittle";
}
public CharsetDecoder newDecoder() {
return new Decoder(this);
}
public CharsetEncoder newEncoder() {
return new Encoder(this);
}
private static class Decoder extends UnicodeDecoder {
public Decoder(Charset cs) {
super(cs, NONE, LITTLE);
}
}
private static class Encoder extends UnicodeEncoder {
public Encoder(Charset cs) {
super(cs, LITTLE, true);
}
}
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
public class UTF_32 extends Unicode
{
public UTF_32() {
super("UTF-32", StandardCharsets.aliases_UTF_32());
}
public String historicalName() {
return "UTF-32";
}
public CharsetDecoder newDecoder() {
return new UTF_32Coder.Decoder(this, UTF_32Coder.NONE);
}
public CharsetEncoder newEncoder() {
return new UTF_32Coder.Encoder(this, UTF_32Coder.BIG, false);
}
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
public class UTF_32BE extends Unicode
{
public UTF_32BE() {
super("UTF-32BE", StandardCharsets.aliases_UTF_32BE());
}
public String historicalName() {
return "UTF-32BE";
}
public CharsetDecoder newDecoder() {
return new UTF_32Coder.Decoder(this, UTF_32Coder.BIG);
}
public CharsetEncoder newEncoder() {
return new UTF_32Coder.Encoder(this, UTF_32Coder.BIG, false);
}
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
public class UTF_32BE_BOM extends Unicode
{
public UTF_32BE_BOM() {
super("X-UTF-32BE-BOM", StandardCharsets.aliases_UTF_32BE_BOM());
}
public String historicalName() {
return "X-UTF-32BE-BOM";
}
public CharsetDecoder newDecoder() {
return new UTF_32Coder.Decoder(this, UTF_32Coder.BIG);
}
public CharsetEncoder newEncoder() {
return new UTF_32Coder.Encoder(this, UTF_32Coder.BIG, true);
}
}

View file

@ -0,0 +1,189 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CoderResult;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
class UTF_32Coder {
protected static final int BOM_BIG = 0xFEFF;
protected static final int BOM_LITTLE = 0xFFFE0000;
protected static final int NONE = 0;
protected static final int BIG = 1;
protected static final int LITTLE = 2;
protected static class Decoder extends CharsetDecoder {
private int currentBO;
private int expectedBO;
protected Decoder(Charset cs, int bo) {
super(cs, 0.25f, 1.0f);
this.expectedBO = bo;
this.currentBO = NONE;
}
private int getCP(ByteBuffer src) {
return (currentBO==BIG)
?(((src.get() & 0xff) << 24) |
((src.get() & 0xff) << 16) |
((src.get() & 0xff) << 8) |
(src.get() & 0xff))
:((src.get() & 0xff) |
((src.get() & 0xff) << 8) |
((src.get() & 0xff) << 16) |
((src.get() & 0xff) << 24));
}
protected CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) {
if (src.remaining() < 4)
return CoderResult.UNDERFLOW;
int mark = src.position();
int cp;
try {
if (currentBO == NONE) {
cp = ((src.get() & 0xff) << 24) |
((src.get() & 0xff) << 16) |
((src.get() & 0xff) << 8) |
(src.get() & 0xff);
if (cp == BOM_BIG && expectedBO != LITTLE) {
currentBO = BIG;
mark += 4;
} else if (cp == BOM_LITTLE && expectedBO != BIG) {
currentBO = LITTLE;
mark += 4;
} else {
if (expectedBO == NONE)
currentBO = BIG;
else
currentBO = expectedBO;
src.position(mark);
}
}
while (src.remaining() >= 4) {
cp = getCP(src);
if (Character.isBmpCodePoint(cp)) {
if (!dst.hasRemaining())
return CoderResult.OVERFLOW;
mark += 4;
dst.put((char) cp);
} else if (Character.isValidCodePoint(cp)) {
if (dst.remaining() < 2)
return CoderResult.OVERFLOW;
mark += 4;
dst.put(Character.highSurrogate(cp));
dst.put(Character.lowSurrogate(cp));
} else {
return CoderResult.malformedForLength(4);
}
}
return CoderResult.UNDERFLOW;
} finally {
src.position(mark);
}
}
protected void implReset() {
currentBO = NONE;
}
}
protected static class Encoder extends CharsetEncoder {
private boolean doBOM = false;
private boolean doneBOM = true;
private int byteOrder;
protected void put(int cp, ByteBuffer dst) {
if (byteOrder==BIG) {
dst.put((byte)(cp >> 24));
dst.put((byte)(cp >> 16));
dst.put((byte)(cp >> 8));
dst.put((byte)cp);
} else {
dst.put((byte)cp);
dst.put((byte)(cp >> 8));
dst.put((byte)(cp >> 16));
dst.put((byte)(cp >> 24));
}
}
protected Encoder(Charset cs, int byteOrder, boolean doBOM) {
super(cs, 4.0f,
doBOM?8.0f:4.0f,
(byteOrder==BIG)?new byte[]{(byte)0, (byte)0, (byte)0xff, (byte)0xfd}
:new byte[]{(byte)0xfd, (byte)0xff, (byte)0, (byte)0});
this.byteOrder = byteOrder;
this.doBOM = doBOM;
this.doneBOM = !doBOM;
}
protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) {
int mark = src.position();
if (!doneBOM && src.hasRemaining()) {
if (dst.remaining() < 4)
return CoderResult.OVERFLOW;
put(BOM_BIG, dst);
doneBOM = true;
}
try {
while (src.hasRemaining()) {
char c = src.get();
if (!Character.isSurrogate(c)) {
if (dst.remaining() < 4)
return CoderResult.OVERFLOW;
mark++;
put(c, dst);
} else if (Character.isHighSurrogate(c)) {
if (!src.hasRemaining())
return CoderResult.UNDERFLOW;
char low = src.get();
if (Character.isLowSurrogate(low)) {
if (dst.remaining() < 4)
return CoderResult.OVERFLOW;
mark += 2;
put(Character.toCodePoint(c, low), dst);
} else {
return CoderResult.malformedForLength(1);
}
} else {
// assert Character.isLowSurrogate(c);
return CoderResult.malformedForLength(1);
}
}
return CoderResult.UNDERFLOW;
} finally {
src.position(mark);
}
}
protected void implReset() {
doneBOM = !doBOM;
}
}
}

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
public class UTF_32LE extends Unicode
{
public UTF_32LE() {
super("UTF-32LE", StandardCharsets.aliases_UTF_32LE());
}
public String historicalName() {
return "UTF-32LE";
}
public CharsetDecoder newDecoder() {
return new UTF_32Coder.Decoder(this, UTF_32Coder.LITTLE);
}
public CharsetEncoder newEncoder() {
return new UTF_32Coder.Encoder(this, UTF_32Coder.LITTLE, false);
}
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
public class UTF_32LE_BOM extends Unicode
{
public UTF_32LE_BOM() {
super("X-UTF-32LE-BOM", StandardCharsets.aliases_UTF_32LE_BOM());
}
public String historicalName() {
return "X-UTF-32LE-BOM";
}
public CharsetDecoder newDecoder() {
return new UTF_32Coder.Decoder(this, UTF_32Coder.LITTLE);
}
public CharsetEncoder newEncoder() {
return new UTF_32Coder.Encoder(this, UTF_32Coder.LITTLE, true);
}
}

View file

@ -0,0 +1,756 @@
/*
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
/* Legal UTF-8 Byte Sequences
*
* # Code Points Bits Bit/Byte pattern
* 1 7 0xxxxxxx
* U+0000..U+007F 00..7F
*
* 2 11 110xxxxx 10xxxxxx
* U+0080..U+07FF C2..DF 80..BF
*
* 3 16 1110xxxx 10xxxxxx 10xxxxxx
* U+0800..U+0FFF E0 A0..BF 80..BF
* U+1000..U+FFFF E1..EF 80..BF 80..BF
*
* 4 21 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
* U+10000..U+3FFFF F0 90..BF 80..BF 80..BF
* U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF
* U+100000..U10FFFF F4 80..8F 80..BF 80..BF
*
*/
public final class UTF_8 extends Unicode {
public static final UTF_8 INSTANCE = new UTF_8();
public UTF_8() {
super("UTF-8", StandardCharsets.aliases_UTF_8());
}
public String historicalName() {
return "UTF8";
}
public CharsetDecoder newDecoder() {
return new Decoder(this);
}
public CharsetEncoder newEncoder() {
return new Encoder(this);
}
static final void updatePositions(Buffer src, int sp,
Buffer dst, int dp) {
src.position(sp - src.arrayOffset());
dst.position(dp - dst.arrayOffset());
}
private static class Decoder extends CharsetDecoder
implements ArrayDecoder {
private Decoder(Charset cs) {
super(cs, 1.0f, 1.0f);
}
private static boolean isNotContinuation(int b) {
return (b & 0xc0) != 0x80;
}
// [E0] [A0..BF] [80..BF]
// [E1..EF] [80..BF] [80..BF]
private static boolean isMalformed3(int b1, int b2, int b3) {
return (b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) ||
(b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80;
}
// only used when there is only one byte left in src buffer
private static boolean isMalformed3_2(int b1, int b2) {
return (b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) ||
(b2 & 0xc0) != 0x80;
}
// [F0] [90..BF] [80..BF] [80..BF]
// [F1..F3] [80..BF] [80..BF] [80..BF]
// [F4] [80..8F] [80..BF] [80..BF]
// only check 80-be range here, the [0xf0,0x80...] and [0xf4,0x90-...]
// will be checked by Character.isSupplementaryCodePoint(uc)
private static boolean isMalformed4(int b2, int b3, int b4) {
return (b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80 ||
(b4 & 0xc0) != 0x80;
}
// only used when there is less than 4 bytes left in src buffer.
// both b1 and b2 should be "& 0xff" before passed in.
private static boolean isMalformed4_2(int b1, int b2) {
return (b1 == 0xf0 && (b2 < 0x90 || b2 > 0xbf)) ||
(b1 == 0xf4 && (b2 & 0xf0) != 0x80) ||
(b2 & 0xc0) != 0x80;
}
// tests if b1 and b2 are malformed as the first 2 bytes of a
// legal`4-byte utf-8 byte sequence.
// only used when there is less than 4 bytes left in src buffer,
// after isMalformed4_2 has been invoked.
private static boolean isMalformed4_3(int b3) {
return (b3 & 0xc0) != 0x80;
}
private static CoderResult lookupN(ByteBuffer src, int n)
{
for (int i = 1; i < n; i++) {
if (isNotContinuation(src.get()))
return CoderResult.malformedForLength(i);
}
return CoderResult.malformedForLength(n);
}
private static CoderResult malformedN(ByteBuffer src, int nb) {
switch (nb) {
case 1:
case 2: // always 1
return CoderResult.malformedForLength(1);
case 3:
int b1 = src.get();
int b2 = src.get(); // no need to lookup b3
return CoderResult.malformedForLength(
((b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) ||
isNotContinuation(b2)) ? 1 : 2);
case 4: // we don't care the speed here
b1 = src.get() & 0xff;
b2 = src.get() & 0xff;
if (b1 > 0xf4 ||
(b1 == 0xf0 && (b2 < 0x90 || b2 > 0xbf)) ||
(b1 == 0xf4 && (b2 & 0xf0) != 0x80) ||
isNotContinuation(b2))
return CoderResult.malformedForLength(1);
if (isNotContinuation(src.get()))
return CoderResult.malformedForLength(2);
return CoderResult.malformedForLength(3);
default:
assert false;
return null;
}
}
private static CoderResult malformed(ByteBuffer src, int sp,
CharBuffer dst, int dp,
int nb)
{
src.position(sp - src.arrayOffset());
CoderResult cr = malformedN(src, nb);
updatePositions(src, sp, dst, dp);
return cr;
}
private static CoderResult malformed(ByteBuffer src,
int mark, int nb)
{
src.position(mark);
CoderResult cr = malformedN(src, nb);
src.position(mark);
return cr;
}
private static CoderResult malformedForLength(ByteBuffer src,
int sp,
CharBuffer dst,
int dp,
int malformedNB)
{
updatePositions(src, sp, dst, dp);
return CoderResult.malformedForLength(malformedNB);
}
private static CoderResult malformedForLength(ByteBuffer src,
int mark,
int malformedNB)
{
src.position(mark);
return CoderResult.malformedForLength(malformedNB);
}
private static CoderResult xflow(Buffer src, int sp, int sl,
Buffer dst, int dp, int nb) {
updatePositions(src, sp, dst, dp);
return (nb == 0 || sl - sp < nb)
? CoderResult.UNDERFLOW : CoderResult.OVERFLOW;
}
private static CoderResult xflow(Buffer src, int mark, int nb) {
src.position(mark);
return (nb == 0 || src.remaining() < nb)
? CoderResult.UNDERFLOW : CoderResult.OVERFLOW;
}
private CoderResult decodeArrayLoop(ByteBuffer src,
CharBuffer dst)
{
// This method is optimized for ASCII input.
byte[] sa = src.array();
int sp = src.arrayOffset() + src.position();
int sl = src.arrayOffset() + src.limit();
char[] da = dst.array();
int dp = dst.arrayOffset() + dst.position();
int dl = dst.arrayOffset() + dst.limit();
int dlASCII = dp + Math.min(sl - sp, dl - dp);
// ASCII only loop
while (dp < dlASCII && sa[sp] >= 0)
da[dp++] = (char) sa[sp++];
while (sp < sl) {
int b1 = sa[sp];
if (b1 >= 0) {
// 1 byte, 7 bits: 0xxxxxxx
if (dp >= dl)
return xflow(src, sp, sl, dst, dp, 1);
da[dp++] = (char) b1;
sp++;
} else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) {
// 2 bytes, 11 bits: 110xxxxx 10xxxxxx
// [C2..DF] [80..BF]
if (sl - sp < 2 || dp >= dl)
return xflow(src, sp, sl, dst, dp, 2);
int b2 = sa[sp + 1];
// Now we check the first byte of 2-byte sequence as
// if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0)
// no longer need to check b1 against c1 & c0 for
// malformed as we did in previous version
// (b1 & 0x1e) == 0x0 || (b2 & 0xc0) != 0x80;
// only need to check the second byte b2.
if (isNotContinuation(b2))
return malformedForLength(src, sp, dst, dp, 1);
da[dp++] = (char) (((b1 << 6) ^ b2)
^
(((byte) 0xC0 << 6) ^
((byte) 0x80 << 0)));
sp += 2;
} else if ((b1 >> 4) == -2) {
// 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx
int srcRemaining = sl - sp;
if (srcRemaining < 3 || dp >= dl) {
if (srcRemaining > 1 && isMalformed3_2(b1, sa[sp + 1]))
return malformedForLength(src, sp, dst, dp, 1);
return xflow(src, sp, sl, dst, dp, 3);
}
int b2 = sa[sp + 1];
int b3 = sa[sp + 2];
if (isMalformed3(b1, b2, b3))
return malformed(src, sp, dst, dp, 3);
char c = (char)
((b1 << 12) ^
(b2 << 6) ^
(b3 ^
(((byte) 0xE0 << 12) ^
((byte) 0x80 << 6) ^
((byte) 0x80 << 0))));
if (Character.isSurrogate(c))
return malformedForLength(src, sp, dst, dp, 3);
da[dp++] = c;
sp += 3;
} else if ((b1 >> 3) == -2) {
// 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
int srcRemaining = sl - sp;
if (srcRemaining < 4 || dl - dp < 2) {
b1 &= 0xff;
if (b1 > 0xf4 ||
srcRemaining > 1 && isMalformed4_2(b1, sa[sp + 1] & 0xff))
return malformedForLength(src, sp, dst, dp, 1);
if (srcRemaining > 2 && isMalformed4_3(sa[sp + 2]))
return malformedForLength(src, sp, dst, dp, 2);
return xflow(src, sp, sl, dst, dp, 4);
}
int b2 = sa[sp + 1];
int b3 = sa[sp + 2];
int b4 = sa[sp + 3];
int uc = ((b1 << 18) ^
(b2 << 12) ^
(b3 << 6) ^
(b4 ^
(((byte) 0xF0 << 18) ^
((byte) 0x80 << 12) ^
((byte) 0x80 << 6) ^
((byte) 0x80 << 0))));
if (isMalformed4(b2, b3, b4) ||
// shortest form check
!Character.isSupplementaryCodePoint(uc)) {
return malformed(src, sp, dst, dp, 4);
}
da[dp++] = Character.highSurrogate(uc);
da[dp++] = Character.lowSurrogate(uc);
sp += 4;
} else
return malformed(src, sp, dst, dp, 1);
}
return xflow(src, sp, sl, dst, dp, 0);
}
private CoderResult decodeBufferLoop(ByteBuffer src,
CharBuffer dst)
{
int mark = src.position();
int limit = src.limit();
while (mark < limit) {
int b1 = src.get();
if (b1 >= 0) {
// 1 byte, 7 bits: 0xxxxxxx
if (dst.remaining() < 1)
return xflow(src, mark, 1); // overflow
dst.put((char) b1);
mark++;
} else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) {
// 2 bytes, 11 bits: 110xxxxx 10xxxxxx
if (limit - mark < 2|| dst.remaining() < 1)
return xflow(src, mark, 2);
int b2 = src.get();
if (isNotContinuation(b2))
return malformedForLength(src, mark, 1);
dst.put((char) (((b1 << 6) ^ b2)
^
(((byte) 0xC0 << 6) ^
((byte) 0x80 << 0))));
mark += 2;
} else if ((b1 >> 4) == -2) {
// 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx
int srcRemaining = limit - mark;
if (srcRemaining < 3 || dst.remaining() < 1) {
if (srcRemaining > 1 && isMalformed3_2(b1, src.get()))
return malformedForLength(src, mark, 1);
return xflow(src, mark, 3);
}
int b2 = src.get();
int b3 = src.get();
if (isMalformed3(b1, b2, b3))
return malformed(src, mark, 3);
char c = (char)
((b1 << 12) ^
(b2 << 6) ^
(b3 ^
(((byte) 0xE0 << 12) ^
((byte) 0x80 << 6) ^
((byte) 0x80 << 0))));
if (Character.isSurrogate(c))
return malformedForLength(src, mark, 3);
dst.put(c);
mark += 3;
} else if ((b1 >> 3) == -2) {
// 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
int srcRemaining = limit - mark;
if (srcRemaining < 4 || dst.remaining() < 2) {
b1 &= 0xff;
if (b1 > 0xf4 ||
srcRemaining > 1 && isMalformed4_2(b1, src.get() & 0xff))
return malformedForLength(src, mark, 1);
if (srcRemaining > 2 && isMalformed4_3(src.get()))
return malformedForLength(src, mark, 2);
return xflow(src, mark, 4);
}
int b2 = src.get();
int b3 = src.get();
int b4 = src.get();
int uc = ((b1 << 18) ^
(b2 << 12) ^
(b3 << 6) ^
(b4 ^
(((byte) 0xF0 << 18) ^
((byte) 0x80 << 12) ^
((byte) 0x80 << 6) ^
((byte) 0x80 << 0))));
if (isMalformed4(b2, b3, b4) ||
// shortest form check
!Character.isSupplementaryCodePoint(uc)) {
return malformed(src, mark, 4);
}
dst.put(Character.highSurrogate(uc));
dst.put(Character.lowSurrogate(uc));
mark += 4;
} else {
return malformed(src, mark, 1);
}
}
return xflow(src, mark, 0);
}
protected CoderResult decodeLoop(ByteBuffer src,
CharBuffer dst)
{
if (src.hasArray() && dst.hasArray())
return decodeArrayLoop(src, dst);
else
return decodeBufferLoop(src, dst);
}
private static ByteBuffer getByteBuffer(ByteBuffer bb, byte[] ba, int sp)
{
if (bb == null)
bb = ByteBuffer.wrap(ba);
bb.position(sp);
return bb;
}
// returns -1 if there is/are malformed byte(s) and the
// "action" for malformed input is not REPLACE.
public int decode(byte[] sa, int sp, int len, char[] da) {
final int sl = sp + len;
int dp = 0;
int dlASCII = Math.min(len, da.length);
ByteBuffer bb = null; // only necessary if malformed
// ASCII only optimized loop
while (dp < dlASCII && sa[sp] >= 0)
da[dp++] = (char) sa[sp++];
while (sp < sl) {
int b1 = sa[sp++];
if (b1 >= 0) {
// 1 byte, 7 bits: 0xxxxxxx
da[dp++] = (char) b1;
} else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) {
// 2 bytes, 11 bits: 110xxxxx 10xxxxxx
if (sp < sl) {
int b2 = sa[sp++];
if (isNotContinuation(b2)) {
if (malformedInputAction() != CodingErrorAction.REPLACE)
return -1;
da[dp++] = replacement().charAt(0);
sp--; // malformedN(bb, 2) always returns 1
} else {
da[dp++] = (char) (((b1 << 6) ^ b2)^
(((byte) 0xC0 << 6) ^
((byte) 0x80 << 0)));
}
continue;
}
if (malformedInputAction() != CodingErrorAction.REPLACE)
return -1;
da[dp++] = replacement().charAt(0);
return dp;
} else if ((b1 >> 4) == -2) {
// 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx
if (sp + 1 < sl) {
int b2 = sa[sp++];
int b3 = sa[sp++];
if (isMalformed3(b1, b2, b3)) {
if (malformedInputAction() != CodingErrorAction.REPLACE)
return -1;
da[dp++] = replacement().charAt(0);
sp -= 3;
bb = getByteBuffer(bb, sa, sp);
sp += malformedN(bb, 3).length();
} else {
char c = (char)((b1 << 12) ^
(b2 << 6) ^
(b3 ^
(((byte) 0xE0 << 12) ^
((byte) 0x80 << 6) ^
((byte) 0x80 << 0))));
if (Character.isSurrogate(c)) {
if (malformedInputAction() != CodingErrorAction.REPLACE)
return -1;
da[dp++] = replacement().charAt(0);
} else {
da[dp++] = c;
}
}
continue;
}
if (malformedInputAction() != CodingErrorAction.REPLACE)
return -1;
if (sp < sl && isMalformed3_2(b1, sa[sp])) {
da[dp++] = replacement().charAt(0);
continue;
}
da[dp++] = replacement().charAt(0);
return dp;
} else if ((b1 >> 3) == -2) {
// 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
if (sp + 2 < sl) {
int b2 = sa[sp++];
int b3 = sa[sp++];
int b4 = sa[sp++];
int uc = ((b1 << 18) ^
(b2 << 12) ^
(b3 << 6) ^
(b4 ^
(((byte) 0xF0 << 18) ^
((byte) 0x80 << 12) ^
((byte) 0x80 << 6) ^
((byte) 0x80 << 0))));
if (isMalformed4(b2, b3, b4) ||
// shortest form check
!Character.isSupplementaryCodePoint(uc)) {
if (malformedInputAction() != CodingErrorAction.REPLACE)
return -1;
da[dp++] = replacement().charAt(0);
sp -= 4;
bb = getByteBuffer(bb, sa, sp);
sp += malformedN(bb, 4).length();
} else {
da[dp++] = Character.highSurrogate(uc);
da[dp++] = Character.lowSurrogate(uc);
}
continue;
}
if (malformedInputAction() != CodingErrorAction.REPLACE)
return -1;
b1 &= 0xff;
if (b1 > 0xf4 ||
sp < sl && isMalformed4_2(b1, sa[sp] & 0xff)) {
da[dp++] = replacement().charAt(0);
continue;
}
sp++;
if (sp < sl && isMalformed4_3(sa[sp])) {
da[dp++] = replacement().charAt(0);
continue;
}
da[dp++] = replacement().charAt(0);
return dp;
} else {
if (malformedInputAction() != CodingErrorAction.REPLACE)
return -1;
da[dp++] = replacement().charAt(0);
}
}
return dp;
}
public boolean isASCIICompatible() {
return true;
}
}
private static final class Encoder extends CharsetEncoder
implements ArrayEncoder {
private Encoder(Charset cs) {
super(cs, 1.1f, 3.0f);
}
public boolean canEncode(char c) {
return !Character.isSurrogate(c);
}
public boolean isLegalReplacement(byte[] repl) {
return ((repl.length == 1 && repl[0] >= 0) ||
super.isLegalReplacement(repl));
}
private static CoderResult overflow(CharBuffer src, int sp,
ByteBuffer dst, int dp) {
updatePositions(src, sp, dst, dp);
return CoderResult.OVERFLOW;
}
private static CoderResult overflow(CharBuffer src, int mark) {
src.position(mark);
return CoderResult.OVERFLOW;
}
private Surrogate.Parser sgp;
private CoderResult encodeArrayLoop(CharBuffer src,
ByteBuffer dst)
{
char[] sa = src.array();
int sp = src.arrayOffset() + src.position();
int sl = src.arrayOffset() + src.limit();
byte[] da = dst.array();
int dp = dst.arrayOffset() + dst.position();
int dl = dst.arrayOffset() + dst.limit();
int dlASCII = dp + Math.min(sl - sp, dl - dp);
// ASCII only loop
while (dp < dlASCII && sa[sp] < '\u0080')
da[dp++] = (byte) sa[sp++];
while (sp < sl) {
char c = sa[sp];
if (c < 0x80) {
// Have at most seven bits
if (dp >= dl)
return overflow(src, sp, dst, dp);
da[dp++] = (byte)c;
} else if (c < 0x800) {
// 2 bytes, 11 bits
if (dl - dp < 2)
return overflow(src, sp, dst, dp);
da[dp++] = (byte)(0xc0 | (c >> 6));
da[dp++] = (byte)(0x80 | (c & 0x3f));
} else if (Character.isSurrogate(c)) {
// Have a surrogate pair
if (sgp == null)
sgp = new Surrogate.Parser();
int uc = sgp.parse(c, sa, sp, sl);
if (uc < 0) {
updatePositions(src, sp, dst, dp);
return sgp.error();
}
if (dl - dp < 4)
return overflow(src, sp, dst, dp);
da[dp++] = (byte)(0xf0 | ((uc >> 18)));
da[dp++] = (byte)(0x80 | ((uc >> 12) & 0x3f));
da[dp++] = (byte)(0x80 | ((uc >> 6) & 0x3f));
da[dp++] = (byte)(0x80 | (uc & 0x3f));
sp++; // 2 chars
} else {
// 3 bytes, 16 bits
if (dl - dp < 3)
return overflow(src, sp, dst, dp);
da[dp++] = (byte)(0xe0 | ((c >> 12)));
da[dp++] = (byte)(0x80 | ((c >> 6) & 0x3f));
da[dp++] = (byte)(0x80 | (c & 0x3f));
}
sp++;
}
updatePositions(src, sp, dst, dp);
return CoderResult.UNDERFLOW;
}
private CoderResult encodeBufferLoop(CharBuffer src,
ByteBuffer dst)
{
int mark = src.position();
while (src.hasRemaining()) {
char c = src.get();
if (c < 0x80) {
// Have at most seven bits
if (!dst.hasRemaining())
return overflow(src, mark);
dst.put((byte)c);
} else if (c < 0x800) {
// 2 bytes, 11 bits
if (dst.remaining() < 2)
return overflow(src, mark);
dst.put((byte)(0xc0 | (c >> 6)));
dst.put((byte)(0x80 | (c & 0x3f)));
} else if (Character.isSurrogate(c)) {
// Have a surrogate pair
if (sgp == null)
sgp = new Surrogate.Parser();
int uc = sgp.parse(c, src);
if (uc < 0) {
src.position(mark);
return sgp.error();
}
if (dst.remaining() < 4)
return overflow(src, mark);
dst.put((byte)(0xf0 | ((uc >> 18))));
dst.put((byte)(0x80 | ((uc >> 12) & 0x3f)));
dst.put((byte)(0x80 | ((uc >> 6) & 0x3f)));
dst.put((byte)(0x80 | (uc & 0x3f)));
mark++; // 2 chars
} else {
// 3 bytes, 16 bits
if (dst.remaining() < 3)
return overflow(src, mark);
dst.put((byte)(0xe0 | ((c >> 12))));
dst.put((byte)(0x80 | ((c >> 6) & 0x3f)));
dst.put((byte)(0x80 | (c & 0x3f)));
}
mark++;
}
src.position(mark);
return CoderResult.UNDERFLOW;
}
protected final CoderResult encodeLoop(CharBuffer src,
ByteBuffer dst)
{
if (src.hasArray() && dst.hasArray())
return encodeArrayLoop(src, dst);
else
return encodeBufferLoop(src, dst);
}
private byte repl = (byte)'?';
protected void implReplaceWith(byte[] newReplacement) {
repl = newReplacement[0];
}
// returns -1 if there is malformed char(s) and the
// "action" for malformed input is not REPLACE.
public int encode(char[] sa, int sp, int len, byte[] da) {
int sl = sp + len;
int dp = 0;
int dlASCII = dp + Math.min(len, da.length);
// ASCII only optimized loop
while (dp < dlASCII && sa[sp] < '\u0080')
da[dp++] = (byte) sa[sp++];
while (sp < sl) {
char c = sa[sp++];
if (c < 0x80) {
// Have at most seven bits
da[dp++] = (byte)c;
} else if (c < 0x800) {
// 2 bytes, 11 bits
da[dp++] = (byte)(0xc0 | (c >> 6));
da[dp++] = (byte)(0x80 | (c & 0x3f));
} else if (Character.isSurrogate(c)) {
if (sgp == null)
sgp = new Surrogate.Parser();
int uc = sgp.parse(c, sa, sp - 1, sl);
if (uc < 0) {
if (malformedInputAction() != CodingErrorAction.REPLACE)
return -1;
da[dp++] = repl;
} else {
da[dp++] = (byte)(0xf0 | ((uc >> 18)));
da[dp++] = (byte)(0x80 | ((uc >> 12) & 0x3f));
da[dp++] = (byte)(0x80 | ((uc >> 6) & 0x3f));
da[dp++] = (byte)(0x80 | (uc & 0x3f));
sp++; // 2 chars
}
} else {
// 3 bytes, 16 bits
da[dp++] = (byte)(0xe0 | ((c >> 12)));
da[dp++] = (byte)(0x80 | ((c >> 6) & 0x3f));
da[dp++] = (byte)(0x80 | (c & 0x3f));
}
}
return dp;
}
public boolean isASCIICompatible() {
return true;
}
}
}

View file

@ -0,0 +1,93 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
import java.nio.charset.Charset;
abstract class Unicode extends Charset
implements HistoricallyNamedCharset
{
public Unicode(String name, String[] aliases) {
super(name, aliases);
}
public boolean contains(Charset cs) {
return ((cs instanceof US_ASCII)
|| (cs instanceof ISO_8859_1)
|| (cs instanceof ISO_8859_15)
|| (cs instanceof ISO_8859_16)
|| (cs instanceof MS1252)
|| (cs instanceof UTF_8)
|| (cs instanceof UTF_16)
|| (cs instanceof UTF_16BE)
|| (cs instanceof UTF_16LE)
|| (cs instanceof UTF_16LE_BOM)
|| (cs.name().equals("GBK"))
|| (cs.name().equals("GB18030"))
|| (cs.name().equals("ISO-8859-2"))
|| (cs.name().equals("ISO-8859-3"))
|| (cs.name().equals("ISO-8859-4"))
|| (cs.name().equals("ISO-8859-5"))
|| (cs.name().equals("ISO-8859-6"))
|| (cs.name().equals("ISO-8859-7"))
|| (cs.name().equals("ISO-8859-8"))
|| (cs.name().equals("ISO-8859-9"))
|| (cs.name().equals("ISO-8859-13"))
|| (cs.name().equals("JIS_X0201"))
|| (cs.name().equals("x-JIS0208"))
|| (cs.name().equals("JIS_X0212-1990"))
|| (cs.name().equals("GB2312"))
|| (cs.name().equals("EUC-KR"))
|| (cs.name().equals("x-EUC-TW"))
|| (cs.name().equals("EUC-JP"))
|| (cs.name().equals("x-euc-jp-linux"))
|| (cs.name().equals("KOI8-R"))
|| (cs.name().equals("TIS-620"))
|| (cs.name().equals("x-ISCII91"))
|| (cs.name().equals("windows-1251"))
|| (cs.name().equals("windows-1253"))
|| (cs.name().equals("windows-1254"))
|| (cs.name().equals("windows-1255"))
|| (cs.name().equals("windows-1256"))
|| (cs.name().equals("windows-1257"))
|| (cs.name().equals("windows-1258"))
|| (cs.name().equals("windows-932"))
|| (cs.name().equals("x-mswin-936"))
|| (cs.name().equals("x-windows-949"))
|| (cs.name().equals("x-windows-950"))
|| (cs.name().equals("windows-31j"))
|| (cs.name().equals("Big5"))
|| (cs.name().equals("Big5-HKSCS"))
|| (cs.name().equals("x-MS950-HKSCS"))
|| (cs.name().equals("ISO-2022-JP"))
|| (cs.name().equals("ISO-2022-KR"))
|| (cs.name().equals("x-ISO-2022-CN-CNS"))
|| (cs.name().equals("x-ISO-2022-CN-GB"))
|| (cs.name().equals("Big5-HKSCS"))
|| (cs.name().equals("x-Johab"))
|| (cs.name().equals("Shift_JIS")));
}
}

View file

@ -0,0 +1,135 @@
/*
* Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderResult;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.MalformedInputException;
abstract class UnicodeDecoder extends CharsetDecoder {
protected static final char BYTE_ORDER_MARK = (char) 0xfeff;
protected static final char REVERSED_MARK = (char) 0xfffe;
protected static final int NONE = 0;
protected static final int BIG = 1;
protected static final int LITTLE = 2;
private final int expectedByteOrder;
private int currentByteOrder;
private int defaultByteOrder = BIG;
public UnicodeDecoder(Charset cs, int bo) {
super(cs, 0.5f, 1.0f);
expectedByteOrder = currentByteOrder = bo;
}
public UnicodeDecoder(Charset cs, int bo, int defaultBO) {
this(cs, bo);
defaultByteOrder = defaultBO;
}
private char decode(int b1, int b2) {
if (currentByteOrder == BIG)
return (char)((b1 << 8) | b2);
else
return (char)((b2 << 8) | b1);
}
protected CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) {
int mark = src.position();
try {
while (src.remaining() > 1) {
int b1 = src.get() & 0xff;
int b2 = src.get() & 0xff;
// Byte Order Mark interpretation
if (currentByteOrder == NONE) {
char c = (char)((b1 << 8) | b2);
if (c == BYTE_ORDER_MARK) {
currentByteOrder = BIG;
mark += 2;
continue;
} else if (c == REVERSED_MARK) {
currentByteOrder = LITTLE;
mark += 2;
continue;
} else {
currentByteOrder = defaultByteOrder;
// FALL THROUGH to process b1, b2 normally
}
}
char c = decode(b1, b2);
if (c == REVERSED_MARK) {
// A reversed BOM cannot occur within middle of stream
return CoderResult.malformedForLength(2);
}
// Surrogates
if (Character.isSurrogate(c)) {
if (Character.isHighSurrogate(c)) {
if (src.remaining() < 2)
return CoderResult.UNDERFLOW;
char c2 = decode(src.get() & 0xff, src.get() & 0xff);
if (!Character.isLowSurrogate(c2))
return CoderResult.malformedForLength(4);
if (dst.remaining() < 2)
return CoderResult.OVERFLOW;
mark += 4;
dst.put(c);
dst.put(c2);
continue;
}
// Unpaired low surrogate
return CoderResult.malformedForLength(2);
}
if (!dst.hasRemaining())
return CoderResult.OVERFLOW;
mark += 2;
dst.put(c);
}
return CoderResult.UNDERFLOW;
} finally {
src.position(mark);
}
}
protected void implReset() {
currentByteOrder = expectedByteOrder;
}
}

View file

@ -0,0 +1,111 @@
/*
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
import java.nio.*;
import java.nio.charset.*;
/**
* Base class for different flavors of UTF-16 encoders
*/
public abstract class UnicodeEncoder extends CharsetEncoder {
protected static final char BYTE_ORDER_MARK = '\uFEFF';
protected static final char REVERSED_MARK = '\uFFFE';
protected static final int BIG = 0;
protected static final int LITTLE = 1;
private int byteOrder; /* Byte order in use */
private boolean usesMark; /* Write an initial BOM */
private boolean needsMark;
protected UnicodeEncoder(Charset cs, int bo, boolean m) {
super(cs, 2.0f,
// Four bytes max if you need a BOM
m ? 4.0f : 2.0f,
// Replacement depends upon byte order
((bo == BIG)
? new byte[] { (byte)0xff, (byte)0xfd }
: new byte[] { (byte)0xfd, (byte)0xff }));
usesMark = needsMark = m;
byteOrder = bo;
}
private void put(char c, ByteBuffer dst) {
if (byteOrder == BIG) {
dst.put((byte)(c >> 8));
dst.put((byte)(c & 0xff));
} else {
dst.put((byte)(c & 0xff));
dst.put((byte)(c >> 8));
}
}
private final Surrogate.Parser sgp = new Surrogate.Parser();
protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) {
int mark = src.position();
if (needsMark && src.hasRemaining()) {
if (dst.remaining() < 2)
return CoderResult.OVERFLOW;
put(BYTE_ORDER_MARK, dst);
needsMark = false;
}
try {
while (src.hasRemaining()) {
char c = src.get();
if (!Character.isSurrogate(c)) {
if (dst.remaining() < 2)
return CoderResult.OVERFLOW;
mark++;
put(c, dst);
continue;
}
int d = sgp.parse(c, src);
if (d < 0)
return sgp.error();
if (dst.remaining() < 4)
return CoderResult.OVERFLOW;
mark += 2;
put(Character.highSurrogate(d), dst);
put(Character.lowSurrogate(d), dst);
}
return CoderResult.UNDERFLOW;
} finally {
src.position(mark);
}
}
protected void implReset() {
needsMark = usesMark;
}
public boolean canEncode(char c) {
return ! Character.isSurrogate(c);
}
}

View file

@ -0,0 +1,94 @@
/*
* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.nio.file.attribute.*;
import java.util.*;
import java.io.IOException;
/**
* Base implementation of AclFileAttributeView
*/
abstract class AbstractAclFileAttributeView
implements AclFileAttributeView, DynamicFileAttributeView
{
private static final String OWNER_NAME = "owner";
private static final String ACL_NAME = "acl";
@Override
public final String name() {
return "acl";
}
@Override
@SuppressWarnings("unchecked")
public final void setAttribute(String attribute, Object value)
throws IOException
{
if (attribute.equals(OWNER_NAME)) {
setOwner((UserPrincipal)value);
return;
}
if (attribute.equals(ACL_NAME)) {
setAcl((List<AclEntry>)value);
return;
}
throw new IllegalArgumentException("'" + name() + ":" +
attribute + "' not recognized");
}
@Override
public final Map<String,Object> readAttributes(String[] attributes)
throws IOException
{
boolean acl = false;
boolean owner = false;
for (String attribute: attributes) {
if (attribute.equals("*")) {
owner = true;
acl = true;
continue;
}
if (attribute.equals(ACL_NAME)) {
acl = true;
continue;
}
if (attribute.equals(OWNER_NAME)) {
owner = true;
continue;
}
throw new IllegalArgumentException("'" + name() + ":" +
attribute + "' not recognized");
}
Map<String,Object> result = new HashMap<>(2);
if (acl)
result.put(ACL_NAME, getAcl());
if (owner)
result.put(OWNER_NAME, getOwner());
return Collections.unmodifiableMap(result);
}
}

View file

@ -0,0 +1,171 @@
/*
* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.nio.file.attribute.*;
import java.util.*;
import java.io.IOException;
/**
* Base implementation of BasicFileAttributeView
*/
abstract class AbstractBasicFileAttributeView
implements BasicFileAttributeView, DynamicFileAttributeView
{
private static final String SIZE_NAME = "size";
private static final String CREATION_TIME_NAME = "creationTime";
private static final String LAST_ACCESS_TIME_NAME = "lastAccessTime";
private static final String LAST_MODIFIED_TIME_NAME = "lastModifiedTime";
private static final String FILE_KEY_NAME = "fileKey";
private static final String IS_DIRECTORY_NAME = "isDirectory";
private static final String IS_REGULAR_FILE_NAME = "isRegularFile";
private static final String IS_SYMBOLIC_LINK_NAME = "isSymbolicLink";
private static final String IS_OTHER_NAME = "isOther";
// the names of the basic attributes
static final Set<String> basicAttributeNames =
Util.newSet(SIZE_NAME,
CREATION_TIME_NAME,
LAST_ACCESS_TIME_NAME,
LAST_MODIFIED_TIME_NAME,
FILE_KEY_NAME,
IS_DIRECTORY_NAME,
IS_REGULAR_FILE_NAME,
IS_SYMBOLIC_LINK_NAME,
IS_OTHER_NAME);
protected AbstractBasicFileAttributeView() { }
@Override
public String name() {
return "basic";
}
@Override
public void setAttribute(String attribute, Object value)
throws IOException
{
if (attribute.equals(LAST_MODIFIED_TIME_NAME)) {
setTimes((FileTime)value, null, null);
return;
}
if (attribute.equals(LAST_ACCESS_TIME_NAME)) {
setTimes(null, (FileTime)value, null);
return;
}
if (attribute.equals(CREATION_TIME_NAME)) {
setTimes(null, null, (FileTime)value);
return;
}
throw new IllegalArgumentException("'" + name() + ":" +
attribute + "' not recognized");
}
/**
* Used to build a map of attribute name/values.
*/
static class AttributesBuilder {
private Set<String> names = new HashSet<>();
private Map<String,Object> map = new HashMap<>();
private boolean copyAll;
private AttributesBuilder(Set<String> allowed, String[] requested) {
for (String name: requested) {
if (name.equals("*")) {
copyAll = true;
} else {
if (!allowed.contains(name))
throw new IllegalArgumentException("'" + name + "' not recognized");
names.add(name);
}
}
}
/**
* Creates builder to build up a map of the matching attributes
*/
static AttributesBuilder create(Set<String> allowed, String[] requested) {
return new AttributesBuilder(allowed, requested);
}
/**
* Returns true if the attribute should be returned in the map
*/
boolean match(String name) {
return copyAll || names.contains(name);
}
void add(String name, Object value) {
map.put(name, value);
}
/**
* Returns the map. Discard all references to the AttributesBuilder
* after invoking this method.
*/
Map<String,Object> unmodifiableMap() {
return Collections.unmodifiableMap(map);
}
}
/**
* Invoked by readAttributes or sub-classes to add all matching basic
* attributes to the builder
*/
final void addRequestedBasicAttributes(BasicFileAttributes attrs,
AttributesBuilder builder)
{
if (builder.match(SIZE_NAME))
builder.add(SIZE_NAME, attrs.size());
if (builder.match(CREATION_TIME_NAME))
builder.add(CREATION_TIME_NAME, attrs.creationTime());
if (builder.match(LAST_ACCESS_TIME_NAME))
builder.add(LAST_ACCESS_TIME_NAME, attrs.lastAccessTime());
if (builder.match(LAST_MODIFIED_TIME_NAME))
builder.add(LAST_MODIFIED_TIME_NAME, attrs.lastModifiedTime());
if (builder.match(FILE_KEY_NAME))
builder.add(FILE_KEY_NAME, attrs.fileKey());
if (builder.match(IS_DIRECTORY_NAME))
builder.add(IS_DIRECTORY_NAME, attrs.isDirectory());
if (builder.match(IS_REGULAR_FILE_NAME))
builder.add(IS_REGULAR_FILE_NAME, attrs.isRegularFile());
if (builder.match(IS_SYMBOLIC_LINK_NAME))
builder.add(IS_SYMBOLIC_LINK_NAME, attrs.isSymbolicLink());
if (builder.match(IS_OTHER_NAME))
builder.add(IS_OTHER_NAME, attrs.isOther());
}
@Override
public Map<String,Object> readAttributes(String[] requested)
throws IOException
{
AttributesBuilder builder =
AttributesBuilder.create(basicAttributeNames, requested);
addRequestedBasicAttributes(readAttributes(), builder);
return builder.unmodifiableMap();
}
}

View file

@ -0,0 +1,157 @@
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.nio.file.Path;
import java.nio.file.LinkOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.spi.FileSystemProvider;
import java.io.IOException;
import java.util.Map;
/**
* Base implementation class of FileSystemProvider
*/
public abstract class AbstractFileSystemProvider extends FileSystemProvider {
protected AbstractFileSystemProvider() { }
/**
* Splits the given attribute name into the name of an attribute view and
* the attribute. If the attribute view is not identified then it assumed
* to be "basic".
*/
private static String[] split(String attribute) {
String[] s = new String[2];
int pos = attribute.indexOf(':');
if (pos == -1) {
s[0] = "basic";
s[1] = attribute;
} else {
s[0] = attribute.substring(0, pos++);
s[1] = (pos == attribute.length()) ? "" : attribute.substring(pos);
}
return s;
}
/**
* Gets a DynamicFileAttributeView by name. Returns {@code null} if the
* view is not available.
*/
abstract DynamicFileAttributeView getFileAttributeView(Path file,
String name,
LinkOption... options);
@Override
public final void setAttribute(Path file,
String attribute,
Object value,
LinkOption... options)
throws IOException
{
String[] s = split(attribute);
if (s[0].length() == 0)
throw new IllegalArgumentException(attribute);
DynamicFileAttributeView view = getFileAttributeView(file, s[0], options);
if (view == null)
throw new UnsupportedOperationException("View '" + s[0] + "' not available");
view.setAttribute(s[1], value);
}
@Override
public final Map<String,Object> readAttributes(Path file, String attributes, LinkOption... options)
throws IOException
{
String[] s = split(attributes);
if (s[0].length() == 0)
throw new IllegalArgumentException(attributes);
DynamicFileAttributeView view = getFileAttributeView(file, s[0], options);
if (view == null)
throw new UnsupportedOperationException("View '" + s[0] + "' not available");
return view.readAttributes(s[1].split(","));
}
/**
* Deletes a file. The {@code failIfNotExists} parameters determines if an
* {@code IOException} is thrown when the file does not exist.
*/
abstract boolean implDelete(Path file, boolean failIfNotExists) throws IOException;
@Override
public final void delete(Path file) throws IOException {
implDelete(file, true);
}
@Override
public final boolean deleteIfExists(Path file) throws IOException {
return implDelete(file, false);
}
/**
* Tests whether a file is a directory.
*
* @return {@code true} if the file is a directory; {@code false} if
* the file does not exist, is not a directory, or it cannot
* be determined if the file is a directory or not.
*/
public boolean isDirectory(Path file) {
try {
return readAttributes(file, BasicFileAttributes.class).isDirectory();
} catch (IOException ioe) {
return false;
}
}
/**
* Tests whether a file is a regular file with opaque content.
*
* @return {@code true} if the file is a regular file; {@code false} if
* the file does not exist, is not a regular file, or it
* cannot be determined if the file is a regular file or not.
*/
public boolean isRegularFile(Path file) {
try {
return readAttributes(file, BasicFileAttributes.class).isRegularFile();
} catch (IOException ioe) {
return false;
}
}
/**
* Checks the existence of a file.
*
* @return {@code true} if the file exists; {@code false} if the file does
* not exist or its existence cannot be determined.
*/
public boolean exists(Path file) {
try {
checkAccess(file);
return true;
} catch (IOException ioe) {
return false;
}
}
}

View file

@ -0,0 +1,144 @@
/*
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.net.FileNameMap;
import java.net.URLConnection;
import java.nio.file.Path;
import java.nio.file.spi.FileTypeDetector;
import java.util.Locale;
import java.io.IOException;
/**
* Base implementation of FileTypeDetector
*/
public abstract class AbstractFileTypeDetector
extends FileTypeDetector
{
protected AbstractFileTypeDetector() {
super();
}
/**
* Returns the extension of a file name, specifically the portion of the
* parameter string after the first dot. If the parameter is {@code null},
* empty, does not contain a dot, or the dot is the last character, then an
* empty string is returned, otherwise the characters after the dot are
* returned.
*
* @param name A file name
* @return The characters after the first dot or an empty string.
*/
protected final String getExtension(String name) {
String ext = "";
if (name != null && !name.isEmpty()) {
int dot = name.indexOf('.');
if ((dot >= 0) && (dot < name.length() - 1)) {
ext = name.substring(dot + 1);
}
}
return ext;
}
/**
* Invokes the appropriate probe method to guess a file's content type,
* and checks that the content type's syntax is valid.
*/
@Override
public final String probeContentType(Path file) throws IOException {
if (file == null)
throw new NullPointerException("'file' is null");
String result = implProbeContentType(file);
// Fall back to content types property.
if (result == null) {
Path fileName = file.getFileName();
if (fileName != null) {
FileNameMap fileNameMap = URLConnection.getFileNameMap();
result = fileNameMap.getContentTypeFor(fileName.toString());
}
}
return (result == null) ? null : parse(result);
}
/**
* Probes the given file to guess its content type.
*/
protected abstract String implProbeContentType(Path file)
throws IOException;
/**
* Parses a candidate content type into its type and subtype, returning
* null if either token is invalid.
*/
private static String parse(String s) {
int slash = s.indexOf('/');
int semicolon = s.indexOf(';');
if (slash < 0)
return null; // no subtype
String type = s.substring(0, slash).trim().toLowerCase(Locale.ENGLISH);
if (!isValidToken(type))
return null; // invalid type
String subtype = (semicolon < 0) ? s.substring(slash + 1) :
s.substring(slash + 1, semicolon);
subtype = subtype.trim().toLowerCase(Locale.ENGLISH);
if (!isValidToken(subtype))
return null; // invalid subtype
StringBuilder sb = new StringBuilder(type.length() + subtype.length() + 1);
sb.append(type);
sb.append('/');
sb.append(subtype);
return sb.toString();
}
/**
* Special characters
*/
private static final String TSPECIALS = "()<>@,;:/[]?=\\\"";
/**
* Returns true if the character is a valid token character.
*/
private static boolean isTokenChar(char c) {
return (c > 040) && (c < 0177) && (TSPECIALS.indexOf(c) < 0);
}
/**
* Returns true if the given string is a legal type or subtype.
*/
private static boolean isValidToken(String s) {
int len = s.length();
if (len == 0)
return false;
for (int i = 0; i < len; i++) {
if (!isTokenChar(s.charAt(i)))
return false;
}
return true;
}
}

View file

@ -0,0 +1,295 @@
/*
* Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.nio.file.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.io.IOException;
import java.util.*;
/**
* Base implementation of background poller thread used in watch service
* implementations. A poller thread waits on events from the file system and
* also services "requests" from clients to register for new events or cancel
* existing registrations.
*/
abstract class AbstractPoller implements Runnable {
// list of requests pending to the poller thread
private final LinkedList<Request> requestList;
// set to true when shutdown
private boolean shutdown;
protected AbstractPoller() {
this.requestList = new LinkedList<>();
this.shutdown = false;
}
/**
* Starts the poller thread
*/
public void start() {
final Runnable thisRunnable = this;
AccessController.doPrivileged(new PrivilegedAction<>() {
@Override
public Object run() {
Thread thr = new Thread(null,
thisRunnable,
"FileSystemWatchService",
0,
false);
thr.setDaemon(true);
thr.start();
return null;
}
});
}
/**
* Wakeup poller thread so that it can service pending requests
*/
abstract void wakeup() throws IOException;
/**
* Executed by poller thread to register directory for changes
*/
abstract Object implRegister(Path path,
Set<? extends WatchEvent.Kind<?>> events,
WatchEvent.Modifier... modifiers);
/**
* Executed by poller thread to cancel key
*/
abstract void implCancelKey(WatchKey key);
/**
* Executed by poller thread to shutdown and cancel all keys
*/
abstract void implCloseAll();
/**
* Requests, and waits on, poller thread to register given file.
*/
final WatchKey register(Path dir,
WatchEvent.Kind<?>[] events,
WatchEvent.Modifier... modifiers)
throws IOException
{
// validate arguments before request to poller
if (dir == null)
throw new NullPointerException();
Set<WatchEvent.Kind<?>> eventSet = new HashSet<>(events.length);
for (WatchEvent.Kind<?> event: events) {
// standard events
if (event == StandardWatchEventKinds.ENTRY_CREATE ||
event == StandardWatchEventKinds.ENTRY_MODIFY ||
event == StandardWatchEventKinds.ENTRY_DELETE)
{
eventSet.add(event);
continue;
}
// OVERFLOW is ignored
if (event == StandardWatchEventKinds.OVERFLOW)
continue;
// null/unsupported
if (event == null)
throw new NullPointerException("An element in event set is 'null'");
throw new UnsupportedOperationException(event.name());
}
if (eventSet.isEmpty())
throw new IllegalArgumentException("No events to register");
return (WatchKey)invoke(RequestType.REGISTER, dir, eventSet, modifiers);
}
/**
* Cancels, and waits on, poller thread to cancel given key.
*/
final void cancel(WatchKey key) {
try {
invoke(RequestType.CANCEL, key);
} catch (IOException x) {
// should not happen
throw new AssertionError(x.getMessage());
}
}
/**
* Shutdown poller thread
*/
final void close() throws IOException {
invoke(RequestType.CLOSE);
}
/**
* Types of request that the poller thread must handle
*/
private static enum RequestType {
REGISTER,
CANCEL,
CLOSE;
}
/**
* Encapsulates a request (command) to the poller thread.
*/
private static class Request {
private final RequestType type;
private final Object[] params;
private boolean completed = false;
private Object result = null;
Request(RequestType type, Object... params) {
this.type = type;
this.params = params;
}
RequestType type() {
return type;
}
Object[] parameters() {
return params;
}
void release(Object result) {
synchronized (this) {
this.completed = true;
this.result = result;
notifyAll();
}
}
/**
* Await completion of the request. The return value is the result of
* the request.
*/
Object awaitResult() {
boolean interrupted = false;
synchronized (this) {
while (!completed) {
try {
wait();
} catch (InterruptedException x) {
interrupted = true;
}
}
if (interrupted)
Thread.currentThread().interrupt();
return result;
}
}
}
/**
* Enqueues request to poller thread and waits for result
*/
private Object invoke(RequestType type, Object... params) throws IOException {
// submit request
Request req = new Request(type, params);
synchronized (requestList) {
if (shutdown) {
throw new ClosedWatchServiceException();
}
requestList.add(req);
// wakeup thread
wakeup();
}
// wait for result
Object result = req.awaitResult();
if (result instanceof RuntimeException)
throw (RuntimeException)result;
if (result instanceof IOException )
throw (IOException)result;
return result;
}
/**
* Invoked by poller thread to process all pending requests
*
* @return true if poller thread should shutdown
*/
@SuppressWarnings("unchecked")
boolean processRequests() {
synchronized (requestList) {
Request req;
while ((req = requestList.poll()) != null) {
// if in process of shutdown then reject request
if (shutdown) {
req.release(new ClosedWatchServiceException());
continue;
}
switch (req.type()) {
/**
* Register directory
*/
case REGISTER: {
Object[] params = req.parameters();
Path path = (Path)params[0];
Set<? extends WatchEvent.Kind<?>> events =
(Set<? extends WatchEvent.Kind<?>>)params[1];
WatchEvent.Modifier[] modifiers =
(WatchEvent.Modifier[])params[2];
req.release(implRegister(path, events, modifiers));
break;
}
/**
* Cancel existing key
*/
case CANCEL : {
Object[] params = req.parameters();
WatchKey key = (WatchKey)params[0];
implCancelKey(key);
req.release(null);
break;
}
/**
* Close watch service
*/
case CLOSE: {
implCloseAll();
req.release(null);
shutdown = true;
break;
}
default:
req.release(new IOException("request not recognized"));
}
}
}
return shutdown;
}
}

View file

@ -0,0 +1,103 @@
/*
* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.nio.ByteBuffer;
import java.nio.file.attribute.UserDefinedFileAttributeView;
import java.io.IOException;
import java.util.*;
/**
* Base implementation of UserDefinedAttributeView
*/
abstract class AbstractUserDefinedFileAttributeView
implements UserDefinedFileAttributeView, DynamicFileAttributeView
{
protected AbstractUserDefinedFileAttributeView() { }
protected void checkAccess(String file,
boolean checkRead,
boolean checkWrite)
{
assert checkRead || checkWrite;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
if (checkRead)
sm.checkRead(file);
if (checkWrite)
sm.checkWrite(file);
sm.checkPermission(new RuntimePermission("accessUserDefinedAttributes"));
}
}
@Override
public final String name() {
return "user";
}
@Override
public final void setAttribute(String attribute, Object value)
throws IOException
{
ByteBuffer bb;
if (value instanceof byte[]) {
bb = ByteBuffer.wrap((byte[])value);
} else {
bb = (ByteBuffer)value;
}
write(attribute, bb);
}
@Override
public final Map<String,Object> readAttributes(String[] attributes)
throws IOException
{
// names of attributes to return
List<String> names = new ArrayList<>();
for (String name: attributes) {
if (name.equals("*")) {
names = list();
break;
} else {
if (name.length() == 0)
throw new IllegalArgumentException();
names.add(name);
}
}
// read each value and return in map
Map<String,Object> result = new HashMap<>();
for (String name: names) {
int size = size(name);
byte[] buf = new byte[size];
int n = read(name, ByteBuffer.wrap(buf));
byte[] value = (n == size) ? buf : Arrays.copyOf(buf, n);
result.put(name, value);
}
return result;
}
}

View file

@ -0,0 +1,223 @@
/*
* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.nio.file.*;
import java.util.*;
/**
* Base implementation class for watch keys.
*/
abstract class AbstractWatchKey implements WatchKey {
/**
* Maximum size of event list (in the future this may be tunable)
*/
static final int MAX_EVENT_LIST_SIZE = 512;
/**
* Special event to signal overflow
*/
static final Event<Object> OVERFLOW_EVENT =
new Event<Object>(StandardWatchEventKinds.OVERFLOW, null);
/**
* Possible key states
*/
private static enum State { READY, SIGNALLED };
// reference to watcher
private final AbstractWatchService watcher;
// reference to the original directory
private final Path dir;
// key state
private State state;
// pending events
private List<WatchEvent<?>> events;
// maps a context to the last event for the context (iff the last queued
// event for the context is an ENTRY_MODIFY event).
private Map<Object,WatchEvent<?>> lastModifyEvents;
protected AbstractWatchKey(Path dir, AbstractWatchService watcher) {
this.watcher = watcher;
this.dir = dir;
this.state = State.READY;
this.events = new ArrayList<>();
this.lastModifyEvents = new HashMap<>();
}
final AbstractWatchService watcher() {
return watcher;
}
/**
* Return the original watchable (Path)
*/
@Override
public Path watchable() {
return dir;
}
/**
* Enqueues this key to the watch service
*/
final void signal() {
synchronized (this) {
if (state == State.READY) {
state = State.SIGNALLED;
watcher.enqueueKey(this);
}
}
}
/**
* Adds the event to this key and signals it.
*/
@SuppressWarnings("unchecked")
final void signalEvent(WatchEvent.Kind<?> kind, Object context) {
boolean isModify = (kind == StandardWatchEventKinds.ENTRY_MODIFY);
synchronized (this) {
int size = events.size();
if (size > 0) {
// if the previous event is an OVERFLOW event or this is a
// repeated event then we simply increment the counter
WatchEvent<?> prev = events.get(size-1);
if ((prev.kind() == StandardWatchEventKinds.OVERFLOW) ||
((kind == prev.kind() &&
Objects.equals(context, prev.context()))))
{
((Event<?>)prev).increment();
return;
}
// if this is a modify event and the last entry for the context
// is a modify event then we simply increment the count
if (!lastModifyEvents.isEmpty()) {
if (isModify) {
WatchEvent<?> ev = lastModifyEvents.get(context);
if (ev != null) {
assert ev.kind() == StandardWatchEventKinds.ENTRY_MODIFY;
((Event<?>)ev).increment();
return;
}
} else {
// not a modify event so remove from the map as the
// last event will no longer be a modify event.
lastModifyEvents.remove(context);
}
}
// if the list has reached the limit then drop pending events
// and queue an OVERFLOW event
if (size >= MAX_EVENT_LIST_SIZE) {
kind = StandardWatchEventKinds.OVERFLOW;
isModify = false;
context = null;
}
}
// non-repeated event
Event<Object> ev =
new Event<>((WatchEvent.Kind<Object>)kind, context);
if (isModify) {
lastModifyEvents.put(context, ev);
} else if (kind == StandardWatchEventKinds.OVERFLOW) {
// drop all pending events
events.clear();
lastModifyEvents.clear();
}
events.add(ev);
signal();
}
}
@Override
public final List<WatchEvent<?>> pollEvents() {
synchronized (this) {
List<WatchEvent<?>> result = events;
events = new ArrayList<>();
lastModifyEvents.clear();
return result;
}
}
@Override
public final boolean reset() {
synchronized (this) {
if (state == State.SIGNALLED && isValid()) {
if (events.isEmpty()) {
state = State.READY;
} else {
// pending events so re-queue key
watcher.enqueueKey(this);
}
}
return isValid();
}
}
/**
* WatchEvent implementation
*/
private static class Event<T> implements WatchEvent<T> {
private final WatchEvent.Kind<T> kind;
private final T context;
// synchronize on watch key to access/increment count
private int count;
Event(WatchEvent.Kind<T> type, T context) {
this.kind = type;
this.context = context;
this.count = 1;
}
@Override
public WatchEvent.Kind<T> kind() {
return kind;
}
@Override
public T context() {
return context;
}
@Override
public int count() {
return count;
}
// for repeated events
void increment() {
count++;
}
}
}

View file

@ -0,0 +1,161 @@
/*
* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.nio.file.*;
import java.util.concurrent.*;
import java.io.IOException;
/**
* Base implementation class for watch services.
*/
abstract class AbstractWatchService implements WatchService {
// signaled keys waiting to be dequeued
private final LinkedBlockingDeque<WatchKey> pendingKeys =
new LinkedBlockingDeque<WatchKey>();
// special key to indicate that watch service is closed
private final WatchKey CLOSE_KEY =
new AbstractWatchKey(null, null) {
@Override
public boolean isValid() {
return true;
}
@Override
public void cancel() {
}
};
// used when closing watch service
private volatile boolean closed;
private final Object closeLock = new Object();
protected AbstractWatchService() {
}
/**
* Register the given object with this watch service
*/
abstract WatchKey register(Path path,
WatchEvent.Kind<?>[] events,
WatchEvent.Modifier... modifers)
throws IOException;
// used by AbstractWatchKey to enqueue key
final void enqueueKey(WatchKey key) {
pendingKeys.offer(key);
}
/**
* Throws ClosedWatchServiceException if watch service is closed
*/
private void checkOpen() {
if (closed)
throw new ClosedWatchServiceException();
}
/**
* Checks the key isn't the special CLOSE_KEY used to unblock threads when
* the watch service is closed.
*/
private void checkKey(WatchKey key) {
if (key == CLOSE_KEY) {
// re-queue in case there are other threads blocked in take/poll
enqueueKey(key);
}
checkOpen();
}
@Override
public final WatchKey poll() {
checkOpen();
WatchKey key = pendingKeys.poll();
checkKey(key);
return key;
}
@Override
public final WatchKey poll(long timeout, TimeUnit unit)
throws InterruptedException
{
checkOpen();
WatchKey key = pendingKeys.poll(timeout, unit);
checkKey(key);
return key;
}
@Override
public final WatchKey take()
throws InterruptedException
{
checkOpen();
WatchKey key = pendingKeys.take();
checkKey(key);
return key;
}
/**
* Tells whether or not this watch service is open.
*/
final boolean isOpen() {
return !closed;
}
/**
* Retrieves the object upon which the close method synchronizes.
*/
final Object closeLock() {
return closeLock;
}
/**
* Closes this watch service. This method is invoked by the close
* method to perform the actual work of closing the watch service.
*/
abstract void implClose() throws IOException;
@Override
public final void close()
throws IOException
{
synchronized (closeLock) {
// nothing to do if already closed
if (closed)
return;
closed = true;
implClose();
// clear pending keys and queue special key to ensure that any
// threads blocked in take/poll wakeup
pendingKeys.clear();
pendingKeys.offer(CLOSE_KEY);
}
}
}

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.nio.file.attribute.BasicFileAttributes;
/**
* Implemented by objects that may hold or cache the attributes of a file.
*/
public interface BasicFileAttributesHolder {
/**
* Returns cached attributes (may be null). If file is a symbolic link then
* the attributes are the link attributes and not the final target of the
* file.
*/
BasicFileAttributes get();
/**
* Invalidates cached attributes
*/
void invalidate();
}

View file

@ -0,0 +1,137 @@
/*
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import jdk.internal.misc.Unsafe;
import java.util.concurrent.ExecutionException;
/**
* Base implementation of a task (typically native) that polls a memory location
* during execution so that it may be aborted/cancelled before completion. The
* task is executed by invoking the {@link runInterruptibly} method defined
* here and cancelled by invoking Thread.interrupt.
*/
abstract class Cancellable implements Runnable {
private static final Unsafe unsafe = Unsafe.getUnsafe();
private final long pollingAddress;
private final Object lock = new Object();
// the following require lock when examining or changing
private boolean completed;
private Throwable exception;
protected Cancellable() {
pollingAddress = unsafe.allocateMemory(4);
unsafe.putIntVolatile(null, pollingAddress, 0);
}
/**
* Returns the memory address of a 4-byte int that should be polled to
* detect cancellation.
*/
protected long addressToPollForCancel() {
return pollingAddress;
}
/**
* The value to write to the polled memory location to indicate that the
* task has been cancelled. If this method is not overridden then it
* defaults to MAX_VALUE.
*/
protected int cancelValue() {
return Integer.MAX_VALUE;
}
/**
* "cancels" the task by writing bits into memory location that it polled
* by the task.
*/
final void cancel() {
synchronized (lock) {
if (!completed) {
unsafe.putIntVolatile(null, pollingAddress, cancelValue());
}
}
}
/**
* Returns the exception thrown by the task or null if the task completed
* successfully.
*/
private Throwable exception() {
synchronized (lock) {
return exception;
}
}
@Override
public final void run() {
try {
implRun();
} catch (Throwable t) {
synchronized (lock) {
exception = t;
}
} finally {
synchronized (lock) {
completed = true;
unsafe.freeMemory(pollingAddress);
}
}
}
/**
* The task body. This should periodically poll the memory location
* to check for cancellation.
*/
abstract void implRun() throws Throwable;
/**
* Invokes the given task in its own thread. If this (meaning the current)
* thread is interrupted then an attempt is make to cancel the background
* thread by writing into the memory location that it polls cooperatively.
*/
static void runInterruptibly(Cancellable task) throws ExecutionException {
Thread t = new Thread(null, task, "NIO-Task", 0, false);
t.start();
boolean cancelledByInterrupt = false;
while (t.isAlive()) {
try {
t.join();
} catch (InterruptedException e) {
cancelledByInterrupt = true;
task.cancel();
}
}
if (cancelledByInterrupt)
Thread.currentThread().interrupt();
Throwable exc = task.exception();
if (exc != null)
throw new ExecutionException(exc);
}
}

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.util.Map;
import java.io.IOException;
/**
* Implemented by FileAttributeView implementations to support access to
* attributes by names.
*/
interface DynamicFileAttributeView {
/**
* Sets/updates the value of an attribute.
*/
void setAttribute(String attribute, Object value) throws IOException;
/**
* Reads a set of file attributes as a bulk operation.
*/
Map<String,Object> readAttributes(String[] attributes) throws IOException;
}

View file

@ -0,0 +1,143 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.nio.file.CopyOption;
import java.nio.file.OpenOption;
import java.nio.file.WatchEvent;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Provides support for handling JDK-specific OpenOption, CopyOption and
* WatchEvent.Modifier types.
*/
public final class ExtendedOptions {
// maps InternalOption to ExternalOption
private static final Map<InternalOption<?>, Wrapper<?>> internalToExternal
= new ConcurrentHashMap<>();
/**
* Wraps an option or modifier.
*/
private static final class Wrapper<T> {
private final Object option;
private final T param;
Wrapper(Object option, T param) {
this.option = option;
this.param = param;
}
T parameter() {
return param;
}
}
/**
* The internal version of a JDK-specific OpenOption, CopyOption or
* WatchEvent.Modifier.
*/
public static final class InternalOption<T> {
InternalOption() { }
private void registerInternal(Object option, T param) {
Wrapper<T> wrapper = new Wrapper<T>(option, param);
internalToExternal.put(this, wrapper);
}
/**
* Register this internal option as a OpenOption.
*/
public void register(OpenOption option) {
registerInternal(option, null);
}
/**
* Register this internal option as a CopyOption.
*/
public void register(CopyOption option) {
registerInternal(option, null);
}
/**
* Register this internal option as a WatchEvent.Modifier.
*/
public void register(WatchEvent.Modifier option) {
registerInternal(option, null);
}
/**
* Register this internal option as a WatchEvent.Modifier with the
* given parameter.
*/
public void register(WatchEvent.Modifier option, T param) {
registerInternal(option, param);
}
/**
* Returns true if the given option (or modifier) maps to this internal
* option.
*/
public boolean matches(Object option) {
Wrapper <?> wrapper = internalToExternal.get(this);
if (wrapper == null)
return false;
else
return option == wrapper.option;
}
/**
* Returns the parameter object associated with this internal option.
*/
@SuppressWarnings("unchecked")
public T parameter() {
Wrapper<?> wrapper = internalToExternal.get(this);
if (wrapper == null)
return null;
else
return (T) wrapper.parameter();
}
}
// Internal equivalents of the options and modifiers defined in
// package com.sun.nio.file
public static final InternalOption<Void> INTERRUPTIBLE = new InternalOption<>();
public static final InternalOption<Void> NOSHARE_READ = new InternalOption<>();
public static final InternalOption<Void> NOSHARE_WRITE = new InternalOption<>();
public static final InternalOption<Void> NOSHARE_DELETE = new InternalOption<>();
public static final InternalOption<Void> FILE_TREE = new InternalOption<>();
public static final InternalOption<Integer> SENSITIVITY_HIGH = new InternalOption<>();
public static final InternalOption<Integer> SENSITIVITY_MEDIUM = new InternalOption<>();
public static final InternalOption<Integer> SENSITIVITY_LOW = new InternalOption<>();
}

View file

@ -0,0 +1,105 @@
/*
* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.nio.file.attribute.*;
import java.util.*;
import java.io.IOException;
/**
* An implementation of FileOwnerAttributeView that delegates to a given
* PosixFileAttributeView or AclFileAttributeView object.
*/
final class FileOwnerAttributeViewImpl
implements FileOwnerAttributeView, DynamicFileAttributeView
{
private static final String OWNER_NAME = "owner";
private final FileAttributeView view;
private final boolean isPosixView;
FileOwnerAttributeViewImpl(PosixFileAttributeView view) {
this.view = view;
this.isPosixView = true;
}
FileOwnerAttributeViewImpl(AclFileAttributeView view) {
this.view = view;
this.isPosixView = false;
}
@Override
public String name() {
return "owner";
}
@Override
public void setAttribute(String attribute, Object value)
throws IOException
{
if (attribute.equals(OWNER_NAME)) {
setOwner((UserPrincipal)value);
} else {
throw new IllegalArgumentException("'" + name() + ":" +
attribute + "' not recognized");
}
}
@Override
public Map<String,Object> readAttributes(String[] attributes) throws IOException {
Map<String,Object> result = new HashMap<>();
for (String attribute: attributes) {
if (attribute.equals("*") || attribute.equals(OWNER_NAME)) {
result.put(OWNER_NAME, getOwner());
} else {
throw new IllegalArgumentException("'" + name() + ":" +
attribute + "' not recognized");
}
}
return result;
}
@Override
public UserPrincipal getOwner() throws IOException {
if (isPosixView) {
return ((PosixFileAttributeView)view).readAttributes().owner();
} else {
return ((AclFileAttributeView)view).getOwner();
}
}
@Override
public void setOwner(UserPrincipal owner)
throws IOException
{
if (isPosixView) {
((PosixFileAttributeView)view).setOwner(owner);
} else {
((AclFileAttributeView)view).setOwner(owner);
}
}
}

View file

@ -0,0 +1,217 @@
/*
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.util.regex.PatternSyntaxException;
public class Globs {
private Globs() { }
private static final String regexMetaChars = ".^$+{[]|()";
private static final String globMetaChars = "\\*?[{";
private static boolean isRegexMeta(char c) {
return regexMetaChars.indexOf(c) != -1;
}
private static boolean isGlobMeta(char c) {
return globMetaChars.indexOf(c) != -1;
}
private static char EOL = 0; //TBD
private static char next(String glob, int i) {
if (i < glob.length()) {
return glob.charAt(i);
}
return EOL;
}
/**
* Creates a regex pattern from the given glob expression.
*
* @throws PatternSyntaxException
*/
private static String toRegexPattern(String globPattern, boolean isDos) {
boolean inGroup = false;
StringBuilder regex = new StringBuilder("^");
int i = 0;
while (i < globPattern.length()) {
char c = globPattern.charAt(i++);
switch (c) {
case '\\':
// escape special characters
if (i == globPattern.length()) {
throw new PatternSyntaxException("No character to escape",
globPattern, i - 1);
}
char next = globPattern.charAt(i++);
if (isGlobMeta(next) || isRegexMeta(next)) {
regex.append('\\');
}
regex.append(next);
break;
case '/':
if (isDos) {
regex.append("\\\\");
} else {
regex.append(c);
}
break;
case '[':
// don't match name separator in class
if (isDos) {
regex.append("[[^\\\\]&&[");
} else {
regex.append("[[^/]&&[");
}
if (next(globPattern, i) == '^') {
// escape the regex negation char if it appears
regex.append("\\^");
i++;
} else {
// negation
if (next(globPattern, i) == '!') {
regex.append('^');
i++;
}
// hyphen allowed at start
if (next(globPattern, i) == '-') {
regex.append('-');
i++;
}
}
boolean hasRangeStart = false;
char last = 0;
while (i < globPattern.length()) {
c = globPattern.charAt(i++);
if (c == ']') {
break;
}
if (c == '/' || (isDos && c == '\\')) {
throw new PatternSyntaxException("Explicit 'name separator' in class",
globPattern, i - 1);
}
// TBD: how to specify ']' in a class?
if (c == '\\' || c == '[' ||
c == '&' && next(globPattern, i) == '&') {
// escape '\', '[' or "&&" for regex class
regex.append('\\');
}
regex.append(c);
if (c == '-') {
if (!hasRangeStart) {
throw new PatternSyntaxException("Invalid range",
globPattern, i - 1);
}
if ((c = next(globPattern, i++)) == EOL || c == ']') {
break;
}
if (c < last) {
throw new PatternSyntaxException("Invalid range",
globPattern, i - 3);
}
regex.append(c);
hasRangeStart = false;
} else {
hasRangeStart = true;
last = c;
}
}
if (c != ']') {
throw new PatternSyntaxException("Missing ']", globPattern, i - 1);
}
regex.append("]]");
break;
case '{':
if (inGroup) {
throw new PatternSyntaxException("Cannot nest groups",
globPattern, i - 1);
}
regex.append("(?:(?:");
inGroup = true;
break;
case '}':
if (inGroup) {
regex.append("))");
inGroup = false;
} else {
regex.append('}');
}
break;
case ',':
if (inGroup) {
regex.append(")|(?:");
} else {
regex.append(',');
}
break;
case '*':
if (next(globPattern, i) == '*') {
// crosses directory boundaries
regex.append(".*");
i++;
} else {
// within directory boundary
if (isDos) {
regex.append("[^\\\\]*");
} else {
regex.append("[^/]*");
}
}
break;
case '?':
if (isDos) {
regex.append("[^\\\\]");
} else {
regex.append("[^/]");
}
break;
default:
if (isRegexMeta(c)) {
regex.append('\\');
}
regex.append(c);
}
}
if (inGroup) {
throw new PatternSyntaxException("Missing '}", globPattern, i - 1);
}
return regex.append('$').toString();
}
static String toUnixRegexPattern(String globPattern) {
return toRegexPattern(globPattern, false);
}
static String toWindowsRegexPattern(String globPattern) {
return toRegexPattern(globPattern, true);
}
}

View file

@ -0,0 +1,89 @@
/*
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.lang.ref.Cleaner.Cleanable;
import jdk.internal.misc.Unsafe;
import jdk.internal.ref.CleanerFactory;
/**
* A light-weight buffer in native memory.
*/
class NativeBuffer {
private static final Unsafe unsafe = Unsafe.getUnsafe();
private final long address;
private final int size;
private final Cleanable cleanable;
// optional "owner" to avoid copying
// (only safe for use by thread-local caches)
private Object owner;
private static class Deallocator implements Runnable {
private final long address;
Deallocator(long address) {
this.address = address;
}
public void run() {
unsafe.freeMemory(address);
}
}
NativeBuffer(int size) {
this.address = unsafe.allocateMemory(size);
this.size = size;
this.cleanable = CleanerFactory.cleaner()
.register(this, new Deallocator(address));
}
void release() {
NativeBuffers.releaseNativeBuffer(this);
}
long address() {
return address;
}
int size() {
return size;
}
void free() {
cleanable.clean();
}
// not synchronized; only safe for use by thread-local caches
void setOwner(Object owner) {
this.owner = owner;
}
// not synchronized; only safe for use by thread-local caches
Object owner() {
return owner;
}
}

View file

@ -0,0 +1,140 @@
/*
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import jdk.internal.misc.Unsafe;
/**
* Factory for native buffers.
*/
class NativeBuffers {
private NativeBuffers() { }
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final int TEMP_BUF_POOL_SIZE = 3;
private static ThreadLocal<NativeBuffer[]> threadLocal =
new ThreadLocal<NativeBuffer[]>();
/**
* Allocates a native buffer, of at least the given size, from the heap.
*/
static NativeBuffer allocNativeBuffer(int size) {
// Make a new one of at least 2k
if (size < 2048) size = 2048;
return new NativeBuffer(size);
}
/**
* Returns a native buffer, of at least the given size, from the thread
* local cache.
*/
static NativeBuffer getNativeBufferFromCache(int size) {
// return from cache if possible
NativeBuffer[] buffers = threadLocal.get();
if (buffers != null) {
for (int i=0; i<TEMP_BUF_POOL_SIZE; i++) {
NativeBuffer buffer = buffers[i];
if (buffer != null && buffer.size() >= size) {
buffers[i] = null;
return buffer;
}
}
}
return null;
}
/**
* Returns a native buffer, of at least the given size. The native buffer
* is taken from the thread local cache if possible; otherwise it is
* allocated from the heap.
*/
static NativeBuffer getNativeBuffer(int size) {
NativeBuffer buffer = getNativeBufferFromCache(size);
if (buffer != null) {
buffer.setOwner(null);
return buffer;
} else {
return allocNativeBuffer(size);
}
}
/**
* Releases the given buffer. If there is space in the thread local cache
* then the buffer goes into the cache; otherwise the memory is deallocated.
*/
static void releaseNativeBuffer(NativeBuffer buffer) {
// create cache if it doesn't exist
NativeBuffer[] buffers = threadLocal.get();
if (buffers == null) {
buffers = new NativeBuffer[TEMP_BUF_POOL_SIZE];
buffers[0] = buffer;
threadLocal.set(buffers);
return;
}
// Put it in an empty slot if such exists
for (int i=0; i<TEMP_BUF_POOL_SIZE; i++) {
if (buffers[i] == null) {
buffers[i] = buffer;
return;
}
}
// Otherwise replace a smaller one in the cache if such exists
for (int i=0; i<TEMP_BUF_POOL_SIZE; i++) {
NativeBuffer existing = buffers[i];
if (existing.size() < buffer.size()) {
existing.free();
buffers[i] = buffer;
return;
}
}
// free it
buffer.free();
}
/**
* Copies a byte array and zero terminator into a given native buffer.
*/
static void copyCStringToNativeBuffer(byte[] cstr, NativeBuffer buffer) {
long offset = Unsafe.ARRAY_BYTE_BASE_OFFSET;
long len = cstr.length;
assert buffer.size() >= (len + 1);
unsafe.copyMemory(cstr, offset, null, buffer.address(), len);
unsafe.putByte(buffer.address() + len, (byte)0);
}
/**
* Copies a byte array and zero terminator into a native buffer, returning
* the buffer.
*/
static NativeBuffer asNativeBuffer(byte[] cstr) {
NativeBuffer buffer = getNativeBuffer(cstr.length+1);
copyCStringToNativeBuffer(cstr, buffer);
return buffer;
}
}

View file

@ -0,0 +1,430 @@
/*
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.nio.file.ClosedWatchServiceException;
import java.nio.file.DirectoryIteratorException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.NotDirectoryException;
import java.nio.file.Path;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.attribute.BasicFileAttributes;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedActionException;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
/**
* Simple WatchService implementation that uses periodic tasks to poll
* registered directories for changes. This implementation is for use on
* operating systems that do not have native file change notification support.
*/
class PollingWatchService
extends AbstractWatchService
{
// map of registrations
private final Map<Object, PollingWatchKey> map = new HashMap<>();
// used to execute the periodic tasks that poll for changes
private final ScheduledExecutorService scheduledExecutor;
PollingWatchService() {
// TBD: Make the number of threads configurable
scheduledExecutor = Executors
.newSingleThreadScheduledExecutor(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(null, r, "FileSystemWatcher", 0, false);
t.setDaemon(true);
return t;
}});
}
/**
* Register the given file with this watch service
*/
@Override
WatchKey register(final Path path,
WatchEvent.Kind<?>[] events,
WatchEvent.Modifier... modifiers)
throws IOException
{
// check events - CCE will be thrown if there are invalid elements
final Set<WatchEvent.Kind<?>> eventSet = new HashSet<>(events.length);
for (WatchEvent.Kind<?> event: events) {
// standard events
if (event == StandardWatchEventKinds.ENTRY_CREATE ||
event == StandardWatchEventKinds.ENTRY_MODIFY ||
event == StandardWatchEventKinds.ENTRY_DELETE)
{
eventSet.add(event);
continue;
}
// OVERFLOW is ignored
if (event == StandardWatchEventKinds.OVERFLOW) {
continue;
}
// null/unsupported
if (event == null)
throw new NullPointerException("An element in event set is 'null'");
throw new UnsupportedOperationException(event.name());
}
if (eventSet.isEmpty())
throw new IllegalArgumentException("No events to register");
// Extended modifiers may be used to specify the sensitivity level
int sensitivity = 10;
if (modifiers.length > 0) {
for (WatchEvent.Modifier modifier: modifiers) {
if (modifier == null)
throw new NullPointerException();
if (ExtendedOptions.SENSITIVITY_HIGH.matches(modifier)) {
sensitivity = ExtendedOptions.SENSITIVITY_HIGH.parameter();
} else if (ExtendedOptions.SENSITIVITY_MEDIUM.matches(modifier)) {
sensitivity = ExtendedOptions.SENSITIVITY_MEDIUM.parameter();
} else if (ExtendedOptions.SENSITIVITY_LOW.matches(modifier)) {
sensitivity = ExtendedOptions.SENSITIVITY_LOW.parameter();
} else {
throw new UnsupportedOperationException("Modifier not supported");
}
}
}
// check if watch service is closed
if (!isOpen())
throw new ClosedWatchServiceException();
// registration is done in privileged block as it requires the
// attributes of the entries in the directory.
try {
int value = sensitivity;
return AccessController.doPrivileged(
new PrivilegedExceptionAction<PollingWatchKey>() {
@Override
public PollingWatchKey run() throws IOException {
return doPrivilegedRegister(path, eventSet, value);
}
});
} catch (PrivilegedActionException pae) {
Throwable cause = pae.getCause();
if (cause != null && cause instanceof IOException)
throw (IOException)cause;
throw new AssertionError(pae);
}
}
// registers directory returning a new key if not already registered or
// existing key if already registered
private PollingWatchKey doPrivilegedRegister(Path path,
Set<? extends WatchEvent.Kind<?>> events,
int sensitivityInSeconds)
throws IOException
{
// check file is a directory and get its file key if possible
BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
if (!attrs.isDirectory()) {
throw new NotDirectoryException(path.toString());
}
Object fileKey = attrs.fileKey();
if (fileKey == null)
throw new AssertionError("File keys must be supported");
// grab close lock to ensure that watch service cannot be closed
synchronized (closeLock()) {
if (!isOpen())
throw new ClosedWatchServiceException();
PollingWatchKey watchKey;
synchronized (map) {
watchKey = map.get(fileKey);
if (watchKey == null) {
// new registration
watchKey = new PollingWatchKey(path, this, fileKey);
map.put(fileKey, watchKey);
} else {
// update to existing registration
watchKey.disable();
}
}
watchKey.enable(events, sensitivityInSeconds);
return watchKey;
}
}
@Override
void implClose() throws IOException {
synchronized (map) {
for (Map.Entry<Object, PollingWatchKey> entry: map.entrySet()) {
PollingWatchKey watchKey = entry.getValue();
watchKey.disable();
watchKey.invalidate();
}
map.clear();
}
AccessController.doPrivileged(new PrivilegedAction<Void>() {
@Override
public Void run() {
scheduledExecutor.shutdown();
return null;
}
});
}
/**
* Entry in directory cache to record file last-modified-time and tick-count
*/
private static class CacheEntry {
private long lastModified;
private int lastTickCount;
CacheEntry(long lastModified, int lastTickCount) {
this.lastModified = lastModified;
this.lastTickCount = lastTickCount;
}
int lastTickCount() {
return lastTickCount;
}
long lastModified() {
return lastModified;
}
void update(long lastModified, int tickCount) {
this.lastModified = lastModified;
this.lastTickCount = tickCount;
}
}
/**
* WatchKey implementation that encapsulates a map of the entries of the
* entries in the directory. Polling the key causes it to re-scan the
* directory and queue keys when entries are added, modified, or deleted.
*/
private class PollingWatchKey extends AbstractWatchKey {
private final Object fileKey;
// current event set
private Set<? extends WatchEvent.Kind<?>> events;
// the result of the periodic task that causes this key to be polled
private ScheduledFuture<?> poller;
// indicates if the key is valid
private volatile boolean valid;
// used to detect files that have been deleted
private int tickCount;
// map of entries in directory
private Map<Path,CacheEntry> entries;
PollingWatchKey(Path dir, PollingWatchService watcher, Object fileKey)
throws IOException
{
super(dir, watcher);
this.fileKey = fileKey;
this.valid = true;
this.tickCount = 0;
this.entries = new HashMap<Path,CacheEntry>();
// get the initial entries in the directory
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
for (Path entry: stream) {
// don't follow links
long lastModified =
Files.getLastModifiedTime(entry, LinkOption.NOFOLLOW_LINKS).toMillis();
entries.put(entry.getFileName(), new CacheEntry(lastModified, tickCount));
}
} catch (DirectoryIteratorException e) {
throw e.getCause();
}
}
Object fileKey() {
return fileKey;
}
@Override
public boolean isValid() {
return valid;
}
void invalidate() {
valid = false;
}
// enables periodic polling
void enable(Set<? extends WatchEvent.Kind<?>> events, long period) {
synchronized (this) {
// update the events
this.events = events;
// create the periodic task
Runnable thunk = new Runnable() { public void run() { poll(); }};
this.poller = scheduledExecutor
.scheduleAtFixedRate(thunk, period, period, TimeUnit.SECONDS);
}
}
// disables periodic polling
void disable() {
synchronized (this) {
if (poller != null)
poller.cancel(false);
}
}
@Override
public void cancel() {
valid = false;
synchronized (map) {
map.remove(fileKey());
}
disable();
}
/**
* Polls the directory to detect for new files, modified files, or
* deleted files.
*/
synchronized void poll() {
if (!valid) {
return;
}
// update tick
tickCount++;
// open directory
DirectoryStream<Path> stream = null;
try {
stream = Files.newDirectoryStream(watchable());
} catch (IOException x) {
// directory is no longer accessible so cancel key
cancel();
signal();
return;
}
// iterate over all entries in directory
try {
for (Path entry: stream) {
long lastModified = 0L;
try {
lastModified =
Files.getLastModifiedTime(entry, LinkOption.NOFOLLOW_LINKS).toMillis();
} catch (IOException x) {
// unable to get attributes of entry. If file has just
// been deleted then we'll report it as deleted on the
// next poll
continue;
}
// lookup cache
CacheEntry e = entries.get(entry.getFileName());
if (e == null) {
// new file found
entries.put(entry.getFileName(),
new CacheEntry(lastModified, tickCount));
// queue ENTRY_CREATE if event enabled
if (events.contains(StandardWatchEventKinds.ENTRY_CREATE)) {
signalEvent(StandardWatchEventKinds.ENTRY_CREATE, entry.getFileName());
continue;
} else {
// if ENTRY_CREATE is not enabled and ENTRY_MODIFY is
// enabled then queue event to avoid missing out on
// modifications to the file immediately after it is
// created.
if (events.contains(StandardWatchEventKinds.ENTRY_MODIFY)) {
signalEvent(StandardWatchEventKinds.ENTRY_MODIFY, entry.getFileName());
}
}
continue;
}
// check if file has changed
if (e.lastModified != lastModified) {
if (events.contains(StandardWatchEventKinds.ENTRY_MODIFY)) {
signalEvent(StandardWatchEventKinds.ENTRY_MODIFY,
entry.getFileName());
}
}
// entry in cache so update poll time
e.update(lastModified, tickCount);
}
} catch (DirectoryIteratorException e) {
// ignore for now; if the directory is no longer accessible
// then the key will be cancelled on the next poll
} finally {
// close directory stream
try {
stream.close();
} catch (IOException x) {
// ignore
}
}
// iterate over cache to detect entries that have been deleted
Iterator<Map.Entry<Path,CacheEntry>> i = entries.entrySet().iterator();
while (i.hasNext()) {
Map.Entry<Path,CacheEntry> mapEntry = i.next();
CacheEntry entry = mapEntry.getValue();
if (entry.lastTickCount() != tickCount) {
Path name = mapEntry.getKey();
// remove from map and queue delete event (if enabled)
i.remove();
if (events.contains(StandardWatchEventKinds.ENTRY_DELETE)) {
signalEvent(StandardWatchEventKinds.ENTRY_DELETE, name);
}
}
}
}
}
}

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.lang.reflect.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
/**
* Utility class for reflection.
*/
class Reflect {
private Reflect() {}
private static void setAccessible(final AccessibleObject ao) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
ao.setAccessible(true);
return null;
}});
}
/**
* Lookup the field of a given class.
*/
static Field lookupField(String className, String fieldName) {
try {
Class<?> cl = Class.forName(className);
Field f = cl.getDeclaredField(fieldName);
setAccessible(f);
return f;
} catch (ClassNotFoundException x) {
throw new AssertionError(x);
} catch (NoSuchFieldException x) {
throw new AssertionError(x);
}
}
}

View file

@ -0,0 +1,132 @@
/*
* Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.util.*;
import java.nio.file.*;
import java.nio.charset.Charset;
import sun.security.action.GetPropertyAction;
/**
* Utility methods
*/
class Util {
private Util() { }
private static final Charset jnuEncoding = Charset.forName(
GetPropertyAction.privilegedGetProperty("sun.jnu.encoding"));
/**
* Returns {@code Charset} corresponding to the sun.jnu.encoding property
*/
static Charset jnuEncoding() {
return jnuEncoding;
}
/**
* Encodes the given String into a sequence of bytes using the {@code Charset}
* specified by the sun.jnu.encoding property.
*/
static byte[] toBytes(String s) {
return s.getBytes(jnuEncoding);
}
/**
* Constructs a new String by decoding the specified array of bytes using the
* {@code Charset} specified by the sun.jnu.encoding property.
*/
static String toString(byte[] bytes) {
return new String(bytes, jnuEncoding);
}
/**
* Splits a string around the given character. The array returned by this
* method contains each substring that is terminated by the character. Use
* for simple string spilting cases when needing to avoid loading regex.
*/
static String[] split(String s, char c) {
int count = 0;
for (int i=0; i<s.length(); i++) {
if (s.charAt(i) == c)
count++;
}
String[] result = new String[count+1];
int n = 0;
int last = 0;
for (int i=0; i<s.length(); i++) {
if (s.charAt(i) == c) {
result[n++] = s.substring(last, i);
last = i + 1;
}
}
result[n] = s.substring(last, s.length());
return result;
}
/**
* Returns a Set containing the given elements.
*/
@SafeVarargs
static <E> Set<E> newSet(E... elements) {
HashSet<E> set = new HashSet<>();
for (E e: elements) {
set.add(e);
}
return set;
}
/**
* Returns a Set containing all the elements of the given Set plus
* the given elements.
*/
@SafeVarargs
static <E> Set<E> newSet(Set<E> other, E... elements) {
HashSet<E> set = new HashSet<>(other);
for (E e: elements) {
set.add(e);
}
return set;
}
/**
* Returns {@code true} if symbolic links should be followed
*/
static boolean followLinks(LinkOption... options) {
boolean followLinks = true;
for (LinkOption option: options) {
if (option == LinkOption.NOFOLLOW_LINKS) {
followLinks = false;
} else if (option == null) {
throw new NullPointerException();
} else {
throw new AssertionError("Should not get here");
}
}
return followLinks;
}
}