mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
8187443: Forest Consolidation: Move files to unified layout
Reviewed-by: darcy, ihse
This commit is contained in:
parent
270fe13182
commit
3789983e89
56923 changed files with 3 additions and 15727 deletions
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 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 apple.security;
|
||||
|
||||
import java.security.*;
|
||||
import static sun.security.util.SecurityConstants.PROVIDER_VER;
|
||||
|
||||
/**
|
||||
* The Apple Security Provider.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Defines the Apple provider.
|
||||
*
|
||||
* This provider only exists to provide access to the Apple keychain-based KeyStore implementation
|
||||
*/
|
||||
@SuppressWarnings("serial") // JDK implementation class
|
||||
public final class AppleProvider extends Provider {
|
||||
|
||||
private static final String info = "Apple Provider";
|
||||
|
||||
private static final class ProviderService extends Provider.Service {
|
||||
ProviderService(Provider p, String type, String algo, String cn) {
|
||||
super(p, type, algo, cn, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object newInstance(Object ctrParamObj)
|
||||
throws NoSuchAlgorithmException {
|
||||
String type = getType();
|
||||
if (ctrParamObj != null) {
|
||||
throw new InvalidParameterException
|
||||
("constructorParameter not used with " + type + " engines");
|
||||
}
|
||||
|
||||
String algo = getAlgorithm();
|
||||
try {
|
||||
if (type.equals("KeyStore")) {
|
||||
if (algo.equals("KeychainStore")) {
|
||||
return new KeychainStore();
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new NoSuchAlgorithmException("Error constructing " +
|
||||
type + " for " + algo + " using Apple", ex);
|
||||
}
|
||||
throw new ProviderException("No impl for " + algo +
|
||||
" " + type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public AppleProvider() {
|
||||
/* We are the Apple provider */
|
||||
super("Apple", PROVIDER_VER, info);
|
||||
|
||||
final Provider p = this;
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
putService(new ProviderService(p, "KeyStore",
|
||||
"KeychainStore", "apple.security.KeychainStore"));
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
1147
src/java.base/macosx/classes/apple/security/KeychainStore.java
Normal file
1147
src/java.base/macosx/classes/apple/security/KeychainStore.java
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 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 java.lang;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
class ClassLoaderHelper {
|
||||
|
||||
private ClassLoaderHelper() {}
|
||||
|
||||
/**
|
||||
* Indicates, whether PATH env variable is allowed to contain quoted entries.
|
||||
*/
|
||||
static final boolean allowsQuotedPathElements = false;
|
||||
|
||||
/**
|
||||
* Returns an alternate path name for the given file
|
||||
* such that if the original pathname did not exist, then the
|
||||
* file may be located at the alternate location.
|
||||
* For mac, this replaces the final .dylib suffix with .jnilib
|
||||
*/
|
||||
static File mapAlternativeName(File lib) {
|
||||
String name = lib.toString();
|
||||
int index = name.lastIndexOf('.');
|
||||
if (index < 0) {
|
||||
return null;
|
||||
}
|
||||
return new File(name.substring(0, index) + ".jnilib");
|
||||
}
|
||||
}
|
122
src/java.base/macosx/classes/java/net/DefaultInterface.java
Normal file
122
src/java.base/macosx/classes/java/net/DefaultInterface.java
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 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 java.net;
|
||||
|
||||
/**
|
||||
* Choose a network interface to be the default for
|
||||
* outgoing IPv6 traffic that does not specify a scope_id (and which needs one).
|
||||
* We choose the first interface that is up and is (in order of preference):
|
||||
* 1. neither loopback nor point to point
|
||||
* 2. point to point
|
||||
* 3. loopback
|
||||
* 4. none.
|
||||
* Platforms that do not require a default interface implement a dummy
|
||||
* that returns null.
|
||||
*/
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.io.IOException;
|
||||
|
||||
class DefaultInterface {
|
||||
|
||||
private static final NetworkInterface defaultInterface =
|
||||
chooseDefaultInterface();
|
||||
|
||||
static NetworkInterface getDefault() {
|
||||
return defaultInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Choose a default interface. This method returns the first interface that
|
||||
* is both "up" and supports multicast. This method chooses an interface in
|
||||
* order of preference:
|
||||
* 1. neither loopback nor point to point
|
||||
* ( prefer interfaces with dual IP support )
|
||||
* 2. point to point
|
||||
* 3. loopback
|
||||
*
|
||||
* @return the chosen interface or {@code null} if there isn't a suitable
|
||||
* default
|
||||
*/
|
||||
private static NetworkInterface chooseDefaultInterface() {
|
||||
Enumeration<NetworkInterface> nifs;
|
||||
|
||||
try {
|
||||
nifs = NetworkInterface.getNetworkInterfaces();
|
||||
} catch (IOException ignore) {
|
||||
// unable to enumerate network interfaces
|
||||
return null;
|
||||
}
|
||||
|
||||
NetworkInterface preferred = null;
|
||||
NetworkInterface ppp = null;
|
||||
NetworkInterface loopback = null;
|
||||
|
||||
while (nifs.hasMoreElements()) {
|
||||
NetworkInterface ni = nifs.nextElement();
|
||||
try {
|
||||
if (!ni.isUp() || !ni.supportsMulticast())
|
||||
continue;
|
||||
|
||||
boolean ip4 = false, ip6 = false;
|
||||
Enumeration<InetAddress> addrs = ni.getInetAddresses();
|
||||
while (addrs.hasMoreElements()) {
|
||||
InetAddress addr = addrs.nextElement();
|
||||
if (!addr.isAnyLocalAddress()) {
|
||||
if (addr instanceof Inet4Address) {
|
||||
ip4 = true;
|
||||
} else if (addr instanceof Inet6Address) {
|
||||
ip6 = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean isLoopback = ni.isLoopback();
|
||||
boolean isPPP = ni.isPointToPoint();
|
||||
if (!isLoopback && !isPPP) {
|
||||
// found an interface that is not the loopback or a
|
||||
// point-to-point interface
|
||||
if (preferred == null) {
|
||||
preferred = ni;
|
||||
} else if (ip4 && ip6){
|
||||
return ni;
|
||||
}
|
||||
}
|
||||
if (ppp == null && isPPP)
|
||||
ppp = ni;
|
||||
if (loopback == null && isLoopback)
|
||||
loopback = ni;
|
||||
|
||||
} catch (IOException skip) { }
|
||||
}
|
||||
|
||||
if (preferred != null) {
|
||||
return preferred;
|
||||
} else {
|
||||
return (ppp != null) ? ppp : loopback;
|
||||
}
|
||||
}
|
||||
}
|
26
src/java.base/macosx/classes/module-info.java.extra
Normal file
26
src/java.base/macosx/classes/module-info.java.extra
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
exports jdk.internal.loader to java.desktop;
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright (c) 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.*;
|
||||
import java.nio.channels.spi.AsynchronousChannelProvider;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.io.IOException;
|
||||
|
||||
public class BsdAsynchronousChannelProvider
|
||||
extends AsynchronousChannelProvider
|
||||
{
|
||||
private static volatile KQueuePort defaultPort;
|
||||
|
||||
private KQueuePort defaultEventPort() throws IOException {
|
||||
if (defaultPort == null) {
|
||||
synchronized (BsdAsynchronousChannelProvider.class) {
|
||||
if (defaultPort == null) {
|
||||
defaultPort = new KQueuePort(this, ThreadPool.getDefault()).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
return defaultPort;
|
||||
}
|
||||
|
||||
public BsdAsynchronousChannelProvider() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousChannelGroup openAsynchronousChannelGroup(int nThreads, ThreadFactory factory)
|
||||
throws IOException
|
||||
{
|
||||
return new KQueuePort(this, ThreadPool.create(nThreads, factory)).start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousChannelGroup openAsynchronousChannelGroup(ExecutorService executor, int initialSize)
|
||||
throws IOException
|
||||
{
|
||||
return new KQueuePort(this, ThreadPool.wrap(executor, initialSize)).start();
|
||||
}
|
||||
|
||||
private Port toPort(AsynchronousChannelGroup group) throws IOException {
|
||||
if (group == null) {
|
||||
return defaultEventPort();
|
||||
} else {
|
||||
if (!(group instanceof KQueuePort))
|
||||
throw new IllegalChannelGroupException();
|
||||
return (Port)group;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(AsynchronousChannelGroup group)
|
||||
throws IOException
|
||||
{
|
||||
return new UnixAsynchronousServerSocketChannelImpl(toPort(group));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousSocketChannel openAsynchronousSocketChannel(AsynchronousChannelGroup group)
|
||||
throws IOException
|
||||
{
|
||||
return new UnixAsynchronousSocketChannelImpl(toPort(group));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 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.spi.AsynchronousChannelProvider;
|
||||
|
||||
/**
|
||||
* Creates this platform's default AsynchronousChannelProvider
|
||||
*/
|
||||
|
||||
public class DefaultAsynchronousChannelProvider {
|
||||
|
||||
/**
|
||||
* Prevent instantiation.
|
||||
*/
|
||||
private DefaultAsynchronousChannelProvider() { }
|
||||
|
||||
/**
|
||||
* Returns the default AsynchronousChannelProvider.
|
||||
*/
|
||||
public static AsynchronousChannelProvider create() {
|
||||
return new BsdAsynchronousChannelProvider();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 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.spi.SelectorProvider;
|
||||
|
||||
/**
|
||||
* Creates this platform's default SelectorProvider
|
||||
*/
|
||||
|
||||
public class DefaultSelectorProvider {
|
||||
|
||||
/**
|
||||
* Prevent instantiation.
|
||||
*/
|
||||
private DefaultSelectorProvider() { }
|
||||
|
||||
/**
|
||||
* Returns the default SelectorProvider.
|
||||
*/
|
||||
public static SelectorProvider create() {
|
||||
return new KQueueSelectorProvider();
|
||||
}
|
||||
}
|
120
src/java.base/macosx/classes/sun/nio/ch/KQueue.java
Normal file
120
src/java.base/macosx/classes/sun/nio/ch/KQueue.java
Normal file
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 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.IOException;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
/**
|
||||
* Provides access to the BSD kqueue facility.
|
||||
*/
|
||||
|
||||
class KQueue {
|
||||
private KQueue() { }
|
||||
|
||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||
|
||||
/**
|
||||
* struct kevent {
|
||||
* uintptr_t ident; // identifier for this event, usually the fd
|
||||
* int16_t filter; // filter for event
|
||||
* uint16_t flags; // general flags
|
||||
* uint32_t fflags; // filter-specific flags
|
||||
* intptr_t data; // filter-specific data
|
||||
* void *udata; // opaque user data identifier
|
||||
* };
|
||||
*/
|
||||
private static final int SIZEOF_KQUEUEEVENT = keventSize();
|
||||
private static final int OFFSET_IDENT = identOffset();
|
||||
private static final int OFFSET_FILTER = filterOffset();
|
||||
private static final int OFFSET_FLAGS = flagsOffset();
|
||||
|
||||
// filters
|
||||
static final int EVFILT_READ = -1;
|
||||
static final int EVFILT_WRITE = -2;
|
||||
|
||||
// flags
|
||||
static final int EV_ADD = 0x0001;
|
||||
static final int EV_ONESHOT = 0x0010;
|
||||
static final int EV_CLEAR = 0x0020;
|
||||
|
||||
/**
|
||||
* Allocates a poll array to handle up to {@code count} events.
|
||||
*/
|
||||
static long allocatePollArray(int count) {
|
||||
return unsafe.allocateMemory(count * SIZEOF_KQUEUEEVENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free a poll array
|
||||
*/
|
||||
static void freePollArray(long address) {
|
||||
unsafe.freeMemory(address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns kevent[i].
|
||||
*/
|
||||
static long getEvent(long address, int i) {
|
||||
return address + (SIZEOF_KQUEUEEVENT*i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file descriptor from a kevent (assuming to be in ident field)
|
||||
*/
|
||||
static int getDescriptor(long address) {
|
||||
return unsafe.getInt(address + OFFSET_IDENT);
|
||||
}
|
||||
|
||||
static int getFilter(long address) {
|
||||
return unsafe.getShort(address + OFFSET_FILTER);
|
||||
}
|
||||
|
||||
static int getFlags(long address) {
|
||||
return unsafe.getShort(address + OFFSET_FLAGS);
|
||||
}
|
||||
|
||||
// -- Native methods --
|
||||
|
||||
private static native int keventSize();
|
||||
|
||||
private static native int identOffset();
|
||||
|
||||
private static native int filterOffset();
|
||||
|
||||
private static native int flagsOffset();
|
||||
|
||||
static native int kqueue() throws IOException;
|
||||
|
||||
static native int keventRegister(int kqpfd, int fd, int filter, int flags);
|
||||
|
||||
static native int keventPoll(int kqpfd, long pollAddress, int nevents)
|
||||
throws IOException;
|
||||
|
||||
static {
|
||||
IOUtil.load();
|
||||
}
|
||||
}
|
211
src/java.base/macosx/classes/sun/nio/ch/KQueueArrayWrapper.java
Normal file
211
src/java.base/macosx/classes/sun/nio/ch/KQueueArrayWrapper.java
Normal file
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* KQueueArrayWrapper.java
|
||||
* Implementation of Selector using FreeBSD / Mac OS X kqueues
|
||||
* Derived from Sun's DevPollArrayWrapper
|
||||
*/
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/*
|
||||
* struct kevent { // 32-bit 64-bit
|
||||
* uintptr_t ident; // 4 8
|
||||
* short filter; // 2 2
|
||||
* u_short flags; // 2 2
|
||||
* u_int fflags; // 4 4
|
||||
* intptr_t data; // 4 8
|
||||
* void *udata; // 4 8
|
||||
* } // Total: 20 32
|
||||
*
|
||||
* The implementation works in 32-bit and 64-bit world. We do this by calling a
|
||||
* native function that actually sets the sizes and offsets of the fields based
|
||||
* on which mode we're in.
|
||||
*/
|
||||
|
||||
class KQueueArrayWrapper {
|
||||
// kevent filters
|
||||
static short EVFILT_READ;
|
||||
static short EVFILT_WRITE;
|
||||
|
||||
// kevent struct
|
||||
// These fields are now set by initStructSizes in the static initializer.
|
||||
static short SIZEOF_KEVENT;
|
||||
static short FD_OFFSET;
|
||||
static short FILTER_OFFSET;
|
||||
|
||||
// kevent array size
|
||||
static final int NUM_KEVENTS = 128;
|
||||
|
||||
// Are we in a 64-bit VM?
|
||||
static boolean is64bit = false;
|
||||
|
||||
// The kevent array (used for outcoming events only)
|
||||
private AllocatedNativeObject keventArray = null;
|
||||
private long keventArrayAddress;
|
||||
|
||||
// The kqueue fd
|
||||
private int kq = -1;
|
||||
|
||||
// The fd of the interrupt line going out
|
||||
private int outgoingInterruptFD;
|
||||
|
||||
// The fd of the interrupt line coming in
|
||||
private int incomingInterruptFD;
|
||||
|
||||
static {
|
||||
IOUtil.load();
|
||||
initStructSizes();
|
||||
String datamodel =
|
||||
GetPropertyAction.privilegedGetProperty("sun.arch.data.model");
|
||||
is64bit = "64".equals(datamodel);
|
||||
}
|
||||
|
||||
KQueueArrayWrapper() {
|
||||
int allocationSize = SIZEOF_KEVENT * NUM_KEVENTS;
|
||||
keventArray = new AllocatedNativeObject(allocationSize, true);
|
||||
keventArrayAddress = keventArray.address();
|
||||
kq = init();
|
||||
}
|
||||
|
||||
// Used to update file description registrations
|
||||
private static class Update {
|
||||
SelChImpl channel;
|
||||
int events;
|
||||
Update(SelChImpl channel, int events) {
|
||||
this.channel = channel;
|
||||
this.events = events;
|
||||
}
|
||||
}
|
||||
|
||||
private LinkedList<Update> updateList = new LinkedList<Update>();
|
||||
|
||||
void initInterrupt(int fd0, int fd1) {
|
||||
outgoingInterruptFD = fd1;
|
||||
incomingInterruptFD = fd0;
|
||||
register0(kq, fd0, 1, 0);
|
||||
}
|
||||
|
||||
int getReventOps(int index) {
|
||||
int result = 0;
|
||||
int offset = SIZEOF_KEVENT*index + FILTER_OFFSET;
|
||||
short filter = keventArray.getShort(offset);
|
||||
|
||||
// This is all that's necessary based on inspection of usage:
|
||||
// SinkChannelImpl, SourceChannelImpl, DatagramChannelImpl,
|
||||
// ServerSocketChannelImpl, SocketChannelImpl
|
||||
if (filter == EVFILT_READ) {
|
||||
result |= Net.POLLIN;
|
||||
} else if (filter == EVFILT_WRITE) {
|
||||
result |= Net.POLLOUT;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int getDescriptor(int index) {
|
||||
int offset = SIZEOF_KEVENT*index + FD_OFFSET;
|
||||
/* The ident field is 8 bytes in 64-bit world, however the API wants us
|
||||
* to return an int. Hence read the 8 bytes but return as an int.
|
||||
*/
|
||||
if (is64bit) {
|
||||
long fd = keventArray.getLong(offset);
|
||||
assert fd <= Integer.MAX_VALUE;
|
||||
return (int) fd;
|
||||
} else {
|
||||
return keventArray.getInt(offset);
|
||||
}
|
||||
}
|
||||
|
||||
void setInterest(SelChImpl channel, int events) {
|
||||
synchronized (updateList) {
|
||||
// update existing registration
|
||||
updateList.add(new Update(channel, events));
|
||||
}
|
||||
}
|
||||
|
||||
void release(SelChImpl channel) {
|
||||
synchronized (updateList) {
|
||||
// flush any pending updates
|
||||
for (Iterator<Update> it = updateList.iterator(); it.hasNext();) {
|
||||
if (it.next().channel == channel) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// remove
|
||||
register0(kq, channel.getFDVal(), 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void updateRegistrations() {
|
||||
synchronized (updateList) {
|
||||
Update u = null;
|
||||
while ((u = updateList.poll()) != null) {
|
||||
SelChImpl ch = u.channel;
|
||||
if (!ch.isOpen())
|
||||
continue;
|
||||
|
||||
register0(kq, ch.getFDVal(), u.events & Net.POLLIN, u.events & Net.POLLOUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void close() throws IOException {
|
||||
if (keventArray != null) {
|
||||
keventArray.free();
|
||||
keventArray = null;
|
||||
}
|
||||
if (kq >= 0) {
|
||||
FileDispatcherImpl.closeIntFD(kq);
|
||||
kq = -1;
|
||||
}
|
||||
}
|
||||
|
||||
int poll(long timeout) {
|
||||
updateRegistrations();
|
||||
int updated = kevent0(kq, keventArrayAddress, NUM_KEVENTS, timeout);
|
||||
return updated;
|
||||
}
|
||||
|
||||
void interrupt() {
|
||||
interrupt(outgoingInterruptFD);
|
||||
}
|
||||
|
||||
private native int init();
|
||||
private static native void initStructSizes();
|
||||
|
||||
private native void register0(int kq, int fd, int read, int write);
|
||||
private native int kevent0(int kq, long keventAddress, int keventCount,
|
||||
long timeout);
|
||||
private static native void interrupt(int fd);
|
||||
}
|
331
src/java.base/macosx/classes/sun/nio/ch/KQueuePort.java
Normal file
331
src/java.base/macosx/classes/sun/nio/ch/KQueuePort.java
Normal file
|
@ -0,0 +1,331 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 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.spi.AsynchronousChannelProvider;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import static sun.nio.ch.KQueue.*;
|
||||
|
||||
/**
|
||||
* AsynchronousChannelGroup implementation based on the BSD kqueue facility.
|
||||
*/
|
||||
|
||||
final class KQueuePort
|
||||
extends Port
|
||||
{
|
||||
// maximum number of events to poll at a time
|
||||
private static final int MAX_KEVENTS_TO_POLL = 512;
|
||||
|
||||
// kqueue file descriptor
|
||||
private final int kqfd;
|
||||
|
||||
// true if kqueue closed
|
||||
private boolean closed;
|
||||
|
||||
// socket pair used for wakeup
|
||||
private final int sp[];
|
||||
|
||||
// number of wakeups pending
|
||||
private final AtomicInteger wakeupCount = new AtomicInteger();
|
||||
|
||||
// address of the poll array passed to kqueue_wait
|
||||
private final long address;
|
||||
|
||||
// encapsulates an event for a channel
|
||||
static class Event {
|
||||
final PollableChannel channel;
|
||||
final int events;
|
||||
|
||||
Event(PollableChannel channel, int events) {
|
||||
this.channel = channel;
|
||||
this.events = events;
|
||||
}
|
||||
|
||||
PollableChannel channel() { return channel; }
|
||||
int events() { return events; }
|
||||
}
|
||||
|
||||
// queue of events for cases that a polling thread dequeues more than one
|
||||
// event
|
||||
private final ArrayBlockingQueue<Event> queue;
|
||||
private final Event NEED_TO_POLL = new Event(null, 0);
|
||||
private final Event EXECUTE_TASK_OR_SHUTDOWN = new Event(null, 0);
|
||||
|
||||
KQueuePort(AsynchronousChannelProvider provider, ThreadPool pool)
|
||||
throws IOException
|
||||
{
|
||||
super(provider, pool);
|
||||
|
||||
// open kqueue
|
||||
this.kqfd = kqueue();
|
||||
|
||||
// create socket pair for wakeup mechanism
|
||||
int[] sv = new int[2];
|
||||
try {
|
||||
socketpair(sv);
|
||||
|
||||
// register one end with kqueue
|
||||
keventRegister(kqfd, sv[0], EVFILT_READ, EV_ADD);
|
||||
} catch (IOException x) {
|
||||
close0(kqfd);
|
||||
throw x;
|
||||
}
|
||||
this.sp = sv;
|
||||
|
||||
// allocate the poll array
|
||||
this.address = allocatePollArray(MAX_KEVENTS_TO_POLL);
|
||||
|
||||
// create the queue and offer the special event to ensure that the first
|
||||
// threads polls
|
||||
this.queue = new ArrayBlockingQueue<Event>(MAX_KEVENTS_TO_POLL);
|
||||
this.queue.offer(NEED_TO_POLL);
|
||||
}
|
||||
|
||||
KQueuePort start() {
|
||||
startThreads(new EventHandlerTask());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release all resources
|
||||
*/
|
||||
private void implClose() {
|
||||
synchronized (this) {
|
||||
if (closed)
|
||||
return;
|
||||
closed = true;
|
||||
}
|
||||
freePollArray(address);
|
||||
close0(sp[0]);
|
||||
close0(sp[1]);
|
||||
close0(kqfd);
|
||||
}
|
||||
|
||||
private void wakeup() {
|
||||
if (wakeupCount.incrementAndGet() == 1) {
|
||||
// write byte to socketpair to force wakeup
|
||||
try {
|
||||
interrupt(sp[1]);
|
||||
} catch (IOException x) {
|
||||
throw new AssertionError(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void executeOnHandlerTask(Runnable task) {
|
||||
synchronized (this) {
|
||||
if (closed)
|
||||
throw new RejectedExecutionException();
|
||||
offerTask(task);
|
||||
wakeup();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void shutdownHandlerTasks() {
|
||||
/*
|
||||
* If no tasks are running then just release resources; otherwise
|
||||
* write to the one end of the socketpair to wakeup any polling threads.
|
||||
*/
|
||||
int nThreads = threadCount();
|
||||
if (nThreads == 0) {
|
||||
implClose();
|
||||
} else {
|
||||
// send interrupt to each thread
|
||||
while (nThreads-- > 0) {
|
||||
wakeup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// invoked by clients to register a file descriptor
|
||||
@Override
|
||||
void startPoll(int fd, int events) {
|
||||
// We use a separate filter for read and write events.
|
||||
// TBD: Measure cost of EV_ONESHOT vs. EV_CLEAR, either will do here.
|
||||
int err = 0;
|
||||
int flags = (EV_ADD|EV_ONESHOT);
|
||||
if ((events & Net.POLLIN) > 0)
|
||||
err = keventRegister(kqfd, fd, EVFILT_READ, flags);
|
||||
if (err == 0 && (events & Net.POLLOUT) > 0)
|
||||
err = keventRegister(kqfd, fd, EVFILT_WRITE, flags);
|
||||
if (err != 0)
|
||||
throw new InternalError("kevent failed: " + err); // should not happen
|
||||
}
|
||||
|
||||
/*
|
||||
* Task to process events from kqueue and dispatch to the channel's
|
||||
* onEvent handler.
|
||||
*
|
||||
* Events are retreived from kqueue in batch and offered to a BlockingQueue
|
||||
* where they are consumed by handler threads. A special "NEED_TO_POLL"
|
||||
* event is used to signal one consumer to re-poll when all events have
|
||||
* been consumed.
|
||||
*/
|
||||
private class EventHandlerTask implements Runnable {
|
||||
private Event poll() throws IOException {
|
||||
try {
|
||||
for (;;) {
|
||||
int n = keventPoll(kqfd, address, MAX_KEVENTS_TO_POLL);
|
||||
/*
|
||||
* 'n' events have been read. Here we map them to their
|
||||
* corresponding channel in batch and queue n-1 so that
|
||||
* they can be handled by other handler threads. The last
|
||||
* event is handled by this thread (and so is not queued).
|
||||
*/
|
||||
fdToChannelLock.readLock().lock();
|
||||
try {
|
||||
while (n-- > 0) {
|
||||
long keventAddress = getEvent(address, n);
|
||||
int fd = getDescriptor(keventAddress);
|
||||
|
||||
// wakeup
|
||||
if (fd == sp[0]) {
|
||||
if (wakeupCount.decrementAndGet() == 0) {
|
||||
// no more wakeups so drain pipe
|
||||
drain1(sp[0]);
|
||||
}
|
||||
|
||||
// queue special event if there are more events
|
||||
// to handle.
|
||||
if (n > 0) {
|
||||
queue.offer(EXECUTE_TASK_OR_SHUTDOWN);
|
||||
continue;
|
||||
}
|
||||
return EXECUTE_TASK_OR_SHUTDOWN;
|
||||
}
|
||||
|
||||
PollableChannel channel = fdToChannel.get(fd);
|
||||
if (channel != null) {
|
||||
int filter = getFilter(keventAddress);
|
||||
int events = 0;
|
||||
if (filter == EVFILT_READ)
|
||||
events = Net.POLLIN;
|
||||
else if (filter == EVFILT_WRITE)
|
||||
events = Net.POLLOUT;
|
||||
|
||||
Event ev = new Event(channel, events);
|
||||
|
||||
// n-1 events are queued; This thread handles
|
||||
// the last one except for the wakeup
|
||||
if (n > 0) {
|
||||
queue.offer(ev);
|
||||
} else {
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
fdToChannelLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// to ensure that some thread will poll when all events have
|
||||
// been consumed
|
||||
queue.offer(NEED_TO_POLL);
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
Invoker.GroupAndInvokeCount myGroupAndInvokeCount =
|
||||
Invoker.getGroupAndInvokeCount();
|
||||
final boolean isPooledThread = (myGroupAndInvokeCount != null);
|
||||
boolean replaceMe = false;
|
||||
Event ev;
|
||||
try {
|
||||
for (;;) {
|
||||
// reset invoke count
|
||||
if (isPooledThread)
|
||||
myGroupAndInvokeCount.resetInvokeCount();
|
||||
|
||||
try {
|
||||
replaceMe = false;
|
||||
ev = queue.take();
|
||||
|
||||
// no events and this thread has been "selected" to
|
||||
// poll for more.
|
||||
if (ev == NEED_TO_POLL) {
|
||||
try {
|
||||
ev = poll();
|
||||
} catch (IOException x) {
|
||||
x.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException x) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// handle wakeup to execute task or shutdown
|
||||
if (ev == EXECUTE_TASK_OR_SHUTDOWN) {
|
||||
Runnable task = pollTask();
|
||||
if (task == null) {
|
||||
// shutdown request
|
||||
return;
|
||||
}
|
||||
// run task (may throw error/exception)
|
||||
replaceMe = true;
|
||||
task.run();
|
||||
continue;
|
||||
}
|
||||
|
||||
// process event
|
||||
try {
|
||||
ev.channel().onEvent(ev.events(), isPooledThread);
|
||||
} catch (Error x) {
|
||||
replaceMe = true; throw x;
|
||||
} catch (RuntimeException x) {
|
||||
replaceMe = true; throw x;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// last handler to exit when shutdown releases resources
|
||||
int remaining = threadExit(this, replaceMe);
|
||||
if (remaining == 0 && isShutdown()) {
|
||||
implClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -- Native methods --
|
||||
|
||||
private static native void socketpair(int[] sv) throws IOException;
|
||||
|
||||
private static native void interrupt(int fd) throws IOException;
|
||||
|
||||
private static native void drain1(int fd) throws IOException;
|
||||
|
||||
private static native void close0(int fd);
|
||||
|
||||
static {
|
||||
IOUtil.load();
|
||||
}
|
||||
}
|
262
src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java
Normal file
262
src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java
Normal file
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* KQueueSelectorImpl.java
|
||||
* Implementation of Selector using FreeBSD / Mac OS X kqueues
|
||||
* Derived from Sun's DevPollSelectorImpl
|
||||
*/
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.FileDescriptor;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.channels.spi.*;
|
||||
import java.util.*;
|
||||
|
||||
class KQueueSelectorImpl
|
||||
extends SelectorImpl
|
||||
{
|
||||
// File descriptors used for interrupt
|
||||
protected int fd0;
|
||||
protected int fd1;
|
||||
|
||||
// The kqueue manipulator
|
||||
KQueueArrayWrapper kqueueWrapper;
|
||||
|
||||
// Count of registered descriptors (including interrupt)
|
||||
private int totalChannels;
|
||||
|
||||
// Map from a file descriptor to an entry containing the selection key
|
||||
private HashMap<Integer,MapEntry> fdMap;
|
||||
|
||||
// True if this Selector has been closed
|
||||
private boolean closed = false;
|
||||
|
||||
// Lock for interrupt triggering and clearing
|
||||
private Object interruptLock = new Object();
|
||||
private boolean interruptTriggered = false;
|
||||
|
||||
// used by updateSelectedKeys to handle cases where the same file
|
||||
// descriptor is polled by more than one filter
|
||||
private long updateCount;
|
||||
|
||||
// Used to map file descriptors to a selection key and "update count"
|
||||
// (see updateSelectedKeys for usage).
|
||||
private static class MapEntry {
|
||||
SelectionKeyImpl ski;
|
||||
long updateCount;
|
||||
MapEntry(SelectionKeyImpl ski) {
|
||||
this.ski = ski;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Package private constructor called by factory method in
|
||||
* the abstract superclass Selector.
|
||||
*/
|
||||
KQueueSelectorImpl(SelectorProvider sp) {
|
||||
super(sp);
|
||||
long fds = IOUtil.makePipe(false);
|
||||
fd0 = (int)(fds >>> 32);
|
||||
fd1 = (int)fds;
|
||||
try {
|
||||
kqueueWrapper = new KQueueArrayWrapper();
|
||||
kqueueWrapper.initInterrupt(fd0, fd1);
|
||||
fdMap = new HashMap<>();
|
||||
totalChannels = 1;
|
||||
} catch (Throwable t) {
|
||||
try {
|
||||
FileDispatcherImpl.closeIntFD(fd0);
|
||||
} catch (IOException ioe0) {
|
||||
t.addSuppressed(ioe0);
|
||||
}
|
||||
try {
|
||||
FileDispatcherImpl.closeIntFD(fd1);
|
||||
} catch (IOException ioe1) {
|
||||
t.addSuppressed(ioe1);
|
||||
}
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected int doSelect(long timeout)
|
||||
throws IOException
|
||||
{
|
||||
int entries = 0;
|
||||
if (closed)
|
||||
throw new ClosedSelectorException();
|
||||
processDeregisterQueue();
|
||||
try {
|
||||
begin();
|
||||
entries = kqueueWrapper.poll(timeout);
|
||||
} finally {
|
||||
end();
|
||||
}
|
||||
processDeregisterQueue();
|
||||
return updateSelectedKeys(entries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the keys whose fd's have been selected by kqueue.
|
||||
* Add the ready keys to the selected key set.
|
||||
* If the interrupt fd has been selected, drain it and clear the interrupt.
|
||||
*/
|
||||
private int updateSelectedKeys(int entries)
|
||||
throws IOException
|
||||
{
|
||||
int numKeysUpdated = 0;
|
||||
boolean interrupted = false;
|
||||
|
||||
// A file descriptor may be registered with kqueue with more than one
|
||||
// filter and so there may be more than one event for a fd. The update
|
||||
// count in the MapEntry tracks when the fd was last updated and this
|
||||
// ensures that the ready ops are updated rather than replaced by a
|
||||
// second or subsequent event.
|
||||
updateCount++;
|
||||
|
||||
for (int i = 0; i < entries; i++) {
|
||||
int nextFD = kqueueWrapper.getDescriptor(i);
|
||||
if (nextFD == fd0) {
|
||||
interrupted = true;
|
||||
} else {
|
||||
MapEntry me = fdMap.get(Integer.valueOf(nextFD));
|
||||
|
||||
// entry is null in the case of an interrupt
|
||||
if (me != null) {
|
||||
int rOps = kqueueWrapper.getReventOps(i);
|
||||
SelectionKeyImpl ski = me.ski;
|
||||
if (selectedKeys.contains(ski)) {
|
||||
// first time this file descriptor has been encountered on this
|
||||
// update?
|
||||
if (me.updateCount != updateCount) {
|
||||
if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
|
||||
numKeysUpdated++;
|
||||
me.updateCount = updateCount;
|
||||
}
|
||||
} else {
|
||||
// ready ops have already been set on this update
|
||||
ski.channel.translateAndUpdateReadyOps(rOps, ski);
|
||||
}
|
||||
} else {
|
||||
ski.channel.translateAndSetReadyOps(rOps, ski);
|
||||
if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
|
||||
selectedKeys.add(ski);
|
||||
numKeysUpdated++;
|
||||
me.updateCount = updateCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (interrupted) {
|
||||
// Clear the wakeup pipe
|
||||
synchronized (interruptLock) {
|
||||
IOUtil.drain(fd0);
|
||||
interruptTriggered = false;
|
||||
}
|
||||
}
|
||||
return numKeysUpdated;
|
||||
}
|
||||
|
||||
|
||||
protected void implClose() throws IOException {
|
||||
if (!closed) {
|
||||
closed = true;
|
||||
|
||||
// prevent further wakeup
|
||||
synchronized (interruptLock) {
|
||||
interruptTriggered = true;
|
||||
}
|
||||
|
||||
FileDispatcherImpl.closeIntFD(fd0);
|
||||
FileDispatcherImpl.closeIntFD(fd1);
|
||||
if (kqueueWrapper != null) {
|
||||
kqueueWrapper.close();
|
||||
kqueueWrapper = null;
|
||||
selectedKeys = null;
|
||||
|
||||
// Deregister channels
|
||||
Iterator<SelectionKey> i = keys.iterator();
|
||||
while (i.hasNext()) {
|
||||
SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
|
||||
deregister(ski);
|
||||
SelectableChannel selch = ski.channel();
|
||||
if (!selch.isOpen() && !selch.isRegistered())
|
||||
((SelChImpl)selch).kill();
|
||||
i.remove();
|
||||
}
|
||||
totalChannels = 0;
|
||||
}
|
||||
fd0 = -1;
|
||||
fd1 = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void implRegister(SelectionKeyImpl ski) {
|
||||
if (closed)
|
||||
throw new ClosedSelectorException();
|
||||
int fd = IOUtil.fdVal(ski.channel.getFD());
|
||||
fdMap.put(Integer.valueOf(fd), new MapEntry(ski));
|
||||
totalChannels++;
|
||||
keys.add(ski);
|
||||
}
|
||||
|
||||
|
||||
protected void implDereg(SelectionKeyImpl ski) throws IOException {
|
||||
int fd = ski.channel.getFDVal();
|
||||
fdMap.remove(Integer.valueOf(fd));
|
||||
kqueueWrapper.release(ski.channel);
|
||||
totalChannels--;
|
||||
keys.remove(ski);
|
||||
selectedKeys.remove(ski);
|
||||
deregister((AbstractSelectionKey)ski);
|
||||
SelectableChannel selch = ski.channel();
|
||||
if (!selch.isOpen() && !selch.isRegistered())
|
||||
((SelChImpl)selch).kill();
|
||||
}
|
||||
|
||||
|
||||
public void putEventOps(SelectionKeyImpl ski, int ops) {
|
||||
if (closed)
|
||||
throw new ClosedSelectorException();
|
||||
kqueueWrapper.setInterest(ski.channel, ops);
|
||||
}
|
||||
|
||||
|
||||
public Selector wakeup() {
|
||||
synchronized (interruptLock) {
|
||||
if (!interruptTriggered) {
|
||||
kqueueWrapper.interrupt();
|
||||
interruptTriggered = true;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* KQueueSelectorProvider.java
|
||||
* Implementation of Selector using FreeBSD / Mac OS X kqueues
|
||||
* Derived from Sun's DevPollSelectorProvider
|
||||
*/
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.channels.spi.*;
|
||||
|
||||
public class KQueueSelectorProvider
|
||||
extends SelectorProviderImpl
|
||||
{
|
||||
public AbstractSelector openSelector() throws IOException {
|
||||
return new KQueueSelectorImpl(this);
|
||||
}
|
||||
}
|
88
src/java.base/macosx/classes/sun/nio/fs/BsdFileStore.java
Normal file
88
src/java.base/macosx/classes/sun/nio/fs/BsdFileStore.java
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* 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.fs;
|
||||
|
||||
import java.nio.file.attribute.*;
|
||||
import java.util.*;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Bsd implementation of FileStore
|
||||
*/
|
||||
|
||||
class BsdFileStore
|
||||
extends UnixFileStore
|
||||
{
|
||||
BsdFileStore(UnixPath file) throws IOException {
|
||||
super(file);
|
||||
}
|
||||
|
||||
BsdFileStore(UnixFileSystem fs, UnixMountEntry entry) throws IOException {
|
||||
super(fs, entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds, and returns, the mount entry for the file system where the file
|
||||
* resides.
|
||||
*/
|
||||
@Override
|
||||
UnixMountEntry findMountEntry() throws IOException {
|
||||
UnixFileSystem fs = file().getFileSystem();
|
||||
|
||||
// step 1: get realpath
|
||||
UnixPath path = null;
|
||||
try {
|
||||
byte[] rp = UnixNativeDispatcher.realpath(file());
|
||||
path = new UnixPath(fs, rp);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file());
|
||||
}
|
||||
|
||||
// step 2: find mount point
|
||||
UnixPath parent = path.getParent();
|
||||
while (parent != null) {
|
||||
UnixFileAttributes attrs = null;
|
||||
try {
|
||||
attrs = UnixFileAttributes.get(parent, true);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(parent);
|
||||
}
|
||||
if (attrs.dev() != dev())
|
||||
break;
|
||||
path = parent;
|
||||
parent = parent.getParent();
|
||||
}
|
||||
|
||||
// step 3: lookup mounted file systems
|
||||
byte[] dir = path.asByteArray();
|
||||
for (UnixMountEntry entry: fs.getMountEntries()) {
|
||||
if (Arrays.equals(dir, entry.dir()))
|
||||
return entry;
|
||||
}
|
||||
|
||||
throw new IOException("Mount point not found in fstab");
|
||||
}
|
||||
}
|
104
src/java.base/macosx/classes/sun/nio/fs/BsdFileSystem.java
Normal file
104
src/java.base/macosx/classes/sun/nio/fs/BsdFileSystem.java
Normal file
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* 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.fs;
|
||||
|
||||
import java.nio.file.*;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.security.AccessController;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/**
|
||||
* Bsd implementation of FileSystem
|
||||
*/
|
||||
|
||||
class BsdFileSystem extends UnixFileSystem {
|
||||
|
||||
BsdFileSystem(UnixFileSystemProvider provider, String dir) {
|
||||
super(provider, dir);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WatchService newWatchService()
|
||||
throws IOException
|
||||
{
|
||||
// use polling implementation until we implement a BSD/kqueue one
|
||||
return new PollingWatchService();
|
||||
}
|
||||
|
||||
// lazy initialization of the list of supported attribute views
|
||||
private static class SupportedFileFileAttributeViewsHolder {
|
||||
static final Set<String> supportedFileAttributeViews =
|
||||
supportedFileAttributeViews();
|
||||
private static Set<String> supportedFileAttributeViews() {
|
||||
Set<String> result = new HashSet<String>();
|
||||
result.addAll(standardFileAttributeViews());
|
||||
return Collections.unmodifiableSet(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> supportedFileAttributeViews() {
|
||||
return SupportedFileFileAttributeViewsHolder.supportedFileAttributeViews;
|
||||
}
|
||||
|
||||
@Override
|
||||
void copyNonPosixAttributes(int ofd, int nfd) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns object to iterate over mount entries
|
||||
*/
|
||||
@Override
|
||||
Iterable<UnixMountEntry> getMountEntries() {
|
||||
ArrayList<UnixMountEntry> entries = new ArrayList<UnixMountEntry>();
|
||||
try {
|
||||
long iter = BsdNativeDispatcher.getfsstat();
|
||||
try {
|
||||
for (;;) {
|
||||
UnixMountEntry entry = new UnixMountEntry();
|
||||
int res = BsdNativeDispatcher.fsstatEntry(iter, entry);
|
||||
if (res < 0)
|
||||
break;
|
||||
entries.add(entry);
|
||||
}
|
||||
} finally {
|
||||
BsdNativeDispatcher.endfsstat(iter);
|
||||
}
|
||||
|
||||
} catch (UnixException x) {
|
||||
// nothing we can do
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
FileStore getFileStore(UnixMountEntry entry) throws IOException {
|
||||
return new BsdFileStore(this, entry);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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.fs;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Bsd implementation of FileSystemProvider
|
||||
*/
|
||||
|
||||
public class BsdFileSystemProvider extends UnixFileSystemProvider {
|
||||
public BsdFileSystemProvider() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
BsdFileSystem newFileSystem(String dir) {
|
||||
return new BsdFileSystem(this, dir);
|
||||
}
|
||||
|
||||
@Override
|
||||
BsdFileStore getFileStore(UnixPath path) throws IOException {
|
||||
return new BsdFileStore(path);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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.fs;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
/**
|
||||
* Bsd specific system calls.
|
||||
*/
|
||||
|
||||
class BsdNativeDispatcher extends UnixNativeDispatcher {
|
||||
protected BsdNativeDispatcher() { }
|
||||
|
||||
/**
|
||||
* struct fsstat_iter *getfsstat();
|
||||
*/
|
||||
static native long getfsstat() throws UnixException;
|
||||
|
||||
/**
|
||||
* int fsstatEntry(struct fsstat_iter * iter, UnixMountEntry entry);
|
||||
*/
|
||||
static native int fsstatEntry(long iter, UnixMountEntry entry)
|
||||
throws UnixException;
|
||||
|
||||
/**
|
||||
* void endfsstat(struct fsstat_iter * iter);
|
||||
*/
|
||||
static native void endfsstat(long iter) throws UnixException;
|
||||
|
||||
// initialize field IDs
|
||||
private static native void initIDs();
|
||||
|
||||
static {
|
||||
initIDs();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 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.fs;
|
||||
|
||||
import java.nio.file.spi.FileSystemProvider;
|
||||
|
||||
/**
|
||||
* Creates this platform's default FileSystemProvider.
|
||||
*/
|
||||
|
||||
public class DefaultFileSystemProvider {
|
||||
private DefaultFileSystemProvider() { }
|
||||
|
||||
/**
|
||||
* Returns the default FileSystemProvider.
|
||||
*/
|
||||
public static FileSystemProvider create() {
|
||||
return new MacOSXFileSystemProvider();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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.fs;
|
||||
|
||||
import java.nio.file.*;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static sun.nio.fs.MacOSXNativeDispatcher.*;
|
||||
|
||||
/**
|
||||
* MacOS implementation of FileSystem
|
||||
*/
|
||||
|
||||
class MacOSXFileSystem extends BsdFileSystem {
|
||||
|
||||
MacOSXFileSystem(UnixFileSystemProvider provider, String dir) {
|
||||
super(provider, dir);
|
||||
}
|
||||
|
||||
// match in unicode canon_eq
|
||||
Pattern compilePathMatchPattern(String expr) {
|
||||
return Pattern.compile(expr, Pattern.CANON_EQ) ;
|
||||
}
|
||||
|
||||
char[] normalizeNativePath(char[] path) {
|
||||
for (char c : path) {
|
||||
if (c > 0x80)
|
||||
return normalizepath(path, kCFStringNormalizationFormD);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
String normalizeJavaPath(String path) {
|
||||
for (int i = 0; i < path.length(); i++) {
|
||||
if (path.charAt(i) > 0x80)
|
||||
return new String(normalizepath(path.toCharArray(),
|
||||
kCFStringNormalizationFormC));
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 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.fs;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.spi.FileTypeDetector;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/**
|
||||
* MacOSX implementation of FileSystemProvider
|
||||
*/
|
||||
|
||||
public class MacOSXFileSystemProvider extends BsdFileSystemProvider {
|
||||
public MacOSXFileSystemProvider() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
MacOSXFileSystem newFileSystem(String dir) {
|
||||
return new MacOSXFileSystem(this, dir);
|
||||
}
|
||||
|
||||
@Override
|
||||
FileTypeDetector getFileTypeDetector() {
|
||||
Path userMimeTypes = Paths.get(GetPropertyAction
|
||||
.privilegedGetProperty("user.home"), ".mime.types");
|
||||
|
||||
return chain(new MimeTypesFileTypeDetector(userMimeTypes),
|
||||
new UTIFileTypeDetector());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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.fs;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
/**
|
||||
* MacOSX specific system calls.
|
||||
*/
|
||||
|
||||
class MacOSXNativeDispatcher extends BsdNativeDispatcher {
|
||||
private MacOSXNativeDispatcher() { }
|
||||
|
||||
static final int kCFStringNormalizationFormC = 2;
|
||||
static final int kCFStringNormalizationFormD = 0;
|
||||
static native char[] normalizepath(char[] path, int form);
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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.fs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
/**
|
||||
* File type detector that uses a file extension to look up its MIME type
|
||||
* via the Apple Uniform Type Identifier interfaces.
|
||||
*/
|
||||
class UTIFileTypeDetector extends AbstractFileTypeDetector {
|
||||
UTIFileTypeDetector() {
|
||||
super();
|
||||
}
|
||||
|
||||
private native String probe0(String fileExtension) throws IOException;
|
||||
|
||||
@Override
|
||||
protected String implProbeContentType(Path path) throws IOException {
|
||||
Path fn = path.getFileName();
|
||||
if (fn == null)
|
||||
return null; // no file name
|
||||
|
||||
String ext = getExtension(fn.toString());
|
||||
if (ext.isEmpty())
|
||||
return null; // no extension
|
||||
|
||||
return probe0(ext);
|
||||
}
|
||||
|
||||
static {
|
||||
AccessController.doPrivileged(new PrivilegedAction<>() {
|
||||
@Override
|
||||
public Void run() {
|
||||
System.loadLibrary("nio");
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,909 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 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.util.locale.provider;
|
||||
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.text.*;
|
||||
import java.text.spi.DateFormatProvider;
|
||||
import java.text.spi.DateFormatSymbolsProvider;
|
||||
import java.text.spi.DecimalFormatSymbolsProvider;
|
||||
import java.text.spi.NumberFormatProvider;
|
||||
import java.util.Collections;
|
||||
import java.util.Calendar;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle.Control;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||
import java.util.spi.CalendarDataProvider;
|
||||
import java.util.spi.CalendarNameProvider;
|
||||
import java.util.spi.CurrencyNameProvider;
|
||||
import java.util.spi.LocaleNameProvider;
|
||||
import java.util.spi.TimeZoneNameProvider;
|
||||
import sun.text.spi.JavaTimeDateTimePatternProvider;
|
||||
import sun.util.spi.CalendarProvider;
|
||||
|
||||
/**
|
||||
* LocaleProviderAdapter implementation for the Mac OS X locale data
|
||||
*
|
||||
* @author Naoto Sato
|
||||
*/
|
||||
public class HostLocaleProviderAdapterImpl {
|
||||
|
||||
// per supported locale instances
|
||||
private static final ConcurrentMap<Locale, SoftReference<AtomicReferenceArray<String>>> dateFormatPatternsMap =
|
||||
new ConcurrentHashMap<>(2);
|
||||
private static final ConcurrentMap<Locale, SoftReference<AtomicReferenceArray<String>>> numberFormatPatternsMap =
|
||||
new ConcurrentHashMap<>(2);
|
||||
private static final ConcurrentMap<Locale, SoftReference<DateFormatSymbols>> dateFormatSymbolsMap =
|
||||
new ConcurrentHashMap<>(2);
|
||||
private static final ConcurrentMap<Locale, SoftReference<DecimalFormatSymbols>> decimalFormatSymbolsMap =
|
||||
new ConcurrentHashMap<>(2);
|
||||
|
||||
// locale categories
|
||||
private static final int CAT_DISPLAY = 0;
|
||||
private static final int CAT_FORMAT = 1;
|
||||
|
||||
// NumberFormat styles
|
||||
private static final int NF_NUMBER = 0;
|
||||
private static final int NF_CURRENCY = 1;
|
||||
private static final int NF_PERCENT = 2;
|
||||
private static final int NF_INTEGER = 3;
|
||||
private static final int NF_MAX = NF_INTEGER;
|
||||
|
||||
// CalendarData value types
|
||||
private static final int CD_FIRSTDAYOFWEEK = 0;
|
||||
private static final int CD_MINIMALDAYSINFIRSTWEEK = 1;
|
||||
|
||||
// Locale/Currency display name types
|
||||
private static final int DN_LOCALE_LANGUAGE = 0;
|
||||
private static final int DN_LOCALE_SCRIPT = 1;
|
||||
private static final int DN_LOCALE_REGION = 2;
|
||||
private static final int DN_LOCALE_VARIANT = 3;
|
||||
private static final int DN_CURRENCY_CODE = 4;
|
||||
private static final int DN_CURRENCY_SYMBOL = 5;
|
||||
|
||||
// TimeZone display name types
|
||||
private static final int DN_TZ_SHORT_STANDARD = 0;
|
||||
private static final int DN_TZ_SHORT_DST = 1;
|
||||
private static final int DN_TZ_LONG_STANDARD = 2;
|
||||
private static final int DN_TZ_LONG_DST = 3;
|
||||
|
||||
private static final Set<Locale> supportedLocaleSet;
|
||||
static {
|
||||
Set<Locale> tmpSet = new HashSet<>();
|
||||
// Assuming the default locales do not include any extensions, so
|
||||
// no stripping is needed here.
|
||||
Locale l = convertMacOSXLocaleToJavaLocale(getDefaultLocale(CAT_FORMAT));
|
||||
tmpSet.addAll(Control.getNoFallbackControl(Control.FORMAT_DEFAULT).getCandidateLocales("", l));
|
||||
l = convertMacOSXLocaleToJavaLocale(getDefaultLocale(CAT_DISPLAY));
|
||||
tmpSet.addAll(Control.getNoFallbackControl(Control.FORMAT_DEFAULT).getCandidateLocales("", l));
|
||||
supportedLocaleSet = Collections.unmodifiableSet(tmpSet);
|
||||
}
|
||||
private static final Locale[] supportedLocale = supportedLocaleSet.toArray(new Locale[0]);
|
||||
|
||||
@SuppressWarnings("fallthrough")
|
||||
private static Locale convertMacOSXLocaleToJavaLocale(String macosxloc) {
|
||||
// MacOSX may return ICU notation, here is the quote from CFLocale doc:
|
||||
// "The corresponding value is a CFString containing the POSIX locale
|
||||
// identifier as used by ICU, such as "ja_JP". If you have a variant
|
||||
// locale or a different currency or calendar, it can be as complex as
|
||||
// "en_US_POSIX@calendar=japanese;currency=EUR" or
|
||||
// "az_Cyrl_AZ@calendar=buddhist;currency=JPY".
|
||||
String[] tmp = macosxloc.split("@");
|
||||
String langTag = tmp[0].replace('_', '-');
|
||||
if (tmp.length > 1) {
|
||||
String[] ext = tmp[1].split(";");
|
||||
for (String keyval : ext) {
|
||||
// We are only interested in "calendar" value for now.
|
||||
if (keyval.startsWith("calendar=")) {
|
||||
String calid = keyval.substring(keyval.indexOf('=')+1);
|
||||
switch (calid) {
|
||||
case "gregorian":
|
||||
langTag += "-u-ca-gregory";
|
||||
break;
|
||||
case "japanese":
|
||||
// Tweak for ja_JP_JP
|
||||
if (tmp[0].equals("ja_JP")) {
|
||||
return JRELocaleConstants.JA_JP_JP;
|
||||
}
|
||||
|
||||
// fall through
|
||||
|
||||
default:
|
||||
langTag += "-u-ca-" + calid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Locale.forLanguageTag(langTag);
|
||||
}
|
||||
|
||||
public static JavaTimeDateTimePatternProvider getJavaTimeDateTimePatternProvider() {
|
||||
return new JavaTimeDateTimePatternProvider() {
|
||||
@Override
|
||||
public Locale[] getAvailableLocales() {
|
||||
return getSupportedCalendarLocales();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupportedLocale(Locale locale) {
|
||||
return isSupportedCalendarLocale(locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJavaTimeDateTimePattern(int timeStyle, int dateStyle, String calType, Locale locale) {
|
||||
return toJavaTimeDateTimePattern(calType, getDateTimePattern(dateStyle, timeStyle, locale));
|
||||
|
||||
}
|
||||
|
||||
private String getDateTimePattern(int dateStyle, int timeStyle, Locale locale) {
|
||||
AtomicReferenceArray<String> dateFormatPatterns;
|
||||
SoftReference<AtomicReferenceArray<String>> ref = dateFormatPatternsMap.get(locale);
|
||||
|
||||
if (ref == null || (dateFormatPatterns = ref.get()) == null) {
|
||||
dateFormatPatterns = new AtomicReferenceArray<>(5 * 5);
|
||||
ref = new SoftReference<>(dateFormatPatterns);
|
||||
dateFormatPatternsMap.put(locale, ref);
|
||||
}
|
||||
int index = (dateStyle + 1) * 5 + timeStyle + 1;
|
||||
String pattern = dateFormatPatterns.get(index);
|
||||
if (pattern == null) {
|
||||
String langTag = locale.toLanguageTag();
|
||||
pattern = translateDateFormatLetters(getCalendarID(langTag),
|
||||
getDateTimePatternNative(dateStyle, timeStyle, langTag));
|
||||
if (!dateFormatPatterns.compareAndSet(index, null, pattern)) {
|
||||
pattern = dateFormatPatterns.get(index);
|
||||
}
|
||||
}
|
||||
return pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will convert JRE Date/time Pattern String to JSR310
|
||||
* type Date/Time Pattern
|
||||
*/
|
||||
private String toJavaTimeDateTimePattern(String calendarType, String jrePattern) {
|
||||
int length = jrePattern.length();
|
||||
StringBuilder sb = new StringBuilder(length);
|
||||
boolean inQuote = false;
|
||||
int count = 0;
|
||||
char lastLetter = 0;
|
||||
for (int i = 0; i < length; i++) {
|
||||
char c = jrePattern.charAt(i);
|
||||
if (c == '\'') {
|
||||
// '' is treated as a single quote regardless of being
|
||||
// in a quoted section.
|
||||
if ((i + 1) < length) {
|
||||
char nextc = jrePattern.charAt(i + 1);
|
||||
if (nextc == '\'') {
|
||||
i++;
|
||||
if (count != 0) {
|
||||
convert(calendarType, lastLetter, count, sb);
|
||||
lastLetter = 0;
|
||||
count = 0;
|
||||
}
|
||||
sb.append("''");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!inQuote) {
|
||||
if (count != 0) {
|
||||
convert(calendarType, lastLetter, count, sb);
|
||||
lastLetter = 0;
|
||||
count = 0;
|
||||
}
|
||||
inQuote = true;
|
||||
} else {
|
||||
inQuote = false;
|
||||
}
|
||||
sb.append(c);
|
||||
continue;
|
||||
}
|
||||
if (inQuote) {
|
||||
sb.append(c);
|
||||
continue;
|
||||
}
|
||||
if (!(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')) {
|
||||
if (count != 0) {
|
||||
convert(calendarType, lastLetter, count, sb);
|
||||
lastLetter = 0;
|
||||
count = 0;
|
||||
}
|
||||
sb.append(c);
|
||||
continue;
|
||||
}
|
||||
if (lastLetter == 0 || lastLetter == c) {
|
||||
lastLetter = c;
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
convert(calendarType, lastLetter, count, sb);
|
||||
lastLetter = c;
|
||||
count = 1;
|
||||
}
|
||||
if (inQuote) {
|
||||
// should not come here.
|
||||
// returning null so that FALLBACK provider will kick in.
|
||||
return null;
|
||||
}
|
||||
if (count != 0) {
|
||||
convert(calendarType, lastLetter, count, sb);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void convert(String calendarType, char letter, int count, StringBuilder sb) {
|
||||
switch (letter) {
|
||||
case 'G':
|
||||
if (calendarType.equals("japanese")) {
|
||||
if (count >= 4) {
|
||||
count = 1;
|
||||
} else {
|
||||
count = 5;
|
||||
}
|
||||
} else if (!calendarType.equals("iso8601")) {
|
||||
// Gregorian calendar is iso8601 for java.time
|
||||
// Adjust the number of 'G's
|
||||
if (count >= 4) {
|
||||
// JRE full -> JavaTime full
|
||||
count = 4;
|
||||
} else {
|
||||
// JRE short -> JavaTime short
|
||||
count = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'y':
|
||||
if (calendarType.equals("japanese") && count >= 4) {
|
||||
// JRE specific "gan-nen" support
|
||||
count = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// JSR 310 and CLDR define 5-letter patterns for narrow text.
|
||||
if (count > 4) {
|
||||
count = 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
appendN(letter, count, sb);
|
||||
}
|
||||
|
||||
private void appendN(char c, int n, StringBuilder sb) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static DateFormatProvider getDateFormatProvider() {
|
||||
return new DateFormatProvider() {
|
||||
|
||||
@Override
|
||||
public Locale[] getAvailableLocales() {
|
||||
return getSupportedCalendarLocales();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupportedLocale(Locale locale) {
|
||||
return isSupportedCalendarLocale(locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateFormat getDateInstance(int style, Locale locale) {
|
||||
return new SimpleDateFormat(getDateTimePattern(style, -1, locale),
|
||||
getCalendarLocale(locale));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateFormat getTimeInstance(int style, Locale locale) {
|
||||
return new SimpleDateFormat(getDateTimePattern(-1, style, locale),
|
||||
getCalendarLocale(locale));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateFormat getDateTimeInstance(int dateStyle,
|
||||
int timeStyle, Locale locale) {
|
||||
return new SimpleDateFormat(getDateTimePattern(dateStyle, timeStyle, locale),
|
||||
getCalendarLocale(locale));
|
||||
}
|
||||
|
||||
private String getDateTimePattern(int dateStyle, int timeStyle, Locale locale) {
|
||||
AtomicReferenceArray<String> dateFormatPatterns;
|
||||
SoftReference<AtomicReferenceArray<String>> ref = dateFormatPatternsMap.get(locale);
|
||||
|
||||
if (ref == null || (dateFormatPatterns = ref.get()) == null) {
|
||||
dateFormatPatterns = new AtomicReferenceArray<>(5 * 5);
|
||||
ref = new SoftReference<>(dateFormatPatterns);
|
||||
dateFormatPatternsMap.put(locale, ref);
|
||||
}
|
||||
|
||||
int index = (dateStyle + 1) * 5 + timeStyle + 1;
|
||||
String pattern = dateFormatPatterns.get(index);
|
||||
if (pattern == null) {
|
||||
String langTag = locale.toLanguageTag();
|
||||
pattern = translateDateFormatLetters(getCalendarID(langTag),
|
||||
getDateTimePatternNative(dateStyle, timeStyle, langTag));
|
||||
if (!dateFormatPatterns.compareAndSet(index, null, pattern)) {
|
||||
pattern = dateFormatPatterns.get(index);
|
||||
}
|
||||
}
|
||||
|
||||
return pattern;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static DateFormatSymbolsProvider getDateFormatSymbolsProvider() {
|
||||
return new DateFormatSymbolsProvider() {
|
||||
@Override
|
||||
public Locale[] getAvailableLocales() {
|
||||
if (isSupportedLocale(Locale.getDefault(Locale.Category.FORMAT))) {
|
||||
return supportedLocale;
|
||||
}
|
||||
return new Locale[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupportedLocale(Locale locale) {
|
||||
// Only supports the locale with Gregorian calendar
|
||||
Locale base = locale.stripExtensions();
|
||||
if (supportedLocaleSet.contains(base)) {
|
||||
return getCalendarID(locale.toLanguageTag()).equals("gregorian");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateFormatSymbols getInstance(Locale locale) {
|
||||
DateFormatSymbols dateFormatSymbols;
|
||||
SoftReference<DateFormatSymbols> ref = dateFormatSymbolsMap.get(locale);
|
||||
|
||||
if (ref == null || (dateFormatSymbols = ref.get()) == null) {
|
||||
dateFormatSymbols = new DateFormatSymbols(locale);
|
||||
String langTag = locale.toLanguageTag();
|
||||
dateFormatSymbols.setAmPmStrings(getAmPmStrings(langTag, dateFormatSymbols.getAmPmStrings()));
|
||||
dateFormatSymbols.setEras(getEras(langTag, dateFormatSymbols.getEras()));
|
||||
dateFormatSymbols.setMonths(getMonths(langTag, dateFormatSymbols.getMonths()));
|
||||
dateFormatSymbols.setShortMonths(getShortMonths(langTag, dateFormatSymbols.getShortMonths()));
|
||||
dateFormatSymbols.setWeekdays(getWeekdays(langTag, dateFormatSymbols.getWeekdays()));
|
||||
dateFormatSymbols.setShortWeekdays(getShortWeekdays(langTag, dateFormatSymbols.getShortWeekdays()));
|
||||
ref = new SoftReference<>(dateFormatSymbols);
|
||||
dateFormatSymbolsMap.put(locale, ref);
|
||||
}
|
||||
return (DateFormatSymbols)dateFormatSymbols.clone();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static NumberFormatProvider getNumberFormatProvider() {
|
||||
return new NumberFormatProvider() {
|
||||
@Override
|
||||
public Locale[] getAvailableLocales() {
|
||||
return supportedLocale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupportedLocale(Locale locale) {
|
||||
// Ignore the extensions for now
|
||||
return supportedLocaleSet.contains(locale.stripExtensions());
|
||||
}
|
||||
|
||||
@Override
|
||||
public NumberFormat getCurrencyInstance(Locale locale) {
|
||||
return new DecimalFormat(getNumberPattern(NF_CURRENCY, locale),
|
||||
DecimalFormatSymbols.getInstance(locale));
|
||||
}
|
||||
|
||||
@Override
|
||||
public NumberFormat getIntegerInstance(Locale locale) {
|
||||
return new DecimalFormat(getNumberPattern(NF_INTEGER, locale),
|
||||
DecimalFormatSymbols.getInstance(locale));
|
||||
}
|
||||
|
||||
@Override
|
||||
public NumberFormat getNumberInstance(Locale locale) {
|
||||
return new DecimalFormat(getNumberPattern(NF_NUMBER, locale),
|
||||
DecimalFormatSymbols.getInstance(locale));
|
||||
}
|
||||
|
||||
@Override
|
||||
public NumberFormat getPercentInstance(Locale locale) {
|
||||
return new DecimalFormat(getNumberPattern(NF_PERCENT, locale),
|
||||
DecimalFormatSymbols.getInstance(locale));
|
||||
}
|
||||
|
||||
private String getNumberPattern(int style, Locale locale) {
|
||||
AtomicReferenceArray<String> numberFormatPatterns;
|
||||
SoftReference<AtomicReferenceArray<String>> ref = numberFormatPatternsMap.get(locale);
|
||||
|
||||
if (ref == null || (numberFormatPatterns = ref.get()) == null) {
|
||||
numberFormatPatterns = new AtomicReferenceArray<>(4);
|
||||
ref = new SoftReference<>(numberFormatPatterns);
|
||||
numberFormatPatternsMap.put(locale, ref);
|
||||
}
|
||||
|
||||
String pattern = numberFormatPatterns.get(style);
|
||||
if (pattern == null) {
|
||||
pattern = getNumberPatternNative(style, locale.toLanguageTag());
|
||||
if (!numberFormatPatterns.compareAndSet(style, null, pattern)) {
|
||||
pattern = numberFormatPatterns.get(style);
|
||||
}
|
||||
}
|
||||
|
||||
return pattern;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static DecimalFormatSymbolsProvider getDecimalFormatSymbolsProvider() {
|
||||
return new DecimalFormatSymbolsProvider() {
|
||||
|
||||
@Override
|
||||
public Locale[] getAvailableLocales() {
|
||||
return supportedLocale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupportedLocale(Locale locale) {
|
||||
// Ignore the extensions for now
|
||||
return supportedLocaleSet.contains(locale.stripExtensions());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DecimalFormatSymbols getInstance(Locale locale) {
|
||||
DecimalFormatSymbols decimalFormatSymbols;
|
||||
SoftReference<DecimalFormatSymbols> ref = decimalFormatSymbolsMap.get(locale);
|
||||
|
||||
if (ref == null || (decimalFormatSymbols = ref.get()) == null) {
|
||||
decimalFormatSymbols = new DecimalFormatSymbols(locale);
|
||||
String langTag = locale.toLanguageTag();
|
||||
|
||||
// DecimalFormatSymbols.setInternationalCurrencySymbol() has
|
||||
// a side effect of setting the currency symbol as well. So
|
||||
// the calling order is relevant here.
|
||||
decimalFormatSymbols.setInternationalCurrencySymbol(getInternationalCurrencySymbol(langTag, decimalFormatSymbols.getInternationalCurrencySymbol()));
|
||||
decimalFormatSymbols.setCurrencySymbol(getCurrencySymbol(langTag, decimalFormatSymbols.getCurrencySymbol()));
|
||||
decimalFormatSymbols.setDecimalSeparator(getDecimalSeparator(langTag, decimalFormatSymbols.getDecimalSeparator()));
|
||||
decimalFormatSymbols.setGroupingSeparator(getGroupingSeparator(langTag, decimalFormatSymbols.getGroupingSeparator()));
|
||||
decimalFormatSymbols.setInfinity(getInfinity(langTag, decimalFormatSymbols.getInfinity()));
|
||||
decimalFormatSymbols.setMinusSign(getMinusSign(langTag, decimalFormatSymbols.getMinusSign()));
|
||||
decimalFormatSymbols.setMonetaryDecimalSeparator(getMonetaryDecimalSeparator(langTag, decimalFormatSymbols.getMonetaryDecimalSeparator()));
|
||||
decimalFormatSymbols.setNaN(getNaN(langTag, decimalFormatSymbols.getNaN()));
|
||||
decimalFormatSymbols.setPercent(getPercent(langTag, decimalFormatSymbols.getPercent()));
|
||||
decimalFormatSymbols.setPerMill(getPerMill(langTag, decimalFormatSymbols.getPerMill()));
|
||||
decimalFormatSymbols.setZeroDigit(getZeroDigit(langTag, decimalFormatSymbols.getZeroDigit()));
|
||||
decimalFormatSymbols.setExponentSeparator(getExponentSeparator(langTag, decimalFormatSymbols.getExponentSeparator()));
|
||||
ref = new SoftReference<>(decimalFormatSymbols);
|
||||
decimalFormatSymbolsMap.put(locale, ref);
|
||||
}
|
||||
return (DecimalFormatSymbols)decimalFormatSymbols.clone();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static CalendarDataProvider getCalendarDataProvider() {
|
||||
return new CalendarDataProvider() {
|
||||
@Override
|
||||
public Locale[] getAvailableLocales() {
|
||||
return getSupportedCalendarLocales();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupportedLocale(Locale locale) {
|
||||
return isSupportedCalendarLocale(locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFirstDayOfWeek(Locale locale) {
|
||||
return getCalendarInt(locale.toLanguageTag(), CD_FIRSTDAYOFWEEK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinimalDaysInFirstWeek(Locale locale) {
|
||||
return getCalendarInt(locale.toLanguageTag(), CD_MINIMALDAYSINFIRSTWEEK);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static CalendarNameProvider getCalendarNameProvider() {
|
||||
return new CalendarNameProvider() {
|
||||
@Override
|
||||
public Locale[] getAvailableLocales() {
|
||||
return getSupportedCalendarLocales();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupportedLocale(Locale locale) {
|
||||
return isSupportedCalendarLocale(locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName(String calType, int field, int value,
|
||||
int style, Locale locale) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Integer> getDisplayNames(String calType,
|
||||
int field, int style, Locale locale) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static CalendarProvider getCalendarProvider() {
|
||||
return new CalendarProvider() {
|
||||
@Override
|
||||
public Locale[] getAvailableLocales() {
|
||||
return getSupportedCalendarLocales();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupportedLocale(Locale locale) {
|
||||
return isSupportedCalendarLocale(locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Calendar getInstance(TimeZone zone, Locale locale) {
|
||||
return new Calendar.Builder()
|
||||
.setLocale(locale)
|
||||
.setCalendarType(getCalendarID(locale.toLanguageTag()))
|
||||
.setTimeZone(zone)
|
||||
.setInstant(System.currentTimeMillis())
|
||||
.build();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static CurrencyNameProvider getCurrencyNameProvider() {
|
||||
return new CurrencyNameProvider() {
|
||||
@Override
|
||||
public Locale[] getAvailableLocales() {
|
||||
return supportedLocale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupportedLocale(Locale locale) {
|
||||
// Ignore the extensions for now
|
||||
return supportedLocaleSet.contains(locale.stripExtensions());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName(String code, Locale locale) {
|
||||
return getDisplayString(locale.toLanguageTag(), DN_CURRENCY_CODE, code);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSymbol(String code, Locale locale) {
|
||||
return getDisplayString(locale.toLanguageTag(), DN_CURRENCY_SYMBOL, code);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static LocaleNameProvider getLocaleNameProvider() {
|
||||
return new LocaleNameProvider() {
|
||||
@Override
|
||||
public Locale[] getAvailableLocales() {
|
||||
return supportedLocale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupportedLocale(Locale locale) {
|
||||
// Ignore the extensions for now
|
||||
return supportedLocaleSet.contains(locale.stripExtensions());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayLanguage(String languageCode, Locale locale) {
|
||||
return getDisplayString(locale.toLanguageTag(), DN_LOCALE_LANGUAGE, languageCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayCountry(String countryCode, Locale locale) {
|
||||
return getDisplayString(locale.toLanguageTag(), DN_LOCALE_REGION, countryCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayScript(String scriptCode, Locale locale) {
|
||||
return getDisplayString(locale.toLanguageTag(), DN_LOCALE_SCRIPT, scriptCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayVariant(String variantCode, Locale locale) {
|
||||
return getDisplayString(locale.toLanguageTag(), DN_LOCALE_VARIANT, variantCode);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static TimeZoneNameProvider getTimeZoneNameProvider() {
|
||||
return new TimeZoneNameProvider() {
|
||||
@Override
|
||||
public Locale[] getAvailableLocales() {
|
||||
return supportedLocale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupportedLocale(Locale locale) {
|
||||
// Ignore the extensions for now
|
||||
return supportedLocaleSet.contains(locale.stripExtensions());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName(String ID, boolean daylight, int style, Locale locale) {
|
||||
return getTimeZoneDisplayString(locale.toLanguageTag(), style * 2 + (daylight ? 1 : 0), ID);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static Locale[] getSupportedCalendarLocales() {
|
||||
if (supportedLocale.length != 0 &&
|
||||
supportedLocaleSet.contains(Locale.JAPAN) &&
|
||||
isJapaneseCalendar()) {
|
||||
Locale[] sup = new Locale[supportedLocale.length+1];
|
||||
sup[0] = JRELocaleConstants.JA_JP_JP;
|
||||
System.arraycopy(supportedLocale, 0, sup, 1, supportedLocale.length);
|
||||
return sup;
|
||||
}
|
||||
return supportedLocale;
|
||||
}
|
||||
|
||||
private static boolean isSupportedCalendarLocale(Locale locale) {
|
||||
Locale base = locale;
|
||||
|
||||
if (base.hasExtensions() || base.getVariant() != "") {
|
||||
base = new Locale.Builder()
|
||||
.setLocale(locale)
|
||||
.clearExtensions()
|
||||
.build();
|
||||
}
|
||||
|
||||
if (!supportedLocaleSet.contains(base)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String requestedCalType = locale.getUnicodeLocaleType("ca");
|
||||
String nativeCalType =
|
||||
getCalendarID(base.toLanguageTag()).replaceFirst("gregorian", "gregory");
|
||||
|
||||
if (requestedCalType == null) {
|
||||
return Calendar.getAvailableCalendarTypes().contains(nativeCalType);
|
||||
} else {
|
||||
return requestedCalType.equals(nativeCalType);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isJapaneseCalendar() {
|
||||
return getCalendarID("ja-JP").equals("japanese");
|
||||
}
|
||||
|
||||
private static Locale getCalendarLocale(Locale locale) {
|
||||
String nativeCalType = getCalendarID(locale.toLanguageTag())
|
||||
.replaceFirst("gregorian", "gregory");
|
||||
if (Calendar.getAvailableCalendarTypes().contains(nativeCalType)) {
|
||||
return new Locale.Builder()
|
||||
.setLocale(locale)
|
||||
.setUnicodeLocaleKeyword("ca", nativeCalType)
|
||||
.build();
|
||||
} else {
|
||||
return locale;
|
||||
}
|
||||
}
|
||||
|
||||
// The following methods are copied from CLDRConverter build tool.
|
||||
private static String translateDateFormatLetters(String calendarType, String cldrFormat) {
|
||||
String pattern = cldrFormat;
|
||||
int length = pattern.length();
|
||||
boolean inQuote = false;
|
||||
StringBuilder jrePattern = new StringBuilder(length);
|
||||
int count = 0;
|
||||
char lastLetter = 0;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
char c = pattern.charAt(i);
|
||||
|
||||
if (c == '\'') {
|
||||
// '' is treated as a single quote regardless of being
|
||||
// in a quoted section.
|
||||
if ((i + 1) < length) {
|
||||
char nextc = pattern.charAt(i + 1);
|
||||
if (nextc == '\'') {
|
||||
i++;
|
||||
if (count != 0) {
|
||||
convert(calendarType, lastLetter, count, jrePattern);
|
||||
lastLetter = 0;
|
||||
count = 0;
|
||||
}
|
||||
jrePattern.append("''");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!inQuote) {
|
||||
if (count != 0) {
|
||||
convert(calendarType, lastLetter, count, jrePattern);
|
||||
lastLetter = 0;
|
||||
count = 0;
|
||||
}
|
||||
inQuote = true;
|
||||
} else {
|
||||
inQuote = false;
|
||||
}
|
||||
jrePattern.append(c);
|
||||
continue;
|
||||
}
|
||||
if (inQuote) {
|
||||
jrePattern.append(c);
|
||||
continue;
|
||||
}
|
||||
if (!(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')) {
|
||||
if (count != 0) {
|
||||
convert(calendarType, lastLetter, count, jrePattern);
|
||||
lastLetter = 0;
|
||||
count = 0;
|
||||
}
|
||||
jrePattern.append(c);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lastLetter == 0 || lastLetter == c) {
|
||||
lastLetter = c;
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
convert(calendarType, lastLetter, count, jrePattern);
|
||||
lastLetter = c;
|
||||
count = 1;
|
||||
}
|
||||
|
||||
if (count != 0) {
|
||||
convert(calendarType, lastLetter, count, jrePattern);
|
||||
}
|
||||
if (cldrFormat.contentEquals(jrePattern)) {
|
||||
return cldrFormat;
|
||||
}
|
||||
return jrePattern.toString();
|
||||
}
|
||||
|
||||
private static void convert(String calendarType, char cldrLetter, int count, StringBuilder sb) {
|
||||
switch (cldrLetter) {
|
||||
case 'G':
|
||||
if (!calendarType.equals("gregorian")) {
|
||||
// Adjust the number of 'G's for JRE SimpleDateFormat
|
||||
if (count == 5) {
|
||||
// CLDR narrow -> JRE short
|
||||
count = 1;
|
||||
} else if (count == 1) {
|
||||
// CLDR abbr -> JRE long
|
||||
count = 4;
|
||||
}
|
||||
}
|
||||
appendN(cldrLetter, count, sb);
|
||||
break;
|
||||
|
||||
// TODO: support 'c' and 'e' in JRE SimpleDateFormat
|
||||
// Use 'u' and 'E' for now.
|
||||
case 'c':
|
||||
case 'e':
|
||||
switch (count) {
|
||||
case 1:
|
||||
sb.append('u');
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
appendN('E', count, sb);
|
||||
break;
|
||||
case 5:
|
||||
appendN('E', 3, sb);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
case 'V':
|
||||
appendN('z', count, sb);
|
||||
break;
|
||||
|
||||
case 'Z':
|
||||
if (count == 4 || count == 5) {
|
||||
sb.append("XXX");
|
||||
}
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
case 'U':
|
||||
case 'q':
|
||||
case 'Q':
|
||||
case 'l':
|
||||
case 'g':
|
||||
case 'j':
|
||||
case 'A':
|
||||
// Unsupported letter. Just append it within quotes
|
||||
sb.append('\'');
|
||||
sb.append(cldrLetter);
|
||||
sb.append('\'');
|
||||
break;
|
||||
|
||||
default:
|
||||
appendN(cldrLetter, count, sb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void appendN(char c, int n, StringBuilder sb) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
// initialize
|
||||
private static native String getDefaultLocale(int cat);
|
||||
|
||||
// For DateFormatProvider
|
||||
private static native String getDateTimePatternNative(int dateStyle, int timeStyle, String langtag);
|
||||
private static native String getCalendarID(String langTag);
|
||||
|
||||
// For NumberFormatProvider
|
||||
private static native String getNumberPatternNative(int style, String langtag);
|
||||
|
||||
// For DateFormatSymbolsProvider
|
||||
private static native String[] getAmPmStrings(String langTag, String[] ampm);
|
||||
private static native String[] getEras(String langTag, String[] eras);
|
||||
private static native String[] getMonths(String langTag, String[] months);
|
||||
private static native String[] getShortMonths(String langTag, String[] smonths);
|
||||
private static native String[] getWeekdays(String langTag, String[] wdays);
|
||||
private static native String[] getShortWeekdays(String langTag, String[] swdays);
|
||||
|
||||
// For DecimalFormatSymbolsProvider
|
||||
private static native String getCurrencySymbol(String langTag, String currencySymbol);
|
||||
private static native char getDecimalSeparator(String langTag, char decimalSeparator);
|
||||
private static native char getGroupingSeparator(String langTag, char groupingSeparator);
|
||||
private static native String getInfinity(String langTag, String infinity);
|
||||
private static native String getInternationalCurrencySymbol(String langTag, String internationalCurrencySymbol);
|
||||
private static native char getMinusSign(String langTag, char minusSign);
|
||||
private static native char getMonetaryDecimalSeparator(String langTag, char monetaryDecimalSeparator);
|
||||
private static native String getNaN(String langTag, String nan);
|
||||
private static native char getPercent(String langTag, char percent);
|
||||
private static native char getPerMill(String langTag, char perMill);
|
||||
private static native char getZeroDigit(String langTag, char zeroDigit);
|
||||
private static native String getExponentSeparator(String langTag, String exponent);
|
||||
|
||||
// For CalendarDataProvider
|
||||
private static native int getCalendarInt(String langTag, int type);
|
||||
|
||||
// For Locale/CurrencyNameProvider
|
||||
private static native String getDisplayString(String langTag, int key, String value);
|
||||
|
||||
// For TimeZoneNameProvider
|
||||
private static native String getTimeZoneDisplayString(String langTag, int style, String value);
|
||||
}
|
34
src/java.base/macosx/conf/x86_64/jvm.cfg
Normal file
34
src/java.base/macosx/conf/x86_64/jvm.cfg
Normal file
|
@ -0,0 +1,34 @@
|
|||
# Copyright (c) 2012, 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.
|
||||
#
|
||||
# List of JVMs that can be used as an option to java, javac, etc.
|
||||
# Order is important -- first in this list is the default JVM.
|
||||
# NOTE that both this file and its format are UNSUPPORTED and
|
||||
# WILL GO AWAY in a future release.
|
||||
#
|
||||
# You may also select a JVM in an arbitrary location with the
|
||||
# "-XXaltjvm=<jvm_dir>" option, but that too is unsupported
|
||||
# and may not be available in a future release.
|
||||
#
|
||||
-server KNOWN
|
||||
-client IGNORE
|
42
src/java.base/macosx/native/include/jni_md.h
Normal file
42
src/java.base/macosx/native/include/jni_md.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 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.
|
||||
*/
|
||||
|
||||
#ifndef _JAVASOFT_JNI_MD_H_
|
||||
#define _JAVASOFT_JNI_MD_H_
|
||||
|
||||
#define JNIEXPORT __attribute__((visibility("default")))
|
||||
#define JNIIMPORT __attribute__((visibility("default")))
|
||||
#define JNICALL
|
||||
|
||||
typedef int jint;
|
||||
#ifdef _LP64 /* 64-bit */
|
||||
typedef long jlong;
|
||||
#else
|
||||
typedef long long jlong;
|
||||
#endif
|
||||
|
||||
typedef signed char jbyte;
|
||||
|
||||
#endif /* !_JAVASOFT_JNI_MD_H_ */
|
80
src/java.base/macosx/native/include/jvm_md.h
Normal file
80
src/java.base/macosx/native/include/jvm_md.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 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.
|
||||
*/
|
||||
|
||||
#ifndef _JAVASOFT_JVM_MD_H_
|
||||
#define _JAVASOFT_JVM_MD_H_
|
||||
|
||||
/*
|
||||
* This file is currently collecting system-specific dregs for the
|
||||
* JNI conversion, which should be sorted out later.
|
||||
*/
|
||||
|
||||
#include <dirent.h> /* For DIR */
|
||||
#include <sys/param.h> /* For MAXPATHLEN */
|
||||
#include <unistd.h> /* For F_OK, R_OK, W_OK */
|
||||
#include <stddef.h> /* For ptrdiff_t */
|
||||
#include <stdint.h> /* For uintptr_t */
|
||||
|
||||
#define JNI_ONLOAD_SYMBOLS {"JNI_OnLoad"}
|
||||
#define JNI_ONUNLOAD_SYMBOLS {"JNI_OnUnload"}
|
||||
|
||||
#define JNI_LIB_PREFIX "lib"
|
||||
#define JNI_LIB_SUFFIX ".dylib"
|
||||
#define VERSIONED_JNI_LIB_NAME(NAME, VERSION) JNI_LIB_PREFIX NAME "." VERSION JNI_LIB_SUFFIX
|
||||
#define JNI_LIB_NAME(NAME) JNI_LIB_PREFIX NAME JNI_LIB_SUFFIX
|
||||
|
||||
#define JVM_MAXPATHLEN MAXPATHLEN
|
||||
|
||||
#define JVM_R_OK R_OK
|
||||
#define JVM_W_OK W_OK
|
||||
#define JVM_X_OK X_OK
|
||||
#define JVM_F_OK F_OK
|
||||
|
||||
/*
|
||||
* File I/O
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
|
||||
/* O Flags */
|
||||
|
||||
#define JVM_O_RDONLY O_RDONLY
|
||||
#define JVM_O_WRONLY O_WRONLY
|
||||
#define JVM_O_RDWR O_RDWR
|
||||
#define JVM_O_O_APPEND O_APPEND
|
||||
#define JVM_O_EXCL O_EXCL
|
||||
#define JVM_O_CREAT O_CREAT
|
||||
|
||||
/* Signals */
|
||||
|
||||
#define JVM_SIGINT SIGINT
|
||||
#define JVM_SIGTERM SIGTERM
|
||||
|
||||
|
||||
#endif /* !_JAVASOFT_JVM_MD_H_ */
|
14
src/java.base/macosx/native/launcher/Info-cmdline.plist
Normal file
14
src/java.base/macosx/native/launcher/Info-cmdline.plist
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>net.java.openjdk.cmd</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
</dict>
|
||||
</plist>
|
18
src/java.base/macosx/native/launcher/Info-privileged.plist
Normal file
18
src/java.base/macosx/native/launcher/Info-privileged.plist
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>net.java.openjdk.cmd</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>OpenJDK Command</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>SecTaskAccess</key>
|
||||
<string>allowed</string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,727 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 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.
|
||||
*/
|
||||
|
||||
#include "sun_util_locale_provider_HostLocaleProviderAdapterImpl.h"
|
||||
#include "jni_util.h"
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define BUFLEN 256
|
||||
|
||||
static CFDateFormatterStyle convertDateFormatterStyle(jint javaStyle);
|
||||
static CFNumberFormatterStyle convertNumberFormatterStyle(jint javaStyle);
|
||||
static void copyArrayElements(JNIEnv *env, CFArrayRef cfarray, jobjectArray jarray, CFIndex sindex, int dindex, int count);
|
||||
static jstring getNumberSymbolString(JNIEnv *env, jstring jlangtag, jstring jdefault, CFStringRef type);
|
||||
static jchar getNumberSymbolChar(JNIEnv *env, jstring jlangtag, jchar jdefault, CFStringRef type);
|
||||
|
||||
// from java_props_macosx.c
|
||||
extern char * getMacOSXLocale(int cat);
|
||||
extern char * getPosixLocale(int cat);
|
||||
|
||||
/*
|
||||
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
|
||||
* Method: getDefaultLocale
|
||||
* Signature: (I)Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDefaultLocale
|
||||
(JNIEnv *env, jclass cls, jint cat) {
|
||||
char * localeString = NULL;
|
||||
int posixCat;
|
||||
jstring ret = NULL;
|
||||
|
||||
switch (cat) {
|
||||
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_CAT_DISPLAY:
|
||||
posixCat = LC_MESSAGES;
|
||||
break;
|
||||
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_CAT_FORMAT:
|
||||
default:
|
||||
posixCat = LC_CTYPE;
|
||||
break;
|
||||
}
|
||||
|
||||
localeString = getMacOSXLocale(posixCat);
|
||||
if (localeString == NULL) {
|
||||
localeString = getPosixLocale(posixCat);
|
||||
if (localeString == NULL) {
|
||||
JNU_ThrowOutOfMemoryError(env, NULL);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
ret = (*env)->NewStringUTF(env, localeString);
|
||||
free(localeString);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
|
||||
* Method: getDateTimePatternNative
|
||||
* Signature: (IILjava/lang/String;)Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDateTimePatternNative
|
||||
(JNIEnv *env, jclass cls, jint dateStyle, jint timeStyle, jstring jlangtag) {
|
||||
jstring ret = NULL;
|
||||
CFLocaleRef cflocale = CFLocaleCopyCurrent();
|
||||
|
||||
if (cflocale != NULL) {
|
||||
CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorDefault,
|
||||
cflocale,
|
||||
convertDateFormatterStyle(dateStyle),
|
||||
convertDateFormatterStyle(timeStyle));
|
||||
if (df != NULL) {
|
||||
char buf[BUFLEN];
|
||||
CFStringRef formatStr = CFDateFormatterGetFormat(df);
|
||||
CFStringGetCString(formatStr, buf, BUFLEN, kCFStringEncodingUTF8);
|
||||
ret = (*env)->NewStringUTF(env, buf);
|
||||
CFRelease(df);
|
||||
}
|
||||
CFRelease(cflocale);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
|
||||
* Method: getCalendarID
|
||||
* Signature: (Ljava/lang/String;)Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCalendarID
|
||||
(JNIEnv *env, jclass cls, jstring jlangtag) {
|
||||
jstring ret = NULL;
|
||||
CFLocaleRef cflocale = CFLocaleCopyCurrent();
|
||||
|
||||
if (cflocale != NULL) {
|
||||
char buf[BUFLEN];
|
||||
CFTypeRef calid = CFLocaleGetValue(cflocale, kCFLocaleCalendarIdentifier);
|
||||
CFStringGetCString((CFStringRef)calid, buf, BUFLEN, kCFStringEncodingUTF8);
|
||||
ret = (*env)->NewStringUTF(env, buf);
|
||||
CFRelease(cflocale);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
|
||||
* Method: getAmPmStrings
|
||||
* Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getAmPmStrings
|
||||
(JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray ampms) {
|
||||
CFLocaleRef cflocale = CFLocaleCopyCurrent();
|
||||
jstring tmp_string;
|
||||
if (cflocale != NULL) {
|
||||
CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorDefault,
|
||||
cflocale,
|
||||
kCFDateFormatterFullStyle,
|
||||
kCFDateFormatterFullStyle);
|
||||
if (df != NULL) {
|
||||
char buf[BUFLEN];
|
||||
CFStringRef amStr = CFDateFormatterCopyProperty(df, kCFDateFormatterAMSymbol);
|
||||
if (amStr != NULL) {
|
||||
CFStringGetCString(amStr, buf, BUFLEN, kCFStringEncodingUTF8);
|
||||
CFRelease(amStr);
|
||||
tmp_string = (*env)->NewStringUTF(env, buf);
|
||||
if (tmp_string != NULL) {
|
||||
(*env)->SetObjectArrayElement(env, ampms, 0, tmp_string);
|
||||
}
|
||||
}
|
||||
if (!(*env)->ExceptionCheck(env)){
|
||||
CFStringRef pmStr = CFDateFormatterCopyProperty(df, kCFDateFormatterPMSymbol);
|
||||
if (pmStr != NULL) {
|
||||
CFStringGetCString(pmStr, buf, BUFLEN, kCFStringEncodingUTF8);
|
||||
CFRelease(pmStr);
|
||||
tmp_string = (*env)->NewStringUTF(env, buf);
|
||||
if (tmp_string != NULL) {
|
||||
(*env)->SetObjectArrayElement(env, ampms, 1, tmp_string);
|
||||
}
|
||||
}
|
||||
}
|
||||
CFRelease(df);
|
||||
}
|
||||
CFRelease(cflocale);
|
||||
}
|
||||
|
||||
return ampms;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
|
||||
* Method: getEras
|
||||
* Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getEras
|
||||
(JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray eras) {
|
||||
CFLocaleRef cflocale = CFLocaleCopyCurrent();
|
||||
if (cflocale != NULL) {
|
||||
CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorDefault,
|
||||
cflocale,
|
||||
kCFDateFormatterFullStyle,
|
||||
kCFDateFormatterFullStyle);
|
||||
if (df != NULL) {
|
||||
CFArrayRef cferas = CFDateFormatterCopyProperty(df, kCFDateFormatterEraSymbols);
|
||||
if (cferas != NULL) {
|
||||
copyArrayElements(env, cferas, eras, 0, 0, CFArrayGetCount(cferas));
|
||||
CFRelease(cferas);
|
||||
}
|
||||
CFRelease(df);
|
||||
}
|
||||
CFRelease(cflocale);
|
||||
}
|
||||
|
||||
return eras;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
|
||||
* Method: getMonths
|
||||
* Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getMonths
|
||||
(JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray months) {
|
||||
CFLocaleRef cflocale = CFLocaleCopyCurrent();
|
||||
if (cflocale != NULL) {
|
||||
CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorDefault,
|
||||
cflocale,
|
||||
kCFDateFormatterFullStyle,
|
||||
kCFDateFormatterFullStyle);
|
||||
if (df != NULL) {
|
||||
CFArrayRef cfmonths = CFDateFormatterCopyProperty(df, kCFDateFormatterMonthSymbols);
|
||||
if (cfmonths != NULL) {
|
||||
copyArrayElements(env, cfmonths, months, 0, 0, CFArrayGetCount(cfmonths));
|
||||
CFRelease(cfmonths);
|
||||
}
|
||||
CFRelease(df);
|
||||
}
|
||||
CFRelease(cflocale);
|
||||
}
|
||||
|
||||
return months;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
|
||||
* Method: getShortMonths
|
||||
* Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getShortMonths
|
||||
(JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray smonths) {
|
||||
CFLocaleRef cflocale = CFLocaleCopyCurrent();
|
||||
if (cflocale != NULL) {
|
||||
CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorDefault,
|
||||
cflocale,
|
||||
kCFDateFormatterFullStyle,
|
||||
kCFDateFormatterFullStyle);
|
||||
if (df != NULL) {
|
||||
CFArrayRef cfsmonths = CFDateFormatterCopyProperty(df, kCFDateFormatterShortMonthSymbols);
|
||||
if (cfsmonths != NULL) {
|
||||
copyArrayElements(env, cfsmonths, smonths, 0, 0, CFArrayGetCount(cfsmonths));
|
||||
CFRelease(cfsmonths);
|
||||
}
|
||||
CFRelease(df);
|
||||
}
|
||||
CFRelease(cflocale);
|
||||
}
|
||||
|
||||
return smonths;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
|
||||
* Method: getWeekdays
|
||||
* Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getWeekdays
|
||||
(JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray wdays) {
|
||||
CFLocaleRef cflocale = CFLocaleCopyCurrent();
|
||||
if (cflocale != NULL) {
|
||||
CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorDefault,
|
||||
cflocale,
|
||||
kCFDateFormatterFullStyle,
|
||||
kCFDateFormatterFullStyle);
|
||||
if (df != NULL) {
|
||||
CFArrayRef cfwdays = CFDateFormatterCopyProperty(df, kCFDateFormatterWeekdaySymbols);
|
||||
if (cfwdays != NULL) {
|
||||
copyArrayElements(env, cfwdays, wdays, 0, 1, CFArrayGetCount(cfwdays));
|
||||
CFRelease(cfwdays);
|
||||
}
|
||||
CFRelease(df);
|
||||
}
|
||||
CFRelease(cflocale);
|
||||
}
|
||||
|
||||
return wdays;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
|
||||
* Method: getShortWeekdays
|
||||
* Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getShortWeekdays
|
||||
(JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray swdays) {
|
||||
CFLocaleRef cflocale = CFLocaleCopyCurrent();
|
||||
if (cflocale != NULL) {
|
||||
CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorDefault,
|
||||
cflocale,
|
||||
kCFDateFormatterFullStyle,
|
||||
kCFDateFormatterFullStyle);
|
||||
if (df != NULL) {
|
||||
CFArrayRef cfswdays = CFDateFormatterCopyProperty(df, kCFDateFormatterShortWeekdaySymbols);
|
||||
if (cfswdays != NULL) {
|
||||
copyArrayElements(env, cfswdays, swdays, 0, 1, CFArrayGetCount(cfswdays));
|
||||
CFRelease(cfswdays);
|
||||
}
|
||||
CFRelease(df);
|
||||
}
|
||||
CFRelease(cflocale);
|
||||
}
|
||||
|
||||
return swdays;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
|
||||
* Method: getNumberPatternNative
|
||||
* Signature: (ILjava/lang/String;)Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getNumberPatternNative
|
||||
(JNIEnv *env, jclass cls, jint numberStyle, jstring jlangtag) {
|
||||
jstring ret = NULL;
|
||||
CFLocaleRef cflocale = CFLocaleCopyCurrent();
|
||||
if (cflocale != NULL) {
|
||||
CFNumberFormatterRef nf = CFNumberFormatterCreate(kCFAllocatorDefault,
|
||||
cflocale,
|
||||
convertNumberFormatterStyle(numberStyle));
|
||||
if (nf != NULL) {
|
||||
char buf[BUFLEN];
|
||||
CFStringRef formatStr = CFNumberFormatterGetFormat(nf);
|
||||
CFStringGetCString(formatStr, buf, BUFLEN, kCFStringEncodingUTF8);
|
||||
ret = (*env)->NewStringUTF(env, buf);
|
||||
CFRelease(nf);
|
||||
}
|
||||
CFRelease(cflocale);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
|
||||
* Method: getCurrencySymbol
|
||||
* Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCurrencySymbol
|
||||
(JNIEnv *env, jclass cls, jstring jlangtag, jstring currencySymbol) {
|
||||
return getNumberSymbolString(env, jlangtag, currencySymbol, kCFNumberFormatterCurrencySymbol);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
|
||||
* Method: getDecimalSeparator
|
||||
* Signature: (Ljava/lang/String;C)C
|
||||
*/
|
||||
JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDecimalSeparator
|
||||
(JNIEnv *env, jclass cls, jstring jlangtag, jchar decimalSeparator) {
|
||||
return getNumberSymbolChar(env, jlangtag, decimalSeparator, kCFNumberFormatterDecimalSeparator);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
|
||||
* Method: getGroupingSeparator
|
||||
* Signature: (Ljava/lang/String;C)C
|
||||
*/
|
||||
JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getGroupingSeparator
|
||||
(JNIEnv *env, jclass cls, jstring jlangtag, jchar groupingSeparator) {
|
||||
return getNumberSymbolChar(env, jlangtag, groupingSeparator, kCFNumberFormatterGroupingSeparator);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
|
||||
* Method: getInfinity
|
||||
* Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getInfinity
|
||||
(JNIEnv *env, jclass cls, jstring jlangtag, jstring infinity) {
|
||||
return getNumberSymbolString(env, jlangtag, infinity, kCFNumberFormatterInfinitySymbol);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
|
||||
* Method: getInternationalCurrencySymbol
|
||||
* Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getInternationalCurrencySymbol
|
||||
(JNIEnv *env, jclass cls, jstring jlangtag, jstring internationalCurrencySymbol) {
|
||||
return getNumberSymbolString(env, jlangtag, internationalCurrencySymbol, kCFNumberFormatterInternationalCurrencySymbol);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
|
||||
* Method: getMinusSign
|
||||
* Signature: (Ljava/lang/String;C)C
|
||||
*/
|
||||
JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getMinusSign
|
||||
(JNIEnv *env, jclass cls, jstring jlangtag, jchar minusSign) {
|
||||
return getNumberSymbolChar(env, jlangtag, minusSign, kCFNumberFormatterMinusSign);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
|
||||
* Method: getMonetaryDecimalSeparator
|
||||
* Signature: (Ljava/lang/String;C)C
|
||||
*/
|
||||
JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getMonetaryDecimalSeparator
|
||||
(JNIEnv *env, jclass cls, jstring jlangtag, jchar monetaryDecimalSeparator) {
|
||||
return getNumberSymbolChar(env, jlangtag, monetaryDecimalSeparator, kCFNumberFormatterCurrencyDecimalSeparator);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
|
||||
* Method: getNaN
|
||||
* Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getNaN
|
||||
(JNIEnv *env, jclass cls, jstring jlangtag, jstring nan) {
|
||||
return getNumberSymbolString(env, jlangtag, nan, kCFNumberFormatterNaNSymbol);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
|
||||
* Method: getPercent
|
||||
* Signature: (Ljava/lang/String;C)C
|
||||
*/
|
||||
JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getPercent
|
||||
(JNIEnv *env, jclass cls, jstring jlangtag, jchar percent) {
|
||||
return getNumberSymbolChar(env, jlangtag, percent, kCFNumberFormatterPercentSymbol);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
|
||||
* Method: getPerMill
|
||||
* Signature: (Ljava/lang/String;C)C
|
||||
*/
|
||||
JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getPerMill
|
||||
(JNIEnv *env, jclass cls, jstring jlangtag, jchar perMill) {
|
||||
return getNumberSymbolChar(env, jlangtag, perMill, kCFNumberFormatterPerMillSymbol);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
|
||||
* Method: getZeroDigit
|
||||
* Signature: (Ljava/lang/String;C)C
|
||||
*/
|
||||
JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getZeroDigit
|
||||
(JNIEnv *env, jclass cls, jstring jlangtag, jchar zeroDigit) {
|
||||
// The following code *should* work, but not for some reason :o
|
||||
//
|
||||
//return getNumberSymbolChar(env, jlangtag, zeroDigit, kCFNumberFormatterZeroSymbol);
|
||||
//
|
||||
// so here is a workaround.
|
||||
jchar ret = zeroDigit;
|
||||
CFLocaleRef cflocale = CFLocaleCopyCurrent();
|
||||
|
||||
if (cflocale != NULL) {
|
||||
CFNumberFormatterRef nf = CFNumberFormatterCreate(kCFAllocatorDefault,
|
||||
cflocale,
|
||||
kCFNumberFormatterNoStyle);
|
||||
if (nf != NULL) {
|
||||
int zero = 0;
|
||||
CFStringRef str = CFNumberFormatterCreateStringWithValue(kCFAllocatorDefault,
|
||||
nf, kCFNumberIntType, &zero);
|
||||
if (str != NULL) {
|
||||
if (CFStringGetLength(str) > 0) {
|
||||
ret = CFStringGetCharacterAtIndex(str, 0);
|
||||
}
|
||||
CFRelease(str);
|
||||
}
|
||||
|
||||
CFRelease(nf);
|
||||
}
|
||||
|
||||
CFRelease(cflocale);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
|
||||
* Method: getExponentSeparator
|
||||
* Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getExponentSeparator
|
||||
(JNIEnv *env, jclass cls, jstring jlangtag, jstring exponent) {
|
||||
return getNumberSymbolString(env, jlangtag, exponent, kCFNumberFormatterExponentSymbol);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
|
||||
* Method: getCalendarInt
|
||||
* Signature: (Ljava/lang/String;I)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCalendarInt
|
||||
(JNIEnv *env, jclass cls, jstring jlangtag, jint type) {
|
||||
jint ret = 0;
|
||||
CFCalendarRef cfcal = CFCalendarCopyCurrent();
|
||||
|
||||
if (cfcal != NULL) {
|
||||
switch (type) {
|
||||
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_CD_FIRSTDAYOFWEEK:
|
||||
ret = CFCalendarGetFirstWeekday(cfcal);
|
||||
break;
|
||||
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_CD_MINIMALDAYSINFIRSTWEEK:
|
||||
ret = CFCalendarGetMinimumDaysInFirstWeek(cfcal);
|
||||
break;
|
||||
default:
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
CFRelease(cfcal);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
|
||||
* Method: getDisplayString
|
||||
* Signature: (Ljava/lang/String;ILjava/lang/String;)Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDisplayString
|
||||
(JNIEnv *env, jclass cls, jstring jlangtag, jint type, jstring value) {
|
||||
jstring ret = NULL;
|
||||
|
||||
const char *clangtag = (*env)->GetStringUTFChars(env, jlangtag, 0);
|
||||
if (clangtag != NULL) {
|
||||
const char *cvalue = (*env)->GetStringUTFChars(env, value, 0);
|
||||
if (cvalue != NULL) {
|
||||
CFStringRef cflangtag =
|
||||
CFStringCreateWithCString(kCFAllocatorDefault, clangtag, kCFStringEncodingUTF8);
|
||||
if (cflangtag != NULL) {
|
||||
CFLocaleRef cflocale = CFLocaleCreate(kCFAllocatorDefault, cflangtag);
|
||||
if (cflocale != NULL) {
|
||||
CFStringRef cfvalue =
|
||||
CFStringCreateWithCString(kCFAllocatorDefault, cvalue, kCFStringEncodingUTF8);
|
||||
if (cfvalue != NULL) {
|
||||
CFStringRef str = NULL;
|
||||
switch (type) {
|
||||
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_LOCALE_LANGUAGE:
|
||||
str = CFLocaleCopyDisplayNameForPropertyValue(cflocale, kCFLocaleLanguageCode, cfvalue);
|
||||
break;
|
||||
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_LOCALE_SCRIPT:
|
||||
str = CFLocaleCopyDisplayNameForPropertyValue(cflocale, kCFLocaleScriptCode, cfvalue);
|
||||
break;
|
||||
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_LOCALE_REGION:
|
||||
str = CFLocaleCopyDisplayNameForPropertyValue(cflocale, kCFLocaleCountryCode, cfvalue);
|
||||
break;
|
||||
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_LOCALE_VARIANT:
|
||||
str = CFLocaleCopyDisplayNameForPropertyValue(cflocale, kCFLocaleVariantCode, cfvalue);
|
||||
break;
|
||||
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_CURRENCY_CODE:
|
||||
str = CFLocaleCopyDisplayNameForPropertyValue(cflocale, kCFLocaleCurrencyCode, cfvalue);
|
||||
break;
|
||||
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_CURRENCY_SYMBOL:
|
||||
str = CFLocaleCopyDisplayNameForPropertyValue(cflocale, kCFLocaleCurrencySymbol, cfvalue);
|
||||
break;
|
||||
}
|
||||
if (str != NULL) {
|
||||
char buf[BUFLEN];
|
||||
CFStringGetCString(str, buf, BUFLEN, kCFStringEncodingUTF8);
|
||||
CFRelease(str);
|
||||
ret = (*env)->NewStringUTF(env, buf);
|
||||
}
|
||||
CFRelease(cfvalue);
|
||||
}
|
||||
CFRelease(cflocale);
|
||||
}
|
||||
CFRelease(cflangtag);
|
||||
}
|
||||
(*env)->ReleaseStringUTFChars(env, value, cvalue);
|
||||
}
|
||||
(*env)->ReleaseStringUTFChars(env, jlangtag, clangtag);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
|
||||
* Method: getTimeZoneDisplayString
|
||||
* Signature: (Ljava/lang/String;ILjava/lang/String;)Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getTimeZoneDisplayString
|
||||
(JNIEnv *env, jclass cls, jstring jlangtag, jint type, jstring tzid) {
|
||||
jstring ret = NULL;
|
||||
|
||||
const char *clangtag = (*env)->GetStringUTFChars(env, jlangtag, 0);
|
||||
if (clangtag != NULL) {
|
||||
const char *ctzid = (*env)->GetStringUTFChars(env, tzid, 0);
|
||||
if (ctzid != NULL) {
|
||||
CFStringRef cflangtag =
|
||||
CFStringCreateWithCString(kCFAllocatorDefault, clangtag, kCFStringEncodingUTF8);
|
||||
if (cflangtag != NULL) {
|
||||
CFLocaleRef cflocale = CFLocaleCreate(kCFAllocatorDefault, cflangtag);
|
||||
if (cflocale != NULL) {
|
||||
CFStringRef cftzid =
|
||||
CFStringCreateWithCString(kCFAllocatorDefault, ctzid, kCFStringEncodingUTF8);
|
||||
if (cftzid != NULL) {
|
||||
CFTimeZoneRef cftz = CFTimeZoneCreateWithName(kCFAllocatorDefault, cftzid, false);
|
||||
if (cftz != NULL) {
|
||||
CFStringRef str = NULL;
|
||||
switch (type) {
|
||||
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_TZ_SHORT_STANDARD:
|
||||
str = CFTimeZoneCopyLocalizedName(cftz, kCFTimeZoneNameStyleShortStandard, cflocale);
|
||||
break;
|
||||
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_TZ_SHORT_DST:
|
||||
str = CFTimeZoneCopyLocalizedName(cftz, kCFTimeZoneNameStyleShortDaylightSaving, cflocale);
|
||||
break;
|
||||
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_TZ_LONG_STANDARD:
|
||||
str = CFTimeZoneCopyLocalizedName(cftz, kCFTimeZoneNameStyleStandard, cflocale);
|
||||
break;
|
||||
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_TZ_LONG_DST:
|
||||
str = CFTimeZoneCopyLocalizedName(cftz, kCFTimeZoneNameStyleDaylightSaving, cflocale);
|
||||
break;
|
||||
}
|
||||
if (str != NULL) {
|
||||
char buf[BUFLEN];
|
||||
CFStringGetCString(str, buf, BUFLEN, kCFStringEncodingUTF8);
|
||||
CFRelease(str);
|
||||
ret = (*env)->NewStringUTF(env, buf);
|
||||
}
|
||||
CFRelease(cftz);
|
||||
}
|
||||
CFRelease(cftzid);
|
||||
}
|
||||
CFRelease(cflocale);
|
||||
}
|
||||
CFRelease(cflangtag);
|
||||
}
|
||||
(*env)->ReleaseStringUTFChars(env, tzid, ctzid);
|
||||
}
|
||||
(*env)->ReleaseStringUTFChars(env, jlangtag, clangtag);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static CFDateFormatterStyle convertDateFormatterStyle(jint javaStyle) {
|
||||
switch (javaStyle) {
|
||||
case 0: // FULL
|
||||
return kCFDateFormatterFullStyle;
|
||||
case 1: // LONG
|
||||
return kCFDateFormatterLongStyle;
|
||||
case 2: // MEDIUM
|
||||
return kCFDateFormatterMediumStyle;
|
||||
case 3: // LONG
|
||||
return kCFDateFormatterShortStyle;
|
||||
case -1: // No style
|
||||
default:
|
||||
return kCFDateFormatterNoStyle;
|
||||
}
|
||||
}
|
||||
|
||||
static CFNumberFormatterStyle convertNumberFormatterStyle(jint javaStyle) {
|
||||
switch (javaStyle) {
|
||||
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_CURRENCY:
|
||||
return kCFNumberFormatterCurrencyStyle;
|
||||
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_INTEGER:
|
||||
return kCFNumberFormatterDecimalStyle;
|
||||
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_NUMBER:
|
||||
return kCFNumberFormatterDecimalStyle;
|
||||
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_PERCENT:
|
||||
return kCFNumberFormatterPercentStyle;
|
||||
default:
|
||||
return kCFNumberFormatterNoStyle;
|
||||
}
|
||||
}
|
||||
|
||||
static void copyArrayElements(JNIEnv *env, CFArrayRef cfarray, jobjectArray jarray, CFIndex sindex, int dindex, int count) {
|
||||
char buf[BUFLEN];
|
||||
jstring tmp_string;
|
||||
|
||||
for (; count > 0; sindex++, dindex++, count--) {
|
||||
CFStringGetCString(CFArrayGetValueAtIndex(cfarray, sindex), buf, BUFLEN, kCFStringEncodingUTF8);
|
||||
tmp_string = (*env)->NewStringUTF(env, buf);
|
||||
if (tmp_string != NULL) {
|
||||
(*env)->SetObjectArrayElement(env, jarray, dindex, tmp_string);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static jstring getNumberSymbolString(JNIEnv *env, jstring jlangtag, jstring jdefault, CFStringRef type) {
|
||||
char buf[BUFLEN];
|
||||
jstring ret = jdefault;
|
||||
CFLocaleRef cflocale = CFLocaleCopyCurrent();
|
||||
|
||||
if (cflocale != NULL) {
|
||||
CFNumberFormatterRef nf = CFNumberFormatterCreate(kCFAllocatorDefault,
|
||||
cflocale,
|
||||
kCFNumberFormatterNoStyle);
|
||||
if (nf != NULL) {
|
||||
CFStringRef str = CFNumberFormatterCopyProperty(nf, type);
|
||||
if (str != NULL) {
|
||||
CFStringGetCString(str, buf, BUFLEN, kCFStringEncodingUTF8);
|
||||
CFRelease(str);
|
||||
ret = (*env)->NewStringUTF(env, buf);
|
||||
}
|
||||
|
||||
CFRelease(nf);
|
||||
}
|
||||
|
||||
CFRelease(cflocale);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static jchar getNumberSymbolChar(JNIEnv *env, jstring jlangtag, jchar jdefault, CFStringRef type) {
|
||||
jchar ret = jdefault;
|
||||
CFLocaleRef cflocale = CFLocaleCopyCurrent();
|
||||
|
||||
if (cflocale != NULL) {
|
||||
CFNumberFormatterRef nf = CFNumberFormatterCreate(kCFAllocatorDefault,
|
||||
cflocale,
|
||||
kCFNumberFormatterNoStyle);
|
||||
if (nf != NULL) {
|
||||
CFStringRef str = CFNumberFormatterCopyProperty(nf, type);
|
||||
if (str != NULL) {
|
||||
if (CFStringGetLength(str) > 0) {
|
||||
ret = CFStringGetCharacterAtIndex(str, 0);
|
||||
}
|
||||
CFRelease(str);
|
||||
}
|
||||
|
||||
CFRelease(nf);
|
||||
}
|
||||
|
||||
CFRelease(cflocale);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
303
src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c
Normal file
303
src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c
Normal file
|
@ -0,0 +1,303 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 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.
|
||||
*/
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "java_lang_ProcessHandleImpl.h"
|
||||
#include "java_lang_ProcessHandleImpl_Info.h"
|
||||
|
||||
#include "ProcessHandleImpl_unix.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
/**
|
||||
* Implementation of native ProcessHandleImpl functions for MAC OS X.
|
||||
* See ProcessHandleImpl_unix.c for more details.
|
||||
*/
|
||||
|
||||
void os_initNative(JNIEnv *env, jclass clazz) {}
|
||||
|
||||
/*
|
||||
* Returns the children of the requested pid and optionally each parent.
|
||||
*
|
||||
* Use sysctl to accumulate any process whose parent pid is zero or matches.
|
||||
* The resulting pids are stored into the array of longs.
|
||||
* The number of pids is returned if they all fit.
|
||||
* If the parentArray is non-null, store the parent pid.
|
||||
* If the array is too short, excess pids are not stored and
|
||||
* the desired length is returned.
|
||||
*/
|
||||
jint os_getChildren(JNIEnv *env, jlong jpid, jlongArray jarray,
|
||||
jlongArray jparentArray, jlongArray jstimesArray) {
|
||||
jlong* pids = NULL;
|
||||
jlong* ppids = NULL;
|
||||
jlong* stimes = NULL;
|
||||
jsize parentArraySize = 0;
|
||||
jsize arraySize = 0;
|
||||
jsize stimesSize = 0;
|
||||
jsize count = 0;
|
||||
size_t bufSize = 0;
|
||||
pid_t pid = (pid_t) jpid;
|
||||
|
||||
arraySize = (*env)->GetArrayLength(env, jarray);
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, -1);
|
||||
if (jparentArray != NULL) {
|
||||
parentArraySize = (*env)->GetArrayLength(env, jparentArray);
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, -1);
|
||||
|
||||
if (arraySize != parentArraySize) {
|
||||
JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (jstimesArray != NULL) {
|
||||
stimesSize = (*env)->GetArrayLength(env, jstimesArray);
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, -1);
|
||||
|
||||
if (arraySize != stimesSize) {
|
||||
JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Get buffer size needed to read all processes
|
||||
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
|
||||
if (sysctl(mib, 4, NULL, &bufSize, NULL, 0) < 0) {
|
||||
JNU_ThrowByNameWithLastError(env,
|
||||
"java/lang/RuntimeException", "sysctl failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Allocate buffer big enough for all processes
|
||||
void *buffer = malloc(bufSize);
|
||||
if (buffer == NULL) {
|
||||
JNU_ThrowOutOfMemoryError(env, "malloc failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Read process info for all processes
|
||||
if (sysctl(mib, 4, buffer, &bufSize, NULL, 0) < 0) {
|
||||
JNU_ThrowByNameWithLastError(env,
|
||||
"java/lang/RuntimeException", "sysctl failed");
|
||||
free(buffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
do { // Block to break out of on Exception
|
||||
struct kinfo_proc *kp = (struct kinfo_proc *) buffer;
|
||||
unsigned long nentries = bufSize / sizeof (struct kinfo_proc);
|
||||
long i;
|
||||
|
||||
pids = (*env)->GetLongArrayElements(env, jarray, NULL);
|
||||
if (pids == NULL) {
|
||||
break;
|
||||
}
|
||||
if (jparentArray != NULL) {
|
||||
ppids = (*env)->GetLongArrayElements(env, jparentArray, NULL);
|
||||
if (ppids == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (jstimesArray != NULL) {
|
||||
stimes = (*env)->GetLongArrayElements(env, jstimesArray, NULL);
|
||||
if (stimes == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Process each entry in the buffer
|
||||
for (i = nentries; --i >= 0; ++kp) {
|
||||
if (pid == 0 || kp->kp_eproc.e_ppid == pid) {
|
||||
if (count < arraySize) {
|
||||
// Only store if it fits
|
||||
pids[count] = (jlong) kp->kp_proc.p_pid;
|
||||
if (ppids != NULL) {
|
||||
// Store the parentPid
|
||||
ppids[count] = (jlong) kp->kp_eproc.e_ppid;
|
||||
}
|
||||
if (stimes != NULL) {
|
||||
// Store the process start time
|
||||
jlong startTime = kp->kp_proc.p_starttime.tv_sec * 1000 +
|
||||
kp->kp_proc.p_starttime.tv_usec / 1000;
|
||||
stimes[count] = startTime;
|
||||
}
|
||||
}
|
||||
count++; // Count to tabulate size needed
|
||||
}
|
||||
}
|
||||
} while (0);
|
||||
|
||||
if (pids != NULL) {
|
||||
(*env)->ReleaseLongArrayElements(env, jarray, pids, 0);
|
||||
}
|
||||
if (ppids != NULL) {
|
||||
(*env)->ReleaseLongArrayElements(env, jparentArray, ppids, 0);
|
||||
}
|
||||
if (stimes != NULL) {
|
||||
(*env)->ReleaseLongArrayElements(env, jstimesArray, stimes, 0);
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
// If more pids than array had size for; count will be greater than array size
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use sysctl and return the ppid, total cputime and start time.
|
||||
* Return: -1 is fail; >= 0 is parent pid
|
||||
* 'total' will contain the running time of 'pid' in nanoseconds.
|
||||
* 'start' will contain the start time of 'pid' in milliseconds since epoch.
|
||||
*/
|
||||
pid_t os_getParentPidAndTimings(JNIEnv *env, pid_t jpid,
|
||||
jlong *totalTime, jlong *startTime) {
|
||||
|
||||
const pid_t pid = (pid_t) jpid;
|
||||
pid_t ppid = -1;
|
||||
struct kinfo_proc kp;
|
||||
size_t bufSize = sizeof kp;
|
||||
|
||||
// Read the process info for the specific pid
|
||||
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
|
||||
|
||||
if (sysctl(mib, 4, &kp, &bufSize, NULL, 0) < 0) {
|
||||
JNU_ThrowByNameWithLastError(env,
|
||||
"java/lang/RuntimeException", "sysctl failed");
|
||||
return -1;
|
||||
}
|
||||
if (bufSize > 0 && kp.kp_proc.p_pid == pid) {
|
||||
*startTime = (jlong) (kp.kp_proc.p_starttime.tv_sec * 1000 +
|
||||
kp.kp_proc.p_starttime.tv_usec / 1000);
|
||||
ppid = kp.kp_eproc.e_ppid;
|
||||
}
|
||||
|
||||
// Get cputime if for current process
|
||||
if (pid == getpid()) {
|
||||
struct rusage usage;
|
||||
if (getrusage(RUSAGE_SELF, &usage) == 0) {
|
||||
jlong microsecs =
|
||||
usage.ru_utime.tv_sec * 1000 * 1000 + usage.ru_utime.tv_usec +
|
||||
usage.ru_stime.tv_sec * 1000 * 1000 + usage.ru_stime.tv_usec;
|
||||
*totalTime = microsecs * 1000;
|
||||
}
|
||||
}
|
||||
|
||||
return ppid;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the uid of a process or -1 on error
|
||||
*/
|
||||
static uid_t getUID(pid_t pid) {
|
||||
struct kinfo_proc kp;
|
||||
size_t bufSize = sizeof kp;
|
||||
|
||||
// Read the process info for the specific pid
|
||||
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
|
||||
|
||||
if (sysctl(mib, 4, &kp, &bufSize, NULL, 0) == 0) {
|
||||
if (bufSize > 0 && kp.kp_proc.p_pid == pid) {
|
||||
return kp.kp_eproc.e_ucred.cr_uid;
|
||||
}
|
||||
}
|
||||
return (uid_t)-1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the command and arguments for the process and store them
|
||||
* into the Info object.
|
||||
*/
|
||||
void os_getCmdlineAndUserInfo(JNIEnv *env, jobject jinfo, pid_t pid) {
|
||||
int mib[3], maxargs, nargs, i;
|
||||
size_t size;
|
||||
char *args, *cp, *sp, *np;
|
||||
|
||||
// Get the UID first. This is done here because it is cheap to do it here
|
||||
// on other platforms like Linux/Solaris/AIX where the uid comes from the
|
||||
// same source like the command line info.
|
||||
unix_getUserInfo(env, jinfo, getUID(pid));
|
||||
|
||||
// Get the maximum size of the arguments
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_ARGMAX;
|
||||
size = sizeof(maxargs);
|
||||
if (sysctl(mib, 2, &maxargs, &size, NULL, 0) == -1) {
|
||||
JNU_ThrowByNameWithLastError(env,
|
||||
"java/lang/RuntimeException", "sysctl failed");
|
||||
return;
|
||||
}
|
||||
|
||||
// Allocate an args buffer and get the arguments
|
||||
args = (char *)malloc(maxargs);
|
||||
if (args == NULL) {
|
||||
JNU_ThrowOutOfMemoryError(env, "malloc failed");
|
||||
return;
|
||||
}
|
||||
|
||||
do { // a block to break out of on error
|
||||
char *argsEnd;
|
||||
jstring cmdexe = NULL;
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROCARGS2;
|
||||
mib[2] = pid;
|
||||
size = (size_t) maxargs;
|
||||
if (sysctl(mib, 3, args, &size, NULL, 0) == -1) {
|
||||
if (errno != EINVAL) {
|
||||
JNU_ThrowByNameWithLastError(env,
|
||||
"java/lang/RuntimeException", "sysctl failed");
|
||||
}
|
||||
break;
|
||||
}
|
||||
memcpy(&nargs, args, sizeof(nargs));
|
||||
|
||||
cp = &args[sizeof(nargs)]; // Strings start after nargs
|
||||
argsEnd = &args[size];
|
||||
|
||||
// Store the command executable path
|
||||
if ((cmdexe = JNU_NewStringPlatform(env, cp)) == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Skip trailing nulls after the executable path
|
||||
for (cp = cp + strnlen(cp, argsEnd - cp); cp < argsEnd; cp++) {
|
||||
if (*cp != '\0') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unix_fillArgArray(env, jinfo, nargs, cp, argsEnd, cmdexe, NULL);
|
||||
} while (0);
|
||||
// Free the arg buffer
|
||||
free(args);
|
||||
}
|
||||
|
470
src/java.base/macosx/native/libjava/java_props_macosx.c
Normal file
470
src/java.base/macosx/native/libjava/java_props_macosx.c
Normal file
|
@ -0,0 +1,470 @@
|
|||
/*
|
||||
* Copyright (c) 1998, 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.
|
||||
*/
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <objc/objc-runtime.h>
|
||||
|
||||
#include <Security/AuthSession.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <SystemConfiguration/SystemConfiguration.h>
|
||||
#include <Foundation/Foundation.h>
|
||||
|
||||
#include "java_props_macosx.h"
|
||||
|
||||
char *getPosixLocale(int cat) {
|
||||
char *lc = setlocale(cat, NULL);
|
||||
if ((lc == NULL) || (strcmp(lc, "C") == 0)) {
|
||||
lc = getenv("LANG");
|
||||
}
|
||||
if (lc == NULL) return NULL;
|
||||
return strdup(lc);
|
||||
}
|
||||
|
||||
#define LOCALEIDLENGTH 128
|
||||
char *getMacOSXLocale(int cat) {
|
||||
const char* retVal = NULL;
|
||||
char localeString[LOCALEIDLENGTH];
|
||||
|
||||
switch (cat) {
|
||||
case LC_MESSAGES:
|
||||
{
|
||||
// get preferred language code
|
||||
CFArrayRef languages = CFLocaleCopyPreferredLanguages();
|
||||
if (languages == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (CFArrayGetCount(languages) <= 0) {
|
||||
CFRelease(languages);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CFStringRef primaryLanguage = (CFStringRef)CFArrayGetValueAtIndex(languages, 0);
|
||||
if (primaryLanguage == NULL) {
|
||||
CFRelease(languages);
|
||||
return NULL;
|
||||
}
|
||||
char languageString[LOCALEIDLENGTH];
|
||||
if (CFStringGetCString(primaryLanguage, languageString,
|
||||
LOCALEIDLENGTH, CFStringGetSystemEncoding()) == false) {
|
||||
CFRelease(languages);
|
||||
return NULL;
|
||||
}
|
||||
CFRelease(languages);
|
||||
|
||||
// Explicitly supply region, if there is none
|
||||
char *hyphenPos = strchr(languageString, '-');
|
||||
int langStrLen = strlen(languageString);
|
||||
|
||||
if (hyphenPos == NULL || // languageString contains ISO639 only, e.g., "en"
|
||||
languageString + langStrLen - hyphenPos == 5) { // ISO639-ScriptCode, e.g., "en-Latn"
|
||||
CFStringGetCString(CFLocaleGetIdentifier(CFLocaleCopyCurrent()),
|
||||
localeString, LOCALEIDLENGTH, CFStringGetSystemEncoding());
|
||||
char *underscorePos = strrchr(localeString, '_');
|
||||
char *region = NULL;
|
||||
|
||||
if (underscorePos != NULL) {
|
||||
region = underscorePos + 1;
|
||||
}
|
||||
|
||||
if (region != NULL) {
|
||||
strcat(languageString, "-");
|
||||
strcat(languageString, region);
|
||||
}
|
||||
}
|
||||
|
||||
retVal = languageString;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
if (!CFStringGetCString(CFLocaleGetIdentifier(CFLocaleCopyCurrent()),
|
||||
localeString, LOCALEIDLENGTH, CFStringGetSystemEncoding())) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
retVal = localeString;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (retVal != NULL) {
|
||||
return strdup(convertToPOSIXLocale(retVal));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Language IDs use the language designators and (optional) region
|
||||
* and script designators of BCP 47. So possible formats are:
|
||||
*
|
||||
* "en" (language designator only)
|
||||
* "haw" (3-letter lanuage designator)
|
||||
* "en-GB" (language with alpha-2 region designator)
|
||||
* "es-419" (language with 3-digit UN M.49 area code)
|
||||
* "zh-Hans" (language with ISO 15924 script designator)
|
||||
* "zh-Hans-US" (language with ISO 15924 script designator and region)
|
||||
* "zh-Hans-419" (language with ISO 15924 script designator and UN M.49)
|
||||
*
|
||||
* convert these tags into POSIX conforming locale string, i.e.,
|
||||
* lang{_region}{@script}. e.g., for "zh-Hans-US" into "zh_US@Hans"
|
||||
*/
|
||||
const char * convertToPOSIXLocale(const char* src) {
|
||||
char* scriptRegion = strchr(src, '-');
|
||||
if (scriptRegion != NULL) {
|
||||
int length = strlen(scriptRegion);
|
||||
char* region = strchr(scriptRegion + 1, '-');
|
||||
char* atMark = NULL;
|
||||
|
||||
if (region == NULL) {
|
||||
// CFLocaleGetIdentifier() returns '_' before region
|
||||
region = strchr(scriptRegion + 1, '_');
|
||||
}
|
||||
|
||||
*scriptRegion = '_';
|
||||
if (length > 5) {
|
||||
// Region and script both exist.
|
||||
char tmpScript[4];
|
||||
int regionLength = length - 6;
|
||||
atMark = scriptRegion + 1 + regionLength;
|
||||
memcpy(tmpScript, scriptRegion + 1, 4);
|
||||
memmove(scriptRegion + 1, region + 1, regionLength);
|
||||
memcpy(atMark + 1, tmpScript, 4);
|
||||
} else if (length == 5) {
|
||||
// script only
|
||||
atMark = scriptRegion;
|
||||
}
|
||||
|
||||
if (atMark != NULL) {
|
||||
*atMark = '@';
|
||||
|
||||
// assert script code
|
||||
assert(isalpha(atMark[1]) &&
|
||||
isalpha(atMark[2]) &&
|
||||
isalpha(atMark[3]) &&
|
||||
isalpha(atMark[4]));
|
||||
}
|
||||
|
||||
assert(((length == 3 || length == 8) &&
|
||||
// '_' followed by a 2 character region designator
|
||||
isalpha(scriptRegion[1]) &&
|
||||
isalpha(scriptRegion[2])) ||
|
||||
((length == 4 || length == 9) &&
|
||||
// '_' followed by a 3-digit UN M.49 area code
|
||||
isdigit(scriptRegion[1]) &&
|
||||
isdigit(scriptRegion[2]) &&
|
||||
isdigit(scriptRegion[3])) ||
|
||||
// '@' followed by a 4 character script code (already validated above)
|
||||
(length == 5));
|
||||
}
|
||||
|
||||
return src;
|
||||
}
|
||||
|
||||
char *setupMacOSXLocale(int cat) {
|
||||
char * ret = getMacOSXLocale(cat);
|
||||
|
||||
if (ret == NULL) {
|
||||
return getPosixLocale(cat);
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
int isInAquaSession() {
|
||||
// environment variable to bypass the aqua session check
|
||||
char *ev = getenv("AWT_FORCE_HEADFUL");
|
||||
if (ev && (strncasecmp(ev, "true", 4) == 0)) {
|
||||
// if "true" then tell the caller we're in an Aqua session without actually checking
|
||||
return 1;
|
||||
}
|
||||
// Is the WindowServer available?
|
||||
SecuritySessionId session_id;
|
||||
SessionAttributeBits session_info;
|
||||
OSStatus status = SessionGetInfo(callerSecuritySession, &session_id, &session_info);
|
||||
if (status == noErr) {
|
||||
if (session_info & sessionHasGraphicAccess) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 10.9 SDK does not include the NSOperatingSystemVersion struct.
|
||||
// For now, create our own
|
||||
typedef struct {
|
||||
NSInteger majorVersion;
|
||||
NSInteger minorVersion;
|
||||
NSInteger patchVersion;
|
||||
} OSVerStruct;
|
||||
|
||||
void setOSNameAndVersion(java_props_t *sprops) {
|
||||
// Hardcode os_name, and fill in os_version
|
||||
sprops->os_name = strdup("Mac OS X");
|
||||
|
||||
char* osVersionCStr = NULL;
|
||||
// Mac OS 10.9 includes the [NSProcessInfo operatingSystemVersion] function,
|
||||
// but it's not in the 10.9 SDK. So, call it via objc_msgSend_stret.
|
||||
if ([[NSProcessInfo processInfo] respondsToSelector:@selector(operatingSystemVersion)]) {
|
||||
OSVerStruct (*procInfoFn)(id rec, SEL sel) = (OSVerStruct(*)(id, SEL))objc_msgSend_stret;
|
||||
OSVerStruct osVer = procInfoFn([NSProcessInfo processInfo],
|
||||
@selector(operatingSystemVersion));
|
||||
NSString *nsVerStr;
|
||||
if (osVer.patchVersion == 0) { // Omit trailing ".0"
|
||||
nsVerStr = [NSString stringWithFormat:@"%ld.%ld",
|
||||
(long)osVer.majorVersion, (long)osVer.minorVersion];
|
||||
} else {
|
||||
nsVerStr = [NSString stringWithFormat:@"%ld.%ld.%ld",
|
||||
(long)osVer.majorVersion, (long)osVer.minorVersion, (long)osVer.patchVersion];
|
||||
}
|
||||
// Copy out the char*
|
||||
osVersionCStr = strdup([nsVerStr UTF8String]);
|
||||
}
|
||||
// Fallback if running on pre-10.9 Mac OS
|
||||
if (osVersionCStr == NULL) {
|
||||
NSDictionary *version = [NSDictionary dictionaryWithContentsOfFile :
|
||||
@"/System/Library/CoreServices/SystemVersion.plist"];
|
||||
if (version != NULL) {
|
||||
NSString *nsVerStr = [version objectForKey : @"ProductVersion"];
|
||||
if (nsVerStr != NULL) {
|
||||
osVersionCStr = strdup([nsVerStr UTF8String]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (osVersionCStr == NULL) {
|
||||
osVersionCStr = strdup("Unknown");
|
||||
}
|
||||
sprops->os_version = osVersionCStr;
|
||||
}
|
||||
|
||||
|
||||
static Boolean getProxyInfoForProtocol(CFDictionaryRef inDict, CFStringRef inEnabledKey,
|
||||
CFStringRef inHostKey, CFStringRef inPortKey,
|
||||
CFStringRef *outProxyHost, int *ioProxyPort) {
|
||||
/* See if the proxy is enabled. */
|
||||
CFNumberRef cf_enabled = CFDictionaryGetValue(inDict, inEnabledKey);
|
||||
if (cf_enabled == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int isEnabled = false;
|
||||
if (!CFNumberGetValue(cf_enabled, kCFNumberIntType, &isEnabled)) {
|
||||
return isEnabled;
|
||||
}
|
||||
|
||||
if (!isEnabled) return false;
|
||||
*outProxyHost = CFDictionaryGetValue(inDict, inHostKey);
|
||||
|
||||
// If cf_host is null, that means the checkbox is set,
|
||||
// but no host was entered. We'll treat that as NOT ENABLED.
|
||||
// If cf_port is null or cf_port isn't a number, that means
|
||||
// no port number was entered. Treat this as ENABLED with the
|
||||
// protocol's default port.
|
||||
if (*outProxyHost == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CFStringGetLength(*outProxyHost) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int newPort = 0;
|
||||
CFNumberRef cf_port = NULL;
|
||||
if ((cf_port = CFDictionaryGetValue(inDict, inPortKey)) != NULL &&
|
||||
CFNumberGetValue(cf_port, kCFNumberIntType, &newPort) &&
|
||||
newPort > 0) {
|
||||
*ioProxyPort = newPort;
|
||||
} else {
|
||||
// bad port or no port - leave *ioProxyPort unchanged
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static char *createUTF8CString(const CFStringRef theString) {
|
||||
if (theString == NULL) return NULL;
|
||||
|
||||
const CFIndex stringLength = CFStringGetLength(theString);
|
||||
const CFIndex bufSize = CFStringGetMaximumSizeForEncoding(stringLength, kCFStringEncodingUTF8) + 1;
|
||||
char *returnVal = (char *)malloc(bufSize);
|
||||
|
||||
if (CFStringGetCString(theString, returnVal, bufSize, kCFStringEncodingUTF8)) {
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
free(returnVal);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Return TRUE if str is a syntactically valid IP address.
|
||||
// Using inet_pton() instead of inet_aton() for IPv6 support.
|
||||
// len is only a hint; cstr must still be nul-terminated
|
||||
static int looksLikeIPAddress(char *cstr, size_t len) {
|
||||
if (len == 0 || (len == 1 && cstr[0] == '.')) return FALSE;
|
||||
|
||||
char dst[16]; // big enough for INET6
|
||||
return (1 == inet_pton(AF_INET, cstr, dst) ||
|
||||
1 == inet_pton(AF_INET6, cstr, dst));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Convert Mac OS X proxy exception entry to Java syntax.
|
||||
// See Radar #3441134 for details.
|
||||
// Returns NULL if this exception should be ignored by Java.
|
||||
// May generate a string with multiple exceptions separated by '|'.
|
||||
static char * createConvertedException(CFStringRef cf_original) {
|
||||
// This is done with char* instead of CFString because inet_pton()
|
||||
// needs a C string.
|
||||
char *c_exception = createUTF8CString(cf_original);
|
||||
if (!c_exception) return NULL;
|
||||
|
||||
int c_len = strlen(c_exception);
|
||||
|
||||
// 1. sanitize exception prefix
|
||||
if (c_len >= 1 && 0 == strncmp(c_exception, ".", 1)) {
|
||||
memmove(c_exception, c_exception+1, c_len);
|
||||
c_len -= 1;
|
||||
} else if (c_len >= 2 && 0 == strncmp(c_exception, "*.", 2)) {
|
||||
memmove(c_exception, c_exception+2, c_len-1);
|
||||
c_len -= 2;
|
||||
}
|
||||
|
||||
// 2. pre-reject other exception wildcards
|
||||
if (strchr(c_exception, '*')) {
|
||||
free(c_exception);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 3. no IP wildcarding
|
||||
if (looksLikeIPAddress(c_exception, c_len)) {
|
||||
return c_exception;
|
||||
}
|
||||
|
||||
// 4. allow domain suffixes
|
||||
// c_exception is now "str\0" - change to "str|*.str\0"
|
||||
c_exception = reallocf(c_exception, c_len+3+c_len+1);
|
||||
if (!c_exception) return NULL;
|
||||
|
||||
strncpy(c_exception+c_len, "|*.", 3);
|
||||
strncpy(c_exception+c_len+3, c_exception, c_len);
|
||||
c_exception[c_len+3+c_len] = '\0';
|
||||
return c_exception;
|
||||
}
|
||||
|
||||
/*
|
||||
* Method for fetching the user.home path and storing it in the property list.
|
||||
* For signed .apps running in the Mac App Sandbox, user.home is set to the
|
||||
* app's sandbox container.
|
||||
*/
|
||||
void setUserHome(java_props_t *sprops) {
|
||||
if (sprops == NULL) { return; }
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
sprops->user_home = createUTF8CString((CFStringRef)NSHomeDirectory());
|
||||
[pool drain];
|
||||
}
|
||||
|
||||
/*
|
||||
* Method for fetching proxy info and storing it in the property list.
|
||||
*/
|
||||
void setProxyProperties(java_props_t *sProps) {
|
||||
if (sProps == NULL) return;
|
||||
|
||||
char buf[16]; /* Used for %d of an int - 16 is plenty */
|
||||
CFStringRef
|
||||
cf_httpHost = NULL,
|
||||
cf_httpsHost = NULL,
|
||||
cf_ftpHost = NULL,
|
||||
cf_socksHost = NULL,
|
||||
cf_gopherHost = NULL;
|
||||
int
|
||||
httpPort = 80, // Default proxy port values
|
||||
httpsPort = 443,
|
||||
ftpPort = 21,
|
||||
socksPort = 1080,
|
||||
gopherPort = 70;
|
||||
|
||||
CFDictionaryRef dict = SCDynamicStoreCopyProxies(NULL);
|
||||
if (dict == NULL) return;
|
||||
|
||||
/* Read the proxy exceptions list */
|
||||
CFArrayRef cf_list = CFDictionaryGetValue(dict, kSCPropNetProxiesExceptionsList);
|
||||
|
||||
CFMutableStringRef cf_exceptionList = NULL;
|
||||
if (cf_list != NULL) {
|
||||
CFIndex len = CFArrayGetCount(cf_list), idx;
|
||||
|
||||
cf_exceptionList = CFStringCreateMutable(NULL, 0);
|
||||
for (idx = (CFIndex)0; idx < len; idx++) {
|
||||
CFStringRef cf_ehost;
|
||||
if ((cf_ehost = CFArrayGetValueAtIndex(cf_list, idx))) {
|
||||
/* Convert this exception from Mac OS X syntax to Java syntax.
|
||||
See Radar #3441134 for details. This may generate a string
|
||||
with multiple Java exceptions separated by '|'. */
|
||||
char *c_exception = createConvertedException(cf_ehost);
|
||||
if (c_exception) {
|
||||
/* Append the host to the list of exclusions. */
|
||||
if (CFStringGetLength(cf_exceptionList) > 0) {
|
||||
CFStringAppendCString(cf_exceptionList, "|", kCFStringEncodingMacRoman);
|
||||
}
|
||||
CFStringAppendCString(cf_exceptionList, c_exception, kCFStringEncodingMacRoman);
|
||||
free(c_exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cf_exceptionList != NULL) {
|
||||
if (CFStringGetLength(cf_exceptionList) > 0) {
|
||||
sProps->exceptionList = createUTF8CString(cf_exceptionList);
|
||||
}
|
||||
CFRelease(cf_exceptionList);
|
||||
}
|
||||
|
||||
#define CHECK_PROXY(protocol, PROTOCOL) \
|
||||
sProps->protocol##ProxyEnabled = \
|
||||
getProxyInfoForProtocol(dict, kSCPropNetProxies##PROTOCOL##Enable, \
|
||||
kSCPropNetProxies##PROTOCOL##Proxy, \
|
||||
kSCPropNetProxies##PROTOCOL##Port, \
|
||||
&cf_##protocol##Host, &protocol##Port); \
|
||||
if (sProps->protocol##ProxyEnabled) { \
|
||||
sProps->protocol##Host = createUTF8CString(cf_##protocol##Host); \
|
||||
snprintf(buf, sizeof(buf), "%d", protocol##Port); \
|
||||
sProps->protocol##Port = malloc(strlen(buf) + 1); \
|
||||
strcpy(sProps->protocol##Port, buf); \
|
||||
}
|
||||
|
||||
CHECK_PROXY(http, HTTP);
|
||||
CHECK_PROXY(https, HTTPS);
|
||||
CHECK_PROXY(ftp, FTP);
|
||||
CHECK_PROXY(socks, SOCKS);
|
||||
CHECK_PROXY(gopher, Gopher);
|
||||
|
||||
#undef CHECK_PROXY
|
||||
|
||||
CFRelease(dict);
|
||||
}
|
33
src/java.base/macosx/native/libjava/java_props_macosx.h
Normal file
33
src/java.base/macosx/native/libjava/java_props_macosx.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 1998, 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.
|
||||
*/
|
||||
|
||||
#include "java_props.h"
|
||||
|
||||
char *setupMacOSXLocale(int cat);
|
||||
const char *convertToPOSIXLocale(const char* src);
|
||||
void setOSNameAndVersion(java_props_t *sprops);
|
||||
void setUserHome(java_props_t *sprops);
|
||||
void setProxyProperties(java_props_t *sProps);
|
||||
int isInAquaSession();
|
943
src/java.base/macosx/native/libjli/java_md_macosx.c
Normal file
943
src/java.base/macosx/native/libjli/java_md_macosx.c
Normal file
|
@ -0,0 +1,943 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 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.
|
||||
*/
|
||||
|
||||
#include "java.h"
|
||||
#include "jvm_md.h"
|
||||
#include <dirent.h>
|
||||
#include <dlfcn.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "manifest_info.h"
|
||||
|
||||
/* Support Cocoa event loop on the main thread */
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#include <objc/objc-runtime.h>
|
||||
#include <objc/objc-auto.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <spawn.h>
|
||||
|
||||
struct NSAppArgs {
|
||||
int argc;
|
||||
char **argv;
|
||||
};
|
||||
|
||||
#define JVM_DLL "libjvm.dylib"
|
||||
#define JAVA_DLL "libjava.dylib"
|
||||
/* FALLBACK avoids naming conflicts with system libraries
|
||||
* (eg, ImageIO's libJPEG.dylib) */
|
||||
#define LD_LIBRARY_PATH "DYLD_FALLBACK_LIBRARY_PATH"
|
||||
|
||||
/*
|
||||
* If a processor / os combination has the ability to run binaries of
|
||||
* two data models and cohabitation of jre/jdk bits with both data
|
||||
* models is supported, then DUAL_MODE is defined. MacOSX is a hybrid
|
||||
* system in that, the universal library can contain all types of libraries
|
||||
* 32/64 and client/server, thus the spawn is capable of linking with the
|
||||
* appropriate library as requested.
|
||||
*
|
||||
* Notes:
|
||||
* 1. VM. DUAL_MODE is disabled, and not supported, however, it is left here in
|
||||
* for experimentation and perhaps enable it in the future.
|
||||
* 2. At the time of this writing, the universal library contains only
|
||||
* a server 64-bit server JVM.
|
||||
* 3. "-client" command line option is supported merely as a command line flag,
|
||||
* for, compatibility reasons, however, a server VM will be launched.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Flowchart of launcher execs and options processing on unix
|
||||
*
|
||||
* The selection of the proper vm shared library to open depends on
|
||||
* several classes of command line options, including vm "flavor"
|
||||
* options (-client, -server) and the data model options, -d32 and
|
||||
* -d64, as well as a version specification which may have come from
|
||||
* the command line or from the manifest of an executable jar file.
|
||||
* The vm selection options are not passed to the running
|
||||
* virtual machine; they must be screened out by the launcher.
|
||||
*
|
||||
* The version specification (if any) is processed first by the
|
||||
* platform independent routine SelectVersion. This may result in
|
||||
* the exec of the specified launcher version.
|
||||
*
|
||||
* Now, in most cases,the launcher will dlopen the target libjvm.so. All
|
||||
* required libraries are loaded by the runtime linker, using the known paths
|
||||
* baked into the shared libraries at compile time. Therefore,
|
||||
* in most cases, the launcher will only exec, if the data models are
|
||||
* mismatched, and will not set any environment variables, regardless of the
|
||||
* data models.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Main
|
||||
* (incoming argv)
|
||||
* |
|
||||
* \|/
|
||||
* CreateExecutionEnvironment
|
||||
* (determines desired data model)
|
||||
* |
|
||||
* |
|
||||
* \|/
|
||||
* Have Desired Model ? --> NO --> Is Dual-Mode ? --> NO --> Exit(with error)
|
||||
* | |
|
||||
* | |
|
||||
* | \|/
|
||||
* | YES
|
||||
* | |
|
||||
* | |
|
||||
* | \|/
|
||||
* | CheckJvmType
|
||||
* | (removes -client, -server etc.)
|
||||
* | |
|
||||
* | |
|
||||
* \|/ \|/
|
||||
* YES Find the desired executable/library
|
||||
* | |
|
||||
* | |
|
||||
* \|/ \|/
|
||||
* CheckJvmType POINT A
|
||||
* (removes -client, -server, etc.)
|
||||
* |
|
||||
* |
|
||||
* \|/
|
||||
* TranslateDashJArgs...
|
||||
* (Prepare to pass args to vm)
|
||||
* |
|
||||
* |
|
||||
* \|/
|
||||
* ParseArguments
|
||||
* (processes version options,
|
||||
* creates argument list for vm,
|
||||
* etc.)
|
||||
* |
|
||||
* |
|
||||
* \|/
|
||||
* POINT A
|
||||
* |
|
||||
* |
|
||||
* \|/
|
||||
* Path is desired JRE ? YES --> Continue
|
||||
* NO
|
||||
* |
|
||||
* |
|
||||
* \|/
|
||||
* Paths have well known
|
||||
* jvm paths ? --> NO --> Continue
|
||||
* YES
|
||||
* |
|
||||
* |
|
||||
* \|/
|
||||
* Does libjvm.so exist
|
||||
* in any of them ? --> NO --> Continue
|
||||
* YES
|
||||
* |
|
||||
* |
|
||||
* \|/
|
||||
* Re-exec / Spawn
|
||||
* |
|
||||
* |
|
||||
* \|/
|
||||
* Main
|
||||
*/
|
||||
|
||||
/* Store the name of the executable once computed */
|
||||
static char *execname = NULL;
|
||||
|
||||
/*
|
||||
* execname accessor from other parts of platform dependent logic
|
||||
*/
|
||||
const char *
|
||||
GetExecName() {
|
||||
return execname;
|
||||
}
|
||||
|
||||
/*
|
||||
* Exports the JNI interface from libjli
|
||||
*
|
||||
* This allows client code to link against the .jre/.jdk bundles,
|
||||
* and not worry about trying to pick a HotSpot to link against.
|
||||
*
|
||||
* Switching architectures is unsupported, since client code has
|
||||
* made that choice before the JVM was requested.
|
||||
*/
|
||||
|
||||
static InvocationFunctions *sExportedJNIFunctions = NULL;
|
||||
static char *sPreferredJVMType = NULL;
|
||||
|
||||
static InvocationFunctions *GetExportedJNIFunctions() {
|
||||
if (sExportedJNIFunctions != NULL) return sExportedJNIFunctions;
|
||||
|
||||
char jrePath[PATH_MAX];
|
||||
jboolean gotJREPath = GetJREPath(jrePath, sizeof(jrePath), JNI_FALSE);
|
||||
if (!gotJREPath) {
|
||||
JLI_ReportErrorMessage("Failed to GetJREPath()");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *preferredJVM = sPreferredJVMType;
|
||||
if (preferredJVM == NULL) {
|
||||
#if defined(__i386__)
|
||||
preferredJVM = "client";
|
||||
#elif defined(__x86_64__)
|
||||
preferredJVM = "server";
|
||||
#else
|
||||
#error "Unknown architecture - needs definition"
|
||||
#endif
|
||||
}
|
||||
|
||||
char jvmPath[PATH_MAX];
|
||||
jboolean gotJVMPath = GetJVMPath(jrePath, preferredJVM, jvmPath, sizeof(jvmPath));
|
||||
if (!gotJVMPath) {
|
||||
JLI_ReportErrorMessage("Failed to GetJVMPath()");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
InvocationFunctions *fxns = malloc(sizeof(InvocationFunctions));
|
||||
jboolean vmLoaded = LoadJavaVM(jvmPath, fxns);
|
||||
if (!vmLoaded) {
|
||||
JLI_ReportErrorMessage("Failed to LoadJavaVM()");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return sExportedJNIFunctions = fxns;
|
||||
}
|
||||
|
||||
#ifndef STATIC_BUILD
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
JNI_GetDefaultJavaVMInitArgs(void *args) {
|
||||
InvocationFunctions *ifn = GetExportedJNIFunctions();
|
||||
if (ifn == NULL) return JNI_ERR;
|
||||
return ifn->GetDefaultJavaVMInitArgs(args);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args) {
|
||||
InvocationFunctions *ifn = GetExportedJNIFunctions();
|
||||
if (ifn == NULL) return JNI_ERR;
|
||||
return ifn->CreateJavaVM(pvm, penv, args);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
JNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen, jsize *nVMs) {
|
||||
InvocationFunctions *ifn = GetExportedJNIFunctions();
|
||||
if (ifn == NULL) return JNI_ERR;
|
||||
return ifn->GetCreatedJavaVMs(vmBuf, bufLen, nVMs);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Allow JLI-aware launchers to specify a client/server preference
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
JLI_SetPreferredJVM(const char *prefJVM) {
|
||||
if (sPreferredJVMType != NULL) {
|
||||
free(sPreferredJVMType);
|
||||
sPreferredJVMType = NULL;
|
||||
}
|
||||
|
||||
if (prefJVM == NULL) return;
|
||||
sPreferredJVMType = strdup(prefJVM);
|
||||
}
|
||||
|
||||
static BOOL awtLoaded = NO;
|
||||
static pthread_mutex_t awtLoaded_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_cond_t awtLoaded_cv = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
JLI_NotifyAWTLoaded()
|
||||
{
|
||||
pthread_mutex_lock(&awtLoaded_mutex);
|
||||
awtLoaded = YES;
|
||||
pthread_cond_signal(&awtLoaded_cv);
|
||||
pthread_mutex_unlock(&awtLoaded_mutex);
|
||||
}
|
||||
|
||||
static int (*main_fptr)(int argc, char **argv) = NULL;
|
||||
|
||||
/*
|
||||
* Unwrap the arguments and re-run main()
|
||||
*/
|
||||
static void *apple_main (void *arg)
|
||||
{
|
||||
if (main_fptr == NULL) {
|
||||
#ifdef STATIC_BUILD
|
||||
extern int main(int argc, char **argv);
|
||||
main_fptr = &main;
|
||||
#else
|
||||
main_fptr = (int (*)())dlsym(RTLD_DEFAULT, "main");
|
||||
#endif
|
||||
if (main_fptr == NULL) {
|
||||
JLI_ReportErrorMessageSys("error locating main entrypoint\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
struct NSAppArgs *args = (struct NSAppArgs *) arg;
|
||||
exit(main_fptr(args->argc, args->argv));
|
||||
}
|
||||
|
||||
static void dummyTimer(CFRunLoopTimerRef timer, void *info) {}
|
||||
|
||||
static void ParkEventLoop() {
|
||||
// RunLoop needs at least one source, and 1e20 is pretty far into the future
|
||||
CFRunLoopTimerRef t = CFRunLoopTimerCreate(kCFAllocatorDefault, 1.0e20, 0.0, 0, 0, dummyTimer, NULL);
|
||||
CFRunLoopAddTimer(CFRunLoopGetCurrent(), t, kCFRunLoopDefaultMode);
|
||||
CFRelease(t);
|
||||
|
||||
// Park this thread in the main run loop.
|
||||
int32_t result;
|
||||
do {
|
||||
result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e20, false);
|
||||
} while (result != kCFRunLoopRunFinished);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mac OS X mandates that the GUI event loop run on very first thread of
|
||||
* an application. This requires that we re-call Java's main() on a new
|
||||
* thread, reserving the 'main' thread for Cocoa.
|
||||
*/
|
||||
static void MacOSXStartup(int argc, char *argv[]) {
|
||||
// Thread already started?
|
||||
static jboolean started = false;
|
||||
if (started) {
|
||||
return;
|
||||
}
|
||||
started = true;
|
||||
|
||||
// Hand off arguments
|
||||
struct NSAppArgs args;
|
||||
args.argc = argc;
|
||||
args.argv = argv;
|
||||
|
||||
// Fire up the main thread
|
||||
pthread_t main_thr;
|
||||
if (pthread_create(&main_thr, NULL, &apple_main, &args) != 0) {
|
||||
JLI_ReportErrorMessageSys("Could not create main thread: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if (pthread_detach(main_thr)) {
|
||||
JLI_ReportErrorMessageSys("pthread_detach() failed: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ParkEventLoop();
|
||||
}
|
||||
|
||||
void
|
||||
CreateExecutionEnvironment(int *pargc, char ***pargv,
|
||||
char jrepath[], jint so_jrepath,
|
||||
char jvmpath[], jint so_jvmpath,
|
||||
char jvmcfg[], jint so_jvmcfg) {
|
||||
jboolean jvmpathExists;
|
||||
|
||||
/* Compute/set the name of the executable */
|
||||
SetExecname(*pargv);
|
||||
|
||||
char * jvmtype = NULL;
|
||||
int argc = *pargc;
|
||||
char **argv = *pargv;
|
||||
|
||||
/* Find out where the JRE is that we will be using. */
|
||||
if (!GetJREPath(jrepath, so_jrepath, JNI_FALSE) ) {
|
||||
JLI_ReportErrorMessage(JRE_ERROR1);
|
||||
exit(2);
|
||||
}
|
||||
JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%sjvm.cfg",
|
||||
jrepath, FILESEP, FILESEP);
|
||||
/* Find the specified JVM type */
|
||||
if (ReadKnownVMs(jvmcfg, JNI_FALSE) < 1) {
|
||||
JLI_ReportErrorMessage(CFG_ERROR7);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
jvmpath[0] = '\0';
|
||||
jvmtype = CheckJvmType(pargc, pargv, JNI_FALSE);
|
||||
if (JLI_StrCmp(jvmtype, "ERROR") == 0) {
|
||||
JLI_ReportErrorMessage(CFG_ERROR9);
|
||||
exit(4);
|
||||
}
|
||||
|
||||
if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath)) {
|
||||
JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath);
|
||||
exit(4);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mac OS X requires the Cocoa event loop to be run on the "main"
|
||||
* thread. Spawn off a new thread to run main() and pass
|
||||
* this thread off to the Cocoa event loop.
|
||||
*/
|
||||
MacOSXStartup(argc, argv);
|
||||
|
||||
/*
|
||||
* we seem to have everything we need
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* VM choosing is done by the launcher (java.c).
|
||||
*/
|
||||
static jboolean
|
||||
GetJVMPath(const char *jrepath, const char *jvmtype,
|
||||
char *jvmpath, jint jvmpathsize)
|
||||
{
|
||||
struct stat s;
|
||||
|
||||
if (JLI_StrChr(jvmtype, '/')) {
|
||||
JLI_Snprintf(jvmpath, jvmpathsize, "%s/" JVM_DLL, jvmtype);
|
||||
} else {
|
||||
/*
|
||||
* macosx client library is built thin, i386 only.
|
||||
* 64 bit client requests must load server library
|
||||
*/
|
||||
JLI_Snprintf(jvmpath, jvmpathsize, "%s/lib/%s/" JVM_DLL, jrepath, jvmtype);
|
||||
}
|
||||
|
||||
JLI_TraceLauncher("Does `%s' exist ... ", jvmpath);
|
||||
|
||||
#ifdef STATIC_BUILD
|
||||
return JNI_TRUE;
|
||||
#else
|
||||
if (stat(jvmpath, &s) == 0) {
|
||||
JLI_TraceLauncher("yes.\n");
|
||||
return JNI_TRUE;
|
||||
} else {
|
||||
JLI_TraceLauncher("no.\n");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Find path to JRE based on .exe's location or registry settings.
|
||||
*/
|
||||
static jboolean
|
||||
GetJREPath(char *path, jint pathsize, jboolean speculative)
|
||||
{
|
||||
char libjava[MAXPATHLEN];
|
||||
|
||||
if (GetApplicationHome(path, pathsize)) {
|
||||
/* Is JRE co-located with the application? */
|
||||
#ifdef STATIC_BUILD
|
||||
char jvm_cfg[MAXPATHLEN];
|
||||
JLI_Snprintf(jvm_cfg, sizeof(jvm_cfg), "%s/lib/jvm.cfg", path);
|
||||
if (access(jvm_cfg, F_OK) == 0) {
|
||||
return JNI_TRUE;
|
||||
}
|
||||
#else
|
||||
JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path);
|
||||
if (access(libjava, F_OK) == 0) {
|
||||
return JNI_TRUE;
|
||||
}
|
||||
#endif
|
||||
/* ensure storage for path + /jre + NULL */
|
||||
if ((JLI_StrLen(path) + 4 + 1) > (size_t) pathsize) {
|
||||
JLI_TraceLauncher("Insufficient space to store JRE path\n");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
/* Does the app ship a private JRE in <apphome>/jre directory? */
|
||||
JLI_Snprintf(libjava, sizeof(libjava), "%s/jre/lib/" JAVA_DLL, path);
|
||||
if (access(libjava, F_OK) == 0) {
|
||||
JLI_StrCat(path, "/jre");
|
||||
JLI_TraceLauncher("JRE path is %s\n", path);
|
||||
return JNI_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* try to find ourselves instead */
|
||||
Dl_info selfInfo;
|
||||
dladdr(&GetJREPath, &selfInfo);
|
||||
|
||||
#ifdef STATIC_BUILD
|
||||
char jvm_cfg[MAXPATHLEN];
|
||||
char *p = NULL;
|
||||
strncpy(jvm_cfg, selfInfo.dli_fname, MAXPATHLEN);
|
||||
p = strrchr(jvm_cfg, '/'); *p = '\0';
|
||||
p = strrchr(jvm_cfg, '/');
|
||||
if (strcmp(p, "/.") == 0) {
|
||||
*p = '\0';
|
||||
p = strrchr(jvm_cfg, '/'); *p = '\0';
|
||||
}
|
||||
else *p = '\0';
|
||||
strncpy(path, jvm_cfg, pathsize);
|
||||
strncat(jvm_cfg, "/lib/jvm.cfg", MAXPATHLEN);
|
||||
if (access(jvm_cfg, F_OK) == 0) {
|
||||
return JNI_TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
char *realPathToSelf = realpath(selfInfo.dli_fname, path);
|
||||
if (realPathToSelf != path) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
size_t pathLen = strlen(realPathToSelf);
|
||||
if (pathLen == 0) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
const char lastPathComponent[] = "/lib/jli/libjli.dylib";
|
||||
size_t sizeOfLastPathComponent = sizeof(lastPathComponent) - 1;
|
||||
if (pathLen < sizeOfLastPathComponent) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
size_t indexOfLastPathComponent = pathLen - sizeOfLastPathComponent;
|
||||
if (0 == strncmp(realPathToSelf + indexOfLastPathComponent, lastPathComponent, sizeOfLastPathComponent - 1)) {
|
||||
realPathToSelf[indexOfLastPathComponent + 1] = '\0';
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
if (!speculative)
|
||||
JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
jboolean
|
||||
LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn)
|
||||
{
|
||||
Dl_info dlinfo;
|
||||
void *libjvm;
|
||||
|
||||
JLI_TraceLauncher("JVM path is %s\n", jvmpath);
|
||||
|
||||
#ifndef STATIC_BUILD
|
||||
libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL);
|
||||
#else
|
||||
libjvm = dlopen(NULL, RTLD_FIRST);
|
||||
#endif
|
||||
if (libjvm == NULL) {
|
||||
JLI_ReportErrorMessage(DLL_ERROR1, __LINE__);
|
||||
JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
ifn->CreateJavaVM = (CreateJavaVM_t)
|
||||
dlsym(libjvm, "JNI_CreateJavaVM");
|
||||
if (ifn->CreateJavaVM == NULL) {
|
||||
JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t)
|
||||
dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs");
|
||||
if (ifn->GetDefaultJavaVMInitArgs == NULL) {
|
||||
JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
ifn->GetCreatedJavaVMs = (GetCreatedJavaVMs_t)
|
||||
dlsym(libjvm, "JNI_GetCreatedJavaVMs");
|
||||
if (ifn->GetCreatedJavaVMs == NULL) {
|
||||
JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the name of the executable
|
||||
*
|
||||
* In order to re-exec securely we need the absolute path of the
|
||||
* executable. On Solaris getexecname(3c) may not return an absolute
|
||||
* path so we use dladdr to get the filename of the executable and
|
||||
* then use realpath to derive an absolute path. From Solaris 9
|
||||
* onwards the filename returned in DL_info structure from dladdr is
|
||||
* an absolute pathname so technically realpath isn't required.
|
||||
* On Linux we read the executable name from /proc/self/exe.
|
||||
* As a fallback, and for platforms other than Solaris and Linux,
|
||||
* we use FindExecName to compute the executable name.
|
||||
*/
|
||||
const char*
|
||||
SetExecname(char **argv)
|
||||
{
|
||||
char* exec_path = NULL;
|
||||
{
|
||||
Dl_info dlinfo;
|
||||
|
||||
#ifdef STATIC_BUILD
|
||||
void *fptr;
|
||||
fptr = (void *)&SetExecname;
|
||||
#else
|
||||
int (*fptr)();
|
||||
fptr = (int (*)())dlsym(RTLD_DEFAULT, "main");
|
||||
#endif
|
||||
if (fptr == NULL) {
|
||||
JLI_ReportErrorMessage(DLL_ERROR3, dlerror());
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
if (dladdr((void*)fptr, &dlinfo)) {
|
||||
char *resolved = (char*)JLI_MemAlloc(PATH_MAX+1);
|
||||
if (resolved != NULL) {
|
||||
exec_path = realpath(dlinfo.dli_fname, resolved);
|
||||
if (exec_path == NULL) {
|
||||
JLI_MemFree(resolved);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (exec_path == NULL) {
|
||||
exec_path = FindExecName(argv[0]);
|
||||
}
|
||||
execname = exec_path;
|
||||
return exec_path;
|
||||
}
|
||||
|
||||
/*
|
||||
* BSD's implementation of CounterGet()
|
||||
*/
|
||||
int64_t
|
||||
CounterGet()
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return (tv.tv_sec * 1000) + tv.tv_usec;
|
||||
}
|
||||
|
||||
|
||||
/* --- Splash Screen shared library support --- */
|
||||
|
||||
static JavaVM* SetJavaVMValue()
|
||||
{
|
||||
JavaVM * jvm = NULL;
|
||||
|
||||
// The handle is good for both the launcher and the libosxapp.dylib
|
||||
void * handle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
|
||||
if (handle) {
|
||||
typedef JavaVM* (*JLI_GetJavaVMInstance_t)();
|
||||
|
||||
JLI_GetJavaVMInstance_t JLI_GetJavaVMInstance =
|
||||
(JLI_GetJavaVMInstance_t)dlsym(handle,
|
||||
"JLI_GetJavaVMInstance");
|
||||
if (JLI_GetJavaVMInstance) {
|
||||
jvm = JLI_GetJavaVMInstance();
|
||||
}
|
||||
|
||||
if (jvm) {
|
||||
typedef void (*OSXAPP_SetJavaVM_t)(JavaVM*);
|
||||
|
||||
OSXAPP_SetJavaVM_t OSXAPP_SetJavaVM =
|
||||
(OSXAPP_SetJavaVM_t)dlsym(handle, "OSXAPP_SetJavaVM");
|
||||
if (OSXAPP_SetJavaVM) {
|
||||
OSXAPP_SetJavaVM(jvm);
|
||||
} else {
|
||||
jvm = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
dlclose(handle);
|
||||
}
|
||||
|
||||
return jvm;
|
||||
}
|
||||
|
||||
static const char* SPLASHSCREEN_SO = JNI_LIB_NAME("splashscreen");
|
||||
|
||||
static void* hSplashLib = NULL;
|
||||
|
||||
void* SplashProcAddress(const char* name) {
|
||||
if (!hSplashLib) {
|
||||
char jrePath[PATH_MAX];
|
||||
if (!GetJREPath(jrePath, sizeof(jrePath), JNI_FALSE)) {
|
||||
JLI_ReportErrorMessage(JRE_ERROR1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char splashPath[PATH_MAX];
|
||||
const int ret = JLI_Snprintf(splashPath, sizeof(splashPath),
|
||||
"%s/lib/%s", jrePath, SPLASHSCREEN_SO);
|
||||
if (ret >= (int)sizeof(splashPath)) {
|
||||
JLI_ReportErrorMessage(JRE_ERROR11);
|
||||
return NULL;
|
||||
}
|
||||
if (ret < 0) {
|
||||
JLI_ReportErrorMessage(JRE_ERROR13);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hSplashLib = dlopen(splashPath, RTLD_LAZY | RTLD_GLOBAL);
|
||||
// It's OK if dlopen() fails. The splash screen library binary file
|
||||
// might have been stripped out from the JRE image to reduce its size
|
||||
// (e.g. on embedded platforms).
|
||||
|
||||
if (hSplashLib) {
|
||||
if (!SetJavaVMValue()) {
|
||||
dlclose(hSplashLib);
|
||||
hSplashLib = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hSplashLib) {
|
||||
void* sym = dlsym(hSplashLib, name);
|
||||
return sym;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void SplashFreeLibrary() {
|
||||
if (hSplashLib) {
|
||||
dlclose(hSplashLib);
|
||||
hSplashLib = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Block current thread and continue execution in a new thread
|
||||
*/
|
||||
int
|
||||
ContinueInNewThread0(int (JNICALL *continuation)(void *), jlong stack_size, void * args) {
|
||||
int rslt;
|
||||
pthread_t tid;
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
||||
|
||||
if (stack_size > 0) {
|
||||
pthread_attr_setstacksize(&attr, stack_size);
|
||||
}
|
||||
pthread_attr_setguardsize(&attr, 0); // no pthread guard page on java threads
|
||||
|
||||
if (pthread_create(&tid, &attr, (void *(*)(void*))continuation, (void*)args) == 0) {
|
||||
void * tmp;
|
||||
pthread_join(tid, &tmp);
|
||||
rslt = (int)(intptr_t)tmp;
|
||||
} else {
|
||||
/*
|
||||
* Continue execution in current thread if for some reason (e.g. out of
|
||||
* memory/LWP) a new thread can't be created. This will likely fail
|
||||
* later in continuation as JNI_CreateJavaVM needs to create quite a
|
||||
* few new threads, anyway, just give it a try..
|
||||
*/
|
||||
rslt = continuation(args);
|
||||
}
|
||||
|
||||
pthread_attr_destroy(&attr);
|
||||
return rslt;
|
||||
}
|
||||
|
||||
void SetJavaLauncherPlatformProps() {
|
||||
/* Linux only */
|
||||
}
|
||||
|
||||
static JavaVM* jvmInstance = NULL;
|
||||
static jboolean sameThread = JNI_FALSE; /* start VM in current thread */
|
||||
|
||||
/*
|
||||
* Note there is a callback on this function from the splashscreen logic,
|
||||
* this as well SetJavaVMValue() needs to be simplified.
|
||||
*/
|
||||
JavaVM*
|
||||
JLI_GetJavaVMInstance()
|
||||
{
|
||||
return jvmInstance;
|
||||
}
|
||||
|
||||
void
|
||||
RegisterThread()
|
||||
{
|
||||
// stubbed out for windows and *nixes.
|
||||
}
|
||||
|
||||
static void
|
||||
SetXDockArgForAWT(const char *arg)
|
||||
{
|
||||
char envVar[80];
|
||||
if (strstr(arg, "-Xdock:name=") == arg) {
|
||||
/*
|
||||
* The APP_NAME_<pid> environment variable is used to pass
|
||||
* an application name as specified with the -Xdock:name command
|
||||
* line option from Java launcher code to the AWT code in order
|
||||
* to assign this name to the app's dock tile on the Mac.
|
||||
* The _<pid> part is added to avoid collisions with child processes.
|
||||
*
|
||||
* WARNING: This environment variable is an implementation detail and
|
||||
* isn't meant for use outside of the core platform. The mechanism for
|
||||
* passing this information from Java launcher to other modules may
|
||||
* change drastically between update release, and it may even be
|
||||
* removed or replaced with another mechanism.
|
||||
*
|
||||
* NOTE: It is used by SWT, and JavaFX.
|
||||
*/
|
||||
snprintf(envVar, sizeof(envVar), "APP_NAME_%d", getpid());
|
||||
setenv(envVar, (arg + 12), 1);
|
||||
}
|
||||
|
||||
if (strstr(arg, "-Xdock:icon=") == arg) {
|
||||
/*
|
||||
* The APP_ICON_<pid> environment variable is used to pass
|
||||
* an application icon as specified with the -Xdock:icon command
|
||||
* line option from Java launcher code to the AWT code in order
|
||||
* to assign this icon to the app's dock tile on the Mac.
|
||||
* The _<pid> part is added to avoid collisions with child processes.
|
||||
*
|
||||
* WARNING: This environment variable is an implementation detail and
|
||||
* isn't meant for use outside of the core platform. The mechanism for
|
||||
* passing this information from Java launcher to other modules may
|
||||
* change drastically between update release, and it may even be
|
||||
* removed or replaced with another mechanism.
|
||||
*
|
||||
* NOTE: It is used by SWT, and JavaFX.
|
||||
*/
|
||||
snprintf(envVar, sizeof(envVar), "APP_ICON_%d", getpid());
|
||||
setenv(envVar, (arg + 12), 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
SetMainClassForAWT(JNIEnv *env, jclass mainClass) {
|
||||
jclass classClass = NULL;
|
||||
NULL_CHECK(classClass = FindBootStrapClass(env, "java/lang/Class"));
|
||||
|
||||
jmethodID getCanonicalNameMID = NULL;
|
||||
NULL_CHECK(getCanonicalNameMID = (*env)->GetMethodID(env, classClass, "getCanonicalName", "()Ljava/lang/String;"));
|
||||
|
||||
jstring mainClassString = (*env)->CallObjectMethod(env, mainClass, getCanonicalNameMID);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
/*
|
||||
* Clears all errors caused by getCanonicalName() on the mainclass and
|
||||
* leaves the JAVA_MAIN_CLASS__<pid> empty.
|
||||
*/
|
||||
(*env)->ExceptionClear(env);
|
||||
return;
|
||||
}
|
||||
|
||||
const char *mainClassName = NULL;
|
||||
NULL_CHECK(mainClassName = (*env)->GetStringUTFChars(env, mainClassString, NULL));
|
||||
|
||||
char envVar[80];
|
||||
/*
|
||||
* The JAVA_MAIN_CLASS_<pid> environment variable is used to pass
|
||||
* the name of a Java class whose main() method is invoked by
|
||||
* the Java launcher code to start the application, to the AWT code
|
||||
* in order to assign the name to the Apple menu bar when the app
|
||||
* is active on the Mac.
|
||||
* The _<pid> part is added to avoid collisions with child processes.
|
||||
*
|
||||
* WARNING: This environment variable is an implementation detail and
|
||||
* isn't meant for use outside of the core platform. The mechanism for
|
||||
* passing this information from Java launcher to other modules may
|
||||
* change drastically between update release, and it may even be
|
||||
* removed or replaced with another mechanism.
|
||||
*
|
||||
* NOTE: It is used by SWT, and JavaFX.
|
||||
*/
|
||||
snprintf(envVar, sizeof(envVar), "JAVA_MAIN_CLASS_%d", getpid());
|
||||
setenv(envVar, mainClassName, 1);
|
||||
|
||||
(*env)->ReleaseStringUTFChars(env, mainClassString, mainClassName);
|
||||
}
|
||||
|
||||
void
|
||||
SetXStartOnFirstThreadArg()
|
||||
{
|
||||
// XXX: BEGIN HACK
|
||||
// short circuit hack for <https://bugs.eclipse.org/bugs/show_bug.cgi?id=211625>
|
||||
// need a way to get AWT/Swing apps launched when spawned from Eclipse,
|
||||
// which currently has no UI to not pass the -XstartOnFirstThread option
|
||||
if (getenv("HACK_IGNORE_START_ON_FIRST_THREAD") != NULL) return;
|
||||
// XXX: END HACK
|
||||
|
||||
sameThread = JNI_TRUE;
|
||||
// Set a variable that tells us we started on the main thread.
|
||||
// This is used by the AWT during startup. (See LWCToolkit.m)
|
||||
char envVar[80];
|
||||
snprintf(envVar, sizeof(envVar), "JAVA_STARTED_ON_FIRST_THREAD_%d", getpid());
|
||||
setenv(envVar, "1", 1);
|
||||
}
|
||||
|
||||
// MacOSX we may continue in the same thread
|
||||
int
|
||||
JVMInit(InvocationFunctions* ifn, jlong threadStackSize,
|
||||
int argc, char **argv,
|
||||
int mode, char *what, int ret) {
|
||||
if (sameThread) {
|
||||
JLI_TraceLauncher("In same thread\n");
|
||||
// need to block this thread against the main thread
|
||||
// so signals get caught correctly
|
||||
__block int rslt = 0;
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
{
|
||||
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock: ^{
|
||||
JavaMainArgs args;
|
||||
args.argc = argc;
|
||||
args.argv = argv;
|
||||
args.mode = mode;
|
||||
args.what = what;
|
||||
args.ifn = *ifn;
|
||||
rslt = JavaMain(&args);
|
||||
}];
|
||||
|
||||
/*
|
||||
* We cannot use dispatch_sync here, because it blocks the main dispatch queue.
|
||||
* Using the main NSRunLoop allows the dispatch queue to run properly once
|
||||
* SWT (or whatever toolkit this is needed for) kicks off it's own NSRunLoop
|
||||
* and starts running.
|
||||
*/
|
||||
[op performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:YES];
|
||||
}
|
||||
[pool drain];
|
||||
return rslt;
|
||||
} else {
|
||||
return ContinueInNewThread(ifn, threadStackSize, argc, argv, mode, what, ret);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Note the jvmInstance must be initialized first before entering into
|
||||
* ShowSplashScreen, as there is a callback into the JLI_GetJavaVMInstance.
|
||||
*/
|
||||
void PostJVMInit(JNIEnv *env, jclass mainClass, JavaVM *vm) {
|
||||
jvmInstance = vm;
|
||||
SetMainClassForAWT(env, mainClass);
|
||||
CHECK_EXCEPTION_RETURN();
|
||||
ShowSplashScreen();
|
||||
}
|
||||
|
||||
jboolean
|
||||
ProcessPlatformOption(const char* arg)
|
||||
{
|
||||
if (JLI_StrCmp(arg, "-XstartOnFirstThread") == 0) {
|
||||
SetXStartOnFirstThreadArg();
|
||||
return JNI_TRUE;
|
||||
} else if (JLI_StrCCmp(arg, "-Xdock:") == 0) {
|
||||
SetXDockArgForAWT(arg);
|
||||
return JNI_TRUE;
|
||||
}
|
||||
// arguments we know not
|
||||
return JNI_FALSE;
|
||||
}
|
47
src/java.base/macosx/native/libjli/java_md_macosx.h
Normal file
47
src/java.base/macosx/native/libjli/java_md_macosx.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
#ifndef JAVA_MD_MACOSX_H
|
||||
#define JAVA_MD_MACOSX_H
|
||||
|
||||
/* CounterGet() is implemented in java_md.c */
|
||||
int64_t CounterGet(void);
|
||||
#define Counter2Micros(counts) (counts)
|
||||
|
||||
/* pointer to environment */
|
||||
#include <crt_externs.h>
|
||||
#define environ (*_NSGetEnviron())
|
||||
|
||||
/*
|
||||
* A collection of useful strings. One should think of these as #define
|
||||
* entries, but actual strings can be more efficient (with many compilers).
|
||||
*/
|
||||
static const char *system_dir = PACKAGE_PATH "/openjdk7";
|
||||
static const char *user_dir = "/java";
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#endif /* JAVA_MD_MACOSX_H */
|
237
src/java.base/macosx/native/libjsig/jsig.c
Normal file
237
src/java.base/macosx/native/libjsig/jsig.c
Normal file
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/* CopyrightVersion 1.2 */
|
||||
|
||||
/* This is a special library that should be loaded before libc &
|
||||
* libthread to interpose the signal handler installation functions:
|
||||
* sigaction(), signal(), sigset().
|
||||
* Used for signal-chaining. See RFE 4381843.
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <dlfcn.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define MASK(sig) ((uint32_t)1 << (sig-1)) // 0 is not a signal.
|
||||
#if (32 < NSIG-1)
|
||||
#error "Not all signals can be encoded in jvmsigs. Adapt its type!"
|
||||
#endif
|
||||
static struct sigaction sact[NSIG]; /* saved signal handlers */
|
||||
static uint32_t jvmsigs = 0; /* signals used by jvm */
|
||||
static __thread bool reentry = false; /* prevent reentry deadlock (per-thread) */
|
||||
|
||||
/* used to synchronize the installation of signal handlers */
|
||||
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
|
||||
static pthread_t tid = 0;
|
||||
|
||||
typedef void (*sa_handler_t)(int);
|
||||
typedef void (*sa_sigaction_t)(int, siginfo_t *, void *);
|
||||
typedef sa_handler_t (*signal_t)(int, sa_handler_t);
|
||||
typedef int (*sigaction_t)(int, const struct sigaction *, struct sigaction *);
|
||||
|
||||
static signal_t os_signal = 0; /* os's version of signal()/sigset() */
|
||||
static sigaction_t os_sigaction = 0; /* os's version of sigaction() */
|
||||
|
||||
static bool jvm_signal_installing = false;
|
||||
static bool jvm_signal_installed = false;
|
||||
|
||||
static void signal_lock() {
|
||||
pthread_mutex_lock(&mutex);
|
||||
/* When the jvm is installing its set of signal handlers, threads
|
||||
* other than the jvm thread should wait */
|
||||
if (jvm_signal_installing) {
|
||||
if (tid != pthread_self()) {
|
||||
pthread_cond_wait(&cond, &mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void signal_unlock() {
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
static sa_handler_t call_os_signal(int sig, sa_handler_t disp,
|
||||
bool is_sigset) {
|
||||
sa_handler_t res;
|
||||
|
||||
if (os_signal == NULL) {
|
||||
if (!is_sigset) {
|
||||
os_signal = (signal_t)dlsym(RTLD_NEXT, "signal");
|
||||
} else {
|
||||
os_signal = (signal_t)dlsym(RTLD_NEXT, "sigset");
|
||||
}
|
||||
if (os_signal == NULL) {
|
||||
printf("%s\n", dlerror());
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
reentry = true;
|
||||
res = (*os_signal)(sig, disp);
|
||||
reentry = false;
|
||||
return res;
|
||||
}
|
||||
|
||||
static void save_signal_handler(int sig, sa_handler_t disp) {
|
||||
sigset_t set;
|
||||
sact[sig].sa_handler = disp;
|
||||
sigemptyset(&set);
|
||||
sact[sig].sa_mask = set;
|
||||
sact[sig].sa_flags = 0;
|
||||
}
|
||||
|
||||
static sa_handler_t set_signal(int sig, sa_handler_t disp, bool is_sigset) {
|
||||
sa_handler_t oldhandler;
|
||||
bool sigused;
|
||||
|
||||
signal_lock();
|
||||
|
||||
sigused = (MASK(sig) & jvmsigs) != 0;
|
||||
if (jvm_signal_installed && sigused) {
|
||||
/* jvm has installed its signal handler for this signal. */
|
||||
/* Save the handler. Don't really install it. */
|
||||
oldhandler = sact[sig].sa_handler;
|
||||
save_signal_handler(sig, disp);
|
||||
|
||||
signal_unlock();
|
||||
return oldhandler;
|
||||
} else if (jvm_signal_installing) {
|
||||
/* jvm is installing its signal handlers. Install the new
|
||||
* handlers and save the old ones. jvm uses sigaction().
|
||||
* Leave the piece here just in case. */
|
||||
oldhandler = call_os_signal(sig, disp, is_sigset);
|
||||
save_signal_handler(sig, oldhandler);
|
||||
|
||||
/* Record the signals used by jvm */
|
||||
jvmsigs |= MASK(sig);
|
||||
|
||||
signal_unlock();
|
||||
return oldhandler;
|
||||
} else {
|
||||
/* jvm has no relation with this signal (yet). Install the
|
||||
* the handler. */
|
||||
oldhandler = call_os_signal(sig, disp, is_sigset);
|
||||
|
||||
signal_unlock();
|
||||
return oldhandler;
|
||||
}
|
||||
}
|
||||
|
||||
sa_handler_t signal(int sig, sa_handler_t disp) {
|
||||
return set_signal(sig, disp, false);
|
||||
}
|
||||
|
||||
sa_handler_t sigset(int sig, sa_handler_t disp) {
|
||||
printf("sigset() is not supported by BSD");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static int call_os_sigaction(int sig, const struct sigaction *act,
|
||||
struct sigaction *oact) {
|
||||
if (os_sigaction == NULL) {
|
||||
os_sigaction = (sigaction_t)dlsym(RTLD_NEXT, "sigaction");
|
||||
if (os_sigaction == NULL) {
|
||||
printf("%s\n", dlerror());
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
return (*os_sigaction)(sig, act, oact);
|
||||
}
|
||||
|
||||
int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) {
|
||||
int res;
|
||||
bool sigused;
|
||||
struct sigaction oldAct;
|
||||
|
||||
if (reentry) {
|
||||
return call_os_sigaction(sig, act, oact);
|
||||
}
|
||||
|
||||
signal_lock();
|
||||
|
||||
sigused = (MASK(sig) & jvmsigs) != 0;
|
||||
if (jvm_signal_installed && sigused) {
|
||||
/* jvm has installed its signal handler for this signal. */
|
||||
/* Save the handler. Don't really install it. */
|
||||
if (oact != NULL) {
|
||||
*oact = sact[sig];
|
||||
}
|
||||
if (act != NULL) {
|
||||
sact[sig] = *act;
|
||||
}
|
||||
|
||||
signal_unlock();
|
||||
return 0;
|
||||
} else if (jvm_signal_installing) {
|
||||
/* jvm is installing its signal handlers. Install the new
|
||||
* handlers and save the old ones. */
|
||||
res = call_os_sigaction(sig, act, &oldAct);
|
||||
sact[sig] = oldAct;
|
||||
if (oact != NULL) {
|
||||
*oact = oldAct;
|
||||
}
|
||||
|
||||
/* Record the signals used by jvm */
|
||||
jvmsigs |= MASK(sig);
|
||||
|
||||
signal_unlock();
|
||||
return res;
|
||||
} else {
|
||||
/* jvm has no relation with this signal (yet). Install the
|
||||
* the handler. */
|
||||
res = call_os_sigaction(sig, act, oact);
|
||||
|
||||
signal_unlock();
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
/* The three functions for the jvm to call into */
|
||||
void JVM_begin_signal_setting() {
|
||||
signal_lock();
|
||||
jvm_signal_installing = true;
|
||||
tid = pthread_self();
|
||||
signal_unlock();
|
||||
}
|
||||
|
||||
void JVM_end_signal_setting() {
|
||||
signal_lock();
|
||||
jvm_signal_installed = true;
|
||||
jvm_signal_installing = false;
|
||||
pthread_cond_broadcast(&cond);
|
||||
signal_unlock();
|
||||
}
|
||||
|
||||
struct sigaction *JVM_get_signal_action(int sig) {
|
||||
/* Does race condition make sense here? */
|
||||
if ((MASK(sig) & jvmsigs) != 0) {
|
||||
return &sact[sig];
|
||||
}
|
||||
return NULL;
|
||||
}
|
284
src/java.base/macosx/native/libnet/DefaultProxySelector.c
Normal file
284
src/java.base/macosx/native/libnet/DefaultProxySelector.c
Normal file
|
@ -0,0 +1,284 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017 SAP SE. 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.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <CoreServices/CoreServices.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
#include "jvm_md.h"
|
||||
|
||||
#include "proxy_util.h"
|
||||
|
||||
#include "sun_net_spi_DefaultProxySelector.h"
|
||||
|
||||
|
||||
/**
|
||||
* For more information on how to use the APIs in "CFProxySupport.h" see:
|
||||
* https://developer.apple.com/legacy/library/samplecode/CFProxySupportTool/Introduction/Intro.html
|
||||
*/
|
||||
|
||||
#define kResolveProxyRunLoopMode CFSTR("sun.net.spi.DefaultProxySelector")
|
||||
|
||||
#define BUFFER_SIZE 1024
|
||||
|
||||
/* Callback for CFNetworkExecuteProxyAutoConfigurationURL. */
|
||||
static void proxyUrlCallback(void * client, CFArrayRef proxies, CFErrorRef error) {
|
||||
/* client is a pointer to a CFTypeRef and holds either proxies or an error. */
|
||||
CFTypeRef* resultPtr = (CFTypeRef *)client;
|
||||
|
||||
if (error != NULL) {
|
||||
*resultPtr = CFRetain(error);
|
||||
} else {
|
||||
*resultPtr = CFRetain(proxies);
|
||||
}
|
||||
CFRunLoopStop(CFRunLoopGetCurrent());
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a new array of proxies containing all the given non-PAC proxies as
|
||||
* well as the results of executing all the given PAC-based proxies, for the
|
||||
* specified URL. 'proxies' is a list that may contain both PAC and non-PAC
|
||||
* proxies.
|
||||
*/
|
||||
static CFArrayRef createExpandedProxiesArray(CFArrayRef proxies, CFURLRef url) {
|
||||
|
||||
CFIndex count;
|
||||
CFIndex index;
|
||||
CFMutableArrayRef expandedProxiesArray;
|
||||
|
||||
expandedProxiesArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
|
||||
if (expandedProxiesArray == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Iterate over the array of proxies */
|
||||
count = CFArrayGetCount(proxies);
|
||||
for (index = 0; index < count ; index++) {
|
||||
CFDictionaryRef currentProxy;
|
||||
CFStringRef proxyType;
|
||||
|
||||
currentProxy = (CFDictionaryRef) CFArrayGetValueAtIndex(proxies, index);
|
||||
if(currentProxy == NULL) {
|
||||
CFRelease(expandedProxiesArray);
|
||||
return NULL;
|
||||
}
|
||||
proxyType = (CFStringRef) CFDictionaryGetValue(currentProxy, kCFProxyTypeKey);
|
||||
if (proxyType == NULL) {
|
||||
CFRelease(expandedProxiesArray);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!CFEqual(proxyType, kCFProxyTypeAutoConfigurationURL)) {
|
||||
/* Non-PAC entry, just copy it to the new array */
|
||||
CFArrayAppendValue(expandedProxiesArray, currentProxy);
|
||||
} else {
|
||||
/* PAC-based URL, execute its script append its results */
|
||||
CFRunLoopSourceRef runLoop;
|
||||
CFURLRef scriptURL;
|
||||
CFTypeRef result = NULL;
|
||||
CFStreamClientContext context = { 0, &result, NULL, NULL, NULL };
|
||||
CFTimeInterval timeout = 5;
|
||||
|
||||
scriptURL = CFDictionaryGetValue(currentProxy, kCFProxyAutoConfigurationURLKey);
|
||||
|
||||
runLoop = CFNetworkExecuteProxyAutoConfigurationURL(scriptURL, url, proxyUrlCallback,
|
||||
&context);
|
||||
if (runLoop != NULL) {
|
||||
/*
|
||||
* Despite the fact that CFNetworkExecuteProxyAutoConfigurationURL has
|
||||
* neither a "Create" nor a "Copy" in the name, we are required to
|
||||
* release the return CFRunLoopSourceRef <rdar://problem/5533931>.
|
||||
*/
|
||||
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoop, kResolveProxyRunLoopMode);
|
||||
CFRunLoopRunInMode(kResolveProxyRunLoopMode, timeout, false);
|
||||
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), runLoop, kResolveProxyRunLoopMode);
|
||||
|
||||
/*
|
||||
* Once the runloop returns, there will be either an error result or
|
||||
* a proxies array result. Do the appropriate thing with that result.
|
||||
*/
|
||||
if (result != NULL) {
|
||||
if (CFGetTypeID(result) == CFArrayGetTypeID()) {
|
||||
/*
|
||||
* Append the new array from the PAC list - it contains
|
||||
* only non-PAC entries.
|
||||
*/
|
||||
CFArrayAppendArray(expandedProxiesArray, result,
|
||||
CFRangeMake(0, CFArrayGetCount(result)));
|
||||
}
|
||||
CFRelease(result);
|
||||
}
|
||||
CFRelease(runLoop);
|
||||
}
|
||||
}
|
||||
}
|
||||
return expandedProxiesArray;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Class: sun_net_spi_DefaultProxySelector
|
||||
* Method: init
|
||||
* Signature: ()Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_sun_net_spi_DefaultProxySelector_init(JNIEnv *env, jclass clazz) {
|
||||
if (!initJavaClass(env)) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Class: sun_net_spi_DefaultProxySelector
|
||||
* Method: getSystemProxies
|
||||
* Signature: ([Ljava/lang/String;Ljava/lang/String;)[Ljava/net/Proxy;
|
||||
*/
|
||||
JNIEXPORT jobjectArray JNICALL
|
||||
Java_sun_net_spi_DefaultProxySelector_getSystemProxies(JNIEnv *env,
|
||||
jobject this,
|
||||
jstring proto,
|
||||
jstring host)
|
||||
{
|
||||
CFDictionaryRef proxyDicRef = NULL;
|
||||
CFURLRef urlRef = NULL;
|
||||
bool proxyFound = false;
|
||||
jobjectArray proxyArray = NULL;
|
||||
const char *cproto;
|
||||
const char *chost;
|
||||
|
||||
/* Get system proxy settings */
|
||||
proxyDicRef = CFNetworkCopySystemProxySettings();
|
||||
if (proxyDicRef == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create CFURLRef from proto and host */
|
||||
cproto = (*env)->GetStringUTFChars(env, proto, NULL);
|
||||
if (cproto != NULL) {
|
||||
chost = (*env)->GetStringUTFChars(env, host, NULL);
|
||||
if (chost != NULL) {
|
||||
char* uri = NULL;
|
||||
size_t protoLen = 0;
|
||||
size_t hostLen = 0;
|
||||
|
||||
protoLen = strlen(cproto);
|
||||
hostLen = strlen(chost);
|
||||
|
||||
/* Construct the uri, cproto + "://" + chost */
|
||||
uri = malloc(protoLen + hostLen + 4);
|
||||
if (uri != NULL) {
|
||||
memcpy(uri, cproto, protoLen);
|
||||
memcpy(uri + protoLen, "://", 3);
|
||||
memcpy(uri + protoLen + 3, chost, hostLen + 1);
|
||||
|
||||
urlRef = CFURLCreateWithBytes(NULL, (const UInt8 *) uri, strlen(uri),
|
||||
kCFStringEncodingUTF8, NULL);
|
||||
free(uri);
|
||||
}
|
||||
(*env)->ReleaseStringUTFChars(env, host, chost);
|
||||
}
|
||||
(*env)->ReleaseStringUTFChars(env, proto, cproto);
|
||||
}
|
||||
if (urlRef != NULL) {
|
||||
CFArrayRef urlProxyArrayRef = CFNetworkCopyProxiesForURL(urlRef, proxyDicRef);
|
||||
if (urlProxyArrayRef != NULL) {
|
||||
CFIndex count;
|
||||
CFIndex index;
|
||||
|
||||
CFArrayRef expandedProxyArray = createExpandedProxiesArray(urlProxyArrayRef, urlRef);
|
||||
CFRelease(urlProxyArrayRef);
|
||||
|
||||
if (expandedProxyArray == NULL) {
|
||||
CFRelease(urlRef);
|
||||
CFRelease(proxyDicRef);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
count = CFArrayGetCount(expandedProxyArray);
|
||||
|
||||
proxyArray = (*env)->NewObjectArray(env, count, proxy_class, NULL);
|
||||
if (proxyArray != NULL || (*env)->ExceptionCheck(env)) {
|
||||
/* Iterate over the expanded array of proxies */
|
||||
for (index = 0; index < count ; index++) {
|
||||
CFDictionaryRef currentProxy;
|
||||
CFStringRef proxyType;
|
||||
jobject proxy = NULL;
|
||||
|
||||
currentProxy = (CFDictionaryRef) CFArrayGetValueAtIndex(expandedProxyArray,
|
||||
index);
|
||||
proxyType = (CFStringRef) CFDictionaryGetValue(currentProxy, kCFProxyTypeKey);
|
||||
if (CFEqual(proxyType, kCFProxyTypeNone)) {
|
||||
/* This entry states no proxy, therefore just add a NO_PROXY object. */
|
||||
proxy = (*env)->GetStaticObjectField(env, proxy_class, pr_no_proxyID);
|
||||
} else {
|
||||
/*
|
||||
* Create a proxy object for this entry.
|
||||
* Differentiate between SOCKS and HTTP type.
|
||||
*/
|
||||
jfieldID typeID = ptype_httpID;
|
||||
if (CFEqual(proxyType, kCFProxyTypeSOCKS)) {
|
||||
typeID = ptype_socksID;
|
||||
}
|
||||
CFNumberRef portNumberRef = (CFNumberRef)CFDictionaryGetValue(currentProxy,
|
||||
(const void*)kCFProxyPortNumberKey);
|
||||
if (portNumberRef != NULL) {
|
||||
int port = 0;
|
||||
if (CFNumberGetValue(portNumberRef, kCFNumberSInt32Type, &port)) {
|
||||
CFStringRef hostNameRef = (CFStringRef)CFDictionaryGetValue(
|
||||
currentProxy, (const void*)kCFProxyHostNameKey);
|
||||
if (hostNameRef != NULL) {
|
||||
char hostNameBuffer[BUFFER_SIZE];
|
||||
if (CFStringGetCString(hostNameRef, hostNameBuffer,
|
||||
BUFFER_SIZE, kCFStringEncodingUTF8)) {
|
||||
proxy = createProxy(env, typeID, &hostNameBuffer[0], port);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (proxy == NULL || (*env)->ExceptionCheck(env)) {
|
||||
proxyArray = NULL;
|
||||
break;
|
||||
}
|
||||
(*env)->SetObjectArrayElement(env, proxyArray, index, proxy);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
proxyArray = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
CFRelease(expandedProxyArray);
|
||||
}
|
||||
CFRelease(urlRef);
|
||||
}
|
||||
CFRelease(proxyDicRef);
|
||||
|
||||
return proxyArray;
|
||||
}
|
500
src/java.base/macosx/native/libnet/bsd_close.c
Normal file
500
src/java.base/macosx/native/libnet/bsd_close.c
Normal file
|
@ -0,0 +1,500 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 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.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/param.h>
|
||||
#include <signal.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include "jvm.h"
|
||||
#include "net_util.h"
|
||||
|
||||
/*
|
||||
* Stack allocated by thread when doing blocking operation
|
||||
*/
|
||||
typedef struct threadEntry {
|
||||
pthread_t thr; /* this thread */
|
||||
struct threadEntry *next; /* next thread */
|
||||
int intr; /* interrupted */
|
||||
} threadEntry_t;
|
||||
|
||||
/*
|
||||
* Heap allocated during initialized - one entry per fd
|
||||
*/
|
||||
typedef struct {
|
||||
pthread_mutex_t lock; /* fd lock */
|
||||
threadEntry_t *threads; /* threads blocked on fd */
|
||||
} fdEntry_t;
|
||||
|
||||
/*
|
||||
* Signal to unblock thread
|
||||
*/
|
||||
static int sigWakeup = SIGIO;
|
||||
|
||||
/*
|
||||
* fdTable holds one entry per file descriptor, up to a certain
|
||||
* maximum.
|
||||
* Theoretically, the number of possible file descriptors can get
|
||||
* large, though usually it does not. Entries for small value file
|
||||
* descriptors are kept in a simple table, which covers most scenarios.
|
||||
* Entries for large value file descriptors are kept in an overflow
|
||||
* table, which is organized as a sparse two dimensional array whose
|
||||
* slabs are allocated on demand. This covers all corner cases while
|
||||
* keeping memory consumption reasonable.
|
||||
*/
|
||||
|
||||
/* Base table for low value file descriptors */
|
||||
static fdEntry_t* fdTable = NULL;
|
||||
/* Maximum size of base table (in number of entries). */
|
||||
static const int fdTableMaxSize = 0x1000; /* 4K */
|
||||
/* Actual size of base table (in number of entries) */
|
||||
static int fdTableLen = 0;
|
||||
/* Max. theoretical number of file descriptors on system. */
|
||||
static int fdLimit = 0;
|
||||
|
||||
/* Overflow table, should base table not be large enough. Organized as
|
||||
* an array of n slabs, each holding 64k entries.
|
||||
*/
|
||||
static fdEntry_t** fdOverflowTable = NULL;
|
||||
/* Number of slabs in the overflow table */
|
||||
static int fdOverflowTableLen = 0;
|
||||
/* Number of entries in one slab */
|
||||
static const int fdOverflowTableSlabSize = 0x10000; /* 64k */
|
||||
pthread_mutex_t fdOverflowTableLock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/*
|
||||
* Null signal handler
|
||||
*/
|
||||
static void sig_wakeup(int sig) {
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialization routine (executed when library is loaded)
|
||||
* Allocate fd tables and sets up signal handler.
|
||||
*/
|
||||
static void __attribute((constructor)) init() {
|
||||
struct rlimit nbr_files;
|
||||
sigset_t sigset;
|
||||
struct sigaction sa;
|
||||
int i = 0;
|
||||
|
||||
/* Determine the maximum number of possible file descriptors. */
|
||||
if (-1 == getrlimit(RLIMIT_NOFILE, &nbr_files)) {
|
||||
fprintf(stderr, "library initialization failed - "
|
||||
"unable to get max # of allocated fds\n");
|
||||
abort();
|
||||
}
|
||||
if (nbr_files.rlim_max != RLIM_INFINITY) {
|
||||
fdLimit = nbr_files.rlim_max;
|
||||
} else {
|
||||
/* We just do not know. */
|
||||
fdLimit = INT_MAX;
|
||||
}
|
||||
|
||||
/* Allocate table for low value file descriptors. */
|
||||
fdTableLen = fdLimit < fdTableMaxSize ? fdLimit : fdTableMaxSize;
|
||||
fdTable = (fdEntry_t*) calloc(fdTableLen, sizeof(fdEntry_t));
|
||||
if (fdTable == NULL) {
|
||||
fprintf(stderr, "library initialization failed - "
|
||||
"unable to allocate file descriptor table - out of memory");
|
||||
abort();
|
||||
} else {
|
||||
for (i = 0; i < fdTableLen; i ++) {
|
||||
pthread_mutex_init(&fdTable[i].lock, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate overflow table, if needed */
|
||||
if (fdLimit > fdTableMaxSize) {
|
||||
fdOverflowTableLen = ((fdLimit - fdTableMaxSize) / fdOverflowTableSlabSize) + 1;
|
||||
fdOverflowTable = (fdEntry_t**) calloc(fdOverflowTableLen, sizeof(fdEntry_t*));
|
||||
if (fdOverflowTable == NULL) {
|
||||
fprintf(stderr, "library initialization failed - "
|
||||
"unable to allocate file descriptor overflow table - out of memory");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup the signal handler
|
||||
*/
|
||||
sa.sa_handler = sig_wakeup;
|
||||
sa.sa_flags = 0;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sigaction(sigWakeup, &sa, NULL);
|
||||
|
||||
sigemptyset(&sigset);
|
||||
sigaddset(&sigset, sigWakeup);
|
||||
sigprocmask(SIG_UNBLOCK, &sigset, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the fd table for this fd.
|
||||
*/
|
||||
static inline fdEntry_t *getFdEntry(int fd)
|
||||
{
|
||||
fdEntry_t* result = NULL;
|
||||
|
||||
if (fd < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* This should not happen. If it does, our assumption about
|
||||
* max. fd value was wrong. */
|
||||
assert(fd < fdLimit);
|
||||
|
||||
if (fd < fdTableMaxSize) {
|
||||
/* fd is in base table. */
|
||||
assert(fd < fdTableLen);
|
||||
result = &fdTable[fd];
|
||||
} else {
|
||||
/* fd is in overflow table. */
|
||||
const int indexInOverflowTable = fd - fdTableMaxSize;
|
||||
const int rootindex = indexInOverflowTable / fdOverflowTableSlabSize;
|
||||
const int slabindex = indexInOverflowTable % fdOverflowTableSlabSize;
|
||||
fdEntry_t* slab = NULL;
|
||||
assert(rootindex < fdOverflowTableLen);
|
||||
assert(slabindex < fdOverflowTableSlabSize);
|
||||
pthread_mutex_lock(&fdOverflowTableLock);
|
||||
/* Allocate new slab in overflow table if needed */
|
||||
if (fdOverflowTable[rootindex] == NULL) {
|
||||
fdEntry_t* const newSlab =
|
||||
(fdEntry_t*)calloc(fdOverflowTableSlabSize, sizeof(fdEntry_t));
|
||||
if (newSlab == NULL) {
|
||||
fprintf(stderr, "Unable to allocate file descriptor overflow"
|
||||
" table slab - out of memory");
|
||||
pthread_mutex_unlock(&fdOverflowTableLock);
|
||||
abort();
|
||||
} else {
|
||||
int i;
|
||||
for (i = 0; i < fdOverflowTableSlabSize; i ++) {
|
||||
pthread_mutex_init(&newSlab[i].lock, NULL);
|
||||
}
|
||||
fdOverflowTable[rootindex] = newSlab;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&fdOverflowTableLock);
|
||||
slab = fdOverflowTable[rootindex];
|
||||
result = &slab[slabindex];
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Start a blocking operation :-
|
||||
* Insert thread onto thread list for the fd.
|
||||
*/
|
||||
static inline void startOp(fdEntry_t *fdEntry, threadEntry_t *self)
|
||||
{
|
||||
self->thr = pthread_self();
|
||||
self->intr = 0;
|
||||
|
||||
pthread_mutex_lock(&(fdEntry->lock));
|
||||
{
|
||||
self->next = fdEntry->threads;
|
||||
fdEntry->threads = self;
|
||||
}
|
||||
pthread_mutex_unlock(&(fdEntry->lock));
|
||||
}
|
||||
|
||||
/*
|
||||
* End a blocking operation :-
|
||||
* Remove thread from thread list for the fd
|
||||
* If fd has been interrupted then set errno to EBADF
|
||||
*/
|
||||
static inline void endOp
|
||||
(fdEntry_t *fdEntry, threadEntry_t *self)
|
||||
{
|
||||
int orig_errno = errno;
|
||||
pthread_mutex_lock(&(fdEntry->lock));
|
||||
{
|
||||
threadEntry_t *curr, *prev=NULL;
|
||||
curr = fdEntry->threads;
|
||||
while (curr != NULL) {
|
||||
if (curr == self) {
|
||||
if (curr->intr) {
|
||||
orig_errno = EBADF;
|
||||
}
|
||||
if (prev == NULL) {
|
||||
fdEntry->threads = curr->next;
|
||||
} else {
|
||||
prev->next = curr->next;
|
||||
}
|
||||
break;
|
||||
}
|
||||
prev = curr;
|
||||
curr = curr->next;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&(fdEntry->lock));
|
||||
errno = orig_errno;
|
||||
}
|
||||
|
||||
/*
|
||||
* Close or dup2 a file descriptor ensuring that all threads blocked on
|
||||
* the file descriptor are notified via a wakeup signal.
|
||||
*
|
||||
* fd1 < 0 => close(fd2)
|
||||
* fd1 >= 0 => dup2(fd1, fd2)
|
||||
*
|
||||
* Returns -1 with errno set if operation fails.
|
||||
*/
|
||||
static int closefd(int fd1, int fd2) {
|
||||
int rv, orig_errno;
|
||||
fdEntry_t *fdEntry = getFdEntry(fd2);
|
||||
if (fdEntry == NULL) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Lock the fd to hold-off additional I/O on this fd.
|
||||
*/
|
||||
pthread_mutex_lock(&(fdEntry->lock));
|
||||
|
||||
{
|
||||
/*
|
||||
* Send a wakeup signal to all threads blocked on this
|
||||
* file descriptor.
|
||||
*/
|
||||
threadEntry_t *curr = fdEntry->threads;
|
||||
while (curr != NULL) {
|
||||
curr->intr = 1;
|
||||
pthread_kill( curr->thr, sigWakeup );
|
||||
curr = curr->next;
|
||||
}
|
||||
|
||||
/*
|
||||
* And close/dup the file descriptor
|
||||
* (restart if interrupted by signal)
|
||||
*/
|
||||
do {
|
||||
if (fd1 < 0) {
|
||||
rv = close(fd2);
|
||||
} else {
|
||||
rv = dup2(fd1, fd2);
|
||||
}
|
||||
} while (rv == -1 && errno == EINTR);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Unlock without destroying errno
|
||||
*/
|
||||
orig_errno = errno;
|
||||
pthread_mutex_unlock(&(fdEntry->lock));
|
||||
errno = orig_errno;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper for dup2 - same semantics as dup2 system call except
|
||||
* that any threads blocked in an I/O system call on fd2 will be
|
||||
* preempted and return -1/EBADF;
|
||||
*/
|
||||
int NET_Dup2(int fd, int fd2) {
|
||||
if (fd < 0) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
return closefd(fd, fd2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper for close - same semantics as close system call
|
||||
* except that any threads blocked in an I/O on fd will be
|
||||
* preempted and the I/O system call will return -1/EBADF.
|
||||
*/
|
||||
int NET_SocketClose(int fd) {
|
||||
return closefd(-1, fd);
|
||||
}
|
||||
|
||||
/************** Basic I/O operations here ***************/
|
||||
|
||||
/*
|
||||
* Macro to perform a blocking IO operation. Restarts
|
||||
* automatically if interrupted by signal (other than
|
||||
* our wakeup signal)
|
||||
*/
|
||||
#define BLOCKING_IO_RETURN_INT(FD, FUNC) { \
|
||||
int ret; \
|
||||
threadEntry_t self; \
|
||||
fdEntry_t *fdEntry = getFdEntry(FD); \
|
||||
if (fdEntry == NULL) { \
|
||||
errno = EBADF; \
|
||||
return -1; \
|
||||
} \
|
||||
do { \
|
||||
startOp(fdEntry, &self); \
|
||||
ret = FUNC; \
|
||||
endOp(fdEntry, &self); \
|
||||
} while (ret == -1 && errno == EINTR); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
int NET_Read(int s, void* buf, size_t len) {
|
||||
BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, 0) );
|
||||
}
|
||||
|
||||
int NET_NonBlockingRead(int s, void* buf, size_t len) {
|
||||
BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, MSG_DONTWAIT));
|
||||
}
|
||||
|
||||
int NET_ReadV(int s, const struct iovec * vector, int count) {
|
||||
BLOCKING_IO_RETURN_INT( s, readv(s, vector, count) );
|
||||
}
|
||||
|
||||
int NET_RecvFrom(int s, void *buf, int len, unsigned int flags,
|
||||
struct sockaddr *from, socklen_t *fromlen) {
|
||||
BLOCKING_IO_RETURN_INT( s, recvfrom(s, buf, len, flags, from, fromlen) );
|
||||
}
|
||||
|
||||
int NET_Send(int s, void *msg, int len, unsigned int flags) {
|
||||
BLOCKING_IO_RETURN_INT( s, send(s, msg, len, flags) );
|
||||
}
|
||||
|
||||
int NET_WriteV(int s, const struct iovec * vector, int count) {
|
||||
BLOCKING_IO_RETURN_INT( s, writev(s, vector, count) );
|
||||
}
|
||||
|
||||
int NET_SendTo(int s, const void *msg, int len, unsigned int
|
||||
flags, const struct sockaddr *to, int tolen) {
|
||||
BLOCKING_IO_RETURN_INT( s, sendto(s, msg, len, flags, to, tolen) );
|
||||
}
|
||||
|
||||
int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen) {
|
||||
BLOCKING_IO_RETURN_INT( s, accept(s, addr, addrlen) );
|
||||
}
|
||||
|
||||
int NET_Connect(int s, struct sockaddr *addr, int addrlen) {
|
||||
BLOCKING_IO_RETURN_INT( s, connect(s, addr, addrlen) );
|
||||
}
|
||||
|
||||
int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout) {
|
||||
BLOCKING_IO_RETURN_INT( ufds[0].fd, poll(ufds, nfds, timeout) );
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper for select(s, timeout). We are using select() on Mac OS due to Bug 7131399.
|
||||
* Auto restarts with adjusted timeout if interrupted by
|
||||
* signal other than our wakeup signal.
|
||||
*/
|
||||
int NET_Timeout(JNIEnv *env, int s, long timeout, jlong nanoTimeStamp) {
|
||||
struct timeval t, *tp = &t;
|
||||
fd_set fds;
|
||||
fd_set* fdsp = NULL;
|
||||
int allocated = 0;
|
||||
threadEntry_t self;
|
||||
fdEntry_t *fdEntry = getFdEntry(s);
|
||||
|
||||
/*
|
||||
* Check that fd hasn't been closed.
|
||||
*/
|
||||
if (fdEntry == NULL) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pick up current time as may need to adjust timeout
|
||||
*/
|
||||
if (timeout > 0) {
|
||||
/* Timed */
|
||||
t.tv_sec = timeout / 1000;
|
||||
t.tv_usec = (timeout % 1000) * 1000;
|
||||
} else if (timeout < 0) {
|
||||
/* Blocking */
|
||||
tp = 0;
|
||||
} else {
|
||||
/* Poll */
|
||||
t.tv_sec = 0;
|
||||
t.tv_usec = 0;
|
||||
}
|
||||
|
||||
if (s < FD_SETSIZE) {
|
||||
fdsp = &fds;
|
||||
FD_ZERO(fdsp);
|
||||
} else {
|
||||
int length = (howmany(s+1, NFDBITS)) * sizeof(int);
|
||||
fdsp = (fd_set *) calloc(1, length);
|
||||
if (fdsp == NULL) {
|
||||
return -1; // errno will be set to ENOMEM
|
||||
}
|
||||
allocated = 1;
|
||||
}
|
||||
FD_SET(s, fdsp);
|
||||
|
||||
jlong prevNanoTime = nanoTimeStamp;
|
||||
jlong nanoTimeout = (jlong) timeout * NET_NSEC_PER_MSEC;
|
||||
for(;;) {
|
||||
int rv;
|
||||
|
||||
/*
|
||||
* call select on the fd. If interrupted by our wakeup signal
|
||||
* errno will be set to EBADF.
|
||||
*/
|
||||
|
||||
startOp(fdEntry, &self);
|
||||
rv = select(s+1, fdsp, 0, 0, tp);
|
||||
endOp(fdEntry, &self);
|
||||
|
||||
/*
|
||||
* If interrupted then adjust timeout. If timeout
|
||||
* has expired return 0 (indicating timeout expired).
|
||||
*/
|
||||
if (rv < 0 && errno == EINTR) {
|
||||
jlong newNanoTime = JVM_NanoTime(env, 0);
|
||||
nanoTimeout -= newNanoTime - prevNanoTime;
|
||||
if (nanoTimeout < NET_NSEC_PER_MSEC) {
|
||||
if (allocated != 0)
|
||||
free(fdsp);
|
||||
return 0;
|
||||
}
|
||||
prevNanoTime = newNanoTime;
|
||||
t.tv_sec = nanoTimeout / NET_NSEC_PER_SEC;
|
||||
t.tv_usec = (nanoTimeout % NET_NSEC_PER_SEC) / NET_NSEC_PER_USEC;
|
||||
|
||||
} else {
|
||||
if (allocated != 0)
|
||||
free(fdsp);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
98
src/java.base/macosx/native/libnio/ch/KQueue.c
Normal file
98
src/java.base/macosx/native/libnio/ch/KQueue.c
Normal file
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
#include "jlong.h"
|
||||
#include "nio_util.h"
|
||||
|
||||
#include "sun_nio_ch_KQueue.h"
|
||||
|
||||
#include <strings.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_KQueue_keventSize(JNIEnv* env, jclass this)
|
||||
{
|
||||
return sizeof(struct kevent);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_KQueue_identOffset(JNIEnv* env, jclass this)
|
||||
{
|
||||
return offsetof(struct kevent, ident);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_KQueue_filterOffset(JNIEnv* env, jclass this)
|
||||
{
|
||||
return offsetof(struct kevent, filter);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_KQueue_flagsOffset(JNIEnv* env, jclass this)
|
||||
{
|
||||
return offsetof(struct kevent, flags);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_KQueue_kqueue(JNIEnv *env, jclass c) {
|
||||
int kqfd = kqueue();
|
||||
if (kqfd < 0) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "kqueue failed");
|
||||
}
|
||||
return kqfd;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_KQueue_keventRegister(JNIEnv *env, jclass c, jint kqfd,
|
||||
jint fd, jint filter, jint flags)
|
||||
|
||||
{
|
||||
struct kevent changes[1];
|
||||
struct timespec timeout = {0, 0};
|
||||
int res;
|
||||
|
||||
EV_SET(&changes[0], fd, filter, flags, 0, 0, 0);
|
||||
RESTARTABLE(kevent(kqfd, &changes[0], 1, NULL, 0, &timeout), res);
|
||||
return (res == -1) ? errno : 0;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_KQueue_keventPoll(JNIEnv *env, jclass c,
|
||||
jint kqfd, jlong address, jint nevents)
|
||||
{
|
||||
struct kevent *events = jlong_to_ptr(address);
|
||||
int res;
|
||||
|
||||
RESTARTABLE(kevent(kqfd, NULL, 0, events, nevents, NULL), res);
|
||||
if (res < 0) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "kqueue failed");
|
||||
}
|
||||
return res;
|
||||
}
|
179
src/java.base/macosx/native/libnio/ch/KQueueArrayWrapper.c
Normal file
179
src/java.base/macosx/native/libnio/ch/KQueueArrayWrapper.c
Normal file
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* KQueueArrayWrapper.c
|
||||
* Implementation of Selector using FreeBSD / Mac OS X kqueues
|
||||
* Derived from Sun's DevPollArrayWrapper
|
||||
*/
|
||||
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
#include "jlong.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_KQueueArrayWrapper_initStructSizes(JNIEnv *env, jclass clazz)
|
||||
{
|
||||
#define CHECK_EXCEPTION() { \
|
||||
if ((*env)->ExceptionCheck(env)) { \
|
||||
goto exceptionOccurred; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CHECK_ERROR_AND_EXCEPTION(_field) { \
|
||||
if (_field == NULL) { \
|
||||
goto badField; \
|
||||
} \
|
||||
CHECK_EXCEPTION(); \
|
||||
}
|
||||
|
||||
|
||||
jfieldID field;
|
||||
|
||||
field = (*env)->GetStaticFieldID(env, clazz, "EVFILT_READ", "S");
|
||||
CHECK_ERROR_AND_EXCEPTION(field);
|
||||
(*env)->SetStaticShortField(env, clazz, field, EVFILT_READ);
|
||||
CHECK_EXCEPTION();
|
||||
|
||||
field = (*env)->GetStaticFieldID(env, clazz, "EVFILT_WRITE", "S");
|
||||
CHECK_ERROR_AND_EXCEPTION(field);
|
||||
(*env)->SetStaticShortField(env, clazz, field, EVFILT_WRITE);
|
||||
CHECK_EXCEPTION();
|
||||
|
||||
field = (*env)->GetStaticFieldID(env, clazz, "SIZEOF_KEVENT", "S");
|
||||
CHECK_ERROR_AND_EXCEPTION(field);
|
||||
(*env)->SetStaticShortField(env, clazz, field, (short) sizeof(struct kevent));
|
||||
CHECK_EXCEPTION();
|
||||
|
||||
field = (*env)->GetStaticFieldID(env, clazz, "FD_OFFSET", "S");
|
||||
CHECK_ERROR_AND_EXCEPTION(field);
|
||||
(*env)->SetStaticShortField(env, clazz, field, (short) offsetof(struct kevent, ident));
|
||||
CHECK_EXCEPTION();
|
||||
|
||||
field = (*env)->GetStaticFieldID(env, clazz, "FILTER_OFFSET", "S");
|
||||
CHECK_ERROR_AND_EXCEPTION(field);
|
||||
(*env)->SetStaticShortField(env, clazz, field, (short) offsetof(struct kevent, filter));
|
||||
CHECK_EXCEPTION();
|
||||
return;
|
||||
|
||||
badField:
|
||||
return;
|
||||
|
||||
exceptionOccurred:
|
||||
return;
|
||||
|
||||
#undef CHECK_EXCEPTION
|
||||
#undef CHECK_ERROR_AND_EXCEPTION
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_KQueueArrayWrapper_init(JNIEnv *env, jobject this)
|
||||
{
|
||||
int kq = kqueue();
|
||||
if (kq < 0) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "KQueueArrayWrapper: kqueue() failed");
|
||||
}
|
||||
return kq;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_KQueueArrayWrapper_register0(JNIEnv *env, jobject this,
|
||||
jint kq, jint fd, jint r, jint w)
|
||||
{
|
||||
struct kevent changes[2];
|
||||
struct kevent errors[2];
|
||||
struct timespec dontBlock = {0, 0};
|
||||
|
||||
// if (r) then { register for read } else { unregister for read }
|
||||
// if (w) then { register for write } else { unregister for write }
|
||||
// Ignore errors - they're probably complaints about deleting non-
|
||||
// added filters - but provide an error array anyway because
|
||||
// kqueue behaves erratically if some of its registrations fail.
|
||||
EV_SET(&changes[0], fd, EVFILT_READ, r ? EV_ADD : EV_DELETE, 0, 0, 0);
|
||||
EV_SET(&changes[1], fd, EVFILT_WRITE, w ? EV_ADD : EV_DELETE, 0, 0, 0);
|
||||
kevent(kq, changes, 2, errors, 2, &dontBlock);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_KQueueArrayWrapper_kevent0(JNIEnv *env, jobject this, jint kq,
|
||||
jlong kevAddr, jint kevCount,
|
||||
jlong timeout)
|
||||
{
|
||||
struct kevent *kevs = (struct kevent *)jlong_to_ptr(kevAddr);
|
||||
struct timespec ts;
|
||||
struct timespec *tsp;
|
||||
int result;
|
||||
|
||||
// Java timeout is in milliseconds. Convert to struct timespec.
|
||||
// Java timeout == -1 : wait forever : timespec timeout of NULL
|
||||
// Java timeout == 0 : return immediately : timespec timeout of zero
|
||||
if (timeout >= 0) {
|
||||
// For some indeterminate reason kevent(2) has been found to fail with
|
||||
// an EINVAL error for timeout values greater than or equal to
|
||||
// 100000001000L. To avoid this problem, clamp the timeout arbitrarily
|
||||
// to the maximum value of a 32-bit signed integer which is
|
||||
// approximately 25 days in milliseconds.
|
||||
const jlong timeoutMax = 0x7fffffff; // java.lang.Integer.MAX_VALUE
|
||||
if (timeout > timeoutMax) {
|
||||
timeout = timeoutMax;
|
||||
}
|
||||
ts.tv_sec = timeout / 1000;
|
||||
ts.tv_nsec = (timeout % 1000) * 1000000; //nanosec = 1 million millisec
|
||||
tsp = &ts;
|
||||
} else {
|
||||
tsp = NULL;
|
||||
}
|
||||
|
||||
result = kevent(kq, NULL, 0, kevs, kevCount, tsp);
|
||||
|
||||
if (result < 0) {
|
||||
if (errno == EINTR) {
|
||||
// ignore EINTR, pretend nothing was selected
|
||||
result = 0;
|
||||
} else {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "KQueueArrayWrapper: kqueue failed");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_KQueueArrayWrapper_interrupt(JNIEnv *env, jclass cls, jint fd)
|
||||
{
|
||||
char c = 1;
|
||||
if (1 != write(fd, &c, 1)) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "KQueueArrayWrapper: interrupt failed");
|
||||
}
|
||||
}
|
||||
|
76
src/java.base/macosx/native/libnio/ch/KQueuePort.c
Normal file
76
src/java.base/macosx/native/libnio/ch/KQueuePort.c
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
#include "jlong.h"
|
||||
#include "nio_util.h"
|
||||
|
||||
#include "sun_nio_ch_KQueuePort.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_KQueuePort_socketpair(JNIEnv* env, jclass clazz, jintArray sv) {
|
||||
int sp[2];
|
||||
if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "socketpair failed");
|
||||
} else {
|
||||
jint res[2];
|
||||
res[0] = (jint)sp[0];
|
||||
res[1] = (jint)sp[1];
|
||||
(*env)->SetIntArrayRegion(env, sv, 0, 2, &res[0]);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_KQueuePort_interrupt(JNIEnv *env, jclass c, jint fd) {
|
||||
int res;
|
||||
int buf[1];
|
||||
buf[0] = 1;
|
||||
RESTARTABLE(write(fd, buf, 1), res);
|
||||
if (res < 0) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "write failed");
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_KQueuePort_drain1(JNIEnv *env, jclass cl, jint fd) {
|
||||
int res;
|
||||
char buf[1];
|
||||
RESTARTABLE(read(fd, buf, 1), res);
|
||||
if (res < 0) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "drain1 failed");
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_KQueuePort_close0(JNIEnv *env, jclass c, jint fd) {
|
||||
int res;
|
||||
RESTARTABLE(close(fd), res);
|
||||
}
|
205
src/java.base/macosx/native/libnio/fs/BsdNativeDispatcher.c
Normal file
205
src/java.base/macosx/native/libnio/fs/BsdNativeDispatcher.c
Normal file
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
#include "jlong.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
#ifdef ST_RDONLY
|
||||
#define statfs statvfs
|
||||
#define getfsstat getvfsstat
|
||||
#define f_flags f_flag
|
||||
#define ISREADONLY ST_RDONLY
|
||||
#else
|
||||
#define ISREADONLY MNT_RDONLY
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static jfieldID entry_name;
|
||||
static jfieldID entry_dir;
|
||||
static jfieldID entry_fstype;
|
||||
static jfieldID entry_options;
|
||||
|
||||
struct fsstat_iter {
|
||||
struct statfs *buf;
|
||||
int pos;
|
||||
int nentries;
|
||||
};
|
||||
|
||||
#include "sun_nio_fs_BsdNativeDispatcher.h"
|
||||
|
||||
static void throwUnixException(JNIEnv* env, int errnum) {
|
||||
jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException",
|
||||
"(I)V", errnum);
|
||||
if (x != NULL) {
|
||||
(*env)->Throw(env, x);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize jfieldIDs
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_fs_BsdNativeDispatcher_initIDs(JNIEnv* env, jclass this)
|
||||
{
|
||||
jclass clazz;
|
||||
|
||||
clazz = (*env)->FindClass(env, "sun/nio/fs/UnixMountEntry");
|
||||
CHECK_NULL(clazz);
|
||||
entry_name = (*env)->GetFieldID(env, clazz, "name", "[B");
|
||||
CHECK_NULL(entry_name);
|
||||
entry_dir = (*env)->GetFieldID(env, clazz, "dir", "[B");
|
||||
CHECK_NULL(entry_dir);
|
||||
entry_fstype = (*env)->GetFieldID(env, clazz, "fstype", "[B");
|
||||
CHECK_NULL(entry_fstype);
|
||||
entry_options = (*env)->GetFieldID(env, clazz, "opts", "[B");
|
||||
CHECK_NULL(entry_options);
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_sun_nio_fs_BsdNativeDispatcher_getfsstat(JNIEnv* env, jclass this)
|
||||
{
|
||||
int nentries;
|
||||
size_t bufsize;
|
||||
struct fsstat_iter *iter = malloc(sizeof(*iter));
|
||||
|
||||
if (iter == NULL) {
|
||||
JNU_ThrowOutOfMemoryError(env, "native heap");
|
||||
return 0;
|
||||
}
|
||||
|
||||
iter->pos = 0;
|
||||
iter->nentries = 0;
|
||||
iter->buf = NULL;
|
||||
|
||||
nentries = getfsstat(NULL, 0, MNT_NOWAIT);
|
||||
|
||||
if (nentries <= 0) {
|
||||
free(iter);
|
||||
throwUnixException(env, errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// It's possible that a new filesystem gets mounted between
|
||||
// the first getfsstat and the second so loop until consistant
|
||||
|
||||
while (nentries != iter->nentries) {
|
||||
if (iter->buf != NULL)
|
||||
free(iter->buf);
|
||||
|
||||
bufsize = nentries * sizeof(struct statfs);
|
||||
iter->nentries = nentries;
|
||||
|
||||
iter->buf = malloc(bufsize);
|
||||
if (iter->buf == NULL) {
|
||||
free(iter);
|
||||
JNU_ThrowOutOfMemoryError(env, "native heap");
|
||||
return 0;
|
||||
}
|
||||
|
||||
nentries = getfsstat(iter->buf, bufsize, MNT_WAIT);
|
||||
if (nentries <= 0) {
|
||||
free(iter->buf);
|
||||
free(iter);
|
||||
throwUnixException(env, errno);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return (jlong)iter;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_fs_BsdNativeDispatcher_fsstatEntry(JNIEnv* env, jclass this,
|
||||
jlong value, jobject entry)
|
||||
{
|
||||
struct fsstat_iter *iter = jlong_to_ptr(value);
|
||||
jsize len;
|
||||
jbyteArray bytes;
|
||||
char* name;
|
||||
char* dir;
|
||||
char* fstype;
|
||||
char* options;
|
||||
dev_t dev;
|
||||
|
||||
if (iter == NULL || iter->pos >= iter->nentries)
|
||||
return -1;
|
||||
|
||||
name = iter->buf[iter->pos].f_mntfromname;
|
||||
dir = iter->buf[iter->pos].f_mntonname;
|
||||
fstype = iter->buf[iter->pos].f_fstypename;
|
||||
if (iter->buf[iter->pos].f_flags & ISREADONLY)
|
||||
options="ro";
|
||||
else
|
||||
options="";
|
||||
|
||||
iter->pos++;
|
||||
|
||||
len = strlen(name);
|
||||
bytes = (*env)->NewByteArray(env, len);
|
||||
if (bytes == NULL)
|
||||
return -1;
|
||||
(*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)name);
|
||||
(*env)->SetObjectField(env, entry, entry_name, bytes);
|
||||
|
||||
len = strlen(dir);
|
||||
bytes = (*env)->NewByteArray(env, len);
|
||||
if (bytes == NULL)
|
||||
return -1;
|
||||
(*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)dir);
|
||||
(*env)->SetObjectField(env, entry, entry_dir, bytes);
|
||||
|
||||
len = strlen(fstype);
|
||||
bytes = (*env)->NewByteArray(env, len);
|
||||
if (bytes == NULL)
|
||||
return -1;
|
||||
(*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)fstype);
|
||||
(*env)->SetObjectField(env, entry, entry_fstype, bytes);
|
||||
|
||||
len = strlen(options);
|
||||
bytes = (*env)->NewByteArray(env, len);
|
||||
if (bytes == NULL)
|
||||
return -1;
|
||||
(*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)options);
|
||||
(*env)->SetObjectField(env, entry, entry_options, bytes);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_fs_BsdNativeDispatcher_endfsstat(JNIEnv* env, jclass this, jlong value)
|
||||
{
|
||||
struct fsstat_iter *iter = jlong_to_ptr(value);
|
||||
|
||||
if (iter != NULL) {
|
||||
free(iter->buf);
|
||||
free(iter);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
#include "jlong.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
JNIEXPORT jcharArray JNICALL
|
||||
Java_sun_nio_fs_MacOSXNativeDispatcher_normalizepath(JNIEnv* env, jclass this,
|
||||
jcharArray path,
|
||||
jint form)
|
||||
{
|
||||
jcharArray result = NULL;
|
||||
char *chars;
|
||||
CFMutableStringRef csref = CFStringCreateMutable(NULL, 0);
|
||||
if (csref == NULL) {
|
||||
JNU_ThrowOutOfMemoryError(env, "native heap");
|
||||
return NULL;
|
||||
}
|
||||
chars = (char*)(*env)->GetPrimitiveArrayCritical(env, path, 0);
|
||||
if (chars != NULL) {
|
||||
char chars_buf[(PATH_MAX + 1) * 2]; // utf16 + zero padding
|
||||
jsize len = (*env)->GetArrayLength(env, path);
|
||||
CFStringAppendCharacters(csref, (const UniChar*)chars, len);
|
||||
(*env)->ReleasePrimitiveArrayCritical(env, path, chars, 0);
|
||||
CFStringNormalize(csref, form);
|
||||
len = CFStringGetLength(csref);
|
||||
if (len < PATH_MAX) {
|
||||
if (CFStringGetCString(csref, chars_buf, sizeof(chars_buf), kCFStringEncodingUTF16)) {
|
||||
result = (*env)->NewCharArray(env, len);
|
||||
if (result != NULL) {
|
||||
(*env)->SetCharArrayRegion(env, result, 0, len, (jchar*)&chars_buf);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int ulen = (len + 1) * 2;
|
||||
chars = malloc(ulen);
|
||||
if (chars == NULL) {
|
||||
JNU_ThrowOutOfMemoryError(env, "native heap");
|
||||
} else {
|
||||
if (CFStringGetCString(csref, chars, ulen, kCFStringEncodingUTF16)) {
|
||||
result = (*env)->NewCharArray(env, len);
|
||||
if (result != NULL) {
|
||||
(*env)->SetCharArrayRegion(env, result, 0, len, (jchar*)chars);
|
||||
}
|
||||
}
|
||||
free(chars);
|
||||
}
|
||||
}
|
||||
}
|
||||
CFRelease(csref);
|
||||
return result;
|
||||
}
|
127
src/java.base/macosx/native/libnio/fs/UTIFileTypeDetector.c
Normal file
127
src/java.base/macosx/native/libnio/fs/UTIFileTypeDetector.c
Normal file
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <CoreServices/CoreServices.h>
|
||||
|
||||
/**
|
||||
* Creates a CF string from the given Java string.
|
||||
* If javaString is NULL, NULL is returned.
|
||||
* If a memory error occurs, and OutOfMemoryError is thrown and
|
||||
* NULL is returned.
|
||||
*/
|
||||
static CFStringRef toCFString(JNIEnv *env, jstring javaString)
|
||||
{
|
||||
if (javaString == NULL) {
|
||||
return NULL;
|
||||
} else {
|
||||
CFStringRef result = NULL;
|
||||
jsize length = (*env)->GetStringLength(env, javaString);
|
||||
const jchar *chars = (*env)->GetStringChars(env, javaString, NULL);
|
||||
if (chars == NULL) {
|
||||
JNU_ThrowOutOfMemoryError(env, "toCFString failed");
|
||||
return NULL;
|
||||
}
|
||||
result = CFStringCreateWithCharacters(NULL, (const UniChar *)chars,
|
||||
length);
|
||||
(*env)->ReleaseStringChars(env, javaString, chars);
|
||||
if (result == NULL) {
|
||||
JNU_ThrowOutOfMemoryError(env, "toCFString failed");
|
||||
return NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Java string from the given CF string.
|
||||
* If cfString is NULL, NULL is returned.
|
||||
* If a memory error occurs, and OutOfMemoryError is thrown and
|
||||
* NULL is returned.
|
||||
*/
|
||||
static jstring toJavaString(JNIEnv *env, CFStringRef cfString)
|
||||
{
|
||||
if (cfString == NULL) {
|
||||
return NULL;
|
||||
} else {
|
||||
jstring javaString = NULL;
|
||||
|
||||
CFIndex length = CFStringGetLength(cfString);
|
||||
const UniChar *constchars = CFStringGetCharactersPtr(cfString);
|
||||
if (constchars) {
|
||||
javaString = (*env)->NewString(env, constchars, length);
|
||||
} else {
|
||||
UniChar *chars = malloc(length * sizeof(UniChar));
|
||||
if (chars == NULL) {
|
||||
JNU_ThrowOutOfMemoryError(env, "toJavaString failed");
|
||||
return NULL;
|
||||
}
|
||||
CFStringGetCharacters(cfString, CFRangeMake(0, length), chars);
|
||||
javaString = (*env)->NewString(env, chars, length);
|
||||
free(chars);
|
||||
}
|
||||
return javaString;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content type corresponding to the supplied file extension.
|
||||
* The mapping is determined using Uniform Type Identifiers (UTIs). If
|
||||
* the file extension parameter is NULL, a CFString cannot be created
|
||||
* from the file extension parameter, there is no UTI corresponding to
|
||||
* the file extension, the UTI cannot supply a MIME type for the file
|
||||
* extension, or a Java string cannot be created, then NULL is returned;
|
||||
* otherwise the MIME type string is returned.
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_sun_nio_fs_UTIFileTypeDetector_probe0(JNIEnv* env, jobject ftd,
|
||||
jstring ext)
|
||||
{
|
||||
jstring result = NULL;
|
||||
|
||||
CFStringRef extension = toCFString(env, ext);
|
||||
if (extension != NULL) {
|
||||
CFStringRef uti =
|
||||
UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension,
|
||||
extension, NULL);
|
||||
CFRelease(extension);
|
||||
|
||||
if (uti != NULL) {
|
||||
CFStringRef mimeType =
|
||||
UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType);
|
||||
CFRelease(uti);
|
||||
|
||||
if (mimeType != NULL) {
|
||||
result = toJavaString(env, mimeType);
|
||||
CFRelease(mimeType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
589
src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m
Normal file
589
src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m
Normal file
|
@ -0,0 +1,589 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*/
|
||||
|
||||
#import "apple_security_KeychainStore.h"
|
||||
|
||||
#import <Security/Security.h>
|
||||
#import <Security/SecImportExport.h>
|
||||
#import <CoreServices/CoreServices.h> // (for require() macros)
|
||||
#import <JavaNativeFoundation/JavaNativeFoundation.h>
|
||||
|
||||
|
||||
static JNF_CLASS_CACHE(jc_KeychainStore, "apple/security/KeychainStore");
|
||||
static JNF_MEMBER_CACHE(jm_createTrustedCertEntry, jc_KeychainStore, "createTrustedCertEntry", "(Ljava/lang/String;JJ[B)V");
|
||||
static JNF_MEMBER_CACHE(jm_createKeyEntry, jc_KeychainStore, "createKeyEntry", "(Ljava/lang/String;JJ[J[[B)V");
|
||||
|
||||
static jstring getLabelFromItem(JNIEnv *env, SecKeychainItemRef inItem)
|
||||
{
|
||||
OSStatus status;
|
||||
jstring returnValue = NULL;
|
||||
char *attribCString = NULL;
|
||||
|
||||
SecKeychainAttribute itemAttrs[] = { { kSecLabelItemAttr, 0, NULL } };
|
||||
SecKeychainAttributeList attrList = { sizeof(itemAttrs) / sizeof(itemAttrs[0]), itemAttrs };
|
||||
|
||||
status = SecKeychainItemCopyContent(inItem, NULL, &attrList, NULL, NULL);
|
||||
|
||||
if(status) {
|
||||
cssmPerror("getLabelFromItem: SecKeychainItemCopyContent", status);
|
||||
goto errOut;
|
||||
}
|
||||
|
||||
attribCString = malloc(itemAttrs[0].length + 1);
|
||||
strncpy(attribCString, itemAttrs[0].data, itemAttrs[0].length);
|
||||
attribCString[itemAttrs[0].length] = '\0';
|
||||
returnValue = (*env)->NewStringUTF(env, attribCString);
|
||||
|
||||
errOut:
|
||||
SecKeychainItemFreeContent(&attrList, NULL);
|
||||
if (attribCString) free(attribCString);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
static jlong getModDateFromItem(JNIEnv *env, SecKeychainItemRef inItem)
|
||||
{
|
||||
OSStatus status;
|
||||
SecKeychainAttribute itemAttrs[] = { { kSecModDateItemAttr, 0, NULL } };
|
||||
SecKeychainAttributeList attrList = { sizeof(itemAttrs) / sizeof(itemAttrs[0]), itemAttrs };
|
||||
jlong returnValue = 0;
|
||||
|
||||
status = SecKeychainItemCopyContent(inItem, NULL, &attrList, NULL, NULL);
|
||||
|
||||
if(status) {
|
||||
// This is almost always missing, so don't dump an error.
|
||||
// cssmPerror("getModDateFromItem: SecKeychainItemCopyContent", status);
|
||||
goto errOut;
|
||||
}
|
||||
|
||||
memcpy(&returnValue, itemAttrs[0].data, itemAttrs[0].length);
|
||||
|
||||
errOut:
|
||||
SecKeychainItemFreeContent(&attrList, NULL);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
static void setLabelForItem(NSString *inLabel, SecKeychainItemRef inItem)
|
||||
{
|
||||
OSStatus status;
|
||||
const char *labelCString = [inLabel UTF8String];
|
||||
|
||||
// Set up attribute vector (each attribute consists of {tag, length, pointer}):
|
||||
SecKeychainAttribute attrs[] = {
|
||||
{ kSecLabelItemAttr, strlen(labelCString), (void *)labelCString }
|
||||
};
|
||||
|
||||
const SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
|
||||
|
||||
// Not changing data here, just attributes.
|
||||
status = SecKeychainItemModifyContent(inItem, &attributes, 0, NULL);
|
||||
|
||||
if(status) {
|
||||
cssmPerror("setLabelForItem: SecKeychainItemModifyContent", status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a SecIdentityRef, do our best to construct a complete, ordered, and
|
||||
* verified cert chain, returning the result in a CFArrayRef. The result is
|
||||
* can be passed back to Java as a chain for a private key.
|
||||
*/
|
||||
static OSStatus completeCertChain(
|
||||
SecIdentityRef identity,
|
||||
SecCertificateRef trustedAnchor, // optional additional trusted anchor
|
||||
bool includeRoot, // include the root in outArray
|
||||
CFArrayRef *outArray) // created and RETURNED
|
||||
{
|
||||
SecTrustRef secTrust = NULL;
|
||||
SecPolicyRef policy = NULL;
|
||||
SecPolicySearchRef policySearch = NULL;
|
||||
SecTrustResultType secTrustResult;
|
||||
CSSM_TP_APPLE_EVIDENCE_INFO *dummyEv; // not used
|
||||
CFArrayRef certChain = NULL; // constructed chain, CERTS ONLY
|
||||
CFMutableArrayRef subjCerts; // passed to SecTrust
|
||||
CFMutableArrayRef certArray; // returned array starting with
|
||||
// identity
|
||||
CFIndex numResCerts;
|
||||
CFIndex dex;
|
||||
OSStatus ortn;
|
||||
SecCertificateRef certRef;
|
||||
|
||||
/* First element in out array is the SecIdentity */
|
||||
certArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
|
||||
CFArrayAppendValue(certArray, identity);
|
||||
|
||||
/* the single element in certs-to-be-evaluated comes from the identity */
|
||||
ortn = SecIdentityCopyCertificate(identity, &certRef);
|
||||
if(ortn) {
|
||||
/* should never happen */
|
||||
cssmPerror("SecIdentityCopyCertificate", ortn);
|
||||
return ortn;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now use SecTrust to get a complete cert chain, using all of the
|
||||
* user's keychains to look for intermediate certs.
|
||||
* NOTE this does NOT handle root certs which are not in the system
|
||||
* root cert DB.
|
||||
*/
|
||||
subjCerts = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks);
|
||||
CFArraySetValueAtIndex(subjCerts, 0, certRef);
|
||||
|
||||
/* the array owns the subject cert ref now */
|
||||
CFRelease(certRef);
|
||||
|
||||
/* Get a SecPolicyRef for generic X509 cert chain verification */
|
||||
ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3,
|
||||
&CSSMOID_APPLE_X509_BASIC,
|
||||
NULL, // value
|
||||
&policySearch);
|
||||
if(ortn) {
|
||||
/* should never happen */
|
||||
cssmPerror("SecPolicySearchCreate", ortn);
|
||||
goto errOut;
|
||||
}
|
||||
ortn = SecPolicySearchCopyNext(policySearch, &policy);
|
||||
if(ortn) {
|
||||
/* should never happen */
|
||||
cssmPerror("SecPolicySearchCopyNext", ortn);
|
||||
goto errOut;
|
||||
}
|
||||
|
||||
/* build a SecTrustRef for specified policy and certs */
|
||||
ortn = SecTrustCreateWithCertificates(subjCerts,
|
||||
policy, &secTrust);
|
||||
if(ortn) {
|
||||
cssmPerror("SecTrustCreateWithCertificates", ortn);
|
||||
goto errOut;
|
||||
}
|
||||
|
||||
if(trustedAnchor) {
|
||||
/*
|
||||
* Tell SecTrust to trust this one in addition to the current
|
||||
* trusted system-wide anchors.
|
||||
*/
|
||||
CFMutableArrayRef newAnchors;
|
||||
CFArrayRef currAnchors;
|
||||
|
||||
ortn = SecTrustCopyAnchorCertificates(&currAnchors);
|
||||
if(ortn) {
|
||||
/* should never happen */
|
||||
cssmPerror("SecTrustCopyAnchorCertificates", ortn);
|
||||
goto errOut;
|
||||
}
|
||||
newAnchors = CFArrayCreateMutableCopy(NULL,
|
||||
CFArrayGetCount(currAnchors) + 1,
|
||||
currAnchors);
|
||||
CFRelease(currAnchors);
|
||||
CFArrayAppendValue(newAnchors, trustedAnchor);
|
||||
ortn = SecTrustSetAnchorCertificates(secTrust, newAnchors);
|
||||
CFRelease(newAnchors);
|
||||
if(ortn) {
|
||||
cssmPerror("SecTrustSetAnchorCertificates", ortn);
|
||||
goto errOut;
|
||||
}
|
||||
}
|
||||
|
||||
/* evaluate: GO */
|
||||
ortn = SecTrustEvaluate(secTrust, &secTrustResult);
|
||||
if(ortn) {
|
||||
cssmPerror("SecTrustEvaluate", ortn);
|
||||
goto errOut;
|
||||
}
|
||||
switch(secTrustResult) {
|
||||
case kSecTrustResultUnspecified:
|
||||
/* cert chain valid, no special UserTrust assignments; drop thru */
|
||||
case kSecTrustResultProceed:
|
||||
/* cert chain valid AND user explicitly trusts this */
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* Cert chain construction failed.
|
||||
* Just go with the single subject cert we were given; maybe the
|
||||
* peer can complete the chain.
|
||||
*/
|
||||
ortn = noErr;
|
||||
goto errOut;
|
||||
}
|
||||
|
||||
/* get resulting constructed cert chain */
|
||||
ortn = SecTrustGetResult(secTrust, &secTrustResult, &certChain, &dummyEv);
|
||||
if(ortn) {
|
||||
cssmPerror("SecTrustEvaluate", ortn);
|
||||
goto errOut;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy certs from constructed chain to our result array, skipping
|
||||
* the leaf (which is already there, as a SecIdentityRef) and possibly
|
||||
* a root.
|
||||
*/
|
||||
numResCerts = CFArrayGetCount(certChain);
|
||||
if(numResCerts < 1) {
|
||||
/*
|
||||
* Can't happen: If chain doesn't verify to a root, we'd
|
||||
* have bailed after SecTrustEvaluate().
|
||||
*/
|
||||
ortn = noErr;
|
||||
goto errOut;
|
||||
}
|
||||
if(!includeRoot) {
|
||||
/* skip the last (root) cert) */
|
||||
numResCerts--;
|
||||
}
|
||||
for(dex=1; dex<numResCerts; dex++) {
|
||||
certRef = (SecCertificateRef)CFArrayGetValueAtIndex(certChain, dex);
|
||||
CFArrayAppendValue(certArray, certRef);
|
||||
}
|
||||
errOut:
|
||||
/* clean up */
|
||||
if(secTrust) {
|
||||
CFRelease(secTrust);
|
||||
}
|
||||
if(subjCerts) {
|
||||
CFRelease(subjCerts);
|
||||
}
|
||||
if(policy) {
|
||||
CFRelease(policy);
|
||||
}
|
||||
if(policySearch) {
|
||||
CFRelease(policySearch);
|
||||
}
|
||||
*outArray = certArray;
|
||||
return ortn;
|
||||
}
|
||||
|
||||
static void addIdentitiesToKeystore(JNIEnv *env, jobject keyStore)
|
||||
{
|
||||
// Search the user keychain list for all identities. Identities are a certificate/private key association that
|
||||
// can be chosen for a purpose such as signing or an SSL connection.
|
||||
SecIdentitySearchRef identitySearch = NULL;
|
||||
// Pass 0 if you want all identities returned by this search
|
||||
OSStatus err = SecIdentitySearchCreate(NULL, 0, &identitySearch);
|
||||
SecIdentityRef theIdentity = NULL;
|
||||
OSErr searchResult = noErr;
|
||||
|
||||
do {
|
||||
searchResult = SecIdentitySearchCopyNext(identitySearch, &theIdentity);
|
||||
|
||||
if (searchResult == noErr) {
|
||||
// Get the cert from the identity, then generate a chain.
|
||||
SecCertificateRef certificate;
|
||||
SecIdentityCopyCertificate(theIdentity, &certificate);
|
||||
CFArrayRef certChain = NULL;
|
||||
|
||||
// *** Should do something with this error...
|
||||
err = completeCertChain(theIdentity, NULL, TRUE, &certChain);
|
||||
|
||||
CFIndex i, certCount = CFArrayGetCount(certChain);
|
||||
|
||||
// Make a java array of certificate data from the chain.
|
||||
jclass byteArrayClass = (*env)->FindClass(env, "[B");
|
||||
if (byteArrayClass == NULL) {
|
||||
goto errOut;
|
||||
}
|
||||
jobjectArray javaCertArray = (*env)->NewObjectArray(env, certCount, byteArrayClass, NULL);
|
||||
// Cleanup first then check for a NULL return code
|
||||
(*env)->DeleteLocalRef(env, byteArrayClass);
|
||||
if (javaCertArray == NULL) {
|
||||
goto errOut;
|
||||
}
|
||||
|
||||
// And, make an array of the certificate refs.
|
||||
jlongArray certRefArray = (*env)->NewLongArray(env, certCount);
|
||||
if (certRefArray == NULL) {
|
||||
goto errOut;
|
||||
}
|
||||
|
||||
SecCertificateRef currCertRef = NULL;
|
||||
|
||||
for (i = 0; i < certCount; i++) {
|
||||
CSSM_DATA currCertData;
|
||||
|
||||
if (i == 0)
|
||||
currCertRef = certificate;
|
||||
else
|
||||
currCertRef = (SecCertificateRef)CFArrayGetValueAtIndex(certChain, i);
|
||||
|
||||
bzero(&currCertData, sizeof(CSSM_DATA));
|
||||
err = SecCertificateGetData(currCertRef, &currCertData);
|
||||
jbyteArray encodedCertData = (*env)->NewByteArray(env, currCertData.Length);
|
||||
if (encodedCertData == NULL) {
|
||||
goto errOut;
|
||||
}
|
||||
(*env)->SetByteArrayRegion(env, encodedCertData, 0, currCertData.Length, (jbyte *)currCertData.Data);
|
||||
(*env)->SetObjectArrayElement(env, javaCertArray, i, encodedCertData);
|
||||
jlong certRefElement = ptr_to_jlong(currCertRef);
|
||||
(*env)->SetLongArrayRegion(env, certRefArray, i, 1, &certRefElement);
|
||||
}
|
||||
|
||||
// Get the private key. When needed we'll export the data from it later.
|
||||
SecKeyRef privateKeyRef;
|
||||
err = SecIdentityCopyPrivateKey(theIdentity, &privateKeyRef);
|
||||
|
||||
// Find the label. It's a 'blob', but we interpret as characters.
|
||||
jstring alias = getLabelFromItem(env, (SecKeychainItemRef)certificate);
|
||||
if (alias == NULL) {
|
||||
goto errOut;
|
||||
}
|
||||
|
||||
// Find the creation date.
|
||||
jlong creationDate = getModDateFromItem(env, (SecKeychainItemRef)certificate);
|
||||
|
||||
// Call back to the Java object to create Java objects corresponding to this security object.
|
||||
jlong nativeKeyRef = ptr_to_jlong(privateKeyRef);
|
||||
JNFCallVoidMethod(env, keyStore, jm_createKeyEntry, alias, creationDate, nativeKeyRef, certRefArray, javaCertArray);
|
||||
}
|
||||
} while (searchResult == noErr);
|
||||
|
||||
errOut:
|
||||
if (identitySearch != NULL) {
|
||||
CFRelease(identitySearch);
|
||||
}
|
||||
}
|
||||
|
||||
static void addCertificatesToKeystore(JNIEnv *env, jobject keyStore)
|
||||
{
|
||||
// Search the user keychain list for all X509 certificates.
|
||||
SecKeychainSearchRef keychainItemSearch = NULL;
|
||||
OSStatus err = SecKeychainSearchCreateFromAttributes(NULL, kSecCertificateItemClass, NULL, &keychainItemSearch);
|
||||
SecKeychainItemRef theItem = NULL;
|
||||
OSErr searchResult = noErr;
|
||||
|
||||
do {
|
||||
searchResult = SecKeychainSearchCopyNext(keychainItemSearch, &theItem);
|
||||
|
||||
if (searchResult == noErr) {
|
||||
// Make a byte array with the DER-encoded contents of the certificate.
|
||||
SecCertificateRef certRef = (SecCertificateRef)theItem;
|
||||
CSSM_DATA currCertificate;
|
||||
err = SecCertificateGetData(certRef, &currCertificate);
|
||||
jbyteArray certData = (*env)->NewByteArray(env, currCertificate.Length);
|
||||
if (certData == NULL) {
|
||||
goto errOut;
|
||||
}
|
||||
(*env)->SetByteArrayRegion(env, certData, 0, currCertificate.Length, (jbyte *)currCertificate.Data);
|
||||
|
||||
// Find the label. It's a 'blob', but we interpret as characters.
|
||||
jstring alias = getLabelFromItem(env, theItem);
|
||||
if (alias == NULL) {
|
||||
goto errOut;
|
||||
}
|
||||
|
||||
// Find the creation date.
|
||||
jlong creationDate = getModDateFromItem(env, theItem);
|
||||
|
||||
// Call back to the Java object to create Java objects corresponding to this security object.
|
||||
jlong nativeRef = ptr_to_jlong(certRef);
|
||||
JNFCallVoidMethod(env, keyStore, jm_createTrustedCertEntry, alias, nativeRef, creationDate, certData);
|
||||
}
|
||||
} while (searchResult == noErr);
|
||||
|
||||
errOut:
|
||||
if (keychainItemSearch != NULL) {
|
||||
CFRelease(keychainItemSearch);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: apple_security_KeychainStore
|
||||
* Method: _getEncodedKeyData
|
||||
* Signature: (J)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_apple_security_KeychainStore__1getEncodedKeyData
|
||||
(JNIEnv *env, jobject this, jlong keyRefLong, jcharArray passwordObj)
|
||||
{
|
||||
SecKeyRef keyRef = (SecKeyRef)jlong_to_ptr(keyRefLong);
|
||||
SecKeyImportExportParameters paramBlock;
|
||||
OSStatus err = noErr;
|
||||
CFDataRef exportedData = NULL;
|
||||
jbyteArray returnValue = NULL;
|
||||
CFStringRef passwordStrRef = NULL;
|
||||
|
||||
jsize passwordLen = 0;
|
||||
jchar *passwordChars = NULL;
|
||||
|
||||
if (passwordObj) {
|
||||
passwordLen = (*env)->GetArrayLength(env, passwordObj);
|
||||
|
||||
if (passwordLen > 0) {
|
||||
passwordChars = (*env)->GetCharArrayElements(env, passwordObj, NULL);
|
||||
if (passwordChars == NULL) {
|
||||
goto errOut;
|
||||
}
|
||||
passwordStrRef = CFStringCreateWithCharacters(kCFAllocatorDefault, passwordChars, passwordLen);
|
||||
}
|
||||
}
|
||||
|
||||
paramBlock.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
|
||||
// Note that setting the flags field **requires** you to pass in a password of some kind. The keychain will not prompt you.
|
||||
paramBlock.flags = 0;
|
||||
paramBlock.passphrase = passwordStrRef;
|
||||
paramBlock.alertTitle = NULL;
|
||||
paramBlock.alertPrompt = NULL;
|
||||
paramBlock.accessRef = NULL;
|
||||
paramBlock.keyUsage = CSSM_KEYUSE_ANY;
|
||||
paramBlock.keyAttributes = CSSM_KEYATTR_RETURN_DEFAULT;
|
||||
|
||||
err = SecKeychainItemExport(keyRef, kSecFormatPKCS12, 0, ¶mBlock, &exportedData);
|
||||
|
||||
if (err == noErr) {
|
||||
CFIndex size = CFDataGetLength(exportedData);
|
||||
returnValue = (*env)->NewByteArray(env, size);
|
||||
if (returnValue == NULL) {
|
||||
goto errOut;
|
||||
}
|
||||
(*env)->SetByteArrayRegion(env, returnValue, 0, size, (jbyte *)CFDataGetBytePtr(exportedData));
|
||||
}
|
||||
|
||||
errOut:
|
||||
if (exportedData) CFRelease(exportedData);
|
||||
if (passwordStrRef) CFRelease(passwordStrRef);
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Class: apple_security_KeychainStore
|
||||
* Method: _scanKeychain
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_apple_security_KeychainStore__1scanKeychain
|
||||
(JNIEnv *env, jobject this)
|
||||
{
|
||||
// Look for 'identities' -- private key and certificate chain pairs -- and add those.
|
||||
// Search for these first, because a certificate that's found here as part of an identity will show up
|
||||
// again later as a certificate.
|
||||
addIdentitiesToKeystore(env, this);
|
||||
|
||||
// Scan current keychain for trusted certificates.
|
||||
addCertificatesToKeystore(env, this);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: apple_security_KeychainStore
|
||||
* Method: _addItemToKeychain
|
||||
* Signature: (Ljava/lang/String;[B)I
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_apple_security_KeychainStore__1addItemToKeychain
|
||||
(JNIEnv *env, jobject this, jstring alias, jboolean isCertificate, jbyteArray rawDataObj, jcharArray passwordObj)
|
||||
{
|
||||
OSStatus err;
|
||||
jlong returnValue = 0;
|
||||
|
||||
JNF_COCOA_ENTER(env);
|
||||
|
||||
jsize dataSize = (*env)->GetArrayLength(env, rawDataObj);
|
||||
jbyte *rawData = (*env)->GetByteArrayElements(env, rawDataObj, NULL);
|
||||
if (rawData == NULL) {
|
||||
goto errOut;
|
||||
}
|
||||
|
||||
CFDataRef cfDataToImport = CFDataCreate(kCFAllocatorDefault, (UInt8 *)rawData, dataSize);
|
||||
CFArrayRef createdItems = NULL;
|
||||
|
||||
SecKeychainRef defaultKeychain = NULL;
|
||||
SecKeychainCopyDefault(&defaultKeychain);
|
||||
|
||||
SecExternalFormat dataFormat = (isCertificate == JNI_TRUE ? kSecFormatX509Cert : kSecFormatWrappedPKCS8);
|
||||
|
||||
// Convert the password obj into a CFStringRef that the keychain importer can use for encryption.
|
||||
SecKeyImportExportParameters paramBlock;
|
||||
CFStringRef passwordStrRef = NULL;
|
||||
|
||||
jsize passwordLen = 0;
|
||||
jchar *passwordChars = NULL;
|
||||
|
||||
if (passwordObj) {
|
||||
passwordLen = (*env)->GetArrayLength(env, passwordObj);
|
||||
passwordChars = (*env)->GetCharArrayElements(env, passwordObj, NULL);
|
||||
passwordStrRef = CFStringCreateWithCharacters(kCFAllocatorDefault, passwordChars, passwordLen);
|
||||
}
|
||||
|
||||
paramBlock.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
|
||||
// Note that setting the flags field **requires** you to pass in a password of some kind. The keychain will not prompt you.
|
||||
paramBlock.flags = 0;
|
||||
paramBlock.passphrase = passwordStrRef;
|
||||
paramBlock.alertTitle = NULL;
|
||||
paramBlock.alertPrompt = NULL;
|
||||
paramBlock.accessRef = NULL;
|
||||
paramBlock.keyUsage = CSSM_KEYUSE_ANY;
|
||||
paramBlock.keyAttributes = CSSM_KEYATTR_RETURN_DEFAULT;
|
||||
|
||||
err = SecKeychainItemImport(cfDataToImport, NULL, &dataFormat, NULL,
|
||||
0, ¶mBlock, defaultKeychain, &createdItems);
|
||||
|
||||
if (err == noErr) {
|
||||
SecKeychainItemRef anItem = (SecKeychainItemRef)CFArrayGetValueAtIndex(createdItems, 0);
|
||||
|
||||
// Don't bother labeling keys. They become part of an identity, and are not an accessible part of the keychain.
|
||||
if (CFGetTypeID(anItem) == SecCertificateGetTypeID()) {
|
||||
setLabelForItem(JNFJavaToNSString(env, alias), anItem);
|
||||
}
|
||||
|
||||
// Retain the item, since it will be released once when the array holding it gets released.
|
||||
CFRetain(anItem);
|
||||
returnValue = ptr_to_jlong(anItem);
|
||||
} else {
|
||||
cssmPerror("_addItemToKeychain: SecKeychainItemImport", err);
|
||||
}
|
||||
|
||||
(*env)->ReleaseByteArrayElements(env, rawDataObj, rawData, JNI_ABORT);
|
||||
|
||||
if (createdItems != NULL) {
|
||||
CFRelease(createdItems);
|
||||
}
|
||||
|
||||
errOut: ;
|
||||
|
||||
JNF_COCOA_EXIT(env);
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: apple_security_KeychainStore
|
||||
* Method: _removeItemFromKeychain
|
||||
* Signature: (J)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_apple_security_KeychainStore__1removeItemFromKeychain
|
||||
(JNIEnv *env, jobject this, jlong keychainItem)
|
||||
{
|
||||
SecKeychainItemRef itemToRemove = jlong_to_ptr(keychainItem);
|
||||
return SecKeychainItemDelete(itemToRemove);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: apple_security_KeychainStore
|
||||
* Method: _releaseKeychainItemRef
|
||||
* Signature: (J)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_apple_security_KeychainStore__1releaseKeychainItemRef
|
||||
(JNIEnv *env, jobject this, jlong keychainItem)
|
||||
{
|
||||
SecKeychainItemRef itemToFree = jlong_to_ptr(keychainItem);
|
||||
CFRelease(itemToFree);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue