mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 12:09:14 +00:00
Merge
This commit is contained in:
commit
83fc52870b
@ -373,7 +373,14 @@ ifeq ($(OPENJDK_TARGET_OS), windows)
|
||||
POLICY_SRC_LIST += $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS)/lib/security/java.policy
|
||||
endif
|
||||
ifndef OPENJDK
|
||||
ifneq (, $(filter $(OPENJDK_TARGET_OS), windows solaris))
|
||||
ifeq ($(OPENJDK_TARGET_OS), windows)
|
||||
ifeq ($(OPENJDK_TARGET_CPU_BITS), 32)
|
||||
POLICY_SRC_LIST += $(JDK_TOPDIR)/src/closed/$(OPENJDK_TARGET_OS)/lib/security/java.policy-win32
|
||||
else
|
||||
POLICY_SRC_LIST += $(JDK_TOPDIR)/src/closed/$(OPENJDK_TARGET_OS)/lib/security/java.policy-win64
|
||||
endif
|
||||
endif
|
||||
ifeq ($(OPENJDK_TARGET_OS), solaris)
|
||||
POLICY_SRC_LIST += $(JDK_TOPDIR)/src/closed/$(OPENJDK_TARGET_OS)/lib/security/java.policy
|
||||
endif
|
||||
endif
|
||||
|
||||
@ -62,7 +62,7 @@ GENDATA += $(GENDATA_UNINAME)
|
||||
|
||||
##########################################################################################
|
||||
|
||||
GENDATA_CURDATA := $(JDK_OUTPUTDIR)/lib/currency.data
|
||||
GENDATA_CURDATA := $(JDK_OUTPUTDIR)/classes/java/util/currency.data
|
||||
|
||||
$(GENDATA_CURDATA): $(JDK_TOPDIR)/make/data/currency/CurrencyData.properties $(BUILD_TOOLS)
|
||||
$(MKDIR) -p $(@D)
|
||||
|
||||
@ -27,7 +27,7 @@ DISABLE_WARNINGS := -Xlint:all,-deprecation,-unchecked,-rawtypes,-cast,-serial,-
|
||||
|
||||
# To build with all warnings enabled, do the following:
|
||||
# make JAVAC_WARNINGS="-Xlint:all -Xmaxwarns 10000"
|
||||
JAVAC_WARNINGS := -Xlint:-unchecked,-deprecation,-overrides,auxiliaryclass,cast,classfile,dep-ann,divzero,empty,fallthrough,overloads,serial,static,try,varargs -Werror
|
||||
JAVAC_WARNINGS := -Xlint:all,-deprecation,-rawtypes,-unchecked -Werror
|
||||
|
||||
# Any java code executed during a JDK build to build other parts of the JDK must be
|
||||
# executed by the bootstrap JDK (probably with -Xbootclasspath/p: ) and for this
|
||||
|
||||
@ -319,7 +319,6 @@ endif
|
||||
|
||||
ifeq ($(OPENJDK_TARGET_OS), macosx)
|
||||
LIBAWT_FILES += awt_LoadLibrary.c
|
||||
LIBAWT_CFLAGS += -F/System/Library/Frameworks/JavaVM.framework/Frameworks
|
||||
endif
|
||||
|
||||
ifeq ($(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU_ARCH), solaris-sparc)
|
||||
@ -484,7 +483,6 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBAWT, \
|
||||
LDFLAGS_SUFFIX_macosx := -lmlib_image -ljvm $(LIBM) \
|
||||
-framework Cocoa \
|
||||
-framework OpenGL \
|
||||
-F/System/Library/Frameworks/JavaVM.framework/Frameworks \
|
||||
-framework JavaNativeFoundation \
|
||||
-framework JavaRuntimeSupport \
|
||||
-framework ApplicationServices \
|
||||
@ -709,21 +707,24 @@ $(BUILD_LIBLCMS): $(BUILD_LIBAWT)
|
||||
|
||||
##########################################################################################
|
||||
|
||||
BUILD_LIBJAVAJPEG_DIR := $(JDK_TOPDIR)/src/share/native/sun/awt/image/jpeg
|
||||
|
||||
ifdef OPENJDK
|
||||
BUILD_LIBJPEG_MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libjpeg/mapfile-vers
|
||||
BUILD_LIBJAVAJPEG_MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libjpeg/mapfile-vers
|
||||
else
|
||||
BUILD_LIBJPEG_MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libjpeg/mapfile-vers-closed
|
||||
BUILD_LIBJPEG_CLOSED_SRC := $(JDK_TOPDIR)/src/closed/share/native/sun/awt/image/jpeg
|
||||
BUILD_LIBJPEG_CLOSED_INCLUDES := -I$(BUILD_LIBJPEG_CLOSED_SRC)
|
||||
BUILD_LIBJAVAJPEG_MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libjpeg/mapfile-vers-closed
|
||||
BUILD_LIBJAVAJPEG_CLOSED_SRC := $(JDK_TOPDIR)/src/closed/share/native/sun/awt/image/jpeg
|
||||
BUILD_LIBJAVAJPEG_CLOSED_INCLUDES := -I$(BUILD_LIBJAVAJPEG_CLOSED_SRC)
|
||||
endif
|
||||
|
||||
BUILD_LIBJPEG_REORDER :=
|
||||
BUILD_LIBJAVAJPEG_REORDER :=
|
||||
ifeq ($(OPENJDK_TARGET_OS), solaris)
|
||||
ifneq ($(OPENJDK_TARGET_CPU), x86_64)
|
||||
BUILD_LIBJPEG_REORDER := $(JDK_TOPDIR)/make/mapfiles/libjpeg/reorder-$(OPENJDK_TARGET_CPU)
|
||||
BUILD_LIBJAVAJPEG_REORDER := $(JDK_TOPDIR)/make/mapfiles/libjpeg/reorder-$(OPENJDK_TARGET_CPU)
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
# Suppress gcc warnings like "variable might be clobbered by 'longjmp'
|
||||
# or 'vfork'": this warning indicates that some variable is placed to
|
||||
# a register by optimized compiler and it's value might be lost on longjmp().
|
||||
@ -735,37 +736,50 @@ endif
|
||||
# $(shell $(EXPR) $(CC_MAJORVER) \> 4 \| \
|
||||
# \( $(CC_MAJORVER) = 4 \& $(CC_MINORVER) \>= 3 \) )
|
||||
# ifeq ($(CC_43_OR_NEWER), 1)
|
||||
# BUILD_LIBJPEG_CFLAGS_linux += -Wno-clobbered
|
||||
# BUILD_LIBJAVAJPEG_CFLAGS_linux += -Wno-clobbered
|
||||
# endif
|
||||
#endif
|
||||
|
||||
$(eval $(call SetupNativeCompilation,BUILD_LIBJPEG, \
|
||||
LIBRARY := jpeg, \
|
||||
ifeq ($(USE_EXTERNAL_LIBJPEG), true)
|
||||
LIBJPEG_LIBS := -ljpeg
|
||||
BUILD_LIBJAVAJPEG_INCLUDE_FILES := \
|
||||
imageIOJPEG.c \
|
||||
jpegdecoder.c
|
||||
BUILD_LIBJAVAJPEG_HEADERS :=
|
||||
else
|
||||
LIBJPEG_LIBS :=
|
||||
BUILD_LIBJAVAJPEG_INCLUDE_FILES :=
|
||||
BUILD_LIBJAVAJPEG_HEADERS := -I$(BUILD_LIBJAVAJPEG_DIR)
|
||||
endif
|
||||
|
||||
$(eval $(call SetupNativeCompilation,BUILD_LIBJAVAJPEG, \
|
||||
LIBRARY := javajpeg, \
|
||||
OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
|
||||
SRC := $(BUILD_LIBJPEG_CLOSED_SRC) \
|
||||
$(JDK_TOPDIR)/src/share/native/sun/awt/image/jpeg, \
|
||||
SRC := $(BUILD_LIBJAVAJPEG_CLOSED_SRC) \
|
||||
$(BUILD_LIBJAVAJPEG_DIR), \
|
||||
INCLUDE_FILES := $(BUILD_LIBJAVAJPEG_INCLUDE_FILES), \
|
||||
LANG := C, \
|
||||
OPTIMIZATION := HIGHEST, \
|
||||
CFLAGS := $(CFLAGS_JDKLIB) \
|
||||
$(BUILD_LIBJPEG_CLOSED_INCLUDES) \
|
||||
-I$(JDK_TOPDIR)/src/share/native/sun/awt/image/jpeg, \
|
||||
MAPFILE := $(BUILD_LIBJPEG_MAPFILE), \
|
||||
LDFLAGS := $(LDFLAGS_JDKLIB) \
|
||||
$(BUILD_LIBJAVAJPEG_CLOSED_INCLUDES) \
|
||||
$(BUILD_LIBJAVAJPEG_HEADERS), \
|
||||
MAPFILE := $(BUILD_LIBJAVAJPEG_MAPFILE), \
|
||||
LDFLAGS := $(LDFLAGS_JDKLIB) $(LIBJPEG_LIBS) \
|
||||
$(call SET_SHARED_LIBRARY_ORIGIN), \
|
||||
LDFLAGS_windows := $(WIN_JAVA_LIB) jvm.lib, \
|
||||
LDFLAGS_SUFFIX := $(LDFLAGS_JDKLIB_SUFFIX), \
|
||||
VERSIONINFO_RESOURCE := $(JDK_TOPDIR)/src/windows/resource/version.rc, \
|
||||
RC_FLAGS := $(RC_FLAGS) \
|
||||
-D "JDK_FNAME=jpeg.dll" \
|
||||
-D "JDK_INTERNAL_NAME=jpeg" \
|
||||
-D "JDK_FNAME=javajpeg.dll" \
|
||||
-D "JDK_INTERNAL_NAME=javajpeg" \
|
||||
-D "JDK_FTYPE=0x2L", \
|
||||
REORDER := $(BUILD_LIBJPEG_REORDER), \
|
||||
REORDER := $(BUILD_LIBJAVAJPEG_REORDER), \
|
||||
OBJECT_DIR := $(JDK_OUTPUTDIR)/objs/libjpeg, \
|
||||
DEBUG_SYMBOLS := $(DEBUG_ALL_BINARIES)))
|
||||
|
||||
$(BUILD_LIBJPEG): $(BUILD_LIBJAVA)
|
||||
$(BUILD_LIBJAVAJPEG): $(BUILD_LIBJAVA)
|
||||
|
||||
BUILD_LIBRARIES += $(BUILD_LIBJPEG)
|
||||
BUILD_LIBRARIES += $(BUILD_LIBJAVAJPEG)
|
||||
|
||||
##########################################################################################
|
||||
|
||||
@ -1130,12 +1144,6 @@ ifeq ($(BUILD_HEADLESS), true)
|
||||
-I$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/sun/jdga \
|
||||
$(foreach dir, $(LIBAWT_HEADLESS_DIRS), -I$(dir))
|
||||
|
||||
ifeq ($(OPENJDK_TARGET_OS), macosx)
|
||||
LIBAWT_HEADLESS_CFLAGS += \
|
||||
-F/System/Library/Frameworks/JavaVM.framework/Frameworks \
|
||||
-F/System/Library/Frameworks/ApplicationServices.framework/Frameworks
|
||||
endif
|
||||
|
||||
LIBAWT_HEADLESS_FILES := \
|
||||
awt_Font.c \
|
||||
HeadlessToolkit.c \
|
||||
@ -1213,6 +1221,13 @@ ifndef BUILD_HEADLESS_ONLY
|
||||
GIFLIB_CFLAGS := -I$(JDK_TOPDIR)/src/share/native/sun/awt/giflib
|
||||
endif
|
||||
|
||||
ifeq ($(USE_EXTERNAL_LIBJPEG), true)
|
||||
LIBJPEG_LDFLAGS := -ljpeg
|
||||
else
|
||||
LIBSPLASHSCREEN_DIRS += $(JDK_TOPDIR)/src/share/native/sun/awt/image/jpeg
|
||||
LIBJPEG_CFLAGS := -I$(JDK_TOPDIR)/src/share/native/sun/awt/image/jpeg
|
||||
endif
|
||||
|
||||
ifeq ($(USE_EXTERNAL_LIBPNG), false)
|
||||
LIBSPLASHSCREEN_DIRS += $(JDK_TOPDIR)/src/share/native/sun/awt/libpng
|
||||
LIBPNG_CFLAGS := -I$(JDK_TOPDIR)/src/share/native/sun/awt/libpng
|
||||
@ -1229,8 +1244,7 @@ ifndef BUILD_HEADLESS_ONLY
|
||||
|
||||
ifeq ($(OPENJDK_TARGET_OS), macosx)
|
||||
LIBSPLASHSCREEN_CFLAGS := -I$(JDK_TOPDIR)/src/macosx/native/sun/awt/splashscreen \
|
||||
$(LIBSPLASHSCREEN_CFLAGS) \
|
||||
-F/System/Library/Frameworks/JavaVM.framework/Frameworks
|
||||
$(LIBSPLASHSCREEN_CFLAGS)
|
||||
LIBSPLASHSCREEN_CFLAGS += -DWITH_MACOSX
|
||||
LIBSPLASHSCREEN_CFLAGS += -I$(JDK_TOPDIR)/src/macosx/native/sun/osxapp
|
||||
|
||||
@ -1260,7 +1274,6 @@ ifndef BUILD_HEADLESS_ONLY
|
||||
-framework ApplicationServices \
|
||||
-framework Foundation \
|
||||
-framework Cocoa \
|
||||
-F/System/Library/Frameworks/JavaVM.framework/Frameworks \
|
||||
-framework JavaNativeFoundation
|
||||
else ifeq ($(OPENJDK_TARGET_OS), windows)
|
||||
LIBSPLASHSCREEN_LDFLAGS_SUFFIX += kernel32.lib user32.lib gdi32.lib delayimp.lib -DELAYLOAD:user32.dll
|
||||
@ -1276,12 +1289,12 @@ ifndef BUILD_HEADLESS_ONLY
|
||||
LANG := C, \
|
||||
OPTIMIZATION := LOW, \
|
||||
CFLAGS := $(LIBSPLASHSCREEN_CFLAGS) $(CFLAGS_JDKLIB) \
|
||||
$(GIFLIB_CFLAGS) $(PNG_CFLAGS), \
|
||||
$(GIFLIB_CFLAGS) $(LIBJPEG_CFLAGS) $(PNG_CFLAGS), \
|
||||
MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libsplashscreen/mapfile-vers, \
|
||||
LDFLAGS := $(LDFLAGS_JDKLIB) \
|
||||
$(call SET_SHARED_LIBRARY_ORIGIN), \
|
||||
LDFLAGS_SUFFIX := $(LIBSPLASHSCREEN_LDFLAGS_SUFFIX) $(LIBZ) \
|
||||
$(GIFLIB_LDFLAGS) $(PNG_LIBS), \
|
||||
$(GIFLIB_LDFLAGS) $(LIBJPEG_LDFLAGS) $(PNG_LIBS), \
|
||||
LDFLAGS_SUFFIX_solaris := -lc, \
|
||||
VERSIONINFO_RESOURCE := $(JDK_TOPDIR)/src/windows/resource/version.rc, \
|
||||
RC_FLAGS := $(RC_FLAGS) \
|
||||
@ -1445,9 +1458,7 @@ ifeq ($(OPENJDK_TARGET_OS), macosx)
|
||||
-I$(JDK_TOPDIR)/src/share/native/sun/awt/image/cvutils \
|
||||
-I$(JDK_TOPDIR)/src/share/native/sun/java2d/loops \
|
||||
-I$(JDK_TOPDIR)/src/share/native/sun/java2d/pipe \
|
||||
-I$(JDK_TOPDIR)/src/share/native/sun/awt/debug \
|
||||
-F/System/Library/Frameworks/JavaVM.framework/Frameworks \
|
||||
-F/System/Library/Frameworks/ApplicationServices.framework/Frameworks, \
|
||||
-I$(JDK_TOPDIR)/src/share/native/sun/awt/debug, \
|
||||
LDFLAGS := $(LDFLAGS_JDKLIB) \
|
||||
$(call SET_SHARED_LIBRARY_ORIGIN), \
|
||||
LDFLAGS_SUFFIX_macosx := -lawt -lmlib_image -losxapp -ljvm $(LIBM) \
|
||||
@ -1458,7 +1469,6 @@ ifeq ($(OPENJDK_TARGET_OS), macosx)
|
||||
-framework Cocoa \
|
||||
-framework Security \
|
||||
-framework ExceptionHandling \
|
||||
-F/System/Library/Frameworks/JavaVM.framework/Frameworks \
|
||||
-framework JavaNativeFoundation \
|
||||
-framework JavaRuntimeSupport \
|
||||
-framework OpenGL \
|
||||
@ -1491,8 +1501,7 @@ ifeq ($(OPENJDK_TARGET_OS), macosx)
|
||||
CFLAGS := $(CFLAGS_JDKLIB) \
|
||||
-I$(JDK_TOPDIR)/src/macosx/native/com/apple/laf \
|
||||
-I$(JDK_TOPDIR)/src/macosx/native/sun/osxapp \
|
||||
-I$(JDK_TOPDIR)/src/macosx/native/sun/awt \
|
||||
-F/System/Library/Frameworks/JavaVM.framework/Frameworks, \
|
||||
-I$(JDK_TOPDIR)/src/macosx/native/sun/awt, \
|
||||
LDFLAGS := $(LDFLAGS_JDKLIB) \
|
||||
$(call SET_SHARED_LIBRARY_ORIGIN) \
|
||||
-Xlinker -rpath -Xlinker @loader_path, \
|
||||
@ -1500,7 +1509,6 @@ ifeq ($(OPENJDK_TARGET_OS), macosx)
|
||||
-framework Cocoa \
|
||||
-framework Carbon \
|
||||
-framework ApplicationServices \
|
||||
-F/System/Library/Frameworks/JavaVM.framework/Frameworks \
|
||||
-framework JavaNativeFoundation \
|
||||
-framework JavaRuntimeSupport \
|
||||
-ljava -ljvm, \
|
||||
|
||||
@ -306,7 +306,7 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBPREFS, \
|
||||
LDFLAGS_SUFFIX_solaris := -ljvm -ljava -lc, \
|
||||
LDFLAGS_SUFFIX_aix := -ljvm -ljava, \
|
||||
LDFLAGS_SUFFIX_windows := advapi32.lib jvm.lib $(WIN_JAVA_LIB), \
|
||||
LDFLAGS_SUFFIX_macosx := -ljvm -framework CoreFoundation, \
|
||||
LDFLAGS_SUFFIX_macosx := -ljvm -framework CoreFoundation -framework Foundation, \
|
||||
VERSIONINFO_RESOURCE := $(JDK_TOPDIR)/src/windows/resource/version.rc, \
|
||||
RC_FLAGS := $(RC_FLAGS) \
|
||||
-D "JDK_FNAME=prefs.dll" \
|
||||
|
||||
@ -32,14 +32,11 @@ ifeq ($(OPENJDK_TARGET_OS), macosx)
|
||||
LANG := C, \
|
||||
OPTIMIZATION := LOW, \
|
||||
CFLAGS := $(CFLAGS_JDKLIB) \
|
||||
-I$(JDK_TOPDIR)/src/macosx/native/apple/applescript \
|
||||
-F/System/Library/Frameworks/JavaVM.framework/Frameworks \
|
||||
-F/System/Library/Frameworks/ApplicationServices.framework/Frameworks, \
|
||||
-I$(JDK_TOPDIR)/src/macosx/native/apple/applescript, \
|
||||
LDFLAGS := $(LDFLAGS_JDKLIB) \
|
||||
$(call SET_SHARED_LIBRARY_ORIGIN), \
|
||||
LDFLAGS_SUFFIX := -framework Cocoa \
|
||||
-framework Carbon \
|
||||
-F/System/Library/Frameworks/JavaVM.framework/Frameworks \
|
||||
-framework JavaNativeFoundation \
|
||||
$(LDFLAGS_JDKLIB_SUFFIX), \
|
||||
OBJECT_DIR := $(JDK_OUTPUTDIR)/objs/libAppleScriptEngine, \
|
||||
@ -63,9 +60,7 @@ ifeq ($(OPENJDK_TARGET_OS), macosx)
|
||||
OPTIMIZATION := LOW, \
|
||||
CFLAGS := $(CFLAGS_JDKLIB) \
|
||||
-I$(JDK_TOPDIR)/src/macosx/native/sun/osxapp \
|
||||
-I$(JDK_OUTPUTDIR)/gensrc_headers_icons \
|
||||
-F/System/Library/Frameworks/JavaVM.framework/Frameworks \
|
||||
-F/System/Library/Frameworks/ApplicationServices.framework/Frameworks, \
|
||||
-I$(JDK_OUTPUTDIR)/gensrc_headers_icons, \
|
||||
LDFLAGS := $(LDFLAGS_JDKLIB) \
|
||||
$(call SET_SHARED_LIBRARY_ORIGIN), \
|
||||
LDFLAGS_SUFFIX_macosx := \
|
||||
@ -76,7 +71,6 @@ ifeq ($(OPENJDK_TARGET_OS), macosx)
|
||||
-framework Cocoa \
|
||||
-framework Security \
|
||||
-framework ExceptionHandling \
|
||||
-F/System/Library/Frameworks/JavaVM.framework/Frameworks \
|
||||
-framework JavaNativeFoundation \
|
||||
-framework JavaRuntimeSupport \
|
||||
-framework OpenGL \
|
||||
@ -107,16 +101,13 @@ ifeq ($(OPENJDK_TARGET_OS), macosx)
|
||||
OPTIMIZATION := LOW, \
|
||||
CFLAGS := $(CFLAGS_JDKLIB) \
|
||||
$(foreach dir, $(LIBOSX_DIRS), -I$(dir)) \
|
||||
-I$(JDK_TOPDIR)/src/macosx/native/sun/osxapp \
|
||||
-F/System/Library/Frameworks/JavaVM.framework/Frameworks \
|
||||
-F/System/Library/Frameworks/ApplicationServices.framework/Frameworks, \
|
||||
-I$(JDK_TOPDIR)/src/macosx/native/sun/osxapp, \
|
||||
LDFLAGS := $(LDFLAGS_JDKLIB) \
|
||||
$(call SET_SHARED_LIBRARY_ORIGIN), \
|
||||
LDFLAGS_SUFFIX_macosx := \
|
||||
-losxapp \
|
||||
-framework Cocoa \
|
||||
-framework ApplicationServices \
|
||||
-F/System/Library/Frameworks/JavaVM.framework/Frameworks \
|
||||
-framework JavaNativeFoundation \
|
||||
-framework JavaRuntimeSupport \
|
||||
-framework Security \
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
# 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
|
||||
@ -130,7 +130,7 @@ ifneq ($(BUILD_CRYPTO), no)
|
||||
BUILD_LIBKRB5_NAME := osxkrb5
|
||||
BUILD_LIBKRB5_SRC := $(JDK_TOPDIR)/src/share/native/sun/security/krb5 \
|
||||
$(JDK_TOPDIR)/src/macosx/native/sun/security/krb5
|
||||
BUILD_LIBKRB5_LIBS := -F/System/Library/Frameworks/JavaVM.framework/Frameworks \
|
||||
BUILD_LIBKRB5_LIBS := \
|
||||
-framework JavaNativeFoundation \
|
||||
-framework Cocoa \
|
||||
-framework SystemConfiguration \
|
||||
@ -147,7 +147,6 @@ ifneq ($(BUILD_CRYPTO), no)
|
||||
CFLAGS := $(CFLAGS_JDKLIB) \
|
||||
-I$(JDK_TOPDIR)/src/share/native/sun/security/krb5, \
|
||||
CFLAGS_windows := -I$(JDK_TOPDIR)/src/windows/native/sun/security/krb5, \
|
||||
CFLAGS_macosx := -F/System/Library/Frameworks/JavaVM.framework/Frameworks, \
|
||||
LDFLAGS := $(LDFLAGS_JDKLIB) \
|
||||
$(call SET_SHARED_LIBRARY_ORIGIN), \
|
||||
LDFLAGS_SUFFIX := $(BUILD_LIBKRB5_LIBS), \
|
||||
|
||||
@ -155,6 +155,7 @@ SUNWprivate_1.1 {
|
||||
g_CMpDataID;
|
||||
colorValueID;
|
||||
mul8table;
|
||||
div8table;
|
||||
jvm;
|
||||
|
||||
# ProcessPath entry points and data
|
||||
|
||||
@ -56,7 +56,6 @@ PROFILE_1_JRE_LIB_FILES := \
|
||||
$(OPENJDK_TARGET_CPU_LEGACY_LIB)/server/Xusage.txt \
|
||||
calendars.properties \
|
||||
classlist \
|
||||
currency.data \
|
||||
ext/localedata.jar \
|
||||
ext/meta-index \
|
||||
ext/sunec.jar \
|
||||
|
||||
@ -57,6 +57,9 @@ import java.util.Map;
|
||||
* @author Jasper Potts
|
||||
*/
|
||||
public class PainterGenerator {
|
||||
|
||||
private static final boolean debug = false;
|
||||
|
||||
//a handful of counters, incremented whenever the associated object type is encounted.
|
||||
//These counters form the basis of the field and method suffixes.
|
||||
//These are all 1 based, because I felt like it :-)
|
||||
@ -384,16 +387,24 @@ public class PainterGenerator {
|
||||
}
|
||||
|
||||
if (Float.isNaN(r)) {
|
||||
System.err.println("[Error] Encountered NaN: encode(" + x + ", " + a + ", " + b + ", " + w + ")");
|
||||
if (debug) {
|
||||
System.err.println("[Error] Encountered NaN: encode(" + x + ", " + a + ", " + b + ", " + w + ")");
|
||||
}
|
||||
return 0;
|
||||
} else if (Float.isInfinite(r)) {
|
||||
System.err.println("[Error] Encountered Infinity: encode(" + x + ", " + a + ", " + b + ", " + w + ")");
|
||||
if (debug) {
|
||||
System.err.println("[Error] Encountered Infinity: encode(" + x + ", " + a + ", " + b + ", " + w + ")");
|
||||
}
|
||||
return 0;
|
||||
} else if (r < 0) {
|
||||
System.err.println("[Error] encoded value was less than 0: encode(" + x + ", " + a + ", " + b + ", " + w + ")");
|
||||
if (debug) {
|
||||
System.err.println("[Error] encoded value was less than 0: encode(" + x + ", " + a + ", " + b + ", " + w + ")");
|
||||
}
|
||||
return 0;
|
||||
} else if (r > 3) {
|
||||
System.err.println("[Error] encoded value was greater than 3: encode(" + x + ", " + a + ", " + b + ", " + w + ")");
|
||||
if (debug) {
|
||||
System.err.println("[Error] encoded value was greater than 3: encode(" + x + ", " + a + ", " + b + ", " + w + ")");
|
||||
}
|
||||
return 3;
|
||||
} else {
|
||||
return r;
|
||||
|
||||
@ -1,180 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package build.tools.tzdb;
|
||||
|
||||
/**
|
||||
* A standard set of date/time fields.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
enum ChronoField {
|
||||
|
||||
/**
|
||||
* The second-of-minute.
|
||||
* <p>
|
||||
* This counts the second within the minute, from 0 to 59.
|
||||
* This field has the same meaning for all calendar systems.
|
||||
*/
|
||||
SECOND_OF_MINUTE("SecondOfMinute", 0, 59),
|
||||
|
||||
/**
|
||||
* The second-of-day.
|
||||
* <p>
|
||||
* This counts the second within the day, from 0 to (24 * 60 * 60) - 1.
|
||||
* This field has the same meaning for all calendar systems.
|
||||
*/
|
||||
SECOND_OF_DAY("SecondOfDay", 0, 86400 - 1),
|
||||
|
||||
/**
|
||||
* The minute-of-hour.
|
||||
* <p>
|
||||
* This counts the minute within the hour, from 0 to 59.
|
||||
* This field has the same meaning for all calendar systems.
|
||||
*/
|
||||
MINUTE_OF_HOUR("MinuteOfHour", 0, 59),
|
||||
|
||||
/**
|
||||
* The hour-of-day.
|
||||
* <p>
|
||||
* This counts the hour within the day, from 0 to 23.
|
||||
* This is the hour that would be observed on a standard 24-hour digital clock.
|
||||
* This field has the same meaning for all calendar systems.
|
||||
*/
|
||||
HOUR_OF_DAY("HourOfDay", 0, 23),
|
||||
|
||||
|
||||
/**
|
||||
* The day-of-month.
|
||||
* <p>
|
||||
* This represents the concept of the day within the month.
|
||||
* In the default ISO calendar system, this has values from 1 to 31 in most months.
|
||||
* April, June, September, November have days from 1 to 30, while February has days
|
||||
* from 1 to 28, or 29 in a leap year.
|
||||
* <p>
|
||||
* Non-ISO calendar systems should implement this field using the most recognized
|
||||
* day-of-month values for users of the calendar system.
|
||||
* Normally, this is a count of days from 1 to the length of the month.
|
||||
*/
|
||||
DAY_OF_MONTH("DayOfMonth", 1, 31),
|
||||
|
||||
/**
|
||||
* The month-of-year, such as March.
|
||||
* <p>
|
||||
* This represents the concept of the month within the year.
|
||||
* In the default ISO calendar system, this has values from January (1) to December (12).
|
||||
* <p>
|
||||
* Non-ISO calendar systems should implement this field using the most recognized
|
||||
* month-of-year values for users of the calendar system.
|
||||
* Normally, this is a count of months starting from 1.
|
||||
*/
|
||||
MONTH_OF_YEAR("MonthOfYear", 1, 12),
|
||||
|
||||
/**
|
||||
* The proleptic year, such as 2012.
|
||||
* <p>
|
||||
* This represents the concept of the year, counting sequentially and using negative numbers.
|
||||
* The proleptic year is not interpreted in terms of the era.
|
||||
* See {@link #YEAR_OF_ERA} for an example showing the mapping from proleptic year to year-of-era.
|
||||
* <p>
|
||||
* The standard mental model for a date is based on three concepts - year, month and day.
|
||||
* These map onto the {@code YEAR}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} fields.
|
||||
* Note that there is no reference to eras.
|
||||
* The full model for a date requires four concepts - era, year, month and day. These map onto
|
||||
* the {@code ERA}, {@code YEAR_OF_ERA}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} fields.
|
||||
* Whether this field or {@code YEAR_OF_ERA} is used depends on which mental model is being used.
|
||||
* See {@link ChronoLocalDate} for more discussion on this topic.
|
||||
* <p>
|
||||
* Non-ISO calendar systems should implement this field as follows.
|
||||
* If the calendar system has only two eras, before and after a fixed date, then the
|
||||
* proleptic-year value must be the same as the year-of-era value for the later era,
|
||||
* and increasingly negative for the earlier era.
|
||||
* If the calendar system has more than two eras, then the proleptic-year value may be
|
||||
* defined with any appropriate value, although defining it to be the same as ISO may be
|
||||
* the best option.
|
||||
*/
|
||||
YEAR("Year", -999_999_999, 999_999_999);
|
||||
|
||||
private final String name;
|
||||
private final int min;
|
||||
private final int max;
|
||||
|
||||
private ChronoField(String name, int min, int max) {
|
||||
this.name = name;
|
||||
this.min= min;
|
||||
this.max= max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the specified value is valid for this field.
|
||||
* <p>
|
||||
*
|
||||
* @param value the value to check
|
||||
* @return the value that was passed in
|
||||
*/
|
||||
public int checkValidValue(int value) {
|
||||
if (value >= min && value <= max) {
|
||||
return value;
|
||||
}
|
||||
throw new DateTimeException("Invalid value for " + name + " value: " + value);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,98 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package build.tools.tzdb;
|
||||
|
||||
/**
|
||||
* Exception used to indicate a problem while calculating a date-time.
|
||||
* <p>
|
||||
* This exception is used to indicate problems with creating, querying
|
||||
* and manipulating date-time objects.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
class DateTimeException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Serialization version.
|
||||
*/
|
||||
private static final long serialVersionUID = -1632418723876261839L;
|
||||
|
||||
/**
|
||||
* Constructs a new date-time exception with the specified message.
|
||||
*
|
||||
* @param message the message to use for this exception, may be null
|
||||
*/
|
||||
public DateTimeException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new date-time exception with the specified message and cause.
|
||||
*
|
||||
* @param message the message to use for this exception, may be null
|
||||
* @param cause the cause of the exception, may be null
|
||||
*/
|
||||
public DateTimeException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,363 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package build.tools.tzdb;
|
||||
|
||||
import static build.tools.tzdb.Utils.*;
|
||||
import static build.tools.tzdb.LocalTime.SECONDS_PER_DAY;
|
||||
import static build.tools.tzdb.ChronoField.DAY_OF_MONTH;
|
||||
import static build.tools.tzdb.ChronoField.MONTH_OF_YEAR;
|
||||
import static build.tools.tzdb.ChronoField.YEAR;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A date without a time-zone in the ISO-8601 calendar system,
|
||||
* such as {@code 2007-12-03}.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
final class LocalDate {
|
||||
|
||||
/**
|
||||
* The minimum supported {@code LocalDate}, '-999999999-01-01'.
|
||||
* This could be used by an application as a "far past" date.
|
||||
*/
|
||||
public static final LocalDate MIN = new LocalDate(YEAR_MIN_VALUE, 1, 1);
|
||||
/**
|
||||
* The maximum supported {@code LocalDate}, '+999999999-12-31'.
|
||||
* This could be used by an application as a "far future" date.
|
||||
*/
|
||||
public static final LocalDate MAX = new LocalDate(YEAR_MAX_VALUE, 12, 31);
|
||||
|
||||
/**
|
||||
* The number of days in a 400 year cycle.
|
||||
*/
|
||||
private static final int DAYS_PER_CYCLE = 146097;
|
||||
/**
|
||||
* The number of days from year zero to year 1970.
|
||||
* There are five 400 year cycles from year zero to 2000.
|
||||
* There are 7 leap years from 1970 to 2000.
|
||||
*/
|
||||
static final long DAYS_0000_TO_1970 = (DAYS_PER_CYCLE * 5L) - (30L * 365L + 7L);
|
||||
|
||||
/**
|
||||
* The year.
|
||||
*/
|
||||
private final int year;
|
||||
/**
|
||||
* The month-of-year.
|
||||
*/
|
||||
private final short month;
|
||||
/**
|
||||
* The day-of-month.
|
||||
*/
|
||||
private final short day;
|
||||
|
||||
/**
|
||||
* Obtains an instance of {@code LocalDate} from a year, month and day.
|
||||
* <p>
|
||||
* The day must be valid for the year and month, otherwise an exception will be thrown.
|
||||
*
|
||||
* @param year the year to represent, from MIN_YEAR to MAX_YEAR
|
||||
* @param month the month-of-year to represent, from 1 (January) to 12 (December)
|
||||
* @param dayOfMonth the day-of-month to represent, from 1 to 31
|
||||
* @return the local date, not null
|
||||
* @throws DateTimeException if the value of any field is out of range
|
||||
* @throws DateTimeException if the day-of-month is invalid for the month-year
|
||||
*/
|
||||
public static LocalDate of(int year, int month, int dayOfMonth) {
|
||||
YEAR.checkValidValue(year);
|
||||
MONTH_OF_YEAR.checkValidValue(month);
|
||||
DAY_OF_MONTH.checkValidValue(dayOfMonth);
|
||||
if (dayOfMonth > 28 && dayOfMonth > lengthOfMonth(month, isLeapYear(year))) {
|
||||
if (dayOfMonth == 29) {
|
||||
throw new DateTimeException("Invalid date 'February 29' as '" + year + "' is not a leap year");
|
||||
} else {
|
||||
throw new DateTimeException("Invalid date '" + month + " " + dayOfMonth + "'");
|
||||
}
|
||||
}
|
||||
return new LocalDate(year, month, dayOfMonth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor, previously validated.
|
||||
*
|
||||
* @param year the year to represent, from MIN_YEAR to MAX_YEAR
|
||||
* @param month the month-of-year to represent, not null
|
||||
* @param dayOfMonth the day-of-month to represent, valid for year-month, from 1 to 31
|
||||
*/
|
||||
private LocalDate(int year, int month, int dayOfMonth) {
|
||||
this.year = year;
|
||||
this.month = (short) month;
|
||||
this.day = (short) dayOfMonth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the year field.
|
||||
* <p>
|
||||
* This method returns the primitive {@code int} value for the year.
|
||||
* <p>
|
||||
* The year returned by this method is proleptic as per {@code get(YEAR)}.
|
||||
* To obtain the year-of-era, use {@code get(YEAR_OF_ERA}.
|
||||
*
|
||||
* @return the year, from MIN_YEAR to MAX_YEAR
|
||||
*/
|
||||
public int getYear() {
|
||||
return year;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the month-of-year field as an int from 1 to 12.
|
||||
*
|
||||
* @return the month-of-year
|
||||
*/
|
||||
public int getMonth() {
|
||||
return month;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the day-of-month field.
|
||||
* <p>
|
||||
* This method returns the primitive {@code int} value for the day-of-month.
|
||||
*
|
||||
* @return the day-of-month, from 1 to 31
|
||||
*/
|
||||
public int getDayOfMonth() {
|
||||
return day;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the day-of-week field, which is an int from 1 to 7.
|
||||
*
|
||||
* @return the day-of-week
|
||||
*/
|
||||
public int getDayOfWeek() {
|
||||
return (int)floorMod(toEpochDay() + 3, 7) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this {@code LocalDate} with the specified number of days added.
|
||||
* <p>
|
||||
* This method adds the specified amount to the days field incrementing the
|
||||
* month and year fields as necessary to ensure the result remains valid.
|
||||
* The result is only invalid if the maximum/minimum year is exceeded.
|
||||
* <p>
|
||||
* For example, 2008-12-31 plus one day would result in 2009-01-01.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param daysToAdd the days to add, may be negative
|
||||
* @return a {@code LocalDate} based on this date with the days added, not null
|
||||
* @throws DateTimeException if the result exceeds the supported date range
|
||||
*/
|
||||
public LocalDate plusDays(long daysToAdd) {
|
||||
if (daysToAdd == 0) {
|
||||
return this;
|
||||
}
|
||||
long mjDay = addExact(toEpochDay(), daysToAdd);
|
||||
return LocalDate.ofEpochDay(mjDay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this {@code LocalDate} with the specified number of days subtracted.
|
||||
* <p>
|
||||
* This method subtracts the specified amount from the days field decrementing the
|
||||
* month and year fields as necessary to ensure the result remains valid.
|
||||
* The result is only invalid if the maximum/minimum year is exceeded.
|
||||
* <p>
|
||||
* For example, 2009-01-01 minus one day would result in 2008-12-31.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param daysToSubtract the days to subtract, may be negative
|
||||
* @return a {@code LocalDate} based on this date with the days subtracted, not null
|
||||
* @throws DateTimeException if the result exceeds the supported date range
|
||||
*/
|
||||
public LocalDate minusDays(long daysToSubtract) {
|
||||
return (daysToSubtract == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-daysToSubtract));
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains an instance of {@code LocalDate} from the epoch day count.
|
||||
* <p>
|
||||
* The Epoch Day count is a simple incrementing count of days
|
||||
* where day 0 is 1970-01-01. Negative numbers represent earlier days.
|
||||
*
|
||||
* @param epochDay the Epoch Day to convert, based on the epoch 1970-01-01
|
||||
* @return the local date, not null
|
||||
* @throws DateTimeException if the epoch days exceeds the supported date range
|
||||
*/
|
||||
public static LocalDate ofEpochDay(long epochDay) {
|
||||
long zeroDay = epochDay + DAYS_0000_TO_1970;
|
||||
// find the march-based year
|
||||
zeroDay -= 60; // adjust to 0000-03-01 so leap day is at end of four year cycle
|
||||
long adjust = 0;
|
||||
if (zeroDay < 0) {
|
||||
// adjust negative years to positive for calculation
|
||||
long adjustCycles = (zeroDay + 1) / DAYS_PER_CYCLE - 1;
|
||||
adjust = adjustCycles * 400;
|
||||
zeroDay += -adjustCycles * DAYS_PER_CYCLE;
|
||||
}
|
||||
long yearEst = (400 * zeroDay + 591) / DAYS_PER_CYCLE;
|
||||
long doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400);
|
||||
if (doyEst < 0) {
|
||||
// fix estimate
|
||||
yearEst--;
|
||||
doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400);
|
||||
}
|
||||
yearEst += adjust; // reset any negative year
|
||||
int marchDoy0 = (int) doyEst;
|
||||
|
||||
// convert march-based values back to january-based
|
||||
int marchMonth0 = (marchDoy0 * 5 + 2) / 153;
|
||||
int month = (marchMonth0 + 2) % 12 + 1;
|
||||
int dom = marchDoy0 - (marchMonth0 * 306 + 5) / 10 + 1;
|
||||
yearEst += marchMonth0 / 10;
|
||||
|
||||
// check year now we are certain it is correct
|
||||
int year = YEAR.checkValidValue((int)yearEst);
|
||||
return new LocalDate(year, month, dom);
|
||||
}
|
||||
|
||||
public long toEpochDay() {
|
||||
long y = year;
|
||||
long m = month;
|
||||
long total = 0;
|
||||
total += 365 * y;
|
||||
if (y >= 0) {
|
||||
total += (y + 3) / 4 - (y + 99) / 100 + (y + 399) / 400;
|
||||
} else {
|
||||
total -= y / -4 - y / -100 + y / -400;
|
||||
}
|
||||
total += ((367 * m - 362) / 12);
|
||||
total += day - 1;
|
||||
if (m > 2) {
|
||||
total--;
|
||||
if (isLeapYear(year) == false) {
|
||||
total--;
|
||||
}
|
||||
}
|
||||
return total - DAYS_0000_TO_1970;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this date to another date.
|
||||
* <p>
|
||||
* The comparison is primarily based on the date, from earliest to latest.
|
||||
* It is "consistent with equals", as defined by {@link Comparable}.
|
||||
* <p>
|
||||
* If all the dates being compared are instances of {@code LocalDate},
|
||||
* then the comparison will be entirely based on the date.
|
||||
* If some dates being compared are in different chronologies, then the
|
||||
* chronology is also considered, see {@link java.time.temporal.ChronoLocalDate#compareTo}.
|
||||
*
|
||||
* @param other the other date to compare to, not null
|
||||
* @return the comparator value, negative if less, positive if greater
|
||||
*/
|
||||
public int compareTo(LocalDate otherDate) {
|
||||
int cmp = (year - otherDate.year);
|
||||
if (cmp == 0) {
|
||||
cmp = (month - otherDate.month);
|
||||
if (cmp == 0) {
|
||||
cmp = (day - otherDate.day);
|
||||
}
|
||||
}
|
||||
return cmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this date is equal to another date.
|
||||
* <p>
|
||||
* Compares this {@code LocalDate} with another ensuring that the date is the same.
|
||||
* <p>
|
||||
* Only objects of type {@code LocalDate} are compared, other types return false.
|
||||
* To compare the dates of two {@code TemporalAccessor} instances, including dates
|
||||
* in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator.
|
||||
*
|
||||
* @param obj the object to check, null returns false
|
||||
* @return true if this is equal to the other date
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof LocalDate) {
|
||||
return compareTo((LocalDate) obj) == 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A hash code for this date.
|
||||
*
|
||||
* @return a suitable hash code
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int yearValue = year;
|
||||
int monthValue = month;
|
||||
int dayValue = day;
|
||||
return (yearValue & 0xFFFFF800) ^ ((yearValue << 11) + (monthValue << 6) + (dayValue));
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,427 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package build.tools.tzdb;
|
||||
|
||||
import static build.tools.tzdb.Utils.*;
|
||||
import static build.tools.tzdb.LocalTime.HOURS_PER_DAY;
|
||||
import static build.tools.tzdb.LocalTime.MICROS_PER_DAY;
|
||||
import static build.tools.tzdb.LocalTime.MILLIS_PER_DAY;
|
||||
import static build.tools.tzdb.LocalTime.MINUTES_PER_DAY;
|
||||
import static build.tools.tzdb.LocalTime.SECONDS_PER_DAY;
|
||||
import static build.tools.tzdb.LocalTime.SECONDS_PER_MINUTE;
|
||||
import static build.tools.tzdb.LocalTime.SECONDS_PER_HOUR;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A date-time without a time-zone in the ISO-8601 calendar system,
|
||||
* such as {@code 2007-12-03T10:15:30}.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
final class LocalDateTime {
|
||||
|
||||
/**
|
||||
* The minimum supported {@code LocalDateTime}, '-999999999-01-01T00:00:00'.
|
||||
* This is the local date-time of midnight at the start of the minimum date.
|
||||
* This combines {@link LocalDate#MIN} and {@link LocalTime#MIN}.
|
||||
* This could be used by an application as a "far past" date-time.
|
||||
*/
|
||||
public static final LocalDateTime MIN = LocalDateTime.of(LocalDate.MIN, LocalTime.MIN);
|
||||
/**
|
||||
* The maximum supported {@code LocalDateTime}, '+999999999-12-31T23:59:59.999999999'.
|
||||
* This is the local date-time just before midnight at the end of the maximum date.
|
||||
* This combines {@link LocalDate#MAX} and {@link LocalTime#MAX}.
|
||||
* This could be used by an application as a "far future" date-time.
|
||||
*/
|
||||
public static final LocalDateTime MAX = LocalDateTime.of(LocalDate.MAX, LocalTime.MAX);
|
||||
|
||||
/**
|
||||
* The date part.
|
||||
*/
|
||||
private final LocalDate date;
|
||||
/**
|
||||
* The time part.
|
||||
*/
|
||||
private final LocalTime time;
|
||||
|
||||
/**
|
||||
* Obtains an instance of {@code LocalDateTime} from year, month,
|
||||
* day, hour and minute, setting the second and nanosecond to zero.
|
||||
* <p>
|
||||
* The day must be valid for the year and month, otherwise an exception will be thrown.
|
||||
* The second and nanosecond fields will be set to zero.
|
||||
*
|
||||
* @param year the year to represent, from MIN_YEAR to MAX_YEAR
|
||||
* @param month the month-of-year to represent, from 1 (January) to 12 (December)
|
||||
* @param dayOfMonth the day-of-month to represent, from 1 to 31
|
||||
* @param hour the hour-of-day to represent, from 0 to 23
|
||||
* @param minute the minute-of-hour to represent, from 0 to 59
|
||||
* @return the local date-time, not null
|
||||
* @throws DateTimeException if the value of any field is out of range
|
||||
* @throws DateTimeException if the day-of-month is invalid for the month-year
|
||||
*/
|
||||
public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute) {
|
||||
LocalDate date = LocalDate.of(year, month, dayOfMonth);
|
||||
LocalTime time = LocalTime.of(hour, minute);
|
||||
return new LocalDateTime(date, time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains an instance of {@code LocalDateTime} from a date and time.
|
||||
*
|
||||
* @param date the local date, not null
|
||||
* @param time the local time, not null
|
||||
* @return the local date-time, not null
|
||||
*/
|
||||
public static LocalDateTime of(LocalDate date, LocalTime time) {
|
||||
Objects.requireNonNull(date, "date");
|
||||
Objects.requireNonNull(time, "time");
|
||||
return new LocalDateTime(date, time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains an instance of {@code LocalDateTime} using seconds from the
|
||||
* epoch of 1970-01-01T00:00:00Z.
|
||||
* <p>
|
||||
* This allows the {@link ChronoField#INSTANT_SECONDS epoch-second} field
|
||||
* to be converted to a local date-time. This is primarily intended for
|
||||
* low-level conversions rather than general application usage.
|
||||
*
|
||||
* @param epochSecond the number of seconds from the epoch of 1970-01-01T00:00:00Z
|
||||
* @param nanoOfSecond the nanosecond within the second, from 0 to 999,999,999
|
||||
* @param offset the zone offset, not null
|
||||
* @return the local date-time, not null
|
||||
* @throws DateTimeException if the result exceeds the supported range
|
||||
*/
|
||||
public static LocalDateTime ofEpochSecond(long epochSecond, int nanoOfSecond, ZoneOffset offset) {
|
||||
Objects.requireNonNull(offset, "offset");
|
||||
long localSecond = epochSecond + offset.getTotalSeconds(); // overflow caught later
|
||||
long localEpochDay = floorDiv(localSecond, SECONDS_PER_DAY);
|
||||
int secsOfDay = (int)floorMod(localSecond, SECONDS_PER_DAY);
|
||||
LocalDate date = LocalDate.ofEpochDay(localEpochDay);
|
||||
LocalTime time = LocalTime.ofSecondOfDay(secsOfDay); // ignore nano
|
||||
return new LocalDateTime(date, time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param date the date part of the date-time, validated not null
|
||||
* @param time the time part of the date-time, validated not null
|
||||
*/
|
||||
private LocalDateTime(LocalDate date, LocalTime time) {
|
||||
this.date = date;
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this date-time with the new date and time, checking
|
||||
* to see if a new object is in fact required.
|
||||
*
|
||||
* @param newDate the date of the new date-time, not null
|
||||
* @param newTime the time of the new date-time, not null
|
||||
* @return the date-time, not null
|
||||
*/
|
||||
private LocalDateTime with(LocalDate newDate, LocalTime newTime) {
|
||||
if (date == newDate && time == newTime) {
|
||||
return this;
|
||||
}
|
||||
return new LocalDateTime(newDate, newTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@code LocalDate} part of this date-time.
|
||||
* <p>
|
||||
* This returns a {@code LocalDate} with the same year, month and day
|
||||
* as this date-time.
|
||||
*
|
||||
* @return the date part of this date-time, not null
|
||||
*/
|
||||
public LocalDate getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the year field.
|
||||
* <p>
|
||||
* This method returns the primitive {@code int} value for the year.
|
||||
* <p>
|
||||
* The year returned by this method is proleptic as per {@code get(YEAR)}.
|
||||
* To obtain the year-of-era, use {@code get(YEAR_OF_ERA}.
|
||||
*
|
||||
* @return the year, from MIN_YEAR to MAX_YEAR
|
||||
*/
|
||||
public int getYear() {
|
||||
return date.getYear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the month-of-year field as an int from 1 to 12.
|
||||
*
|
||||
* @return the month-of-year
|
||||
*/
|
||||
public int getMonth() {
|
||||
return date.getMonth();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the day-of-month field.
|
||||
* <p>
|
||||
* This method returns the primitive {@code int} value for the day-of-month.
|
||||
*
|
||||
* @return the day-of-month, from 1 to 31
|
||||
*/
|
||||
public int getDayOfMonth() {
|
||||
return date.getDayOfMonth();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the day-of-week field, which is an integer from 1 to 7.
|
||||
*
|
||||
* @return the day-of-week, from 1 to 7
|
||||
*/
|
||||
public int getDayOfWeek() {
|
||||
return date.getDayOfWeek();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@code LocalTime} part of this date-time.
|
||||
* <p>
|
||||
* This returns a {@code LocalTime} with the same hour, minute, second and
|
||||
* nanosecond as this date-time.
|
||||
*
|
||||
* @return the time part of this date-time, not null
|
||||
*/
|
||||
public LocalTime getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the hour-of-day field.
|
||||
*
|
||||
* @return the hour-of-day, from 0 to 23
|
||||
*/
|
||||
public int getHour() {
|
||||
return time.getHour();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minute-of-hour field.
|
||||
*
|
||||
* @return the minute-of-hour, from 0 to 59
|
||||
*/
|
||||
public int getMinute() {
|
||||
return time.getMinute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the second-of-minute field.
|
||||
*
|
||||
* @return the second-of-minute, from 0 to 59
|
||||
*/
|
||||
public int getSecond() {
|
||||
return time.getSecond();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this date-time to the number of seconds from the epoch
|
||||
* of 1970-01-01T00:00:00Z.
|
||||
* <p>
|
||||
* This combines this local date-time and the specified offset to calculate the
|
||||
* epoch-second value, which is the number of elapsed seconds from 1970-01-01T00:00:00Z.
|
||||
* Instants on the time-line after the epoch are positive, earlier are negative.
|
||||
* <p>
|
||||
* This default implementation calculates from the epoch-day of the date and the
|
||||
* second-of-day of the time.
|
||||
*
|
||||
* @param offset the offset to use for the conversion, not null
|
||||
* @return the number of seconds from the epoch of 1970-01-01T00:00:00Z
|
||||
*/
|
||||
public long toEpochSecond(ZoneOffset offset) {
|
||||
Objects.requireNonNull(offset, "offset");
|
||||
long epochDay = getDate().toEpochDay();
|
||||
long secs = epochDay * 86400 + getTime().toSecondOfDay();
|
||||
secs -= offset.getTotalSeconds();
|
||||
return secs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this {@code LocalDateTime} with the specified period in days added.
|
||||
* <p>
|
||||
* This method adds the specified amount to the days field incrementing the
|
||||
* month and year fields as necessary to ensure the result remains valid.
|
||||
* The result is only invalid if the maximum/minimum year is exceeded.
|
||||
* <p>
|
||||
* For example, 2008-12-31 plus one day would result in 2009-01-01.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param days the days to add, may be negative
|
||||
* @return a {@code LocalDateTime} based on this date-time with the days added, not null
|
||||
* @throws DateTimeException if the result exceeds the supported date range
|
||||
*/
|
||||
public LocalDateTime plusDays(long days) {
|
||||
LocalDate newDate = date.plusDays(days);
|
||||
return with(newDate, time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this {@code LocalDateTime} with the specified period in seconds added.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param seconds the seconds to add, may be negative
|
||||
* @return a {@code LocalDateTime} based on this date-time with the seconds added, not null
|
||||
* @throws DateTimeException if the result exceeds the supported date range
|
||||
*/
|
||||
public LocalDateTime plusSeconds(long seconds) {
|
||||
return plusWithOverflow(date, 0, 0, seconds, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this {@code LocalDateTime} with the specified period added.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param newDate the new date to base the calculation on, not null
|
||||
* @param hours the hours to add, may be negative
|
||||
* @param minutes the minutes to add, may be negative
|
||||
* @param seconds the seconds to add, may be negative
|
||||
* @param nanos the nanos to add, may be negative
|
||||
* @param sign the sign to determine add or subtract
|
||||
* @return the combined result, not null
|
||||
*/
|
||||
private LocalDateTime plusWithOverflow(LocalDate newDate, long hours, long minutes, long seconds, int sign) {
|
||||
if ((hours | minutes | seconds) == 0) {
|
||||
return with(newDate, time);
|
||||
}
|
||||
long totDays = seconds / SECONDS_PER_DAY + // max/24*60*60
|
||||
minutes / MINUTES_PER_DAY + // max/24*60
|
||||
hours / HOURS_PER_DAY; // max/24
|
||||
totDays *= sign; // total max*0.4237...
|
||||
long totSecs = (seconds % SECONDS_PER_DAY) +
|
||||
(minutes % MINUTES_PER_DAY) * SECONDS_PER_MINUTE +
|
||||
(hours % HOURS_PER_DAY) * SECONDS_PER_HOUR;
|
||||
long curSoD = time.toSecondOfDay();
|
||||
totSecs = totSecs * sign + curSoD; // total 432000000000000
|
||||
totDays += floorDiv(totSecs, SECONDS_PER_DAY);
|
||||
|
||||
int newSoD = (int)floorMod(totSecs, SECONDS_PER_DAY);
|
||||
LocalTime newTime = (newSoD == curSoD ? time : LocalTime.ofSecondOfDay(newSoD));
|
||||
return with(newDate.plusDays(totDays), newTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this date-time to another date-time.
|
||||
* <p>
|
||||
* The comparison is primarily based on the date-time, from earliest to latest.
|
||||
* It is "consistent with equals", as defined by {@link Comparable}.
|
||||
* <p>
|
||||
* If all the date-times being compared are instances of {@code LocalDateTime},
|
||||
* then the comparison will be entirely based on the date-time.
|
||||
* If some dates being compared are in different chronologies, then the
|
||||
* chronology is also considered, see {@link ChronoLocalDateTime#compareTo}.
|
||||
*
|
||||
* @param other the other date-time to compare to, not null
|
||||
* @return the comparator value, negative if less, positive if greater
|
||||
*/
|
||||
public int compareTo(LocalDateTime other) {
|
||||
int cmp = date.compareTo(other.getDate());
|
||||
if (cmp == 0) {
|
||||
cmp = time.compareTo(other.getTime());
|
||||
}
|
||||
return cmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this date-time is equal to another date-time.
|
||||
* <p>
|
||||
* Compares this {@code LocalDateTime} with another ensuring that the date-time is the same.
|
||||
* Only objects of type {@code LocalDateTime} are compared, other types return false.
|
||||
*
|
||||
* @param obj the object to check, null returns false
|
||||
* @return true if this is equal to the other date-time
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof LocalDateTime) {
|
||||
LocalDateTime other = (LocalDateTime) obj;
|
||||
return date.equals(other.date) && time.equals(other.time);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A hash code for this date-time.
|
||||
*
|
||||
* @return a suitable hash code
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return date.hashCode() ^ time.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,388 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package build.tools.tzdb;
|
||||
|
||||
import static build.tools.tzdb.ChronoField.HOUR_OF_DAY;
|
||||
import static build.tools.tzdb.ChronoField.MINUTE_OF_HOUR;
|
||||
import static build.tools.tzdb.ChronoField.SECOND_OF_MINUTE;
|
||||
import static build.tools.tzdb.ChronoField.SECOND_OF_DAY;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A time without time-zone in the ISO-8601 calendar system,
|
||||
* such as {@code 10:15:30}.
|
||||
*
|
||||
*/
|
||||
final class LocalTime {
|
||||
|
||||
/**
|
||||
* The minimum supported {@code LocalTime}, '00:00'.
|
||||
* This is the time of midnight at the start of the day.
|
||||
*/
|
||||
public static final LocalTime MIN;
|
||||
/**
|
||||
* The minimum supported {@code LocalTime}, '23:59:59.999999999'.
|
||||
* This is the time just before midnight at the end of the day.
|
||||
*/
|
||||
public static final LocalTime MAX;
|
||||
/**
|
||||
* The time of midnight at the start of the day, '00:00'.
|
||||
*/
|
||||
public static final LocalTime MIDNIGHT;
|
||||
/**
|
||||
* The time of noon in the middle of the day, '12:00'.
|
||||
*/
|
||||
public static final LocalTime NOON;
|
||||
/**
|
||||
* Constants for the local time of each hour.
|
||||
*/
|
||||
private static final LocalTime[] HOURS = new LocalTime[24];
|
||||
static {
|
||||
for (int i = 0; i < HOURS.length; i++) {
|
||||
HOURS[i] = new LocalTime(i, 0, 0);
|
||||
}
|
||||
MIDNIGHT = HOURS[0];
|
||||
NOON = HOURS[12];
|
||||
MIN = HOURS[0];
|
||||
MAX = new LocalTime(23, 59, 59);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hours per day.
|
||||
*/
|
||||
static final int HOURS_PER_DAY = 24;
|
||||
/**
|
||||
* Minutes per hour.
|
||||
*/
|
||||
static final int MINUTES_PER_HOUR = 60;
|
||||
/**
|
||||
* Minutes per day.
|
||||
*/
|
||||
static final int MINUTES_PER_DAY = MINUTES_PER_HOUR * HOURS_PER_DAY;
|
||||
/**
|
||||
* Seconds per minute.
|
||||
*/
|
||||
static final int SECONDS_PER_MINUTE = 60;
|
||||
/**
|
||||
* Seconds per hour.
|
||||
*/
|
||||
static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
|
||||
/**
|
||||
* Seconds per day.
|
||||
*/
|
||||
static final int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY;
|
||||
/**
|
||||
* Milliseconds per day.
|
||||
*/
|
||||
static final long MILLIS_PER_DAY = SECONDS_PER_DAY * 1000L;
|
||||
/**
|
||||
* Microseconds per day.
|
||||
*/
|
||||
static final long MICROS_PER_DAY = SECONDS_PER_DAY * 1000_000L;
|
||||
|
||||
/**
|
||||
* The hour.
|
||||
*/
|
||||
private final byte hour;
|
||||
/**
|
||||
* The minute.
|
||||
*/
|
||||
private final byte minute;
|
||||
/**
|
||||
* The second.
|
||||
*/
|
||||
private final byte second;
|
||||
|
||||
/**
|
||||
* Obtains an instance of {@code LocalTime} from an hour and minute.
|
||||
* <p>
|
||||
* The second and nanosecond fields will be set to zero by this factory method.
|
||||
* <p>
|
||||
* This factory may return a cached value, but applications must not rely on this.
|
||||
*
|
||||
* @param hour the hour-of-day to represent, from 0 to 23
|
||||
* @param minute the minute-of-hour to represent, from 0 to 59
|
||||
* @return the local time, not null
|
||||
* @throws DateTimeException if the value of any field is out of range
|
||||
*/
|
||||
public static LocalTime of(int hour, int minute) {
|
||||
HOUR_OF_DAY.checkValidValue(hour);
|
||||
if (minute == 0) {
|
||||
return HOURS[hour]; // for performance
|
||||
}
|
||||
MINUTE_OF_HOUR.checkValidValue(minute);
|
||||
return new LocalTime(hour, minute, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains an instance of {@code LocalTime} from an hour, minute and second.
|
||||
* <p>
|
||||
* The nanosecond field will be set to zero by this factory method.
|
||||
* <p>
|
||||
* This factory may return a cached value, but applications must not rely on this.
|
||||
*
|
||||
* @param hour the hour-of-day to represent, from 0 to 23
|
||||
* @param minute the minute-of-hour to represent, from 0 to 59
|
||||
* @param second the second-of-minute to represent, from 0 to 59
|
||||
* @return the local time, not null
|
||||
* @throws DateTimeException if the value of any field is out of range
|
||||
*/
|
||||
public static LocalTime of(int hour, int minute, int second) {
|
||||
HOUR_OF_DAY.checkValidValue(hour);
|
||||
if ((minute | second) == 0) {
|
||||
return HOURS[hour]; // for performance
|
||||
}
|
||||
MINUTE_OF_HOUR.checkValidValue(minute);
|
||||
SECOND_OF_MINUTE.checkValidValue(second);
|
||||
return new LocalTime(hour, minute, second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains an instance of {@code LocalTime} from a second-of-day value.
|
||||
* <p>
|
||||
* This factory may return a cached value, but applications must not rely on this.
|
||||
*
|
||||
* @param secondOfDay the second-of-day, from {@code 0} to {@code 24 * 60 * 60 - 1}
|
||||
* @return the local time, not null
|
||||
* @throws DateTimeException if the second-of-day value is invalid
|
||||
*/
|
||||
public static LocalTime ofSecondOfDay(int secondOfDay) {
|
||||
SECOND_OF_DAY.checkValidValue(secondOfDay);
|
||||
int hours = secondOfDay / SECONDS_PER_HOUR;
|
||||
secondOfDay -= hours * SECONDS_PER_HOUR;
|
||||
int minutes = secondOfDay / SECONDS_PER_MINUTE;
|
||||
secondOfDay -= minutes * SECONDS_PER_MINUTE;
|
||||
return create(hours, minutes, secondOfDay);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a local time from the hour, minute, second and nanosecond fields.
|
||||
* <p>
|
||||
* This factory may return a cached value, but applications must not rely on this.
|
||||
*
|
||||
* @param hour the hour-of-day to represent, validated from 0 to 23
|
||||
* @param minute the minute-of-hour to represent, validated from 0 to 59
|
||||
* @param second the second-of-minute to represent, validated from 0 to 59
|
||||
* @return the local time, not null
|
||||
*/
|
||||
private static LocalTime create(int hour, int minute, int second) {
|
||||
if ((minute | second) == 0) {
|
||||
return HOURS[hour];
|
||||
}
|
||||
return new LocalTime(hour, minute, second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor, previously validated.
|
||||
*
|
||||
* @param hour the hour-of-day to represent, validated from 0 to 23
|
||||
* @param minute the minute-of-hour to represent, validated from 0 to 59
|
||||
* @param second the second-of-minute to represent, validated from 0 to 59
|
||||
*/
|
||||
private LocalTime(int hour, int minute, int second) {
|
||||
this.hour = (byte) hour;
|
||||
this.minute = (byte) minute;
|
||||
this.second = (byte) second;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the hour-of-day field.
|
||||
*
|
||||
* @return the hour-of-day, from 0 to 23
|
||||
*/
|
||||
public int getHour() {
|
||||
return hour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minute-of-hour field.
|
||||
*
|
||||
* @return the minute-of-hour, from 0 to 59
|
||||
*/
|
||||
public int getMinute() {
|
||||
return minute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the second-of-minute field.
|
||||
*
|
||||
* @return the second-of-minute, from 0 to 59
|
||||
*/
|
||||
public int getSecond() {
|
||||
return second;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this {@code LocalTime} with the specified period in seconds added.
|
||||
* <p>
|
||||
* This adds the specified number of seconds to this time, returning a new time.
|
||||
* The calculation wraps around midnight.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param secondstoAdd the seconds to add, may be negative
|
||||
* @return a {@code LocalTime} based on this time with the seconds added, not null
|
||||
*/
|
||||
public LocalTime plusSeconds(long secondstoAdd) {
|
||||
if (secondstoAdd == 0) {
|
||||
return this;
|
||||
}
|
||||
int sofd = hour * SECONDS_PER_HOUR +
|
||||
minute * SECONDS_PER_MINUTE + second;
|
||||
int newSofd = ((int) (secondstoAdd % SECONDS_PER_DAY) + sofd + SECONDS_PER_DAY) % SECONDS_PER_DAY;
|
||||
if (sofd == newSofd) {
|
||||
return this;
|
||||
}
|
||||
int newHour = newSofd / SECONDS_PER_HOUR;
|
||||
int newMinute = (newSofd / SECONDS_PER_MINUTE) % MINUTES_PER_HOUR;
|
||||
int newSecond = newSofd % SECONDS_PER_MINUTE;
|
||||
return create(newHour, newMinute, newSecond);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this {@code LocalTime} with the specified period in seconds subtracted.
|
||||
* <p>
|
||||
* This subtracts the specified number of seconds from this time, returning a new time.
|
||||
* The calculation wraps around midnight.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param secondsToSubtract the seconds to subtract, may be negative
|
||||
* @return a {@code LocalTime} based on this time with the seconds subtracted, not null
|
||||
*/
|
||||
public LocalTime minusSeconds(long secondsToSubtract) {
|
||||
return plusSeconds(-(secondsToSubtract % SECONDS_PER_DAY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the time as seconds of day,
|
||||
* from {@code 0} to {@code 24 * 60 * 60 - 1}.
|
||||
*
|
||||
* @return the second-of-day equivalent to this time
|
||||
*/
|
||||
public int toSecondOfDay() {
|
||||
int total = hour * SECONDS_PER_HOUR;
|
||||
total += minute * SECONDS_PER_MINUTE;
|
||||
total += second;
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this {@code LocalTime} to another time.
|
||||
* <p>
|
||||
* The comparison is based on the time-line position of the local times within a day.
|
||||
* It is "consistent with equals", as defined by {@link Comparable}.
|
||||
*
|
||||
* @param other the other time to compare to, not null
|
||||
* @return the comparator value, negative if less, positive if greater
|
||||
* @throws NullPointerException if {@code other} is null
|
||||
*/
|
||||
public int compareTo(LocalTime other) {
|
||||
int cmp = Integer.compare(hour, other.hour);
|
||||
if (cmp == 0) {
|
||||
cmp = Integer.compare(minute, other.minute);
|
||||
if (cmp == 0) {
|
||||
cmp = Integer.compare(second, other.second);
|
||||
}
|
||||
}
|
||||
return cmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this time is equal to another time.
|
||||
* <p>
|
||||
* The comparison is based on the time-line position of the time within a day.
|
||||
* <p>
|
||||
* Only objects of type {@code LocalTime} are compared, other types return false.
|
||||
* To compare the date of two {@code TemporalAccessor} instances, use
|
||||
* {@link ChronoField#NANO_OF_DAY} as a comparator.
|
||||
*
|
||||
* @param obj the object to check, null returns false
|
||||
* @return true if this is equal to the other time
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof LocalTime) {
|
||||
LocalTime other = (LocalTime) obj;
|
||||
return hour == other.hour && minute == other.minute &&
|
||||
second == other.second;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A hash code for this time.
|
||||
*
|
||||
* @return a suitable hash code
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
long sod = toSecondOfDay();
|
||||
return (int) (sod ^ (sod >>> 32));
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,117 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package build.tools.tzdb;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A definition of the way a local time can be converted to the actual
|
||||
* transition date-time.
|
||||
* <p>
|
||||
* Time zone rules are expressed in one of three ways:
|
||||
* <p><ul>
|
||||
* <li>Relative to UTC</li>
|
||||
* <li>Relative to the standard offset in force</li>
|
||||
* <li>Relative to the wall offset (what you would see on a clock on the wall)</li>
|
||||
* </ul><p>
|
||||
*/
|
||||
public enum TimeDefinition {
|
||||
/** The local date-time is expressed in terms of the UTC offset. */
|
||||
UTC,
|
||||
/** The local date-time is expressed in terms of the wall offset. */
|
||||
WALL,
|
||||
/** The local date-time is expressed in terms of the standard offset. */
|
||||
STANDARD;
|
||||
|
||||
/**
|
||||
* Converts the specified local date-time to the local date-time actually
|
||||
* seen on a wall clock.
|
||||
* <p>
|
||||
* This method converts using the type of this enum.
|
||||
* The output is defined relative to the 'before' offset of the transition.
|
||||
* <p>
|
||||
* The UTC type uses the UTC offset.
|
||||
* The STANDARD type uses the standard offset.
|
||||
* The WALL type returns the input date-time.
|
||||
* The result is intended for use with the wall-offset.
|
||||
*
|
||||
* @param dateTime the local date-time, not null
|
||||
* @param standardOffset the standard offset, not null
|
||||
* @param wallOffset the wall offset, not null
|
||||
* @return the date-time relative to the wall/before offset, not null
|
||||
*/
|
||||
public LocalDateTime createDateTime(LocalDateTime dateTime, ZoneOffset standardOffset, ZoneOffset wallOffset) {
|
||||
switch (this) {
|
||||
case UTC: {
|
||||
int difference = wallOffset.getTotalSeconds() - ZoneOffset.UTC.getTotalSeconds();
|
||||
return dateTime.plusSeconds(difference);
|
||||
}
|
||||
case STANDARD: {
|
||||
int difference = wallOffset.getTotalSeconds() - standardOffset.getTotalSeconds();
|
||||
return dateTime.plusSeconds(difference);
|
||||
}
|
||||
default: // WALL
|
||||
return dateTime;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -56,8 +56,6 @@
|
||||
*/
|
||||
package build.tools.tzdb;
|
||||
|
||||
import static build.tools.tzdb.Utils.*;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@ -179,15 +177,41 @@ public final class TzdbZoneRulesCompiler {
|
||||
System.exit(1);
|
||||
System.err.println("Source directory does not contain file: VERSION");
|
||||
}
|
||||
|
||||
// load source files
|
||||
printVerbose("Compiling TZDB version " + version);
|
||||
// parse source files
|
||||
for (Path file : srcFiles) {
|
||||
printVerbose("Parsing file: " + file);
|
||||
parseFile(file);
|
||||
}
|
||||
TzdbZoneRulesProvider provider = new TzdbZoneRulesProvider(srcFiles);
|
||||
|
||||
// build zone rules
|
||||
printVerbose("Building rules");
|
||||
buildZoneRules();
|
||||
|
||||
// Build the rules, zones and links into real zones.
|
||||
SortedMap<String, ZoneRules> builtZones = new TreeMap<>();
|
||||
|
||||
// build zones
|
||||
for (String zoneId : provider.getZoneIds()) {
|
||||
printVerbose("Building zone " + zoneId);
|
||||
builtZones.put(zoneId, provider.getZoneRules(zoneId));
|
||||
}
|
||||
|
||||
// build aliases
|
||||
Map<String, String> links = provider.getAliasMap();
|
||||
for (String aliasId : links.keySet()) {
|
||||
String realId = links.get(aliasId);
|
||||
printVerbose("Linking alias " + aliasId + " to " + realId);
|
||||
ZoneRules realRules = builtZones.get(realId);
|
||||
if (realRules == null) {
|
||||
realId = links.get(realId); // try again (handle alias liked to alias)
|
||||
printVerbose("Relinking alias " + aliasId + " to " + realId);
|
||||
realRules = builtZones.get(realId);
|
||||
if (realRules == null) {
|
||||
throw new IllegalArgumentException("Alias '" + aliasId + "' links to invalid zone '" + realId);
|
||||
}
|
||||
links.put(aliasId, realId);
|
||||
}
|
||||
builtZones.put(aliasId, realRules);
|
||||
}
|
||||
|
||||
// output to file
|
||||
printVerbose("Outputting tzdb file: " + dstFile);
|
||||
outputFile(dstFile, version, builtZones, links);
|
||||
@ -269,361 +293,13 @@ public final class TzdbZoneRulesCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
private static final Pattern YEAR = Pattern.compile("(?i)(?<min>min)|(?<max>max)|(?<only>only)|(?<year>[0-9]+)");
|
||||
private static final Pattern MONTH = Pattern.compile("(?i)(jan)|(feb)|(mar)|(apr)|(may)|(jun)|(jul)|(aug)|(sep)|(oct)|(nov)|(dec)");
|
||||
private static final Matcher DOW = Pattern.compile("(?i)(mon)|(tue)|(wed)|(thu)|(fri)|(sat)|(sun)").matcher("");
|
||||
private static final Matcher TIME = Pattern.compile("(?<neg>-)?+(?<hour>[0-9]{1,2})(:(?<minute>[0-5][0-9]))?+(:(?<second>[0-5][0-9]))?+").matcher("");
|
||||
|
||||
/** The TZDB rules. */
|
||||
private final Map<String, List<TZDBRule>> rules = new HashMap<>();
|
||||
|
||||
/** The TZDB zones. */
|
||||
private final Map<String, List<TZDBZone>> zones = new HashMap<>();
|
||||
|
||||
/** The TZDB links. */
|
||||
private final Map<String, String> links = new HashMap<>();
|
||||
|
||||
/** The built zones. */
|
||||
private final SortedMap<String, ZoneRules> builtZones = new TreeMap<>();
|
||||
|
||||
/** Whether to output verbose messages. */
|
||||
private boolean verbose;
|
||||
|
||||
/**
|
||||
* private contructor
|
||||
*/
|
||||
private TzdbZoneRulesCompiler() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a source file.
|
||||
*
|
||||
* @param file the file being read, not null
|
||||
* @throws Exception if an error occurs
|
||||
*/
|
||||
private void parseFile(Path file) throws Exception {
|
||||
int lineNumber = 1;
|
||||
String line = null;
|
||||
try {
|
||||
List<String> lines = Files.readAllLines(file, StandardCharsets.ISO_8859_1);
|
||||
List<TZDBZone> openZone = null;
|
||||
for (; lineNumber < lines.size(); lineNumber++) {
|
||||
line = lines.get(lineNumber);
|
||||
int index = line.indexOf('#'); // remove comments (doesn't handle # in quotes)
|
||||
if (index >= 0) {
|
||||
line = line.substring(0, index);
|
||||
}
|
||||
if (line.trim().length() == 0) { // ignore blank lines
|
||||
continue;
|
||||
}
|
||||
Scanner s = new Scanner(line);
|
||||
if (openZone != null && Character.isWhitespace(line.charAt(0)) && s.hasNext()) {
|
||||
if (parseZoneLine(s, openZone)) {
|
||||
openZone = null;
|
||||
}
|
||||
} else {
|
||||
if (s.hasNext()) {
|
||||
String first = s.next();
|
||||
if (first.equals("Zone")) {
|
||||
openZone = new ArrayList<>();
|
||||
try {
|
||||
zones.put(s.next(), openZone);
|
||||
if (parseZoneLine(s, openZone)) {
|
||||
openZone = null;
|
||||
}
|
||||
} catch (NoSuchElementException x) {
|
||||
printVerbose("Invalid Zone line in file: " + file + ", line: " + line);
|
||||
throw new IllegalArgumentException("Invalid Zone line");
|
||||
}
|
||||
} else {
|
||||
openZone = null;
|
||||
if (first.equals("Rule")) {
|
||||
try {
|
||||
parseRuleLine(s);
|
||||
} catch (NoSuchElementException x) {
|
||||
printVerbose("Invalid Rule line in file: " + file + ", line: " + line);
|
||||
throw new IllegalArgumentException("Invalid Rule line");
|
||||
}
|
||||
} else if (first.equals("Link")) {
|
||||
try {
|
||||
String realId = s.next();
|
||||
String aliasId = s.next();
|
||||
links.put(aliasId, realId);
|
||||
} catch (NoSuchElementException x) {
|
||||
printVerbose("Invalid Link line in file: " + file + ", line: " + line);
|
||||
throw new IllegalArgumentException("Invalid Link line");
|
||||
}
|
||||
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown line");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new Exception("Failed while parsing file '" + file + "' on line " + lineNumber + " '" + line + "'", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a Rule line.
|
||||
*
|
||||
* @param s the line scanner, not null
|
||||
*/
|
||||
private void parseRuleLine(Scanner s) {
|
||||
TZDBRule rule = new TZDBRule();
|
||||
String name = s.next();
|
||||
if (rules.containsKey(name) == false) {
|
||||
rules.put(name, new ArrayList<TZDBRule>());
|
||||
}
|
||||
rules.get(name).add(rule);
|
||||
rule.startYear = parseYear(s, 0);
|
||||
rule.endYear = parseYear(s, rule.startYear);
|
||||
if (rule.startYear > rule.endYear) {
|
||||
throw new IllegalArgumentException("Year order invalid: " + rule.startYear + " > " + rule.endYear);
|
||||
}
|
||||
parseOptional(s.next()); // type is unused
|
||||
parseMonthDayTime(s, rule);
|
||||
rule.savingsAmount = parsePeriod(s.next());
|
||||
rule.text = parseOptional(s.next());
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a Zone line.
|
||||
*
|
||||
* @param s the line scanner, not null
|
||||
* @return true if the zone is complete
|
||||
*/
|
||||
private boolean parseZoneLine(Scanner s, List<TZDBZone> zoneList) {
|
||||
TZDBZone zone = new TZDBZone();
|
||||
zoneList.add(zone);
|
||||
zone.standardOffset = parseOffset(s.next());
|
||||
String savingsRule = parseOptional(s.next());
|
||||
if (savingsRule == null) {
|
||||
zone.fixedSavingsSecs = 0;
|
||||
zone.savingsRule = null;
|
||||
} else {
|
||||
try {
|
||||
zone.fixedSavingsSecs = parsePeriod(savingsRule);
|
||||
zone.savingsRule = null;
|
||||
} catch (Exception ex) {
|
||||
zone.fixedSavingsSecs = null;
|
||||
zone.savingsRule = savingsRule;
|
||||
}
|
||||
}
|
||||
zone.text = s.next();
|
||||
if (s.hasNext()) {
|
||||
zone.year = Integer.parseInt(s.next());
|
||||
if (s.hasNext()) {
|
||||
parseMonthDayTime(s, zone);
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a Rule line.
|
||||
*
|
||||
* @param s the line scanner, not null
|
||||
* @param mdt the object to parse into, not null
|
||||
*/
|
||||
private void parseMonthDayTime(Scanner s, TZDBMonthDayTime mdt) {
|
||||
mdt.month = parseMonth(s);
|
||||
if (s.hasNext()) {
|
||||
String dayRule = s.next();
|
||||
if (dayRule.startsWith("last")) {
|
||||
mdt.dayOfMonth = -1;
|
||||
mdt.dayOfWeek = parseDayOfWeek(dayRule.substring(4));
|
||||
mdt.adjustForwards = false;
|
||||
} else {
|
||||
int index = dayRule.indexOf(">=");
|
||||
if (index > 0) {
|
||||
mdt.dayOfWeek = parseDayOfWeek(dayRule.substring(0, index));
|
||||
dayRule = dayRule.substring(index + 2);
|
||||
} else {
|
||||
index = dayRule.indexOf("<=");
|
||||
if (index > 0) {
|
||||
mdt.dayOfWeek = parseDayOfWeek(dayRule.substring(0, index));
|
||||
mdt.adjustForwards = false;
|
||||
dayRule = dayRule.substring(index + 2);
|
||||
}
|
||||
}
|
||||
mdt.dayOfMonth = Integer.parseInt(dayRule);
|
||||
}
|
||||
if (s.hasNext()) {
|
||||
String timeStr = s.next();
|
||||
int secsOfDay = parseSecs(timeStr);
|
||||
if (secsOfDay == 86400) {
|
||||
mdt.endOfDay = true;
|
||||
secsOfDay = 0;
|
||||
}
|
||||
LocalTime time = LocalTime.ofSecondOfDay(secsOfDay);
|
||||
mdt.time = time;
|
||||
mdt.timeDefinition = parseTimeDefinition(timeStr.charAt(timeStr.length() - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int parseYear(Scanner s, int defaultYear) {
|
||||
if (s.hasNext(YEAR)) {
|
||||
s.next(YEAR);
|
||||
MatchResult mr = s.match();
|
||||
if (mr.group(1) != null) {
|
||||
return 1900; // systemv has min
|
||||
} else if (mr.group(2) != null) {
|
||||
return YEAR_MAX_VALUE;
|
||||
} else if (mr.group(3) != null) {
|
||||
return defaultYear;
|
||||
}
|
||||
return Integer.parseInt(mr.group(4));
|
||||
/*
|
||||
if (mr.group("min") != null) {
|
||||
//return YEAR_MIN_VALUE;
|
||||
return 1900; // systemv has min
|
||||
} else if (mr.group("max") != null) {
|
||||
return YEAR_MAX_VALUE;
|
||||
} else if (mr.group("only") != null) {
|
||||
return defaultYear;
|
||||
}
|
||||
return Integer.parseInt(mr.group("year"));
|
||||
*/
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown year: " + s.next());
|
||||
}
|
||||
|
||||
private int parseMonth(Scanner s) {
|
||||
if (s.hasNext(MONTH)) {
|
||||
s.next(MONTH);
|
||||
for (int moy = 1; moy < 13; moy++) {
|
||||
if (s.match().group(moy) != null) {
|
||||
return moy;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown month: " + s.next());
|
||||
}
|
||||
|
||||
private int parseDayOfWeek(String str) {
|
||||
if (DOW.reset(str).matches()) {
|
||||
for (int dow = 1; dow < 8; dow++) {
|
||||
if (DOW.group(dow) != null) {
|
||||
return dow;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown day-of-week: " + str);
|
||||
}
|
||||
|
||||
private String parseOptional(String str) {
|
||||
return str.equals("-") ? null : str;
|
||||
}
|
||||
|
||||
private int parseSecs(String str) {
|
||||
if (str.equals("-")) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
if (TIME.reset(str).find()) {
|
||||
int secs = Integer.parseInt(TIME.group("hour")) * 60 * 60;
|
||||
if (TIME.group("minute") != null) {
|
||||
secs += Integer.parseInt(TIME.group("minute")) * 60;
|
||||
}
|
||||
if (TIME.group("second") != null) {
|
||||
secs += Integer.parseInt(TIME.group("second"));
|
||||
}
|
||||
if (TIME.group("neg") != null) {
|
||||
secs = -secs;
|
||||
}
|
||||
return secs;
|
||||
}
|
||||
} catch (NumberFormatException x) {}
|
||||
throw new IllegalArgumentException(str);
|
||||
}
|
||||
|
||||
private ZoneOffset parseOffset(String str) {
|
||||
int secs = parseSecs(str);
|
||||
return ZoneOffset.ofTotalSeconds(secs);
|
||||
}
|
||||
|
||||
private int parsePeriod(String str) {
|
||||
return parseSecs(str);
|
||||
}
|
||||
|
||||
private TimeDefinition parseTimeDefinition(char c) {
|
||||
switch (c) {
|
||||
case 's':
|
||||
case 'S':
|
||||
// standard time
|
||||
return TimeDefinition.STANDARD;
|
||||
case 'u':
|
||||
case 'U':
|
||||
case 'g':
|
||||
case 'G':
|
||||
case 'z':
|
||||
case 'Z':
|
||||
// UTC
|
||||
return TimeDefinition.UTC;
|
||||
case 'w':
|
||||
case 'W':
|
||||
default:
|
||||
// wall time
|
||||
return TimeDefinition.WALL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the rules, zones and links into real zones.
|
||||
*
|
||||
* @throws Exception if an error occurs
|
||||
*/
|
||||
private void buildZoneRules() throws Exception {
|
||||
// build zones
|
||||
for (String zoneId : zones.keySet()) {
|
||||
printVerbose("Building zone " + zoneId);
|
||||
List<TZDBZone> tzdbZones = zones.get(zoneId);
|
||||
ZoneRulesBuilder bld = new ZoneRulesBuilder();
|
||||
for (TZDBZone tzdbZone : tzdbZones) {
|
||||
bld = tzdbZone.addToBuilder(bld, rules);
|
||||
}
|
||||
builtZones.put(zoneId, bld.toRules(zoneId));
|
||||
}
|
||||
|
||||
// build aliases
|
||||
for (String aliasId : links.keySet()) {
|
||||
String realId = links.get(aliasId);
|
||||
printVerbose("Linking alias " + aliasId + " to " + realId);
|
||||
ZoneRules realRules = builtZones.get(realId);
|
||||
if (realRules == null) {
|
||||
realId = links.get(realId); // try again (handle alias liked to alias)
|
||||
printVerbose("Relinking alias " + aliasId + " to " + realId);
|
||||
realRules = builtZones.get(realId);
|
||||
if (realRules == null) {
|
||||
throw new IllegalArgumentException("Alias '" + aliasId + "' links to invalid zone '" + realId);
|
||||
}
|
||||
links.put(aliasId, realId);
|
||||
}
|
||||
builtZones.put(aliasId, realRules);
|
||||
}
|
||||
// remove UTC and GMT
|
||||
// builtZones.remove("UTC");
|
||||
// builtZones.remove("GMT");
|
||||
// builtZones.remove("GMT0");
|
||||
builtZones.remove("GMT+0");
|
||||
builtZones.remove("GMT-0");
|
||||
links.remove("GMT+0");
|
||||
links.remove("GMT-0");
|
||||
// remove ROC, which is not supported in j.u.tz
|
||||
builtZones.remove("ROC");
|
||||
links.remove("ROC");
|
||||
// remove EST, HST and MST. They are supported via
|
||||
// the short-id mapping
|
||||
builtZones.remove("EST");
|
||||
builtZones.remove("HST");
|
||||
builtZones.remove("MST");
|
||||
}
|
||||
private TzdbZoneRulesCompiler() {}
|
||||
|
||||
/**
|
||||
* Prints a verbose message.
|
||||
@ -635,109 +311,4 @@ public final class TzdbZoneRulesCompiler {
|
||||
System.out.println(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class representing a month-day-time in the TZDB file.
|
||||
*/
|
||||
abstract class TZDBMonthDayTime {
|
||||
/** The month of the cutover. */
|
||||
int month = 1;
|
||||
/** The day-of-month of the cutover. */
|
||||
int dayOfMonth = 1;
|
||||
/** Whether to adjust forwards. */
|
||||
boolean adjustForwards = true;
|
||||
/** The day-of-week of the cutover. */
|
||||
int dayOfWeek = -1;
|
||||
/** The time of the cutover. */
|
||||
LocalTime time = LocalTime.MIDNIGHT;
|
||||
/** Whether this is midnight end of day. */
|
||||
boolean endOfDay;
|
||||
/** The time of the cutover. */
|
||||
TimeDefinition timeDefinition = TimeDefinition.WALL;
|
||||
void adjustToFowards(int year) {
|
||||
if (adjustForwards == false && dayOfMonth > 0) {
|
||||
LocalDate adjustedDate = LocalDate.of(year, month, dayOfMonth).minusDays(6);
|
||||
dayOfMonth = adjustedDate.getDayOfMonth();
|
||||
month = adjustedDate.getMonth();
|
||||
adjustForwards = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class representing a rule line in the TZDB file.
|
||||
*/
|
||||
final class TZDBRule extends TZDBMonthDayTime {
|
||||
/** The start year. */
|
||||
int startYear;
|
||||
/** The end year. */
|
||||
int endYear;
|
||||
/** The amount of savings. */
|
||||
int savingsAmount;
|
||||
/** The text name of the zone. */
|
||||
String text;
|
||||
|
||||
void addToBuilder(ZoneRulesBuilder bld) {
|
||||
adjustToFowards(2004); // irrelevant, treat as leap year
|
||||
bld.addRuleToWindow(startYear, endYear, month, dayOfMonth, dayOfWeek, time, endOfDay, timeDefinition, savingsAmount);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class representing a linked set of zone lines in the TZDB file.
|
||||
*/
|
||||
final class TZDBZone extends TZDBMonthDayTime {
|
||||
/** The standard offset. */
|
||||
ZoneOffset standardOffset;
|
||||
/** The fixed savings amount. */
|
||||
Integer fixedSavingsSecs;
|
||||
/** The savings rule. */
|
||||
String savingsRule;
|
||||
/** The text name of the zone. */
|
||||
String text;
|
||||
/** The year of the cutover. */
|
||||
int year = YEAR_MAX_VALUE;
|
||||
|
||||
ZoneRulesBuilder addToBuilder(ZoneRulesBuilder bld, Map<String, List<TZDBRule>> rules) {
|
||||
if (year != YEAR_MAX_VALUE) {
|
||||
bld.addWindow(standardOffset, toDateTime(year), timeDefinition);
|
||||
} else {
|
||||
bld.addWindowForever(standardOffset);
|
||||
}
|
||||
if (fixedSavingsSecs != null) {
|
||||
bld.setFixedSavingsToWindow(fixedSavingsSecs);
|
||||
} else {
|
||||
List<TZDBRule> tzdbRules = rules.get(savingsRule);
|
||||
if (tzdbRules == null) {
|
||||
throw new IllegalArgumentException("Rule not found: " + savingsRule);
|
||||
}
|
||||
for (TZDBRule tzdbRule : tzdbRules) {
|
||||
tzdbRule.addToBuilder(bld);
|
||||
}
|
||||
}
|
||||
return bld;
|
||||
}
|
||||
|
||||
private LocalDateTime toDateTime(int year) {
|
||||
adjustToFowards(year);
|
||||
LocalDate date;
|
||||
if (dayOfMonth == -1) {
|
||||
dayOfMonth = lengthOfMonth(month, isLeapYear(year));
|
||||
date = LocalDate.of(year, month, dayOfMonth);
|
||||
if (dayOfWeek != -1) {
|
||||
date = previousOrSame(date, dayOfWeek);
|
||||
}
|
||||
} else {
|
||||
date = LocalDate.of(year, month, dayOfMonth);
|
||||
if (dayOfWeek != -1) {
|
||||
date = nextOrSame(date, dayOfWeek);
|
||||
}
|
||||
}
|
||||
LocalDateTime ldt = LocalDateTime.of(date, time);
|
||||
if (endOfDay) {
|
||||
ldt = ldt.plusDays(1);
|
||||
}
|
||||
return ldt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
843
jdk/make/src/classes/build/tools/tzdb/TzdbZoneRulesProvider.java
Normal file
843
jdk/make/src/classes/build/tools/tzdb/TzdbZoneRulesProvider.java
Normal file
@ -0,0 +1,843 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package build.tools.tzdb;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.NavigableMap;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.time.*;
|
||||
import java.time.Year;
|
||||
import java.time.chrono.IsoChronology;
|
||||
import java.time.temporal.TemporalAdjusters;
|
||||
import java.time.zone.ZoneOffsetTransition;
|
||||
import java.time.zone.ZoneOffsetTransitionRule;
|
||||
import java.time.zone.ZoneOffsetTransitionRule.TimeDefinition;
|
||||
import java.time.zone.ZoneRulesException;
|
||||
|
||||
/**
|
||||
* Compile and build time-zone rules from IANA timezone data
|
||||
*
|
||||
* @author Xueming Shen
|
||||
* @author Stephen Colebourne
|
||||
* @author Michael Nascimento Santos
|
||||
*
|
||||
* @since 1.9
|
||||
*/
|
||||
|
||||
class TzdbZoneRulesProvider {
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
*
|
||||
* @throws ZoneRulesException if unable to load
|
||||
*/
|
||||
public TzdbZoneRulesProvider(List<Path> files) {
|
||||
try {
|
||||
load(files);
|
||||
} catch (Exception ex) {
|
||||
throw new ZoneRulesException("Unable to load TZDB time-zone rules", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public Set<String> getZoneIds() {
|
||||
return new TreeSet(regionIds);
|
||||
}
|
||||
|
||||
public Map<String, String> getAliasMap() {
|
||||
return links;
|
||||
}
|
||||
|
||||
public ZoneRules getZoneRules(String zoneId) {
|
||||
Object obj = zones.get(zoneId);
|
||||
if (obj == null) {
|
||||
String zoneId0 = zoneId;
|
||||
if (links.containsKey(zoneId)) {
|
||||
zoneId = links.get(zoneId);
|
||||
obj = zones.get(zoneId);
|
||||
}
|
||||
if (obj == null) {
|
||||
throw new ZoneRulesException("Unknown time-zone ID: " + zoneId0);
|
||||
}
|
||||
}
|
||||
if (obj instanceof ZoneRules) {
|
||||
return (ZoneRules)obj;
|
||||
}
|
||||
try {
|
||||
ZoneRules zrules = buildRules(zoneId, (List<ZoneLine>)obj);
|
||||
zones.put(zoneId, zrules);
|
||||
return zrules;
|
||||
} catch (Exception ex) {
|
||||
throw new ZoneRulesException(
|
||||
"Invalid binary time-zone data: TZDB:" + zoneId, ex);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* All the regions that are available.
|
||||
*/
|
||||
private List<String> regionIds = new ArrayList<>(600);
|
||||
|
||||
/**
|
||||
* Zone region to rules mapping
|
||||
*/
|
||||
private final Map<String, Object> zones = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* compatibility list
|
||||
*/
|
||||
private static HashSet<String> excludedZones;
|
||||
static {
|
||||
// (1) exclude EST, HST and MST. They are supported
|
||||
// via the short-id mapping
|
||||
// (2) remove UTC and GMT
|
||||
// (3) remove ROC, which is not supported in j.u.tz
|
||||
excludedZones = new HashSet<>(10);
|
||||
excludedZones.add("EST");
|
||||
excludedZones.add("HST");
|
||||
excludedZones.add("MST");
|
||||
excludedZones.add("GMT+0");
|
||||
excludedZones.add("GMT-0");
|
||||
excludedZones.add("ROC");
|
||||
}
|
||||
|
||||
private Map<String, String> links = new HashMap<>(150);
|
||||
private Map<String, List<RuleLine>> rules = new HashMap<>(500);
|
||||
|
||||
private void load(List<Path> files) throws IOException {
|
||||
|
||||
for (Path file : files) {
|
||||
List<ZoneLine> openZone = null;
|
||||
try {
|
||||
for (String line : Files.readAllLines(file, StandardCharsets.ISO_8859_1)) {
|
||||
if (line.length() == 0 || line.charAt(0) == '#') {
|
||||
continue;
|
||||
}
|
||||
//StringIterator itr = new StringIterator(line);
|
||||
String[] tokens = split(line);
|
||||
if (openZone != null && // continuing zone line
|
||||
Character.isWhitespace(line.charAt(0)) &&
|
||||
tokens.length > 0) {
|
||||
ZoneLine zLine = new ZoneLine();
|
||||
openZone.add(zLine);
|
||||
if (zLine.parse(tokens, 0)) {
|
||||
openZone = null;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("Zone")) { // parse Zone line
|
||||
String name = tokens[1];
|
||||
if (excludedZones.contains(name)){
|
||||
continue;
|
||||
}
|
||||
if (zones.containsKey(name)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Duplicated zone name in file: " + name +
|
||||
", line: [" + line + "]");
|
||||
}
|
||||
openZone = new ArrayList<>(10);
|
||||
zones.put(name, openZone);
|
||||
regionIds.add(name);
|
||||
ZoneLine zLine = new ZoneLine();
|
||||
openZone.add(zLine);
|
||||
if (zLine.parse(tokens, 2)) {
|
||||
openZone = null;
|
||||
}
|
||||
} else if (line.startsWith("Rule")) { // parse Rule line
|
||||
String name = tokens[1];
|
||||
if (!rules.containsKey(name)) {
|
||||
rules.put(name, new ArrayList<RuleLine>(10));
|
||||
}
|
||||
rules.get(name).add(new RuleLine().parse(tokens));
|
||||
} else if (line.startsWith("Link")) { // parse link line
|
||||
if (tokens.length >= 3) {
|
||||
String realId = tokens[1];
|
||||
String aliasId = tokens[2];
|
||||
if (excludedZones.contains(aliasId)){
|
||||
continue;
|
||||
}
|
||||
links.put(aliasId, realId);
|
||||
regionIds.add(aliasId);
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid Link line in file" +
|
||||
file + ", line: [" + line + "]");
|
||||
}
|
||||
} else {
|
||||
// skip unknown line
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("Failed while processing file [" + file +
|
||||
"]", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String[] split(String str) {
|
||||
int off = 0;
|
||||
int end = str.length();
|
||||
ArrayList<String> list = new ArrayList<>(10);
|
||||
while (off < end) {
|
||||
char c = str.charAt(off);
|
||||
if (c == '\t' || c == ' ') {
|
||||
off++;
|
||||
continue;
|
||||
}
|
||||
if (c == '#') { // comment
|
||||
break;
|
||||
}
|
||||
int start = off;
|
||||
while (off < end) {
|
||||
c = str.charAt(off);
|
||||
if (c == ' ' || c == '\t') {
|
||||
break;
|
||||
}
|
||||
off++;
|
||||
}
|
||||
if (start != off) {
|
||||
list.add(str.substring(start, off));
|
||||
}
|
||||
}
|
||||
return list.toArray(new String[list.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Class representing a month-day-time in the TZDB file.
|
||||
*/
|
||||
private static abstract class MonthDayTime {
|
||||
/** The month of the cutover. */
|
||||
Month month = Month.JANUARY;
|
||||
|
||||
/** The day-of-month of the cutover. */
|
||||
int dayOfMonth = 1;
|
||||
|
||||
/** Whether to adjust forwards. */
|
||||
boolean adjustForwards = true;
|
||||
|
||||
/** The day-of-week of the cutover. */
|
||||
DayOfWeek dayOfWeek;
|
||||
|
||||
/** The time of the cutover, in second of day */
|
||||
int secsOfDay = 0;
|
||||
|
||||
/** Whether this is midnight end of day. */
|
||||
boolean endOfDay;
|
||||
/** The time of the cutover. */
|
||||
|
||||
TimeDefinition timeDefinition = TimeDefinition.WALL;
|
||||
|
||||
void adjustToForwards(int year) {
|
||||
if (adjustForwards == false && dayOfMonth > 0) {
|
||||
// weekDay<=monthDay case, don't have it in tzdb data for now
|
||||
LocalDate adjustedDate = LocalDate.of(year, month, dayOfMonth).minusDays(6);
|
||||
dayOfMonth = adjustedDate.getDayOfMonth();
|
||||
month = adjustedDate.getMonth();
|
||||
adjustForwards = true;
|
||||
}
|
||||
}
|
||||
|
||||
LocalDateTime toDateTime(int year) {
|
||||
LocalDate date;
|
||||
if (dayOfMonth < 0) {
|
||||
int monthLen = month.length(IsoChronology.INSTANCE.isLeapYear(year));
|
||||
date = LocalDate.of(year, month, monthLen + 1 + dayOfMonth);
|
||||
if (dayOfWeek != null) {
|
||||
date = date.with(TemporalAdjusters.previousOrSame(dayOfWeek));
|
||||
}
|
||||
} else {
|
||||
date = LocalDate.of(year, month, dayOfMonth);
|
||||
if (dayOfWeek != null) {
|
||||
date = date.with(TemporalAdjusters.nextOrSame(dayOfWeek));
|
||||
}
|
||||
}
|
||||
if (endOfDay) {
|
||||
date = date.plusDays(1);
|
||||
}
|
||||
return LocalDateTime.of(date, LocalTime.ofSecondOfDay(secsOfDay));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the MonthDaytime segment of a tzdb line.
|
||||
*/
|
||||
private void parse(String[] tokens, int off) {
|
||||
month = parseMonth(tokens[off++]);
|
||||
if (off < tokens.length) {
|
||||
String dayRule = tokens[off++];
|
||||
if (dayRule.startsWith("last")) {
|
||||
dayOfMonth = -1;
|
||||
dayOfWeek = parseDayOfWeek(dayRule.substring(4));
|
||||
adjustForwards = false;
|
||||
} else {
|
||||
int index = dayRule.indexOf(">=");
|
||||
if (index > 0) {
|
||||
dayOfWeek = parseDayOfWeek(dayRule.substring(0, index));
|
||||
dayRule = dayRule.substring(index + 2);
|
||||
} else {
|
||||
index = dayRule.indexOf("<=");
|
||||
if (index > 0) {
|
||||
dayOfWeek = parseDayOfWeek(dayRule.substring(0, index));
|
||||
adjustForwards = false;
|
||||
dayRule = dayRule.substring(index + 2);
|
||||
}
|
||||
}
|
||||
dayOfMonth = Integer.parseInt(dayRule);
|
||||
if (dayOfMonth < -28 || dayOfMonth > 31 || dayOfMonth == 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Day of month indicator must be between -28 and 31 inclusive excluding zero");
|
||||
}
|
||||
}
|
||||
if (off < tokens.length) {
|
||||
String timeStr = tokens[off++];
|
||||
secsOfDay = parseSecs(timeStr);
|
||||
if (secsOfDay == 86400) {
|
||||
// time must be midnight when end of day flag is true
|
||||
endOfDay = true;
|
||||
secsOfDay = 0;
|
||||
}
|
||||
timeDefinition = parseTimeDefinition(timeStr.charAt(timeStr.length() - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int parseYear(String year, int defaultYear) {
|
||||
switch (year.toLowerCase()) {
|
||||
case "min": return 1900;
|
||||
case "max": return Year.MAX_VALUE;
|
||||
case "only": return defaultYear;
|
||||
}
|
||||
return Integer.parseInt(year);
|
||||
}
|
||||
|
||||
Month parseMonth(String mon) {
|
||||
switch (mon) {
|
||||
case "Jan": return Month.JANUARY;
|
||||
case "Feb": return Month.FEBRUARY;
|
||||
case "Mar": return Month.MARCH;
|
||||
case "Apr": return Month.APRIL;
|
||||
case "May": return Month.MAY;
|
||||
case "Jun": return Month.JUNE;
|
||||
case "Jul": return Month.JULY;
|
||||
case "Aug": return Month.AUGUST;
|
||||
case "Sep": return Month.SEPTEMBER;
|
||||
case "Oct": return Month.OCTOBER;
|
||||
case "Nov": return Month.NOVEMBER;
|
||||
case "Dec": return Month.DECEMBER;
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown month: " + mon);
|
||||
}
|
||||
|
||||
DayOfWeek parseDayOfWeek(String dow) {
|
||||
switch (dow) {
|
||||
case "Mon": return DayOfWeek.MONDAY;
|
||||
case "Tue": return DayOfWeek.TUESDAY;
|
||||
case "Wed": return DayOfWeek.WEDNESDAY;
|
||||
case "Thu": return DayOfWeek.THURSDAY;
|
||||
case "Fri": return DayOfWeek.FRIDAY;
|
||||
case "Sat": return DayOfWeek.SATURDAY;
|
||||
case "Sun": return DayOfWeek.SUNDAY;
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown day-of-week: " + dow);
|
||||
}
|
||||
|
||||
String parseOptional(String str) {
|
||||
return str.equals("-") ? null : str;
|
||||
}
|
||||
|
||||
static final boolean isDigit(char c) {
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
private int parseSecs(String time) {
|
||||
if (time.equals("-")) {
|
||||
return 0;
|
||||
}
|
||||
// faster hack
|
||||
int secs = 0;
|
||||
int sign = 1;
|
||||
int off = 0;
|
||||
int len = time.length();
|
||||
if (off < len && time.charAt(off) == '-') {
|
||||
sign = -1;
|
||||
off++;
|
||||
}
|
||||
char c0, c1;
|
||||
if (off < len && isDigit(c0 = time.charAt(off++))) {
|
||||
int hour = c0 - '0';
|
||||
if (off < len && isDigit(c1 = time.charAt(off))) {
|
||||
hour = hour * 10 + c1 - '0';
|
||||
off++;
|
||||
}
|
||||
secs = hour * 60 * 60;
|
||||
if (off < len && time.charAt(off++) == ':') {
|
||||
if (off + 1 < len &&
|
||||
isDigit(c0 = time.charAt(off++)) &&
|
||||
isDigit(c1 = time.charAt(off++))) {
|
||||
// minutes
|
||||
secs += ((c0 - '0') * 10 + c1 - '0') * 60;
|
||||
if (off < len && time.charAt(off++) == ':') {
|
||||
if (off + 1 < len &&
|
||||
isDigit(c0 = time.charAt(off++)) &&
|
||||
isDigit(c1 = time.charAt(off++))) {
|
||||
// seconds
|
||||
secs += ((c0 - '0') * 10 + c1 - '0');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return secs * sign;
|
||||
}
|
||||
throw new IllegalArgumentException("[" + time + "]");
|
||||
}
|
||||
|
||||
int parseOffset(String str) {
|
||||
int secs = parseSecs(str);
|
||||
if (Math.abs(secs) > 18 * 60 * 60) {
|
||||
throw new IllegalArgumentException(
|
||||
"Zone offset not in valid range: -18:00 to +18:00");
|
||||
}
|
||||
return secs;
|
||||
}
|
||||
|
||||
int parsePeriod(String str) {
|
||||
return parseSecs(str);
|
||||
}
|
||||
|
||||
TimeDefinition parseTimeDefinition(char c) {
|
||||
switch (c) {
|
||||
case 's':
|
||||
case 'S':
|
||||
// standard time
|
||||
return TimeDefinition.STANDARD;
|
||||
case 'u':
|
||||
case 'U':
|
||||
case 'g':
|
||||
case 'G':
|
||||
case 'z':
|
||||
case 'Z':
|
||||
// UTC
|
||||
return TimeDefinition.UTC;
|
||||
case 'w':
|
||||
case 'W':
|
||||
default:
|
||||
// wall time
|
||||
return TimeDefinition.WALL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class representing a rule line in the TZDB file.
|
||||
*/
|
||||
private static class RuleLine extends MonthDayTime {
|
||||
/** The start year. */
|
||||
int startYear;
|
||||
|
||||
/** The end year. */
|
||||
int endYear;
|
||||
|
||||
/** The amount of savings, in seconds. */
|
||||
int savingsAmount;
|
||||
|
||||
/** The text name of the zone. */
|
||||
String text;
|
||||
|
||||
/**
|
||||
* Converts this to a transition rule.
|
||||
*
|
||||
* @param standardOffset the active standard offset, not null
|
||||
* @param savingsBeforeSecs the active savings before the transition in seconds
|
||||
* @return the transition, not null
|
||||
*/
|
||||
ZoneOffsetTransitionRule toTransitionRule(ZoneOffset stdOffset, int savingsBefore) {
|
||||
// rule shared by different zones, so don't change it
|
||||
Month month = this.month;
|
||||
int dayOfMonth = this.dayOfMonth;
|
||||
DayOfWeek dayOfWeek = this.dayOfWeek;
|
||||
boolean endOfDay = this.endOfDay;
|
||||
|
||||
// optimize stored format
|
||||
if (dayOfMonth < 0) {
|
||||
if (month != Month.FEBRUARY) { // not Month.FEBRUARY
|
||||
dayOfMonth = month.maxLength() - 6;
|
||||
}
|
||||
}
|
||||
if (endOfDay && dayOfMonth > 0 &&
|
||||
(dayOfMonth == 28 && month == Month.FEBRUARY) == false) {
|
||||
LocalDate date = LocalDate.of(2004, month, dayOfMonth).plusDays(1); // leap-year
|
||||
month = date.getMonth();
|
||||
dayOfMonth = date.getDayOfMonth();
|
||||
if (dayOfWeek != null) {
|
||||
dayOfWeek = dayOfWeek.plus(1);
|
||||
}
|
||||
endOfDay = false;
|
||||
}
|
||||
// build rule
|
||||
return ZoneOffsetTransitionRule.of(
|
||||
//month, dayOfMonth, dayOfWeek, time, endOfDay, timeDefinition,
|
||||
month, dayOfMonth, dayOfWeek,
|
||||
LocalTime.ofSecondOfDay(secsOfDay), endOfDay, timeDefinition,
|
||||
stdOffset,
|
||||
ZoneOffset.ofTotalSeconds(stdOffset.getTotalSeconds() + savingsBefore),
|
||||
ZoneOffset.ofTotalSeconds(stdOffset.getTotalSeconds() + savingsAmount));
|
||||
}
|
||||
|
||||
RuleLine parse(String[] tokens) {
|
||||
startYear = parseYear(tokens[2], 0);
|
||||
endYear = parseYear(tokens[3], startYear);
|
||||
if (startYear > endYear) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid <Rule> line/Year order invalid:" + startYear + " > " + endYear);
|
||||
}
|
||||
//parseOptional(s.next()); // type is unused
|
||||
super.parse(tokens, 5); // monthdaytime parsing
|
||||
savingsAmount = parsePeriod(tokens[8]);
|
||||
//rule.text = parseOptional(s.next());
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class representing a linked set of zone lines in the TZDB file.
|
||||
*/
|
||||
private static class ZoneLine extends MonthDayTime {
|
||||
/** The standard offset. */
|
||||
int stdOffsetSecs;
|
||||
|
||||
/** The fixed savings amount. */
|
||||
int fixedSavingsSecs = 0;
|
||||
|
||||
/** The savings rule. */
|
||||
String savingsRule;
|
||||
|
||||
/** The text name of the zone. */
|
||||
String text;
|
||||
|
||||
/** The cutover year */
|
||||
int year = Year.MAX_VALUE;
|
||||
|
||||
/** The cutover date time */
|
||||
LocalDateTime ldt;
|
||||
|
||||
/** The cutover date/time in epoch seconds/UTC */
|
||||
long ldtSecs = Long.MIN_VALUE;
|
||||
|
||||
LocalDateTime toDateTime() {
|
||||
if (ldt == null) {
|
||||
ldt = toDateTime(year);
|
||||
}
|
||||
return ldt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the date-time epoch second in the wall offset for the local
|
||||
* date-time at the end of the window.
|
||||
*
|
||||
* @param savingsSecs the amount of savings in use in seconds
|
||||
* @return the created date-time epoch second in the wall offset, not null
|
||||
*/
|
||||
long toDateTimeEpochSecond(int savingsSecs) {
|
||||
if (ldtSecs == Long.MIN_VALUE) {
|
||||
ldtSecs = toDateTime().toEpochSecond(ZoneOffset.UTC);
|
||||
}
|
||||
switch(timeDefinition) {
|
||||
case UTC: return ldtSecs;
|
||||
case STANDARD: return ldtSecs - stdOffsetSecs;
|
||||
default: return ldtSecs - (stdOffsetSecs + savingsSecs); // WALL
|
||||
}
|
||||
}
|
||||
|
||||
boolean parse(String[] tokens, int off) {
|
||||
stdOffsetSecs = parseOffset(tokens[off++]);
|
||||
savingsRule = parseOptional(tokens[off++]);
|
||||
if (savingsRule != null && savingsRule.length() > 0 &&
|
||||
(savingsRule.charAt(0) == '-' || isDigit(savingsRule.charAt(0)))) {
|
||||
try {
|
||||
fixedSavingsSecs = parsePeriod(savingsRule);
|
||||
savingsRule = null;
|
||||
} catch (Exception ex) {
|
||||
fixedSavingsSecs = 0;
|
||||
}
|
||||
}
|
||||
text = tokens[off++];
|
||||
if (off < tokens.length) {
|
||||
year = Integer.parseInt(tokens[off++]);
|
||||
if (off < tokens.length) {
|
||||
super.parse(tokens, off); // MonthDayTime
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class representing a rule line in the TZDB file for a particular year.
|
||||
*/
|
||||
private static class TransRule implements Comparable<TransRule>
|
||||
{
|
||||
private int year;
|
||||
private RuleLine rule;
|
||||
|
||||
/** The trans date/time */
|
||||
private LocalDateTime ldt;
|
||||
|
||||
/** The trans date/time in epoch seconds (assume UTC) */
|
||||
long ldtSecs;
|
||||
|
||||
TransRule(int year, RuleLine rule) {
|
||||
this.year = year;
|
||||
this.rule = rule;
|
||||
this.ldt = rule.toDateTime(year);
|
||||
this.ldtSecs = ldt.toEpochSecond(ZoneOffset.UTC);
|
||||
}
|
||||
|
||||
ZoneOffsetTransition toTransition(ZoneOffset standardOffset, int savingsBeforeSecs) {
|
||||
// copy of code in ZoneOffsetTransitionRule to avoid infinite loop
|
||||
ZoneOffset wallOffset = ZoneOffset.ofTotalSeconds(
|
||||
standardOffset.getTotalSeconds() + savingsBeforeSecs);
|
||||
ZoneOffset offsetAfter = ZoneOffset.ofTotalSeconds(
|
||||
standardOffset.getTotalSeconds() + rule.savingsAmount);
|
||||
LocalDateTime dt = rule.timeDefinition
|
||||
.createDateTime(ldt, standardOffset, wallOffset);
|
||||
return ZoneOffsetTransition.of(dt, wallOffset, offsetAfter);
|
||||
}
|
||||
|
||||
long toEpochSecond(ZoneOffset stdOffset, int savingsBeforeSecs) {
|
||||
switch(rule.timeDefinition) {
|
||||
case UTC: return ldtSecs;
|
||||
case STANDARD: return ldtSecs - stdOffset.getTotalSeconds();
|
||||
default: return ldtSecs - (stdOffset.getTotalSeconds() + savingsBeforeSecs); // WALL
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if this a real transition with the active savings in seconds
|
||||
*
|
||||
* @param savingsBefore the active savings in seconds
|
||||
* @return true, if savings changes
|
||||
*/
|
||||
boolean isTransition(int savingsBefore) {
|
||||
return rule.savingsAmount != savingsBefore;
|
||||
}
|
||||
|
||||
public int compareTo(TransRule other) {
|
||||
return (ldtSecs < other.ldtSecs)? -1 : ((ldtSecs == other.ldtSecs) ? 0 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
private ZoneRules buildRules(String zoneId, List<ZoneLine> zones) {
|
||||
if (zones.isEmpty()) {
|
||||
throw new IllegalStateException("No available zone window");
|
||||
}
|
||||
final List<ZoneOffsetTransition> standardTransitionList = new ArrayList<>(4);
|
||||
final List<ZoneOffsetTransition> transitionList = new ArrayList<>(256);
|
||||
final List<ZoneOffsetTransitionRule> lastTransitionRuleList = new ArrayList<>(2);
|
||||
|
||||
final ZoneLine zone0 = zones.get(0);
|
||||
// initialize the standard offset, wallOffset and savings for loop
|
||||
|
||||
//ZoneOffset stdOffset = zone0.standardOffset;
|
||||
ZoneOffset stdOffset = ZoneOffset.ofTotalSeconds(zone0.stdOffsetSecs);
|
||||
|
||||
int savings = zone0.fixedSavingsSecs;
|
||||
ZoneOffset wallOffset = ZoneOffset.ofTotalSeconds(stdOffset.getTotalSeconds() + savings);
|
||||
|
||||
// start ldt of each zone window
|
||||
LocalDateTime zoneStart = LocalDateTime.MIN;
|
||||
|
||||
// first stanard offset
|
||||
ZoneOffset firstStdOffset = stdOffset;
|
||||
// first wall offset
|
||||
ZoneOffset firstWallOffset = wallOffset;
|
||||
|
||||
for (ZoneLine zone : zones) {
|
||||
// check if standard offset changed, update it if yes
|
||||
ZoneOffset stdOffsetPrev = stdOffset; // for effectiveSavings check
|
||||
if (zone.stdOffsetSecs != stdOffset.getTotalSeconds()) {
|
||||
ZoneOffset stdOffsetNew = ZoneOffset.ofTotalSeconds(zone.stdOffsetSecs);
|
||||
standardTransitionList.add(
|
||||
ZoneOffsetTransition.of(
|
||||
LocalDateTime.ofEpochSecond(zoneStart.toEpochSecond(wallOffset),
|
||||
0,
|
||||
stdOffset),
|
||||
stdOffset,
|
||||
stdOffsetNew));
|
||||
stdOffset = stdOffsetNew;
|
||||
}
|
||||
|
||||
LocalDateTime zoneEnd;
|
||||
if (zone.year == Year.MAX_VALUE) {
|
||||
zoneEnd = LocalDateTime.MAX;
|
||||
} else {
|
||||
zoneEnd = zone.toDateTime();
|
||||
}
|
||||
if (zoneEnd.compareTo(zoneStart) < 0) {
|
||||
throw new IllegalStateException("Windows must be in date-time order: " +
|
||||
zoneEnd + " < " + zoneStart);
|
||||
}
|
||||
// calculate effective savings at the start of the window
|
||||
List<TransRule> trules = null;
|
||||
List<TransRule> lastRules = null;
|
||||
|
||||
int effectiveSavings = zone.fixedSavingsSecs;
|
||||
if (zone.savingsRule != null) {
|
||||
List<RuleLine> tzdbRules = rules.get(zone.savingsRule);
|
||||
if (tzdbRules == null) {
|
||||
throw new IllegalArgumentException("<Rule> not found: " +
|
||||
zone.savingsRule);
|
||||
}
|
||||
trules = new ArrayList<>(256);
|
||||
lastRules = new ArrayList<>(2);
|
||||
int lastRulesStartYear = Year.MIN_VALUE;
|
||||
|
||||
// merge the rules to transitions
|
||||
for (RuleLine rule : tzdbRules) {
|
||||
if (rule.startYear > zoneEnd.getYear()) {
|
||||
// rules will not be used for this zone entry
|
||||
continue;
|
||||
}
|
||||
rule.adjustToForwards(2004); // irrelevant, treat as leap year
|
||||
|
||||
int startYear = rule.startYear;
|
||||
int endYear = rule.endYear;
|
||||
if (zoneEnd.equals(LocalDateTime.MAX)) {
|
||||
if (endYear == Year.MAX_VALUE) {
|
||||
endYear = startYear;
|
||||
lastRules.add(new TransRule(endYear, rule));
|
||||
lastRulesStartYear = Math.max(startYear, lastRulesStartYear);
|
||||
}
|
||||
} else {
|
||||
if (endYear == Year.MAX_VALUE) {
|
||||
//endYear = zoneEnd.getYear();
|
||||
endYear = zone.year;
|
||||
}
|
||||
}
|
||||
int year = startYear;
|
||||
while (year <= endYear) {
|
||||
trules.add(new TransRule(year, rule));
|
||||
year++;
|
||||
}
|
||||
}
|
||||
|
||||
// last rules, fill the gap years between different last rules
|
||||
if (zoneEnd.equals(LocalDateTime.MAX)) {
|
||||
lastRulesStartYear = Math.max(lastRulesStartYear, zoneStart.getYear()) + 1;
|
||||
for (TransRule rule : lastRules) {
|
||||
if (rule.year <= lastRulesStartYear) {
|
||||
int year = rule.year;
|
||||
while (year <= lastRulesStartYear) {
|
||||
trules.add(new TransRule(year, rule.rule));
|
||||
year++;
|
||||
}
|
||||
rule.year = lastRulesStartYear;
|
||||
rule.ldt = rule.rule.toDateTime(year);
|
||||
rule.ldtSecs = rule.ldt.toEpochSecond(ZoneOffset.UTC);
|
||||
}
|
||||
}
|
||||
Collections.sort(lastRules);
|
||||
}
|
||||
// sort the merged rules
|
||||
Collections.sort(trules);
|
||||
|
||||
effectiveSavings = 0;
|
||||
for (TransRule rule : trules) {
|
||||
if (rule.toEpochSecond(stdOffsetPrev, savings) >
|
||||
zoneStart.toEpochSecond(wallOffset)) {
|
||||
// previous savings amount found, which could be the
|
||||
// savings amount at the instant that the window starts
|
||||
// (hence isAfter)
|
||||
break;
|
||||
}
|
||||
effectiveSavings = rule.rule.savingsAmount;
|
||||
}
|
||||
}
|
||||
// check if the start of the window represents a transition
|
||||
ZoneOffset effectiveWallOffset =
|
||||
ZoneOffset.ofTotalSeconds(stdOffset.getTotalSeconds() + effectiveSavings);
|
||||
|
||||
if (!wallOffset.equals(effectiveWallOffset)) {
|
||||
transitionList.add(ZoneOffsetTransition.of(zoneStart,
|
||||
wallOffset,
|
||||
effectiveWallOffset));
|
||||
}
|
||||
savings = effectiveSavings;
|
||||
// apply rules within the window
|
||||
if (trules != null) {
|
||||
long zoneStartEpochSecs = zoneStart.toEpochSecond(wallOffset);
|
||||
for (TransRule trule : trules) {
|
||||
if (trule.isTransition(savings)) {
|
||||
long epochSecs = trule.toEpochSecond(stdOffset, savings);
|
||||
if (epochSecs < zoneStartEpochSecs ||
|
||||
epochSecs >= zone.toDateTimeEpochSecond(savings)) {
|
||||
continue;
|
||||
}
|
||||
transitionList.add(trule.toTransition(stdOffset, savings));
|
||||
savings = trule.rule.savingsAmount;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lastRules != null) {
|
||||
for (TransRule trule : lastRules) {
|
||||
lastTransitionRuleList.add(trule.rule.toTransitionRule(stdOffset, savings));
|
||||
savings = trule.rule.savingsAmount;
|
||||
}
|
||||
}
|
||||
|
||||
// finally we can calculate the true end of the window, passing it to the next window
|
||||
wallOffset = ZoneOffset.ofTotalSeconds(stdOffset.getTotalSeconds() + savings);
|
||||
zoneStart = LocalDateTime.ofEpochSecond(zone.toDateTimeEpochSecond(savings),
|
||||
0,
|
||||
wallOffset);
|
||||
}
|
||||
return new ZoneRules(firstStdOffset,
|
||||
firstWallOffset,
|
||||
standardTransitionList,
|
||||
transitionList,
|
||||
lastTransitionRuleList);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,176 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package build.tools.tzdb;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
class Utils {
|
||||
|
||||
// Returns the largest (closest to positive infinity)
|
||||
public static long floorDiv(long x, long y) {
|
||||
long r = x / y;
|
||||
// if the signs are different and modulo not zero, round down
|
||||
if ((x ^ y) < 0 && (r * y != x)) {
|
||||
r--;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
// Returns the floor modulus of the {@code long} arguments.
|
||||
public static long floorMod(long x, long y) {
|
||||
return x - floorDiv(x, y) * y;
|
||||
}
|
||||
|
||||
// Returns the sum of its arguments,
|
||||
public static long addExact(long x, long y) {
|
||||
long r = x + y;
|
||||
// HD 2-12 Overflow iff both arguments have the opposite sign of the result
|
||||
if (((x ^ r) & (y ^ r)) < 0) {
|
||||
throw new ArithmeticException("long overflow");
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
// Year
|
||||
|
||||
// Returns true if the specified year is a leap year.
|
||||
public static boolean isLeapYear(int year) {
|
||||
return ((year & 3) == 0) && ((year % 100) != 0 || (year % 400) == 0);
|
||||
}
|
||||
|
||||
// The minimum supported year, '-999,999,999'.
|
||||
public static final int YEAR_MIN_VALUE = -999_999_999;
|
||||
|
||||
// The maximum supported year, '+999,999,999'.
|
||||
public static final int YEAR_MAX_VALUE = 999_999_999;
|
||||
|
||||
|
||||
// Gets the length of the specified month in days.
|
||||
public static int lengthOfMonth(int month, boolean leapYear) {
|
||||
switch (month) {
|
||||
case 2: //FEBRUARY:
|
||||
return (leapYear ? 29 : 28);
|
||||
case 4: //APRIL:
|
||||
case 6: //JUNE:
|
||||
case 9: //SEPTEMBER:
|
||||
case 11: //NOVEMBER:
|
||||
return 30;
|
||||
default:
|
||||
return 31;
|
||||
}
|
||||
}
|
||||
|
||||
// Gets the maximum length of the specified month in days.
|
||||
public static int maxLengthOfMonth(int month) {
|
||||
switch (month) {
|
||||
case 2: //FEBRUARY:
|
||||
return 29;
|
||||
case 4: //APRIL:
|
||||
case 6: //JUNE:
|
||||
case 9: //SEPTEMBER:
|
||||
case 11: //NOVEMBER:
|
||||
return 30;
|
||||
default:
|
||||
return 31;
|
||||
}
|
||||
}
|
||||
|
||||
// DayOfWeek
|
||||
|
||||
// Returns the day-of-week that is the specified number of days after
|
||||
// this one, from 1 to 7 for Monday to Sunday.
|
||||
public static int plusDayOfWeek(int dow, long days) {
|
||||
int amount = (int) (days % 7);
|
||||
return (dow - 1 + (amount + 7)) % 7 + 1;
|
||||
}
|
||||
|
||||
// Returns the day-of-week that is the specified number of days before
|
||||
// this one, from 1 to 7 for Monday to Sunday.
|
||||
public static int minusDayOfWeek(int dow, long days) {
|
||||
return plusDayOfWeek(dow, -(days % 7));
|
||||
}
|
||||
|
||||
// Adjusts the date to the first occurrence of the specified day-of-week
|
||||
// before the date being adjusted unless it is already on that day in
|
||||
// which case the same object is returned.
|
||||
public static LocalDate previousOrSame(LocalDate date, int dayOfWeek) {
|
||||
return adjust(date, dayOfWeek, 1);
|
||||
}
|
||||
|
||||
// Adjusts the date to the first occurrence of the specified day-of-week
|
||||
// after the date being adjusted unless it is already on that day in
|
||||
// which case the same object is returned.
|
||||
public static LocalDate nextOrSame(LocalDate date, int dayOfWeek) {
|
||||
return adjust(date, dayOfWeek, 0);
|
||||
}
|
||||
|
||||
// Implementation of next, previous or current day-of-week.
|
||||
// @param relative whether the current date is a valid answer
|
||||
private static final LocalDate adjust(LocalDate date, int dow, int relative) {
|
||||
int calDow = date.getDayOfWeek();
|
||||
if (relative < 2 && calDow == dow) {
|
||||
return date;
|
||||
}
|
||||
if ((relative & 1) == 0) {
|
||||
int daysDiff = calDow - dow;
|
||||
return date.plusDays(daysDiff >= 0 ? 7 - daysDiff : -daysDiff);
|
||||
} else {
|
||||
int daysDiff = dow - calDow;
|
||||
return date.minusDays(daysDiff >= 0 ? 7 - daysDiff : -daysDiff);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,474 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package build.tools.tzdb;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* A time-zone offset from Greenwich/UTC, such as {@code +02:00}.
|
||||
* <p>
|
||||
* A time-zone offset is the period of time that a time-zone differs from Greenwich/UTC.
|
||||
* This is usually a fixed number of hours and minutes.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
final class ZoneOffset implements Comparable<ZoneOffset> {
|
||||
|
||||
/** Cache of time-zone offset by offset in seconds. */
|
||||
private static final ConcurrentMap<Integer, ZoneOffset> SECONDS_CACHE = new ConcurrentHashMap<>(16, 0.75f, 4);
|
||||
/** Cache of time-zone offset by ID. */
|
||||
private static final ConcurrentMap<String, ZoneOffset> ID_CACHE = new ConcurrentHashMap<>(16, 0.75f, 4);
|
||||
|
||||
/**
|
||||
* The number of seconds per hour.
|
||||
*/
|
||||
private static final int SECONDS_PER_HOUR = 60 * 60;
|
||||
/**
|
||||
* The number of seconds per minute.
|
||||
*/
|
||||
private static final int SECONDS_PER_MINUTE = 60;
|
||||
/**
|
||||
* The number of minutes per hour.
|
||||
*/
|
||||
private static final int MINUTES_PER_HOUR = 60;
|
||||
/**
|
||||
* The abs maximum seconds.
|
||||
*/
|
||||
private static final int MAX_SECONDS = 18 * SECONDS_PER_HOUR;
|
||||
/**
|
||||
* Serialization version.
|
||||
*/
|
||||
private static final long serialVersionUID = 2357656521762053153L;
|
||||
|
||||
/**
|
||||
* The time-zone offset for UTC, with an ID of 'Z'.
|
||||
*/
|
||||
public static final ZoneOffset UTC = ZoneOffset.ofTotalSeconds(0);
|
||||
/**
|
||||
* Constant for the maximum supported offset.
|
||||
*/
|
||||
public static final ZoneOffset MIN = ZoneOffset.ofTotalSeconds(-MAX_SECONDS);
|
||||
/**
|
||||
* Constant for the maximum supported offset.
|
||||
*/
|
||||
public static final ZoneOffset MAX = ZoneOffset.ofTotalSeconds(MAX_SECONDS);
|
||||
|
||||
/**
|
||||
* The total offset in seconds.
|
||||
*/
|
||||
private final int totalSeconds;
|
||||
/**
|
||||
* The string form of the time-zone offset.
|
||||
*/
|
||||
private final transient String id;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains an instance of {@code ZoneOffset} using the ID.
|
||||
* <p>
|
||||
* This method parses the string ID of a {@code ZoneOffset} to
|
||||
* return an instance. The parsing accepts all the formats generated by
|
||||
* {@link #getId()}, plus some additional formats:
|
||||
* <p><ul>
|
||||
* <li>{@code Z} - for UTC
|
||||
* <li>{@code +h}
|
||||
* <li>{@code +hh}
|
||||
* <li>{@code +hh:mm}
|
||||
* <li>{@code -hh:mm}
|
||||
* <li>{@code +hhmm}
|
||||
* <li>{@code -hhmm}
|
||||
* <li>{@code +hh:mm:ss}
|
||||
* <li>{@code -hh:mm:ss}
|
||||
* <li>{@code +hhmmss}
|
||||
* <li>{@code -hhmmss}
|
||||
* </ul><p>
|
||||
* Note that ± means either the plus or minus symbol.
|
||||
* <p>
|
||||
* The ID of the returned offset will be normalized to one of the formats
|
||||
* described by {@link #getId()}.
|
||||
* <p>
|
||||
* The maximum supported range is from +18:00 to -18:00 inclusive.
|
||||
*
|
||||
* @param offsetId the offset ID, not null
|
||||
* @return the zone-offset, not null
|
||||
* @throws DateTimeException if the offset ID is invalid
|
||||
*/
|
||||
@SuppressWarnings("fallthrough")
|
||||
public static ZoneOffset of(String offsetId) {
|
||||
Objects.requireNonNull(offsetId, "offsetId");
|
||||
// "Z" is always in the cache
|
||||
ZoneOffset offset = ID_CACHE.get(offsetId);
|
||||
if (offset != null) {
|
||||
return offset;
|
||||
}
|
||||
|
||||
// parse - +h, +hh, +hhmm, +hh:mm, +hhmmss, +hh:mm:ss
|
||||
final int hours, minutes, seconds;
|
||||
switch (offsetId.length()) {
|
||||
case 2:
|
||||
offsetId = offsetId.charAt(0) + "0" + offsetId.charAt(1); // fallthru
|
||||
case 3:
|
||||
hours = parseNumber(offsetId, 1, false);
|
||||
minutes = 0;
|
||||
seconds = 0;
|
||||
break;
|
||||
case 5:
|
||||
hours = parseNumber(offsetId, 1, false);
|
||||
minutes = parseNumber(offsetId, 3, false);
|
||||
seconds = 0;
|
||||
break;
|
||||
case 6:
|
||||
hours = parseNumber(offsetId, 1, false);
|
||||
minutes = parseNumber(offsetId, 4, true);
|
||||
seconds = 0;
|
||||
break;
|
||||
case 7:
|
||||
hours = parseNumber(offsetId, 1, false);
|
||||
minutes = parseNumber(offsetId, 3, false);
|
||||
seconds = parseNumber(offsetId, 5, false);
|
||||
break;
|
||||
case 9:
|
||||
hours = parseNumber(offsetId, 1, false);
|
||||
minutes = parseNumber(offsetId, 4, true);
|
||||
seconds = parseNumber(offsetId, 7, true);
|
||||
break;
|
||||
default:
|
||||
throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid");
|
||||
}
|
||||
char first = offsetId.charAt(0);
|
||||
if (first != '+' && first != '-') {
|
||||
throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid: Plus/minus not found when expected");
|
||||
}
|
||||
if (first == '-') {
|
||||
return ofHoursMinutesSeconds(-hours, -minutes, -seconds);
|
||||
} else {
|
||||
return ofHoursMinutesSeconds(hours, minutes, seconds);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a two digit zero-prefixed number.
|
||||
*
|
||||
* @param offsetId the offset ID, not null
|
||||
* @param pos the position to parse, valid
|
||||
* @param precededByColon should this number be prefixed by a precededByColon
|
||||
* @return the parsed number, from 0 to 99
|
||||
*/
|
||||
private static int parseNumber(CharSequence offsetId, int pos, boolean precededByColon) {
|
||||
if (precededByColon && offsetId.charAt(pos - 1) != ':') {
|
||||
throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid: Colon not found when expected");
|
||||
}
|
||||
char ch1 = offsetId.charAt(pos);
|
||||
char ch2 = offsetId.charAt(pos + 1);
|
||||
if (ch1 < '0' || ch1 > '9' || ch2 < '0' || ch2 > '9') {
|
||||
throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid: Non numeric characters found");
|
||||
}
|
||||
return (ch1 - 48) * 10 + (ch2 - 48);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains an instance of {@code ZoneOffset} using an offset in hours.
|
||||
*
|
||||
* @param hours the time-zone offset in hours, from -18 to +18
|
||||
* @return the zone-offset, not null
|
||||
* @throws DateTimeException if the offset is not in the required range
|
||||
*/
|
||||
public static ZoneOffset ofHours(int hours) {
|
||||
return ofHoursMinutesSeconds(hours, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains an instance of {@code ZoneOffset} using an offset in
|
||||
* hours and minutes.
|
||||
* <p>
|
||||
* The sign of the hours and minutes components must match.
|
||||
* Thus, if the hours is negative, the minutes must be negative or zero.
|
||||
* If the hours is zero, the minutes may be positive, negative or zero.
|
||||
*
|
||||
* @param hours the time-zone offset in hours, from -18 to +18
|
||||
* @param minutes the time-zone offset in minutes, from 0 to ±59, sign matches hours
|
||||
* @return the zone-offset, not null
|
||||
* @throws DateTimeException if the offset is not in the required range
|
||||
*/
|
||||
public static ZoneOffset ofHoursMinutes(int hours, int minutes) {
|
||||
return ofHoursMinutesSeconds(hours, minutes, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains an instance of {@code ZoneOffset} using an offset in
|
||||
* hours, minutes and seconds.
|
||||
* <p>
|
||||
* The sign of the hours, minutes and seconds components must match.
|
||||
* Thus, if the hours is negative, the minutes and seconds must be negative or zero.
|
||||
*
|
||||
* @param hours the time-zone offset in hours, from -18 to +18
|
||||
* @param minutes the time-zone offset in minutes, from 0 to ±59, sign matches hours and seconds
|
||||
* @param seconds the time-zone offset in seconds, from 0 to ±59, sign matches hours and minutes
|
||||
* @return the zone-offset, not null
|
||||
* @throws DateTimeException if the offset is not in the required range
|
||||
*/
|
||||
public static ZoneOffset ofHoursMinutesSeconds(int hours, int minutes, int seconds) {
|
||||
validate(hours, minutes, seconds);
|
||||
int totalSeconds = totalSeconds(hours, minutes, seconds);
|
||||
return ofTotalSeconds(totalSeconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the offset fields.
|
||||
*
|
||||
* @param hours the time-zone offset in hours, from -18 to +18
|
||||
* @param minutes the time-zone offset in minutes, from 0 to ±59
|
||||
* @param seconds the time-zone offset in seconds, from 0 to ±59
|
||||
* @throws DateTimeException if the offset is not in the required range
|
||||
*/
|
||||
private static void validate(int hours, int minutes, int seconds) {
|
||||
if (hours < -18 || hours > 18) {
|
||||
throw new DateTimeException("Zone offset hours not in valid range: value " + hours +
|
||||
" is not in the range -18 to 18");
|
||||
}
|
||||
if (hours > 0) {
|
||||
if (minutes < 0 || seconds < 0) {
|
||||
throw new DateTimeException("Zone offset minutes and seconds must be positive because hours is positive");
|
||||
}
|
||||
} else if (hours < 0) {
|
||||
if (minutes > 0 || seconds > 0) {
|
||||
throw new DateTimeException("Zone offset minutes and seconds must be negative because hours is negative");
|
||||
}
|
||||
} else if ((minutes > 0 && seconds < 0) || (minutes < 0 && seconds > 0)) {
|
||||
throw new DateTimeException("Zone offset minutes and seconds must have the same sign");
|
||||
}
|
||||
if (Math.abs(minutes) > 59) {
|
||||
throw new DateTimeException("Zone offset minutes not in valid range: abs(value) " +
|
||||
Math.abs(minutes) + " is not in the range 0 to 59");
|
||||
}
|
||||
if (Math.abs(seconds) > 59) {
|
||||
throw new DateTimeException("Zone offset seconds not in valid range: abs(value) " +
|
||||
Math.abs(seconds) + " is not in the range 0 to 59");
|
||||
}
|
||||
if (Math.abs(hours) == 18 && (Math.abs(minutes) > 0 || Math.abs(seconds) > 0)) {
|
||||
throw new DateTimeException("Zone offset not in valid range: -18:00 to +18:00");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the total offset in seconds.
|
||||
*
|
||||
* @param hours the time-zone offset in hours, from -18 to +18
|
||||
* @param minutes the time-zone offset in minutes, from 0 to ±59, sign matches hours and seconds
|
||||
* @param seconds the time-zone offset in seconds, from 0 to ±59, sign matches hours and minutes
|
||||
* @return the total in seconds
|
||||
*/
|
||||
private static int totalSeconds(int hours, int minutes, int seconds) {
|
||||
return hours * SECONDS_PER_HOUR + minutes * SECONDS_PER_MINUTE + seconds;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains an instance of {@code ZoneOffset} specifying the total offset in seconds
|
||||
* <p>
|
||||
* The offset must be in the range {@code -18:00} to {@code +18:00}, which corresponds to -64800 to +64800.
|
||||
*
|
||||
* @param totalSeconds the total time-zone offset in seconds, from -64800 to +64800
|
||||
* @return the ZoneOffset, not null
|
||||
* @throws DateTimeException if the offset is not in the required range
|
||||
*/
|
||||
public static ZoneOffset ofTotalSeconds(int totalSeconds) {
|
||||
if (Math.abs(totalSeconds) > MAX_SECONDS) {
|
||||
throw new DateTimeException("Zone offset not in valid range: -18:00 to +18:00");
|
||||
}
|
||||
if (totalSeconds % (15 * SECONDS_PER_MINUTE) == 0) {
|
||||
Integer totalSecs = totalSeconds;
|
||||
ZoneOffset result = SECONDS_CACHE.get(totalSecs);
|
||||
if (result == null) {
|
||||
result = new ZoneOffset(totalSeconds);
|
||||
SECONDS_CACHE.putIfAbsent(totalSecs, result);
|
||||
result = SECONDS_CACHE.get(totalSecs);
|
||||
ID_CACHE.putIfAbsent(result.getId(), result);
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
return new ZoneOffset(totalSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param totalSeconds the total time-zone offset in seconds, from -64800 to +64800
|
||||
*/
|
||||
private ZoneOffset(int totalSeconds) {
|
||||
super();
|
||||
this.totalSeconds = totalSeconds;
|
||||
id = buildId(totalSeconds);
|
||||
}
|
||||
|
||||
private static String buildId(int totalSeconds) {
|
||||
if (totalSeconds == 0) {
|
||||
return "Z";
|
||||
} else {
|
||||
int absTotalSeconds = Math.abs(totalSeconds);
|
||||
StringBuilder buf = new StringBuilder();
|
||||
int absHours = absTotalSeconds / SECONDS_PER_HOUR;
|
||||
int absMinutes = (absTotalSeconds / SECONDS_PER_MINUTE) % MINUTES_PER_HOUR;
|
||||
buf.append(totalSeconds < 0 ? "-" : "+")
|
||||
.append(absHours < 10 ? "0" : "").append(absHours)
|
||||
.append(absMinutes < 10 ? ":0" : ":").append(absMinutes);
|
||||
int absSeconds = absTotalSeconds % SECONDS_PER_MINUTE;
|
||||
if (absSeconds != 0) {
|
||||
buf.append(absSeconds < 10 ? ":0" : ":").append(absSeconds);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total zone offset in seconds.
|
||||
* <p>
|
||||
* This is the primary way to access the offset amount.
|
||||
* It returns the total of the hours, minutes and seconds fields as a
|
||||
* single offset that can be added to a time.
|
||||
*
|
||||
* @return the total zone offset amount in seconds
|
||||
*/
|
||||
public int getTotalSeconds() {
|
||||
return totalSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the normalized zone offset ID.
|
||||
* <p>
|
||||
* The ID is minor variation to the standard ISO-8601 formatted string
|
||||
* for the offset. There are three formats:
|
||||
* <p><ul>
|
||||
* <li>{@code Z} - for UTC (ISO-8601)
|
||||
* <li>{@code +hh:mm} or {@code -hh:mm} - if the seconds are zero (ISO-8601)
|
||||
* <li>{@code +hh:mm:ss} or {@code -hh:mm:ss} - if the seconds are non-zero (not ISO-8601)
|
||||
* </ul><p>
|
||||
*
|
||||
* @return the zone offset ID, not null
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this offset to another offset in descending order.
|
||||
* <p>
|
||||
* The offsets are compared in the order that they occur for the same time
|
||||
* of day around the world. Thus, an offset of {@code +10:00} comes before an
|
||||
* offset of {@code +09:00} and so on down to {@code -18:00}.
|
||||
* <p>
|
||||
* The comparison is "consistent with equals", as defined by {@link Comparable}.
|
||||
*
|
||||
* @param other the other date to compare to, not null
|
||||
* @return the comparator value, negative if less, postive if greater
|
||||
* @throws NullPointerException if {@code other} is null
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(ZoneOffset other) {
|
||||
return other.totalSeconds - totalSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this offset is equal to another offset.
|
||||
* <p>
|
||||
* The comparison is based on the amount of the offset in seconds.
|
||||
* This is equivalent to a comparison by ID.
|
||||
*
|
||||
* @param obj the object to check, null returns false
|
||||
* @return true if this is equal to the other offset
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof ZoneOffset) {
|
||||
return totalSeconds == ((ZoneOffset) obj).totalSeconds;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A hash code for this offset.
|
||||
*
|
||||
* @return a suitable hash code
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return totalSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs this offset as a {@code String}, using the normalized ID.
|
||||
*
|
||||
* @return a string representation of this offset, not null
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return id;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,290 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package build.tools.tzdb;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A transition between two offsets caused by a discontinuity in the local time-line.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
final class ZoneOffsetTransition implements Comparable<ZoneOffsetTransition> {
|
||||
|
||||
/**
|
||||
* The local transition date-time at the transition.
|
||||
*/
|
||||
private final LocalDateTime transition;
|
||||
/**
|
||||
* The offset before transition.
|
||||
*/
|
||||
private final ZoneOffset offsetBefore;
|
||||
/**
|
||||
* The offset after transition.
|
||||
*/
|
||||
private final ZoneOffset offsetAfter;
|
||||
|
||||
/**
|
||||
* Creates an instance defining a transition between two offsets.
|
||||
*
|
||||
* @param transition the transition date-time with the offset before the transition, not null
|
||||
* @param offsetBefore the offset before the transition, not null
|
||||
* @param offsetAfter the offset at and after the transition, not null
|
||||
*/
|
||||
ZoneOffsetTransition(LocalDateTime transition, ZoneOffset offsetBefore, ZoneOffset offsetAfter) {
|
||||
Objects.requireNonNull(transition, "transition");
|
||||
Objects.requireNonNull(offsetBefore, "offsetBefore");
|
||||
Objects.requireNonNull(offsetAfter, "offsetAfter");
|
||||
if (offsetBefore.equals(offsetAfter)) {
|
||||
throw new IllegalArgumentException("Offsets must not be equal");
|
||||
}
|
||||
this.transition = transition;
|
||||
this.offsetBefore = offsetBefore;
|
||||
this.offsetAfter = offsetAfter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance from epoch-second and offsets.
|
||||
*
|
||||
* @param epochSecond the transition epoch-second
|
||||
* @param offsetBefore the offset before the transition, not null
|
||||
* @param offsetAfter the offset at and after the transition, not null
|
||||
*/
|
||||
ZoneOffsetTransition(long epochSecond, ZoneOffset offsetBefore, ZoneOffset offsetAfter) {
|
||||
this.transition = LocalDateTime.ofEpochSecond(epochSecond, 0, offsetBefore);
|
||||
this.offsetBefore = offsetBefore;
|
||||
this.offsetAfter = offsetAfter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the transition instant as an epoch second.
|
||||
*
|
||||
* @return the transition epoch second
|
||||
*/
|
||||
public long toEpochSecond() {
|
||||
return transition.toEpochSecond(offsetBefore);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the local transition date-time, as would be expressed with the 'before' offset.
|
||||
* <p>
|
||||
* This is the date-time where the discontinuity begins expressed with the 'before' offset.
|
||||
* At this instant, the 'after' offset is actually used, therefore the combination of this
|
||||
* date-time and the 'before' offset will never occur.
|
||||
* <p>
|
||||
* The combination of the 'before' date-time and offset represents the same instant
|
||||
* as the 'after' date-time and offset.
|
||||
*
|
||||
* @return the transition date-time expressed with the before offset, not null
|
||||
*/
|
||||
public LocalDateTime getDateTimeBefore() {
|
||||
return transition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the local transition date-time, as would be expressed with the 'after' offset.
|
||||
* <p>
|
||||
* This is the first date-time after the discontinuity, when the new offset applies.
|
||||
* <p>
|
||||
* The combination of the 'before' date-time and offset represents the same instant
|
||||
* as the 'after' date-time and offset.
|
||||
*
|
||||
* @return the transition date-time expressed with the after offset, not null
|
||||
*/
|
||||
public LocalDateTime getDateTimeAfter() {
|
||||
return transition.plusSeconds(getDurationSeconds());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the offset before the transition.
|
||||
* <p>
|
||||
* This is the offset in use before the instant of the transition.
|
||||
*
|
||||
* @return the offset before the transition, not null
|
||||
*/
|
||||
public ZoneOffset getOffsetBefore() {
|
||||
return offsetBefore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the offset after the transition.
|
||||
* <p>
|
||||
* This is the offset in use on and after the instant of the transition.
|
||||
*
|
||||
* @return the offset after the transition, not null
|
||||
*/
|
||||
public ZoneOffset getOffsetAfter() {
|
||||
return offsetAfter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the duration of the transition in seconds.
|
||||
*
|
||||
* @return the duration in seconds
|
||||
*/
|
||||
private int getDurationSeconds() {
|
||||
return getOffsetAfter().getTotalSeconds() - getOffsetBefore().getTotalSeconds();
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this transition represent a gap in the local time-line.
|
||||
* <p>
|
||||
* Gaps occur where there are local date-times that simply do not not exist.
|
||||
* An example would be when the offset changes from {@code +01:00} to {@code +02:00}.
|
||||
* This might be described as 'the clocks will move forward one hour tonight at 1am'.
|
||||
*
|
||||
* @return true if this transition is a gap, false if it is an overlap
|
||||
*/
|
||||
public boolean isGap() {
|
||||
return getOffsetAfter().getTotalSeconds() > getOffsetBefore().getTotalSeconds();
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this transition represent a gap in the local time-line.
|
||||
* <p>
|
||||
* Overlaps occur where there are local date-times that exist twice.
|
||||
* An example would be when the offset changes from {@code +02:00} to {@code +01:00}.
|
||||
* This might be described as 'the clocks will move back one hour tonight at 2am'.
|
||||
*
|
||||
* @return true if this transition is an overlap, false if it is a gap
|
||||
*/
|
||||
public boolean isOverlap() {
|
||||
return getOffsetAfter().getTotalSeconds() < getOffsetBefore().getTotalSeconds();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the specified offset is valid during this transition.
|
||||
* <p>
|
||||
* This checks to see if the given offset will be valid at some point in the transition.
|
||||
* A gap will always return false.
|
||||
* An overlap will return true if the offset is either the before or after offset.
|
||||
*
|
||||
* @param offset the offset to check, null returns false
|
||||
* @return true if the offset is valid during the transition
|
||||
*/
|
||||
public boolean isValidOffset(ZoneOffset offset) {
|
||||
return isGap() ? false : (getOffsetBefore().equals(offset) || getOffsetAfter().equals(offset));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the valid offsets during this transition.
|
||||
* <p>
|
||||
* A gap will return an empty list, while an overlap will return both offsets.
|
||||
*
|
||||
* @return the list of valid offsets
|
||||
*/
|
||||
List<ZoneOffset> getValidOffsets() {
|
||||
if (isGap()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return Arrays.asList(getOffsetBefore(), getOffsetAfter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this transition to another based on the transition instant.
|
||||
* <p>
|
||||
* This compares the instants of each transition.
|
||||
* The offsets are ignored, making this order inconsistent with equals.
|
||||
*
|
||||
* @param transition the transition to compare to, not null
|
||||
* @return the comparator value, negative if less, positive if greater
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(ZoneOffsetTransition transition) {
|
||||
return Long.compare(this.toEpochSecond(), transition.toEpochSecond());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this object equals another.
|
||||
* <p>
|
||||
* The entire state of the object is compared.
|
||||
*
|
||||
* @param other the other object to compare to, null returns false
|
||||
* @return true if equal
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == this) {
|
||||
return true;
|
||||
}
|
||||
if (other instanceof ZoneOffsetTransition) {
|
||||
ZoneOffsetTransition d = (ZoneOffsetTransition) other;
|
||||
return transition.equals(d.transition) &&
|
||||
offsetBefore.equals(d.offsetBefore) && offsetAfter.equals(d.offsetAfter);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a suitable hash code.
|
||||
*
|
||||
* @return the hash code
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return transition.hashCode() ^ offsetBefore.hashCode() ^ Integer.rotateLeft(offsetAfter.hashCode(), 16);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,223 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package build.tools.tzdb;
|
||||
|
||||
import static build.tools.tzdb.Utils.*;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A rule expressing how to create a transition.
|
||||
* <p>
|
||||
* This class allows rules for identifying future transitions to be expressed.
|
||||
* A rule might be written in many forms:
|
||||
* <p><ul>
|
||||
* <li>the 16th March
|
||||
* <li>the Sunday on or after the 16th March
|
||||
* <li>the Sunday on or before the 16th March
|
||||
* <li>the last Sunday in February
|
||||
* </ul><p>
|
||||
* These different rule types can be expressed and queried.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
final class ZoneOffsetTransitionRule {
|
||||
|
||||
/**
|
||||
* The month of the month-day of the first day of the cutover week.
|
||||
* The actual date will be adjusted by the dowChange field.
|
||||
*/
|
||||
final int month;
|
||||
/**
|
||||
* The day-of-month of the month-day of the cutover week.
|
||||
* If positive, it is the start of the week where the cutover can occur.
|
||||
* If negative, it represents the end of the week where cutover can occur.
|
||||
* The value is the number of days from the end of the month, such that
|
||||
* {@code -1} is the last day of the month, {@code -2} is the second
|
||||
* to last day, and so on.
|
||||
*/
|
||||
final byte dom;
|
||||
/**
|
||||
* The cutover day-of-week, -1 to retain the day-of-month.
|
||||
*/
|
||||
final int dow;
|
||||
/**
|
||||
* The cutover time in the 'before' offset.
|
||||
*/
|
||||
final LocalTime time;
|
||||
/**
|
||||
* Whether the cutover time is midnight at the end of day.
|
||||
*/
|
||||
final boolean timeEndOfDay;
|
||||
/**
|
||||
* The definition of how the local time should be interpreted.
|
||||
*/
|
||||
final TimeDefinition timeDefinition;
|
||||
/**
|
||||
* The standard offset at the cutover.
|
||||
*/
|
||||
final ZoneOffset standardOffset;
|
||||
/**
|
||||
* The offset before the cutover.
|
||||
*/
|
||||
final ZoneOffset offsetBefore;
|
||||
/**
|
||||
* The offset after the cutover.
|
||||
*/
|
||||
final ZoneOffset offsetAfter;
|
||||
|
||||
/**
|
||||
* Creates an instance defining the yearly rule to create transitions between two offsets.
|
||||
*
|
||||
* @param month the month of the month-day of the first day of the cutover week, from 1 to 12
|
||||
* @param dayOfMonthIndicator the day of the month-day of the cutover week, positive if the week is that
|
||||
* day or later, negative if the week is that day or earlier, counting from the last day of the month,
|
||||
* from -28 to 31 excluding 0
|
||||
* @param dayOfWeek the required day-of-week, -1 if the month-day should not be changed
|
||||
* @param time the cutover time in the 'before' offset, not null
|
||||
* @param timeEndOfDay whether the time is midnight at the end of day
|
||||
* @param timeDefnition how to interpret the cutover
|
||||
* @param standardOffset the standard offset in force at the cutover, not null
|
||||
* @param offsetBefore the offset before the cutover, not null
|
||||
* @param offsetAfter the offset after the cutover, not null
|
||||
* @throws IllegalArgumentException if the day of month indicator is invalid
|
||||
* @throws IllegalArgumentException if the end of day flag is true when the time is not midnight
|
||||
*/
|
||||
ZoneOffsetTransitionRule(
|
||||
int month,
|
||||
int dayOfMonthIndicator,
|
||||
int dayOfWeek,
|
||||
LocalTime time,
|
||||
boolean timeEndOfDay,
|
||||
TimeDefinition timeDefnition,
|
||||
ZoneOffset standardOffset,
|
||||
ZoneOffset offsetBefore,
|
||||
ZoneOffset offsetAfter) {
|
||||
Objects.requireNonNull(time, "time");
|
||||
Objects.requireNonNull(timeDefnition, "timeDefnition");
|
||||
Objects.requireNonNull(standardOffset, "standardOffset");
|
||||
Objects.requireNonNull(offsetBefore, "offsetBefore");
|
||||
Objects.requireNonNull(offsetAfter, "offsetAfter");
|
||||
if (month < 1 || month > 12) {
|
||||
throw new IllegalArgumentException("month must be between 1 and 12");
|
||||
}
|
||||
if (dayOfMonthIndicator < -28 || dayOfMonthIndicator > 31 || dayOfMonthIndicator == 0) {
|
||||
throw new IllegalArgumentException("Day of month indicator must be between -28 and 31 inclusive excluding zero");
|
||||
}
|
||||
if (timeEndOfDay && time.equals(LocalTime.MIDNIGHT) == false) {
|
||||
throw new IllegalArgumentException("Time must be midnight when end of day flag is true");
|
||||
}
|
||||
this.month = month;
|
||||
this.dom = (byte) dayOfMonthIndicator;
|
||||
this.dow = dayOfWeek;
|
||||
this.time = time;
|
||||
this.timeEndOfDay = timeEndOfDay;
|
||||
this.timeDefinition = timeDefnition;
|
||||
this.standardOffset = standardOffset;
|
||||
this.offsetBefore = offsetBefore;
|
||||
this.offsetAfter = offsetAfter;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Checks if this object equals another.
|
||||
* <p>
|
||||
* The entire state of the object is compared.
|
||||
*
|
||||
* @param otherRule the other object to compare to, null returns false
|
||||
* @return true if equal
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object otherRule) {
|
||||
if (otherRule == this) {
|
||||
return true;
|
||||
}
|
||||
if (otherRule instanceof ZoneOffsetTransitionRule) {
|
||||
ZoneOffsetTransitionRule other = (ZoneOffsetTransitionRule) otherRule;
|
||||
return month == other.month && dom == other.dom && dow == other.dow &&
|
||||
timeDefinition == other.timeDefinition &&
|
||||
time.equals(other.time) &&
|
||||
timeEndOfDay == other.timeEndOfDay &&
|
||||
standardOffset.equals(other.standardOffset) &&
|
||||
offsetBefore.equals(other.offsetBefore) &&
|
||||
offsetAfter.equals(other.offsetAfter);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a suitable hash code.
|
||||
*
|
||||
* @return the hash code
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = ((time.toSecondOfDay() + (timeEndOfDay ? 1 : 0)) << 15) +
|
||||
(month << 11) + ((dom + 32) << 5) +
|
||||
((dow == -1 ? 8 : dow) << 2) + (timeDefinition.ordinal());
|
||||
return hash ^ standardOffset.hashCode() ^
|
||||
offsetBefore.hashCode() ^ offsetAfter.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
@ -64,6 +64,12 @@ package build.tools.tzdb;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectOutput;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.zone.ZoneOffsetTransition;
|
||||
import java.time.zone.ZoneOffsetTransitionRule;
|
||||
import java.time.zone.ZoneOffsetTransitionRule.TimeDefinition;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -224,15 +230,15 @@ final class ZoneRules {
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
static void writeRule(ZoneOffsetTransitionRule rule, DataOutput out) throws IOException {
|
||||
int month = rule.month;
|
||||
byte dom = rule.dom;
|
||||
int dow = rule.dow;
|
||||
LocalTime time = rule.time;
|
||||
boolean timeEndOfDay = rule.timeEndOfDay;
|
||||
TimeDefinition timeDefinition = rule.timeDefinition;
|
||||
ZoneOffset standardOffset = rule.standardOffset;
|
||||
ZoneOffset offsetBefore = rule.offsetBefore;
|
||||
ZoneOffset offsetAfter = rule.offsetAfter;
|
||||
int month = rule.getMonth().getValue();
|
||||
byte dom = (byte)rule.getDayOfMonthIndicator();
|
||||
int dow = rule.getDayOfWeek().getValue();
|
||||
LocalTime time = rule.getLocalTime();
|
||||
boolean timeEndOfDay = rule.isMidnightEndOfDay();
|
||||
TimeDefinition timeDefinition = rule.getTimeDefinition();
|
||||
ZoneOffset standardOffset = rule.getStandardOffset();
|
||||
ZoneOffset offsetBefore = rule.getOffsetBefore();
|
||||
ZoneOffset offsetAfter = rule.getOffsetAfter();
|
||||
|
||||
int timeSecs = (timeEndOfDay ? 86400 : time.toSecondOfDay());
|
||||
int stdOffset = standardOffset.getTotalSeconds();
|
||||
|
||||
@ -1,743 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package build.tools.tzdb;
|
||||
|
||||
import static build.tools.tzdb.Utils.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A mutable builder used to create all the rules for a historic time-zone.
|
||||
* <p>
|
||||
* The rules of a time-zone describe how the offset changes over time.
|
||||
* The rules are created by building windows on the time-line within which
|
||||
* the different rules apply. The rules may be one of two kinds:
|
||||
* <p><ul>
|
||||
* <li>Fixed savings - A single fixed amount of savings from the standard offset will apply.</li>
|
||||
* <li>Rules - A set of one or more rules describe how daylight savings changes during the window.</li>
|
||||
* </ul><p>
|
||||
*
|
||||
* <h4>Implementation notes</h4>
|
||||
* This class is a mutable builder used to create zone instances.
|
||||
* It must only be used from a single thread.
|
||||
* The created instances are immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public class ZoneRulesBuilder {
|
||||
|
||||
/**
|
||||
* The list of windows.
|
||||
*/
|
||||
private List<TZWindow> windowList = new ArrayList<>();
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Constructs an instance of the builder that can be used to create zone rules.
|
||||
* <p>
|
||||
* The builder is used by adding one or more windows representing portions
|
||||
* of the time-line. The standard offset from UTC/Greenwich will be constant
|
||||
* within a window, although two adjacent windows can have the same standard offset.
|
||||
* <p>
|
||||
* Within each window, there can either be a
|
||||
* {@link #setFixedSavingsToWindow fixed savings amount} or a
|
||||
* {@link #addRuleToWindow list of rules}.
|
||||
*/
|
||||
public ZoneRulesBuilder() {
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Adds a window to the builder that can be used to filter a set of rules.
|
||||
* <p>
|
||||
* This method defines and adds a window to the zone where the standard offset is specified.
|
||||
* The window limits the effect of subsequent additions of transition rules
|
||||
* or fixed savings. If neither rules or fixed savings are added to the window
|
||||
* then the window will default to no savings.
|
||||
* <p>
|
||||
* Each window must be added sequentially, as the start instant of the window
|
||||
* is derived from the until instant of the previous window.
|
||||
*
|
||||
* @param standardOffset the standard offset, not null
|
||||
* @param until the date-time that the offset applies until, not null
|
||||
* @param untilDefinition the time type for the until date-time, not null
|
||||
* @return this, for chaining
|
||||
* @throws IllegalStateException if the window order is invalid
|
||||
*/
|
||||
public ZoneRulesBuilder addWindow(
|
||||
ZoneOffset standardOffset,
|
||||
LocalDateTime until,
|
||||
TimeDefinition untilDefinition) {
|
||||
Objects.requireNonNull(standardOffset, "standardOffset");
|
||||
Objects.requireNonNull(until, "until");
|
||||
Objects.requireNonNull(untilDefinition, "untilDefinition");
|
||||
TZWindow window = new TZWindow(standardOffset, until, untilDefinition);
|
||||
if (windowList.size() > 0) {
|
||||
TZWindow previous = windowList.get(windowList.size() - 1);
|
||||
window.validateWindowOrder(previous);
|
||||
}
|
||||
windowList.add(window);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a window that applies until the end of time to the builder that can be
|
||||
* used to filter a set of rules.
|
||||
* <p>
|
||||
* This method defines and adds a window to the zone where the standard offset is specified.
|
||||
* The window limits the effect of subsequent additions of transition rules
|
||||
* or fixed savings. If neither rules or fixed savings are added to the window
|
||||
* then the window will default to no savings.
|
||||
* <p>
|
||||
* This must be added after all other windows.
|
||||
* No more windows can be added after this one.
|
||||
*
|
||||
* @param standardOffset the standard offset, not null
|
||||
* @return this, for chaining
|
||||
* @throws IllegalStateException if a forever window has already been added
|
||||
*/
|
||||
public ZoneRulesBuilder addWindowForever(ZoneOffset standardOffset) {
|
||||
return addWindow(standardOffset, LocalDateTime.MAX, TimeDefinition.WALL);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Sets the previously added window to have fixed savings.
|
||||
* <p>
|
||||
* Setting a window to have fixed savings simply means that a single daylight
|
||||
* savings amount applies throughout the window. The window could be small,
|
||||
* such as a single summer, or large, such as a multi-year daylight savings.
|
||||
* <p>
|
||||
* A window can either have fixed savings or rules but not both.
|
||||
*
|
||||
* @param fixedSavingAmountSecs the amount of saving to use for the whole window, not null
|
||||
* @return this, for chaining
|
||||
* @throws IllegalStateException if no window has yet been added
|
||||
* @throws IllegalStateException if the window already has rules
|
||||
*/
|
||||
public ZoneRulesBuilder setFixedSavingsToWindow(int fixedSavingAmountSecs) {
|
||||
if (windowList.isEmpty()) {
|
||||
throw new IllegalStateException("Must add a window before setting the fixed savings");
|
||||
}
|
||||
TZWindow window = windowList.get(windowList.size() - 1);
|
||||
window.setFixedSavings(fixedSavingAmountSecs);
|
||||
return this;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Adds a single transition rule to the current window.
|
||||
* <p>
|
||||
* This adds a rule such that the offset, expressed as a daylight savings amount,
|
||||
* changes at the specified date-time.
|
||||
*
|
||||
* @param transitionDateTime the date-time that the transition occurs as defined by timeDefintion, not null
|
||||
* @param timeDefinition the definition of how to convert local to actual time, not null
|
||||
* @param savingAmountSecs the amount of saving from the standard offset after the transition in seconds
|
||||
* @return this, for chaining
|
||||
* @throws IllegalStateException if no window has yet been added
|
||||
* @throws IllegalStateException if the window already has fixed savings
|
||||
* @throws IllegalStateException if the window has reached the maximum capacity of 2000 rules
|
||||
*/
|
||||
public ZoneRulesBuilder addRuleToWindow(
|
||||
LocalDateTime transitionDateTime,
|
||||
TimeDefinition timeDefinition,
|
||||
int savingAmountSecs) {
|
||||
Objects.requireNonNull(transitionDateTime, "transitionDateTime");
|
||||
return addRuleToWindow(
|
||||
transitionDateTime.getYear(), transitionDateTime.getYear(),
|
||||
transitionDateTime.getMonth(), transitionDateTime.getDayOfMonth(),
|
||||
-1, transitionDateTime.getTime(), false, timeDefinition, savingAmountSecs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a single transition rule to the current window.
|
||||
* <p>
|
||||
* This adds a rule such that the offset, expressed as a daylight savings amount,
|
||||
* changes at the specified date-time.
|
||||
*
|
||||
* @param year the year of the transition, from MIN_YEAR to MAX_YEAR
|
||||
* @param month the month of the transition, not null
|
||||
* @param dayOfMonthIndicator the day-of-month of the transition, adjusted by dayOfWeek,
|
||||
* from 1 to 31 adjusted later, or -1 to -28 adjusted earlier from the last day of the month
|
||||
* @param time the time that the transition occurs as defined by timeDefintion, not null
|
||||
* @param timeEndOfDay whether midnight is at the end of day
|
||||
* @param timeDefinition the definition of how to convert local to actual time, not null
|
||||
* @param savingAmountSecs the amount of saving from the standard offset after the transition in seconds
|
||||
* @return this, for chaining
|
||||
* @throws DateTimeException if a date-time field is out of range
|
||||
* @throws IllegalStateException if no window has yet been added
|
||||
* @throws IllegalStateException if the window already has fixed savings
|
||||
* @throws IllegalStateException if the window has reached the maximum capacity of 2000 rules
|
||||
*/
|
||||
public ZoneRulesBuilder addRuleToWindow(
|
||||
int year,
|
||||
int month,
|
||||
int dayOfMonthIndicator,
|
||||
LocalTime time,
|
||||
boolean timeEndOfDay,
|
||||
TimeDefinition timeDefinition,
|
||||
int savingAmountSecs) {
|
||||
return addRuleToWindow(year, year, month, dayOfMonthIndicator, -1, time, timeEndOfDay, timeDefinition, savingAmountSecs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a multi-year transition rule to the current window.
|
||||
* <p>
|
||||
* This adds a rule such that the offset, expressed as a daylight savings amount,
|
||||
* changes at the specified date-time for each year in the range.
|
||||
*
|
||||
* @param startYear the start year of the rule, from MIN_YEAR to MAX_YEAR
|
||||
* @param endYear the end year of the rule, from MIN_YEAR to MAX_YEAR
|
||||
* @param month the month of the transition, from 1 to 12
|
||||
* @param dayOfMonthIndicator the day-of-month of the transition, adjusted by dayOfWeek,
|
||||
* from 1 to 31 adjusted later, or -1 to -28 adjusted earlier from the last day of the month
|
||||
* @param dayOfWeek the day-of-week to adjust to, -1 if day-of-month should not be adjusted
|
||||
* @param time the time that the transition occurs as defined by timeDefintion, not null
|
||||
* @param timeEndOfDay whether midnight is at the end of day
|
||||
* @param timeDefinition the definition of how to convert local to actual time, not null
|
||||
* @param savingAmountSecs the amount of saving from the standard offset after the transition in seconds
|
||||
* @return this, for chaining
|
||||
* @throws DateTimeException if a date-time field is out of range
|
||||
* @throws IllegalArgumentException if the day of month indicator is invalid
|
||||
* @throws IllegalArgumentException if the end of day midnight flag does not match the time
|
||||
* @throws IllegalStateException if no window has yet been added
|
||||
* @throws IllegalStateException if the window already has fixed savings
|
||||
* @throws IllegalStateException if the window has reached the maximum capacity of 2000 rules
|
||||
*/
|
||||
public ZoneRulesBuilder addRuleToWindow(
|
||||
int startYear,
|
||||
int endYear,
|
||||
int month,
|
||||
int dayOfMonthIndicator,
|
||||
int dayOfWeek,
|
||||
LocalTime time,
|
||||
boolean timeEndOfDay,
|
||||
TimeDefinition timeDefinition,
|
||||
int savingAmountSecs) {
|
||||
Objects.requireNonNull(time, "time");
|
||||
Objects.requireNonNull(timeDefinition, "timeDefinition");
|
||||
if (dayOfMonthIndicator < -28 || dayOfMonthIndicator > 31 || dayOfMonthIndicator == 0) {
|
||||
throw new IllegalArgumentException("Day of month indicator must be between -28 and 31 inclusive excluding zero");
|
||||
}
|
||||
if (timeEndOfDay && time.equals(LocalTime.MIDNIGHT) == false) {
|
||||
throw new IllegalArgumentException("Time must be midnight when end of day flag is true");
|
||||
}
|
||||
if (windowList.isEmpty()) {
|
||||
throw new IllegalStateException("Must add a window before adding a rule");
|
||||
}
|
||||
TZWindow window = windowList.get(windowList.size() - 1);
|
||||
window.addRule(startYear, endYear, month, dayOfMonthIndicator, dayOfWeek, time, timeEndOfDay, timeDefinition, savingAmountSecs);
|
||||
return this;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Completes the build converting the builder to a set of time-zone rules.
|
||||
* <p>
|
||||
* Calling this method alters the state of the builder.
|
||||
* Further rules should not be added to this builder once this method is called.
|
||||
*
|
||||
* @param zoneId the time-zone ID, not null
|
||||
* @return the zone rules, not null
|
||||
* @throws IllegalStateException if no windows have been added
|
||||
* @throws IllegalStateException if there is only one rule defined as being forever for any given window
|
||||
*/
|
||||
public ZoneRules toRules(String zoneId) {
|
||||
Objects.requireNonNull(zoneId, "zoneId");
|
||||
if (windowList.isEmpty()) {
|
||||
throw new IllegalStateException("No windows have been added to the builder");
|
||||
}
|
||||
|
||||
final List<ZoneOffsetTransition> standardTransitionList = new ArrayList<>(4);
|
||||
final List<ZoneOffsetTransition> transitionList = new ArrayList<>(256);
|
||||
final List<ZoneOffsetTransitionRule> lastTransitionRuleList = new ArrayList<>(2);
|
||||
|
||||
// initialize the standard offset calculation
|
||||
final TZWindow firstWindow = windowList.get(0);
|
||||
ZoneOffset loopStandardOffset = firstWindow.standardOffset;
|
||||
int loopSavings = 0;
|
||||
if (firstWindow.fixedSavingAmountSecs != null) {
|
||||
loopSavings = firstWindow.fixedSavingAmountSecs;
|
||||
}
|
||||
final ZoneOffset firstWallOffset = ZoneOffset.ofTotalSeconds(loopStandardOffset.getTotalSeconds() + loopSavings);
|
||||
LocalDateTime loopWindowStart = LocalDateTime.of(YEAR_MIN_VALUE, 1, 1, 0, 0);
|
||||
ZoneOffset loopWindowOffset = firstWallOffset;
|
||||
|
||||
// build the windows and rules to interesting data
|
||||
for (TZWindow window : windowList) {
|
||||
// tidy the state
|
||||
window.tidy(loopWindowStart.getYear());
|
||||
|
||||
// calculate effective savings at the start of the window
|
||||
Integer effectiveSavings = window.fixedSavingAmountSecs;
|
||||
if (effectiveSavings == null) {
|
||||
// apply rules from this window together with the standard offset and
|
||||
// savings from the last window to find the savings amount applicable
|
||||
// at start of this window
|
||||
effectiveSavings = 0;
|
||||
for (TZRule rule : window.ruleList) {
|
||||
if (rule.toEpochSecond(loopStandardOffset, loopSavings) > loopWindowStart.toEpochSecond(loopWindowOffset)) {
|
||||
// previous savings amount found, which could be the savings amount at
|
||||
// the instant that the window starts (hence isAfter)
|
||||
break;
|
||||
}
|
||||
effectiveSavings = rule.savingAmountSecs;
|
||||
}
|
||||
}
|
||||
|
||||
// check if standard offset changed, and update it
|
||||
if (loopStandardOffset.equals(window.standardOffset) == false) {
|
||||
standardTransitionList.add(
|
||||
new ZoneOffsetTransition(
|
||||
LocalDateTime.ofEpochSecond(loopWindowStart.toEpochSecond(loopWindowOffset), 0, loopStandardOffset),
|
||||
loopStandardOffset, window.standardOffset));
|
||||
loopStandardOffset = window.standardOffset;
|
||||
}
|
||||
|
||||
// check if the start of the window represents a transition
|
||||
ZoneOffset effectiveWallOffset = ZoneOffset.ofTotalSeconds(loopStandardOffset.getTotalSeconds() + effectiveSavings);
|
||||
if (loopWindowOffset.equals(effectiveWallOffset) == false) {
|
||||
transitionList.add(new ZoneOffsetTransition(loopWindowStart, loopWindowOffset, effectiveWallOffset));
|
||||
}
|
||||
loopSavings = effectiveSavings;
|
||||
|
||||
// apply rules within the window
|
||||
for (TZRule rule : window.ruleList) {
|
||||
if (rule.isTransition(loopSavings)) {
|
||||
ZoneOffsetTransition trans = rule.toTransition(loopStandardOffset, loopSavings);
|
||||
if (trans.toEpochSecond() < loopWindowStart.toEpochSecond(loopWindowOffset) == false &&
|
||||
trans.toEpochSecond() < window.createDateTimeEpochSecond(loopSavings)) {
|
||||
transitionList.add(trans);
|
||||
loopSavings = rule.savingAmountSecs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// calculate last rules
|
||||
for (TZRule lastRule : window.lastRuleList) {
|
||||
lastTransitionRuleList.add(lastRule.toTransitionRule(loopStandardOffset, loopSavings));
|
||||
loopSavings = lastRule.savingAmountSecs;
|
||||
}
|
||||
|
||||
// finally we can calculate the true end of the window, passing it to the next window
|
||||
loopWindowOffset = window.createWallOffset(loopSavings);
|
||||
loopWindowStart = LocalDateTime.ofEpochSecond(
|
||||
window.createDateTimeEpochSecond(loopSavings), 0, loopWindowOffset);
|
||||
}
|
||||
|
||||
return new ZoneRules(
|
||||
firstWindow.standardOffset, firstWallOffset, standardTransitionList,
|
||||
transitionList, lastTransitionRuleList);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* A definition of a window in the time-line.
|
||||
* The window will have one standard offset and will either have a
|
||||
* fixed DST savings or a set of rules.
|
||||
*/
|
||||
class TZWindow {
|
||||
/** The standard offset during the window, not null. */
|
||||
private final ZoneOffset standardOffset;
|
||||
/** The end local time, not null. */
|
||||
private final LocalDateTime windowEnd;
|
||||
/** The type of the end time, not null. */
|
||||
private final TimeDefinition timeDefinition;
|
||||
|
||||
/** The fixed amount of the saving to be applied during this window. */
|
||||
private Integer fixedSavingAmountSecs;
|
||||
/** The rules for the current window. */
|
||||
private List<TZRule> ruleList = new ArrayList<>();
|
||||
/** The latest year that the last year starts at. */
|
||||
private int maxLastRuleStartYear = YEAR_MIN_VALUE;
|
||||
/** The last rules. */
|
||||
private List<TZRule> lastRuleList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param standardOffset the standard offset applicable during the window, not null
|
||||
* @param windowEnd the end of the window, relative to the time definition, null if forever
|
||||
* @param timeDefinition the time definition for calculating the true end, not null
|
||||
*/
|
||||
TZWindow(
|
||||
ZoneOffset standardOffset,
|
||||
LocalDateTime windowEnd,
|
||||
TimeDefinition timeDefinition) {
|
||||
super();
|
||||
this.windowEnd = windowEnd;
|
||||
this.timeDefinition = timeDefinition;
|
||||
this.standardOffset = standardOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the fixed savings amount for the window.
|
||||
*
|
||||
* @param fixedSavingAmount the amount of daylight saving to apply throughout the window, may be null
|
||||
* @throws IllegalStateException if the window already has rules
|
||||
*/
|
||||
void setFixedSavings(int fixedSavingAmount) {
|
||||
if (ruleList.size() > 0 || lastRuleList.size() > 0) {
|
||||
throw new IllegalStateException("Window has DST rules, so cannot have fixed savings");
|
||||
}
|
||||
this.fixedSavingAmountSecs = fixedSavingAmount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a rule to the current window.
|
||||
*
|
||||
* @param startYear the start year of the rule, from MIN_YEAR to MAX_YEAR
|
||||
* @param endYear the end year of the rule, from MIN_YEAR to MAX_YEAR
|
||||
* @param month the month of the transition, not null
|
||||
* @param dayOfMonthIndicator the day-of-month of the transition, adjusted by dayOfWeek,
|
||||
* from 1 to 31 adjusted later, or -1 to -28 adjusted earlier from the last day of the month
|
||||
* @param dayOfWeek the day-of-week to adjust to, null if day-of-month should not be adjusted
|
||||
* @param time the time that the transition occurs as defined by timeDefintion, not null
|
||||
* @param timeEndOfDay whether midnight is at the end of day
|
||||
* @param timeDefinition the definition of how to convert local to actual time, not null
|
||||
* @param savingAmountSecs the amount of saving from the standard offset in seconds
|
||||
* @throws IllegalStateException if the window already has fixed savings
|
||||
* @throws IllegalStateException if the window has reached the maximum capacity of 2000 rules
|
||||
*/
|
||||
void addRule(
|
||||
int startYear,
|
||||
int endYear,
|
||||
int month,
|
||||
int dayOfMonthIndicator,
|
||||
int dayOfWeek,
|
||||
LocalTime time,
|
||||
boolean timeEndOfDay,
|
||||
TimeDefinition timeDefinition,
|
||||
int savingAmountSecs) {
|
||||
|
||||
if (fixedSavingAmountSecs != null) {
|
||||
throw new IllegalStateException("Window has a fixed DST saving, so cannot have DST rules");
|
||||
}
|
||||
if (ruleList.size() >= 2000) {
|
||||
throw new IllegalStateException("Window has reached the maximum number of allowed rules");
|
||||
}
|
||||
boolean lastRule = false;
|
||||
if (endYear == YEAR_MAX_VALUE) {
|
||||
lastRule = true;
|
||||
endYear = startYear;
|
||||
}
|
||||
int year = startYear;
|
||||
while (year <= endYear) {
|
||||
TZRule rule = new TZRule(year, month, dayOfMonthIndicator, dayOfWeek, time, timeEndOfDay, timeDefinition, savingAmountSecs);
|
||||
if (lastRule) {
|
||||
lastRuleList.add(rule);
|
||||
maxLastRuleStartYear = Math.max(startYear, maxLastRuleStartYear);
|
||||
} else {
|
||||
ruleList.add(rule);
|
||||
}
|
||||
year++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that this window is after the previous one.
|
||||
*
|
||||
* @param previous the previous window, not null
|
||||
* @throws IllegalStateException if the window order is invalid
|
||||
*/
|
||||
void validateWindowOrder(TZWindow previous) {
|
||||
if (windowEnd.compareTo(previous.windowEnd) < 0) {
|
||||
throw new IllegalStateException("Windows must be added in date-time order: " +
|
||||
windowEnd + " < " + previous.windowEnd);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds rules to make the last rules all start from the same year.
|
||||
* Also add one more year to avoid weird case where penultimate year has odd offset.
|
||||
*
|
||||
* @param windowStartYear the window start year
|
||||
* @throws IllegalStateException if there is only one rule defined as being forever
|
||||
*/
|
||||
void tidy(int windowStartYear) {
|
||||
if (lastRuleList.size() == 1) {
|
||||
throw new IllegalStateException("Cannot have only one rule defined as being forever");
|
||||
}
|
||||
|
||||
// handle last rules
|
||||
if (windowEnd.equals(LocalDateTime.MAX)) {
|
||||
// setup at least one real rule, which closes off other windows nicely
|
||||
maxLastRuleStartYear = Math.max(maxLastRuleStartYear, windowStartYear) + 1;
|
||||
for (TZRule lastRule : lastRuleList) {
|
||||
addRule(lastRule.year, maxLastRuleStartYear, lastRule.month, lastRule.dayOfMonthIndicator,
|
||||
lastRule.dayOfWeek, lastRule.time, lastRule.timeEndOfDay, lastRule.timeDefinition, lastRule.savingAmountSecs);
|
||||
lastRule.year = maxLastRuleStartYear + 1;
|
||||
}
|
||||
if (maxLastRuleStartYear == YEAR_MAX_VALUE) {
|
||||
lastRuleList.clear();
|
||||
} else {
|
||||
maxLastRuleStartYear++;
|
||||
}
|
||||
} else {
|
||||
// convert all within the endYear limit
|
||||
int endYear = windowEnd.getYear();
|
||||
for (TZRule lastRule : lastRuleList) {
|
||||
addRule(lastRule.year, endYear + 1, lastRule.month, lastRule.dayOfMonthIndicator,
|
||||
lastRule.dayOfWeek, lastRule.time, lastRule.timeEndOfDay, lastRule.timeDefinition, lastRule.savingAmountSecs);
|
||||
}
|
||||
lastRuleList.clear();
|
||||
maxLastRuleStartYear = YEAR_MAX_VALUE;
|
||||
}
|
||||
|
||||
// ensure lists are sorted
|
||||
Collections.sort(ruleList);
|
||||
Collections.sort(lastRuleList);
|
||||
|
||||
// default fixed savings to zero
|
||||
if (ruleList.size() == 0 && fixedSavingAmountSecs == null) {
|
||||
fixedSavingAmountSecs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the window is empty.
|
||||
*
|
||||
* @return true if the window is only a standard offset
|
||||
*/
|
||||
boolean isSingleWindowStandardOffset() {
|
||||
return windowEnd.equals(LocalDateTime.MAX) && timeDefinition == TimeDefinition.WALL &&
|
||||
fixedSavingAmountSecs == null && lastRuleList.isEmpty() && ruleList.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the wall offset for the local date-time at the end of the window.
|
||||
*
|
||||
* @param savingsSecs the amount of savings in use in seconds
|
||||
* @return the created date-time epoch second in the wall offset, not null
|
||||
*/
|
||||
ZoneOffset createWallOffset(int savingsSecs) {
|
||||
return ZoneOffset.ofTotalSeconds(standardOffset.getTotalSeconds() + savingsSecs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the offset date-time for the local date-time at the end of the window.
|
||||
*
|
||||
* @param savingsSecs the amount of savings in use in seconds
|
||||
* @return the created date-time epoch second in the wall offset, not null
|
||||
*/
|
||||
long createDateTimeEpochSecond(int savingsSecs) {
|
||||
ZoneOffset wallOffset = createWallOffset(savingsSecs);
|
||||
LocalDateTime ldt = timeDefinition.createDateTime(windowEnd, standardOffset, wallOffset);
|
||||
return ldt.toEpochSecond(wallOffset);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* A definition of the way a local time can be converted to an offset time.
|
||||
*/
|
||||
class TZRule implements Comparable<TZRule> {
|
||||
private int year;
|
||||
private int month;
|
||||
private int dayOfMonthIndicator;
|
||||
private int dayOfWeek;
|
||||
private LocalTime time;
|
||||
private boolean timeEndOfDay; // Whether the local time is end of day.
|
||||
private TimeDefinition timeDefinition; // The type of the time.
|
||||
private int savingAmountSecs; // The amount of the saving to be applied after this point.
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param year the year
|
||||
* @param month the month, value from 1 to 12
|
||||
* @param dayOfMonthIndicator the day-of-month of the transition, adjusted by dayOfWeek,
|
||||
* from 1 to 31 adjusted later, or -1 to -28 adjusted earlier from the last day of the month
|
||||
* @param dayOfWeek the day-of-week, -1 if day-of-month is exact
|
||||
* @param time the time, not null
|
||||
* @param timeEndOfDay whether midnight is at the end of day
|
||||
* @param timeDefinition the time definition, not null
|
||||
* @param savingAfterSecs the savings amount in seconds
|
||||
*/
|
||||
TZRule(int year, int month, int dayOfMonthIndicator,
|
||||
int dayOfWeek, LocalTime time, boolean timeEndOfDay,
|
||||
TimeDefinition timeDefinition, int savingAfterSecs) {
|
||||
this.year = year;
|
||||
this.month = month;
|
||||
this.dayOfMonthIndicator = dayOfMonthIndicator;
|
||||
this.dayOfWeek = dayOfWeek;
|
||||
this.time = time;
|
||||
this.timeEndOfDay = timeEndOfDay;
|
||||
this.timeDefinition = timeDefinition;
|
||||
this.savingAmountSecs = savingAfterSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this to a transition.
|
||||
*
|
||||
* @param standardOffset the active standard offset, not null
|
||||
* @param savingsBeforeSecs the active savings in seconds
|
||||
* @return the transition, not null
|
||||
*/
|
||||
ZoneOffsetTransition toTransition(ZoneOffset standardOffset, int savingsBeforeSecs) {
|
||||
// copy of code in ZoneOffsetTransitionRule to avoid infinite loop
|
||||
LocalDate date = toLocalDate();
|
||||
LocalDateTime ldt = LocalDateTime.of(date, time);
|
||||
ZoneOffset wallOffset = ZoneOffset.ofTotalSeconds(standardOffset.getTotalSeconds() + savingsBeforeSecs);
|
||||
LocalDateTime dt = timeDefinition.createDateTime(ldt, standardOffset, wallOffset);
|
||||
ZoneOffset offsetAfter = ZoneOffset.ofTotalSeconds(standardOffset.getTotalSeconds() + savingAmountSecs);
|
||||
return new ZoneOffsetTransition(dt, wallOffset, offsetAfter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the apoch second of this rules with the specified
|
||||
* active standard offset and active savings
|
||||
*
|
||||
* @param standardOffset the active standard offset, not null
|
||||
* @param savingsBeforeSecs the active savings in seconds
|
||||
* @return the transition epoch second
|
||||
*/
|
||||
long toEpochSecond(ZoneOffset standardOffset, int savingsBeforeSecs) {
|
||||
LocalDateTime ldt = LocalDateTime.of(toLocalDate(), time);
|
||||
ZoneOffset wallOffset = ZoneOffset.ofTotalSeconds(standardOffset.getTotalSeconds() + savingsBeforeSecs);
|
||||
return timeDefinition.createDateTime(ldt, standardOffset, wallOffset)
|
||||
.toEpochSecond(wallOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if this a real transition with the active savings in seconds
|
||||
*
|
||||
* @param savingsBeforeSecs the active savings in seconds
|
||||
* @return true, if savings in seconds changes
|
||||
*/
|
||||
boolean isTransition(int savingsBeforeSecs) {
|
||||
return savingAmountSecs != savingsBeforeSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this to a transition rule.
|
||||
*
|
||||
* @param standardOffset the active standard offset, not null
|
||||
* @param savingsBeforeSecs the active savings before the transition in seconds
|
||||
* @return the transition, not null
|
||||
*/
|
||||
ZoneOffsetTransitionRule toTransitionRule(ZoneOffset standardOffset, int savingsBeforeSecs) {
|
||||
// optimize stored format
|
||||
if (dayOfMonthIndicator < 0) {
|
||||
if (month != 2) { // not Month.FEBRUARY
|
||||
dayOfMonthIndicator = maxLengthOfMonth(month) - 6;
|
||||
}
|
||||
}
|
||||
if (timeEndOfDay && dayOfMonthIndicator > 0 &&
|
||||
(dayOfMonthIndicator == 28 && month == 2) == false) {
|
||||
LocalDate date = LocalDate.of(2004, month, dayOfMonthIndicator).plusDays(1); // leap-year
|
||||
month = date.getMonth();
|
||||
dayOfMonthIndicator = date.getDayOfMonth();
|
||||
if (dayOfWeek != -1) {
|
||||
dayOfWeek = plusDayOfWeek(dayOfWeek, 1);
|
||||
}
|
||||
timeEndOfDay = false;
|
||||
}
|
||||
// build rule
|
||||
return new ZoneOffsetTransitionRule(
|
||||
month, dayOfMonthIndicator, dayOfWeek, time, timeEndOfDay, timeDefinition,
|
||||
standardOffset,
|
||||
ZoneOffset.ofTotalSeconds(standardOffset.getTotalSeconds() + savingsBeforeSecs),
|
||||
ZoneOffset.ofTotalSeconds(standardOffset.getTotalSeconds() + savingAmountSecs));
|
||||
}
|
||||
|
||||
public int compareTo(TZRule other) {
|
||||
int cmp = year - other.year;
|
||||
cmp = (cmp == 0 ? month - other.month : cmp);
|
||||
if (cmp == 0) {
|
||||
// convert to date to handle dow/domIndicator/timeEndOfDay
|
||||
LocalDate thisDate = toLocalDate();
|
||||
LocalDate otherDate = other.toLocalDate();
|
||||
cmp = thisDate.compareTo(otherDate);
|
||||
}
|
||||
cmp = (cmp == 0 ? time.compareTo(other.time) : cmp);
|
||||
return cmp;
|
||||
}
|
||||
|
||||
private LocalDate toLocalDate() {
|
||||
LocalDate date;
|
||||
if (dayOfMonthIndicator < 0) {
|
||||
int monthLen = lengthOfMonth(month, isLeapYear(year));
|
||||
date = LocalDate.of(year, month, monthLen + 1 + dayOfMonthIndicator);
|
||||
if (dayOfWeek != -1) {
|
||||
date = previousOrSame(date, dayOfWeek);
|
||||
}
|
||||
} else {
|
||||
date = LocalDate.of(year, month, dayOfMonthIndicator);
|
||||
if (dayOfWeek != -1) {
|
||||
date = nextOrSame(date, dayOfWeek);
|
||||
}
|
||||
}
|
||||
if (timeEndOfDay) {
|
||||
date = date.plusDays(1);
|
||||
}
|
||||
return date;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -110,6 +110,7 @@ int main(int argc, const char* argv[]) {
|
||||
emit_inet("StandardSocketOptions.IP_MULTICAST_LOOP", IPPROTO_IP, IP_MULTICAST_LOOP);
|
||||
|
||||
#ifdef AF_INET6
|
||||
emit_inet6("StandardSocketOptions.IP_TOS", IPPROTO_IPV6, IPV6_TCLASS);
|
||||
emit_inet6("StandardSocketOptions.IP_MULTICAST_IF", IPPROTO_IPV6, IPV6_MULTICAST_IF);
|
||||
emit_inet6("StandardSocketOptions.IP_MULTICAST_TTL", IPPROTO_IPV6, IPV6_MULTICAST_HOPS);
|
||||
emit_inet6("StandardSocketOptions.IP_MULTICAST_LOOP", IPPROTO_IPV6, IPV6_MULTICAST_LOOP);
|
||||
|
||||
@ -522,15 +522,17 @@ public class AquaComboBoxUI extends BasicComboBoxUI implements Sizeable {
|
||||
};
|
||||
|
||||
@SuppressWarnings("serial") // anonymous class
|
||||
private static Action hideAction = new AbstractAction() {
|
||||
private final Action hideAction = new AbstractAction() {
|
||||
@Override
|
||||
public void actionPerformed(final ActionEvent e) {
|
||||
final JComboBox comboBox = (JComboBox)e.getSource();
|
||||
comboBox.firePopupMenuCanceled();
|
||||
comboBox.setPopupVisible(false);
|
||||
}
|
||||
|
||||
if (comboBox.isPopupVisible()) {
|
||||
comboBox.firePopupMenuCanceled();
|
||||
comboBox.setPopupVisible(false);
|
||||
}
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return comboBox.isPopupVisible() && super.isEnabled();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -366,6 +366,11 @@ class AquaFileSystemModel extends AbstractTableModel implements PropertyChangeLi
|
||||
final SortableFile otherFile = (SortableFile)other;
|
||||
return otherFile.fFile.equals(fFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(fFile);
|
||||
}
|
||||
}
|
||||
|
||||
class LoadFilesThread extends Thread {
|
||||
|
||||
@ -29,18 +29,9 @@ import java.awt.*;
|
||||
import javax.swing.*;
|
||||
|
||||
import sun.lwawt.macosx.CPlatformWindow;
|
||||
import sun.swing.SwingAccessor;
|
||||
|
||||
class ScreenPopupFactory extends PopupFactory {
|
||||
static {
|
||||
java.security.AccessController.doPrivileged(
|
||||
new java.security.PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
System.loadLibrary("osxui");
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static final Float TRANSLUCENT = new Float(248f/255f);
|
||||
static final Float OPAQUE = new Float(1.0f);
|
||||
|
||||
@ -59,19 +50,13 @@ class ScreenPopupFactory extends PopupFactory {
|
||||
return (Window)w;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since we can't change the signature of PopupFactory, we have to call the
|
||||
* private method getPopup(Component, Component, int, int, int) through JNI
|
||||
* (see AquaLookAndFeel.m)
|
||||
*/
|
||||
native Popup _getHeavyWeightPopup(Component comp, Component invoker, int x, int y);
|
||||
|
||||
public Popup getPopup(final Component comp, final Component invoker, final int x, final int y) {
|
||||
if (invoker == null) throw new IllegalArgumentException("Popup.getPopup must be passed non-null contents");
|
||||
|
||||
final Popup popup;
|
||||
if (fIsActive) {
|
||||
popup = _getHeavyWeightPopup(comp, invoker, x, y);
|
||||
popup = SwingAccessor.getPopupFactoryAccessor()
|
||||
.getHeavyWeightPopup(this, comp, invoker, x, y);
|
||||
} else {
|
||||
popup = super.getPopup(comp, invoker, x, y);
|
||||
}
|
||||
|
||||
@ -415,7 +415,7 @@ public final class CStrike extends FontStrike {
|
||||
generalCache = new HashMap<Integer, Long>();
|
||||
}
|
||||
|
||||
generalCache.put(new Integer(index), new Long(value));
|
||||
generalCache.put(new Integer(index), Long.valueOf(value));
|
||||
}
|
||||
|
||||
public synchronized void dispose() {
|
||||
|
||||
@ -317,6 +317,8 @@ public abstract class LWComponentPeer<T extends Component, D extends JComponent>
|
||||
* subclasses to initialize specific peers properties.
|
||||
*/
|
||||
void initializeImpl() {
|
||||
// note that these methods can be overridden by the user and
|
||||
// can return some strange values like null.
|
||||
setBackground(target.getBackground());
|
||||
setForeground(target.getForeground());
|
||||
setFont(target.getFont());
|
||||
|
||||
@ -443,6 +443,12 @@ public class LWWindowPeer
|
||||
getPlatformWindow().updateIconImages();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBackground(final Color c) {
|
||||
super.setBackground(c);
|
||||
updateOpaque();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOpacity(float opacity) {
|
||||
getPlatformWindow().setOpacity(opacity);
|
||||
|
||||
@ -97,7 +97,8 @@ public class CEmbeddedFrame extends EmbeddedFrame {
|
||||
public void handleKeyEvent(int eventType, int modifierFlags, String characters,
|
||||
String charsIgnoringMods, boolean isRepeat, short keyCode,
|
||||
boolean needsKeyTyped) {
|
||||
responder.handleKeyEvent(eventType, modifierFlags, charsIgnoringMods, keyCode, needsKeyTyped, isRepeat);
|
||||
responder.handleKeyEvent(eventType, modifierFlags, characters, charsIgnoringMods,
|
||||
keyCode, needsKeyTyped, isRepeat);
|
||||
}
|
||||
|
||||
public void handleInputEvent(String text) {
|
||||
|
||||
@ -29,12 +29,18 @@ import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Insets;
|
||||
import java.awt.MenuBar;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Window;
|
||||
import sun.awt.CGraphicsDevice;
|
||||
import sun.awt.CGraphicsEnvironment;
|
||||
import sun.awt.CausedFocusEvent;
|
||||
import sun.awt.LightweightFrame;
|
||||
import sun.java2d.SurfaceData;
|
||||
import sun.lwawt.LWLightweightFramePeer;
|
||||
import sun.lwawt.LWWindowPeer;
|
||||
import sun.lwawt.PlatformWindow;
|
||||
|
||||
@ -72,11 +78,6 @@ public class CPlatformLWWindow extends CPlatformWindow {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphicsDevice getGraphicsDevice() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceData getScreenSurface() {
|
||||
return null;
|
||||
@ -199,4 +200,24 @@ public class CPlatformLWWindow extends CPlatformWindow {
|
||||
public long getLayerPtr() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphicsDevice getGraphicsDevice() {
|
||||
CGraphicsEnvironment ge = (CGraphicsEnvironment)GraphicsEnvironment.
|
||||
getLocalGraphicsEnvironment();
|
||||
|
||||
LWLightweightFramePeer peer = (LWLightweightFramePeer)getPeer();
|
||||
int scale = ((LightweightFrame)peer.getTarget()).getScaleFactor();
|
||||
|
||||
Rectangle bounds = ((LightweightFrame)peer.getTarget()).getHostBounds();
|
||||
for (GraphicsDevice d : ge.getScreenDevices()) {
|
||||
if (d.getDefaultConfiguration().getBounds().intersects(bounds) &&
|
||||
((CGraphicsDevice)d).getScaleFactor() == scale)
|
||||
{
|
||||
return d;
|
||||
}
|
||||
}
|
||||
// We shouldn't be here...
|
||||
return ge.getDefaultScreenDevice();
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +125,7 @@ final class CPlatformResponder {
|
||||
/**
|
||||
* Handles key events.
|
||||
*/
|
||||
void handleKeyEvent(int eventType, int modifierFlags, String chars,
|
||||
void handleKeyEvent(int eventType, int modifierFlags, String chars, String charsIgnoringModifiers,
|
||||
short keyCode, boolean needsKeyTyped, boolean needsKeyReleased) {
|
||||
boolean isFlagsChangedEvent =
|
||||
isNpapiCallback ? (eventType == CocoaConstants.NPCocoaEventFlagsChanged) :
|
||||
@ -153,7 +153,10 @@ final class CPlatformResponder {
|
||||
testChar = chars.charAt(0);
|
||||
}
|
||||
|
||||
int[] in = new int[] {testChar, isDeadChar ? 1 : 0, modifierFlags, keyCode};
|
||||
char testCharIgnoringModifiers = charsIgnoringModifiers != null && charsIgnoringModifiers.length() > 0 ?
|
||||
charsIgnoringModifiers.charAt(0) : KeyEvent.CHAR_UNDEFINED;
|
||||
|
||||
int[] in = new int[] {testCharIgnoringModifiers, isDeadChar ? 1 : 0, modifierFlags, keyCode};
|
||||
int[] out = new int[3]; // [jkeyCode, jkeyLocation, deadChar]
|
||||
|
||||
postsTyped = NSEvent.nsToJavaKeyInfo(in, out);
|
||||
|
||||
@ -200,7 +200,7 @@ public class CPlatformView extends CFRetainedResource {
|
||||
}
|
||||
|
||||
private void deliverKeyEvent(NSEvent event) {
|
||||
responder.handleKeyEvent(event.getType(), event.getModifierFlags(),
|
||||
responder.handleKeyEvent(event.getType(), event.getModifierFlags(), event.getCharacters(),
|
||||
event.getCharactersIgnoringModifiers(), event.getKeyCode(), true, false);
|
||||
}
|
||||
|
||||
|
||||
@ -119,6 +119,7 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
|
||||
static final int NONACTIVATING = 1 << 24;
|
||||
static final int IS_DIALOG = 1 << 25;
|
||||
static final int IS_MODAL = 1 << 26;
|
||||
static final int IS_POPUP = 1 << 27;
|
||||
|
||||
static final int _STYLE_PROP_BITMASK = DECORATED | TEXTURED | UNIFIED | UTILITY | HUD | SHEET | CLOSEABLE | MINIMIZABLE | RESIZABLE;
|
||||
|
||||
@ -318,6 +319,7 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
|
||||
styleBits = SET(styleBits, TEXTURED, false);
|
||||
// Popups in applets don't activate applet's process
|
||||
styleBits = SET(styleBits, NONACTIVATING, true);
|
||||
styleBits = SET(styleBits, IS_POPUP, true);
|
||||
}
|
||||
|
||||
if (Window.Type.UTILITY.equals(target.getType())) {
|
||||
@ -744,20 +746,22 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
|
||||
@Override
|
||||
public void setOpaque(boolean isOpaque) {
|
||||
CWrapper.NSWindow.setOpaque(getNSWindowPtr(), isOpaque);
|
||||
boolean isTextured = (peer == null)? false : peer.isTextured();
|
||||
if (!isOpaque && !isTextured) {
|
||||
long clearColor = CWrapper.NSColor.clearColor();
|
||||
CWrapper.NSWindow.setBackgroundColor(getNSWindowPtr(), clearColor);
|
||||
boolean isTextured = (peer == null) ? false : peer.isTextured();
|
||||
if (!isTextured) {
|
||||
if (!isOpaque) {
|
||||
CWrapper.NSWindow.setBackgroundColor(getNSWindowPtr(), 0);
|
||||
} else if (peer != null) {
|
||||
Color color = peer.getBackground();
|
||||
if (color != null) {
|
||||
int rgb = color.getRGB();
|
||||
CWrapper.NSWindow.setBackgroundColor(getNSWindowPtr(), rgb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//This is a temporary workaround. Looks like after 7124236 will be fixed
|
||||
//the correct place for invalidateShadow() is CGLayer.drawInCGLContext.
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
invalidateShadow();
|
||||
}
|
||||
});
|
||||
SwingUtilities.invokeLater(this::invalidateShadow);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -61,7 +61,14 @@ final class CWrapper {
|
||||
|
||||
static native void setAlphaValue(long window, float alpha);
|
||||
static native void setOpaque(long window, boolean opaque);
|
||||
static native void setBackgroundColor(long window, long color);
|
||||
|
||||
/**
|
||||
* Sets background color of the NSWindow.
|
||||
*
|
||||
* @param window the pointer of the NSWindow
|
||||
* @param color the color in argb format
|
||||
*/
|
||||
static native void setBackgroundColor(long window, int color);
|
||||
|
||||
static native void miniaturize(long window);
|
||||
static native void deminiaturize(long window);
|
||||
@ -82,8 +89,4 @@ final class CWrapper {
|
||||
|
||||
static native void setToolTip(long view, String msg);
|
||||
}
|
||||
|
||||
static final class NSColor {
|
||||
static native long clearColor();
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,13 +47,15 @@ final class NSEvent {
|
||||
|
||||
// Key event information
|
||||
private short keyCode;
|
||||
private String characters;
|
||||
private String charactersIgnoringModifiers;
|
||||
|
||||
// Called from native
|
||||
NSEvent(int type, int modifierFlags, short keyCode, String charactersIgnoringModifiers) {
|
||||
NSEvent(int type, int modifierFlags, short keyCode, String characters, String charactersIgnoringModifiers) {
|
||||
this.type = type;
|
||||
this.modifierFlags = modifierFlags;
|
||||
this.keyCode = keyCode;
|
||||
this.characters = characters;
|
||||
this.charactersIgnoringModifiers = charactersIgnoringModifiers;
|
||||
}
|
||||
|
||||
@ -121,12 +123,16 @@ final class NSEvent {
|
||||
return charactersIgnoringModifiers;
|
||||
}
|
||||
|
||||
String getCharacters() {
|
||||
return characters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NSEvent[" + getType() + " ," + getModifierFlags() + " ,"
|
||||
+ getClickCount() + " ," + getButtonNumber() + " ," + getX() + " ,"
|
||||
+ getY() + " ," + getAbsX() + " ," + getAbsY()+ " ," + getKeyCode() + " ,"
|
||||
+ getCharactersIgnoringModifiers() + "]";
|
||||
+ getCharacters() + " ," + getCharactersIgnoringModifiers() + "]";
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#import "com_apple_laf_ScreenPopupFactory.h"
|
||||
#import <JavaNativeFoundation/JavaNativeFoundation.h>
|
||||
|
||||
static JNF_CLASS_CACHE(sjc_PopupFactory, "javax/swing/PopupFactory");
|
||||
static JNF_MEMBER_CACHE(jm_getPopup, sjc_PopupFactory, "getPopup", "(Ljava/awt/Component;Ljava/awt/Component;III)Ljavax/swing/Popup;");
|
||||
|
||||
/*
|
||||
* Class: com_apple_laf_ScreenPopupFactory
|
||||
* Method: _getHeavyWeightPopup
|
||||
* Signature: (Ljava/awt/Component;Ljava/awt/Component;II)Ljavax/swing/Popup;
|
||||
*/
|
||||
JNIEXPORT jobject /* javax.swing.Popup */ JNICALL Java_com_apple_laf_ScreenPopupFactory__1getHeavyWeightPopup
|
||||
(JNIEnv *env, jobject screenPopupFactory, jobject comp, jobject invoker, jint x, jint y) {
|
||||
jobject popup;
|
||||
JNF_COCOA_ENTER(env);
|
||||
popup = JNFCallObjectMethod(env, screenPopupFactory, jm_getPopup, comp, invoker, x, y, 2);
|
||||
JNF_COCOA_EXIT(env);
|
||||
return popup;
|
||||
}
|
||||
@ -1,207 +0,0 @@
|
||||
// !$*UTF8*$!
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
{
|
||||
00E6828EFEC88D1A11DB9C8B /* Project object */ = {
|
||||
activeBuildConfigurationName = Release;
|
||||
activeExecutable = 6A9FA6570246BA6C0CC91562 /* JObjC */;
|
||||
activeTarget = EB9FD8610AEECCF5008E157E /* JObjC */;
|
||||
addToTargets = (
|
||||
4CEBA78E08679EF10015D03E /* JNILib */,
|
||||
);
|
||||
breakpointsGroup = 0AB3651F0B2F67B300788B6C /* XCBreakpointsBucket */;
|
||||
codeSenseManager = 0AB364DB0B2F66FD00788B6C /* Code sense */;
|
||||
executables = (
|
||||
6A9FA6570246BA6C0CC91562 /* JObjC */,
|
||||
);
|
||||
perUserDictionary = {
|
||||
PBXConfiguration.PBXFileTableDataSource3.PBXExecutablesDataSource = {
|
||||
PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
|
||||
PBXFileTableDataSourceColumnSortingKey = PBXExecutablesDataSource_NameID;
|
||||
PBXFileTableDataSourceColumnWidthsKey = (
|
||||
22,
|
||||
300,
|
||||
131,
|
||||
);
|
||||
PBXFileTableDataSourceColumnsKey = (
|
||||
PBXExecutablesDataSource_ActiveFlagID,
|
||||
PBXExecutablesDataSource_NameID,
|
||||
PBXExecutablesDataSource_CommentsID,
|
||||
);
|
||||
};
|
||||
PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = {
|
||||
PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
|
||||
PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
|
||||
PBXFileTableDataSourceColumnWidthsKey = (
|
||||
20,
|
||||
245,
|
||||
20,
|
||||
48,
|
||||
43,
|
||||
43,
|
||||
20,
|
||||
);
|
||||
PBXFileTableDataSourceColumnsKey = (
|
||||
PBXFileDataSource_FiletypeID,
|
||||
PBXFileDataSource_Filename_ColumnID,
|
||||
PBXFileDataSource_Built_ColumnID,
|
||||
PBXFileDataSource_ObjectSize_ColumnID,
|
||||
PBXFileDataSource_Errors_ColumnID,
|
||||
PBXFileDataSource_Warnings_ColumnID,
|
||||
PBXFileDataSource_Target_ColumnID,
|
||||
);
|
||||
};
|
||||
PBXConfiguration.PBXTargetDataSource.PBXTargetDataSource = {
|
||||
PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
|
||||
PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
|
||||
PBXFileTableDataSourceColumnWidthsKey = (
|
||||
20,
|
||||
200,
|
||||
65,
|
||||
20,
|
||||
48,
|
||||
43,
|
||||
43,
|
||||
);
|
||||
PBXFileTableDataSourceColumnsKey = (
|
||||
PBXFileDataSource_FiletypeID,
|
||||
PBXFileDataSource_Filename_ColumnID,
|
||||
PBXTargetDataSource_PrimaryAttribute,
|
||||
PBXFileDataSource_Built_ColumnID,
|
||||
PBXFileDataSource_ObjectSize_ColumnID,
|
||||
PBXFileDataSource_Errors_ColumnID,
|
||||
PBXFileDataSource_Warnings_ColumnID,
|
||||
);
|
||||
};
|
||||
};
|
||||
sourceControlManager = 0AB364DA0B2F66FD00788B6C /* Source Control */;
|
||||
userBuildSettings = {
|
||||
};
|
||||
};
|
||||
0AB364DA0B2F66FD00788B6C /* Source Control */ = {
|
||||
isa = PBXSourceControlManager;
|
||||
fallbackIsa = XCSourceControlManager;
|
||||
isSCMEnabled = 0;
|
||||
scmConfiguration = {
|
||||
};
|
||||
scmType = "";
|
||||
};
|
||||
0AB364DB0B2F66FD00788B6C /* Code sense */ = {
|
||||
isa = PBXCodeSenseManager;
|
||||
indexTemplatePath = "";
|
||||
};
|
||||
0AB3651F0B2F67B300788B6C /* XCBreakpointsBucket */ = {
|
||||
isa = XCBreakpointsBucket;
|
||||
name = "Project Breakpoints";
|
||||
objects = (
|
||||
);
|
||||
};
|
||||
0AB365570B2F6ABB00788B6C /* JObjCdylib.c */ = {
|
||||
uiCtxt = {
|
||||
sepNavIntBoundsRect = "{{0, 0}, {847, 783}}";
|
||||
sepNavSelRange = "{0, 0}";
|
||||
sepNavVisRect = "{{0, 0}, {847, 783}}";
|
||||
sepNavWindowFrame = "{{84, 198}, {886, 912}}";
|
||||
};
|
||||
};
|
||||
0A3CC35E0B94BB8800F6BA26 /* java */ = {
|
||||
isa = PBXFileReference;
|
||||
explicitFileType = "compiled.mach-o.executable";
|
||||
name = java;
|
||||
path = /usr/bin/java;
|
||||
sourceTree = "<absolute>";
|
||||
};
|
||||
363028F90383184400C91562 /* Manifest */ = {
|
||||
uiCtxt = {
|
||||
sepNavIntBoundsRect = "{{0, 0}, {847, 783}}";
|
||||
sepNavSelRange = "{0, 0}";
|
||||
sepNavVisRect = "{{0, 0}, {847, 783}}";
|
||||
sepNavWindowFrame = "{{38, 240}, {886, 912}}";
|
||||
};
|
||||
};
|
||||
4CEBA78E08679EF10015D03E /* Dylib */ = {
|
||||
activeExec = 0;
|
||||
};
|
||||
6A9FA6570246BA6C0CC91562 /* JObjC */ = {
|
||||
isa = PBXExecutable;
|
||||
activeArgIndex = 0;
|
||||
activeArgIndices = (
|
||||
YES,
|
||||
);
|
||||
argumentStrings = (
|
||||
"-cp JObjC.jar JObjC",
|
||||
);
|
||||
autoAttachOnCrash = 1;
|
||||
configStateDict = {
|
||||
"PBXLSLaunchAction-0" = {
|
||||
PBXLSLaunchAction = 0;
|
||||
PBXLSLaunchStartAction = 1;
|
||||
PBXLSLaunchStdioStyle = 2;
|
||||
PBXLSLaunchStyle = 0;
|
||||
class = PBXLSRunLaunchConfig;
|
||||
displayName = "Executable Runner";
|
||||
identifier = com.apple.Xcode.launch.runConfig;
|
||||
remoteHostInfo = "";
|
||||
startActionInfo = "";
|
||||
};
|
||||
"PBXLSLaunchAction-1" = {
|
||||
PBXLSLaunchAction = 1;
|
||||
PBXLSLaunchStartAction = 1;
|
||||
PBXLSLaunchStdioStyle = 2;
|
||||
PBXLSLaunchStyle = 0;
|
||||
class = PBXJavaDebuggingNativeLaunchConfig;
|
||||
displayName = "Java Debugger";
|
||||
identifier = com.apple.Xcode.launch.JavaDebugNativeConfig;
|
||||
remoteHostInfo = "";
|
||||
startActionInfo = "";
|
||||
};
|
||||
};
|
||||
customDataFormattersEnabled = 1;
|
||||
debuggerPlugin = GDBDebugging;
|
||||
disassemblyDisplayState = 0;
|
||||
dylibVariantSuffix = "";
|
||||
enableDebugStr = 1;
|
||||
environmentEntries = (
|
||||
);
|
||||
executableSystemSymbolLevel = 0;
|
||||
executableUserSymbolLevel = 0;
|
||||
launchableReference = 0A3CC35E0B94BB8800F6BA26 /* java */;
|
||||
libgmallocEnabled = 0;
|
||||
name = JObjC;
|
||||
sourceDirectories = (
|
||||
);
|
||||
startupPath = "dist";
|
||||
};
|
||||
EB9FD8610AEECCF5008E157E /* JObjC */ = {
|
||||
activeExec = 0;
|
||||
};
|
||||
EB9FD8720AEECD83008E157E /* build.xml */ = {
|
||||
uiCtxt = {
|
||||
sepNavIntBoundsRect = "{{0, 0}, {847, 1260}}";
|
||||
sepNavSelRange = "{1260, 0}";
|
||||
sepNavVisRect = "{{0, 8}, {847, 783}}";
|
||||
sepNavWindowFrame = "{{752, 266}, {886, 912}}";
|
||||
};
|
||||
};
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,132 +0,0 @@
|
||||
#title JObjC
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
JObjC core provides a pure Java interface for calling C functions and
|
||||
sending ObjC messages. Given some information, it can marshal types
|
||||
automatically.
|
||||
|
||||
It also parses BridgeSupport to generate Java wrappers around
|
||||
Framework bundles. These wrappers rely on the core to provide access
|
||||
to the C constants, enums, structs, functions, ObjC classes, etc of a
|
||||
framework.
|
||||
|
||||
* How to build it
|
||||
|
||||
Your best option is `ant all`. There's an Xcode "B&I" target that
|
||||
works for buildit.
|
||||
|
||||
You'll need a recent JavaNativeFoundation, and perhaps some other
|
||||
things. Everything is usually there on SnowLeopard (or Leopard after
|
||||
the common ~javabuild/bin/update runs).
|
||||
|
||||
The build process is quite involved. Xcode takes care of the native
|
||||
parts, ant takes care of the Java parts, and there's an unholy mix of
|
||||
external targets and hidden dependencies that keep Xcode and ant (and
|
||||
buildit on top of that) from stepping on each other. So a warning: the
|
||||
ant and Xcode targets don't have proper dependencies set up because of
|
||||
this. They have some dependencies configured, but not the entire
|
||||
chain. This is because of the jumping back and forth between
|
||||
externals. If you run the aggregate targets (Xcode B&I, ant all, ant
|
||||
test, ant bench), everything's is good. But if you manually invoke
|
||||
individual targets, chances are you'll miss something. Let's go over
|
||||
it all step by step:
|
||||
|
||||
** ant gen-pcoder
|
||||
|
||||
The PrimitiveCoder subclasses have a lot of boiler plate which
|
||||
simplifies the generated MixedPrimitiveCoder classes. So instead of
|
||||
maintaining it, I maintain a tiny Haskell script that spits out the
|
||||
Java code. This ant target runs that script if Haskell is available on
|
||||
the system. If it isn't available, this will silently fail. That's
|
||||
okay, because chances are the PrimitiveCoder.java that you got from
|
||||
svn is current and does not need to be updated.
|
||||
|
||||
** ant build-core / Xcode build-core-java
|
||||
|
||||
Build core simply builds the JObjC core java classes, and also
|
||||
generates headers for the JNI for Xcode.
|
||||
|
||||
** ant build-core-native / Xcode build-core-native
|
||||
|
||||
Xcode builds the native core, using the headers from the Java core. It
|
||||
generates libJObjC.dylib.
|
||||
|
||||
** ant build-generator / Xcode build-generator-java
|
||||
|
||||
ant builds the generator.
|
||||
|
||||
** ant run-generator / Xcode run-generator
|
||||
|
||||
ant runs the generator, using the core Java and native classes.
|
||||
|
||||
What is rungen? And what's run-generator-old? run-generator-old is the
|
||||
preferred way to run the generator from ant, but there's a strange bug
|
||||
when running from buildit that causes run-generator-old to
|
||||
freeze. Pratik was helping me debug it, inspecting the stack and
|
||||
snooping dtrace probes, but we never found the reason for the
|
||||
block. So I figured that maybe if I just add a layer of indirection
|
||||
maybe it'll work around that. And it did. Sad but true.
|
||||
|
||||
** ant build-generated / Xcode build-generated-java
|
||||
|
||||
Build the generator output.
|
||||
|
||||
** ant build-additions / Xcode build-additions-java
|
||||
|
||||
Builds java additions.
|
||||
|
||||
** ant build-additions-native / Xcode build-additions-native
|
||||
|
||||
This builds a new version of libJObjC.dylib. It will rebuild
|
||||
everything from the core, and include everything from additions.
|
||||
|
||||
** ant assemble-product / Xcode assemble-product-java
|
||||
|
||||
Create a jar, copy products to destination, etc.
|
||||
|
||||
* How to test it
|
||||
|
||||
The test cases also contain a Java component and a native component,
|
||||
and are built similarly to the above. The benchmarks are built
|
||||
together with the tests. So "ant build-test" and "ant
|
||||
build-test-native" will build both the benchmarks and the test. "ant
|
||||
test" will run the test. "ant bench" will run benchmarks. If you only
|
||||
want to run a specific benchmark, you can pass a regexp in the
|
||||
environment variable BENCH_MATCH.
|
||||
|
||||
<src>
|
||||
ant test
|
||||
ant bench
|
||||
BENCH_MATCH=Foo ant bench
|
||||
</src>
|
||||
|
||||
Test and bench reports will end up in
|
||||
build/JObjC.build/Debug/test-reports/
|
||||
|
||||
* How to use it
|
||||
|
||||
Include the jar in your classpath and set your java.library.path to
|
||||
the directory that contains the dylib. Same thing for app bundles.
|
||||
@ -1,27 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
egrep "(TODO|FIXME|XXX|HACK)" -r src
|
||||
@ -1,54 +0,0 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
# makefile for generating a stable set of bridgesupport files that change timestamp
|
||||
# only when the bridgesupport data actually changes
|
||||
|
||||
FRAMEWORKS_DIR = /System/Library/Frameworks
|
||||
GBM = /usr/bin/gen_bridge_metadata
|
||||
GEN_HEADERS = $(addsuffix .headers,$(FRAMEWORKS))
|
||||
GEN_BRIDGESUPPORT = $(addsuffix .bridgesupport,$(FRAMEWORKS))
|
||||
|
||||
%.bridgesupport : %.headers $(FRAMEWORKS_DIR)/%.framework/Headers/*.h
|
||||
@echo "generating bridge support for" $<
|
||||
if [ -f $(FRAMEWORKS_DIR)/$(<:.headers=.framework)/Resources/BridgeSupport/$(<:.headers=Full.bridgesupport) ] ; \
|
||||
then cp $(FRAMEWORKS_DIR)/$(<:.headers=.framework)/Resources/BridgeSupport/$(<:.headers=Full.bridgesupport) $@ ; \
|
||||
else $(GBM) -F complete --framework $(<:.headers=.framework) -o $@ ; \
|
||||
fi
|
||||
if cmp -s $@ $(STABLE_GEN_DIR)/$(@:.bridgesupport=Full.bridgesupport) ; \
|
||||
then : ; \
|
||||
else cp $@ $(STABLE_GEN_DIR)/$(@:.bridgesupport=Full.bridgesupport) ; \
|
||||
fi
|
||||
|
||||
%.headers : $(FRAMEWORKS_DIR)/%.framework/Headers
|
||||
@echo linking $<
|
||||
ln -s $< $@
|
||||
|
||||
$(STABLE_GEN_DIR):
|
||||
mkdir -p $(STABLE_GEN_DIR)
|
||||
|
||||
$(GEN_BRIDGESUPPORT): $(GEN_HEADERS) $(STABLE_GEN_DIR)
|
||||
|
||||
all: $(GEN_BRIDGESUPPORT)
|
||||
@ -1,520 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
-->
|
||||
<project name="JObjC" default="install" basedir=".">
|
||||
<property environment="env"/>
|
||||
<echoproperties/>
|
||||
|
||||
<target name="installhdrs">
|
||||
<echo>Nothing to do for install-headers build phase</echo>
|
||||
</target>
|
||||
|
||||
<target name="installsrc">
|
||||
<echo>Nothing to do for install-source build phase</echo>
|
||||
</target>
|
||||
|
||||
<property name="redirection-target-defined" value="${env.PRODUCT_NAME}"/>
|
||||
|
||||
<target name="install" description="Redirects to the target specified in $PRODUCT_NAME">
|
||||
<fail unless="env.PRODUCT_NAME" status="-1">
|
||||
This Ant build file depends on the native Xcode project to invoke
|
||||
targets by defining $PRODUCT_NAME to specify the target.
|
||||
</fail>
|
||||
|
||||
<echo>--- Redirecting to target "${env.PRODUCT_NAME}"</echo>
|
||||
<antcall target="${env.PRODUCT_NAME}"/>
|
||||
</target>
|
||||
|
||||
<property name="compile.debug" value="true"/>
|
||||
|
||||
<!-- building from the command line / xcode b&i -->
|
||||
<condition property="src" value="." else="${env.SRCROOT}">
|
||||
<not><isset property="env.SRCROOT"/></not>
|
||||
</condition>
|
||||
|
||||
<condition property="cfg" value="Debug" else="${env.CONFIGURATION}">
|
||||
<not><isset property="env.CONFIGURATION"/></not>
|
||||
</condition>
|
||||
|
||||
<condition property="obj" value="build/JObjC.build/${cfg}" else="${env.OBJROOT}">
|
||||
<not><isset property="env.OBJROOT"/></not>
|
||||
</condition>
|
||||
|
||||
<condition property="dst" value="build/${cfg}" else="${env.DSTROOT}/${cfg}">
|
||||
<not><isset property="env.DSTROOT"/></not>
|
||||
</condition>
|
||||
|
||||
<condition property="ARCHS" value="ppc i386 x86_64" else="${env.RC_ARCHS}">
|
||||
<not><isset property="env.RC_ARCHS"/></not>
|
||||
</condition>
|
||||
|
||||
<!-- -/- -->
|
||||
|
||||
<property name="bin" location="${obj}/bin"/>
|
||||
<property name="gendoc" location="${obj}/doc"/>
|
||||
|
||||
<condition property="nativelib.dir" value="${dst}">
|
||||
<not><isset property="env.CONFIGURATION_BUILD_DIR"/></not>
|
||||
</condition>
|
||||
<condition property="nativelib.dir" value="${env.CONFIGURATION_BUILD_DIR}">
|
||||
<isset property="env.CONFIGURATION_BUILD_DIR"/>
|
||||
</condition>
|
||||
<property name="nativelib.file" location="${nativelib.dir}/libJObjC.dylib" />
|
||||
|
||||
<property name="jniheaders" location="${obj}/src/jni_headers"/>
|
||||
|
||||
<property name="core.src" location="${src}/src/core/java"/>
|
||||
<property name="core.bin" location="${bin}/core"/>
|
||||
<property name="core.jniheaders" location="${jniheaders}/core"/>
|
||||
<property name="core.nativelib.dir" location="${nativelib.dir}"/>
|
||||
|
||||
<property name="generator.src" location="${src}/src/generator/java"/>
|
||||
<property name="generator.bin" location="${bin}/generator"/>
|
||||
|
||||
<property name="generated.src" location="${obj}/src/jobjc"/>
|
||||
<property name="generated.bin" location="${bin}/generated"/>
|
||||
|
||||
<property name="additions.src" location="${src}/src/runtime-additions"/>
|
||||
<property name="additions.bin" location="${bin}/additions"/>
|
||||
<property name="additions.jniheaders" location="${jniheaders}/additions"/>
|
||||
<property name="additions.nativelib.dir" location="${nativelib.dir}"/>
|
||||
|
||||
<property name="test.src" location="${src}/src/tests/java"/>
|
||||
<property name="test.bin" location="${bin}/test"/>
|
||||
<property name="test.jniheaders" location="${jniheaders}/test"/>
|
||||
<property name="test.reports" location="${obj}/test-reports"/>
|
||||
|
||||
<condition property="product.target_path"
|
||||
value="/System/Library/Java/Extensions"
|
||||
else="${env.INSTALL_PATH}">
|
||||
<not><isset property="env.INSTALL_PATH"/></not>
|
||||
</condition>
|
||||
|
||||
<echo message="(Settings :src '${src}' :cfg '${cfg}' :obj '${obj}' :dst '${dst}')"/>
|
||||
|
||||
<path id="test.lib.path.id">
|
||||
<fileset dir="/usr/share/java">
|
||||
<include name="**/*.jar"/>
|
||||
</fileset>
|
||||
</path>
|
||||
|
||||
<property name="product.jarfile.dir" location="${obj}"/>
|
||||
<property name="product.jarfile.name" value="JObjC.jar"/>
|
||||
<property name="product.jarfile" location="${product.jarfile.dir}/${product.jarfile.name}"/>
|
||||
|
||||
<target name="gen-pcoder" description="Generate PrimitiveCoder.java">
|
||||
<exec executable="ruby" failonerror="true">
|
||||
<arg value="${src}/run-and-write-if-okay"/>
|
||||
<arg value="${src}/src/core/PrimitiveCoder.hs"/>
|
||||
<arg value="${src}/src/core/java/com/apple/jobjc/PrimitiveCoder.java"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="build-core" depends="gen-pcoder" description="Compile the core runtime classes">
|
||||
<mkdir dir="${core.bin}" />
|
||||
<!-- Compile PrimitiveCoder first to work around javac bug. -->
|
||||
<javac srcdir="${core.src}" destdir="${core.bin}" source="1.5" target="1.5" debug="${compile.debug}"
|
||||
includes="**/PrimitiveCoder.java"
|
||||
includeantruntime="false">
|
||||
<classpath>
|
||||
<path location="${obj}/../langtools/dist/lib/classes.jar"/>
|
||||
</classpath>
|
||||
</javac>
|
||||
<javac srcdir="${core.src}" destdir="${core.bin}" source="1.5" target="1.5" debug="${compile.debug}" includeantruntime="false">
|
||||
<classpath>
|
||||
<path location="${obj}/../langtools/dist/lib/classes.jar"/>
|
||||
</classpath>
|
||||
</javac>
|
||||
|
||||
<exec executable="/usr/bin/perl" outputproperty="core.classes" failonerror="true">
|
||||
<arg value="${src}/extract_classes.pl"/>
|
||||
<arg path="${core.bin}"/>
|
||||
</exec>
|
||||
|
||||
<mkdir dir="${core.jniheaders}" />
|
||||
<javah destdir="${core.jniheaders}" class="${core.classes}">
|
||||
<classpath path="${core.bin}"/>
|
||||
</javah>
|
||||
</target>
|
||||
|
||||
<target name="build-core-native" depends="build-core">
|
||||
<exec executable="xcodebuild" failonerror="true">
|
||||
<env key="CC" value=""/>
|
||||
<env key="CXX" value=""/>
|
||||
<arg value="-configuration"/>
|
||||
<arg value="${cfg}"/>
|
||||
<arg value="-target"/>
|
||||
<arg value="build-core-native"/>
|
||||
<arg value="SRCROOT=${src}"/>
|
||||
<arg value="OBJROOT=${obj}"/>
|
||||
<arg value="DSTROOT=${dst}"/>
|
||||
<arg value="TARGET_TEMP_DIR=${env.DSTROOT}"/>
|
||||
<arg value="PROJECT_TEMP_DIR=${env.DSTROOT}"/>
|
||||
<arg value="BUILD_DIR=${env.DSTROOT}"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<!-- macosx jdk 7 puts jobjc core classes on the bootclasspath by default -->
|
||||
<target name="build-generator" description="Compile and assemble the generator">
|
||||
<mkdir dir="${generator.bin}"/>
|
||||
<javac srcdir="${generator.src}" destdir="${generator.bin}" source="1.5" target="1.5" debug="${compile.debug}" includeantruntime="false">
|
||||
<compilerarg value="-version"/>
|
||||
<compilerarg value="-Xbootclasspath/p:${core.bin}"/>
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<!-- Use this indirection hack to work around buildit lockup when
|
||||
running the generator. -->
|
||||
<target name="run-generator" depends="build-generator" description="Invoke the assembled generator">
|
||||
<mkdir dir="${generated.src}"/>
|
||||
<exec executable="ruby" failonerror="true">
|
||||
<arg value="${src}/rungen"/>
|
||||
<arg value="install"/>
|
||||
<arg value="${product.jarfile.name}"/>
|
||||
<arg value="${nativelib.dir}"/>
|
||||
<arg value="${obj}"/>
|
||||
<arg value="${ARCHS}"/>
|
||||
<arg value="${env.STABLE_GEN_DIR}"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="run-generator-old" depends="build-generator" description="Invoke the assembled generator">
|
||||
<mkdir dir="${generated.src}"/>
|
||||
<java classname="com.apple.internal.jobjc.generator.Generator" fork="true" failonerror="true">
|
||||
<jvmarg value="-Xms128m" />
|
||||
<jvmarg value="-Xmx512m" />
|
||||
<assertions><enable/></assertions>
|
||||
<classpath>
|
||||
<path location="${core.bin}"/>
|
||||
<path location="${generator.bin}"/>
|
||||
</classpath>
|
||||
<sysproperty key="java.library.path" value="${core.nativelib.dir}"/>
|
||||
<arg value="dst=${generated.src}"/>
|
||||
</java>
|
||||
</target>
|
||||
|
||||
<target name="build-generated" description="Build and assemble the JObjC core and all generated frameworks">
|
||||
<mkdir dir="${generated.bin}"/>
|
||||
<javac srcdir="${generated.src}" destdir="${generated.bin}" source="1.5" target="1.5" fork="yes" memoryMaximumSize="512m" debug="${compile.debug}" includeantruntime="false">
|
||||
<classpath>
|
||||
<path location="${core.bin}"/>
|
||||
</classpath>
|
||||
<compilerarg value="-version"/>
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<target name="build-additions" depends="build-generated">
|
||||
<mkdir dir="${additions.bin}"/>
|
||||
<javac srcdir="${additions.src}" destdir="${additions.bin}" source="1.5" target="1.5" debug="${compile.debug}" includeantruntime="false">
|
||||
<classpath>
|
||||
<path location="${core.bin}"/>
|
||||
<path location="${generated.bin}"/>
|
||||
</classpath>
|
||||
<compilerarg value="-version"/>
|
||||
</javac>
|
||||
|
||||
<exec executable="/usr/bin/perl" outputproperty="additions.classes" failonerror="true">
|
||||
<arg value="${src}/extract_classes.pl"/>
|
||||
<arg path="${additions.bin}"/>
|
||||
</exec>
|
||||
|
||||
<mkdir dir="${additions.jniheaders}"/>
|
||||
<javah destdir="${additions.jniheaders}" class="${additions.classes}">
|
||||
<classpath>
|
||||
<path location="${core.bin}"/>
|
||||
<path location="${generated.bin}"/>
|
||||
<path location="${additions.bin}"/>
|
||||
</classpath>
|
||||
</javah>
|
||||
</target>
|
||||
|
||||
<target name="build-additions-native">
|
||||
<exec executable="xcodebuild" failonerror="true">
|
||||
<env key="CC" value=""/>
|
||||
<env key="CXX" value=""/>
|
||||
<arg value="-configuration"/>
|
||||
<arg value="${cfg}"/>
|
||||
<arg value="-target"/>
|
||||
<arg value="build-additions-native"/>
|
||||
<arg value="SRCROOT=${src}"/>
|
||||
<arg value="OBJROOT=${obj}"/>
|
||||
<arg value="DSTROOT=${dst}"/>
|
||||
<arg value="TARGET_TEMP_DIR=${env.DSTROOT}"/>
|
||||
<arg value="PROJECT_TEMP_DIR=${env.DSTROOT}"/>
|
||||
<arg value="BUILD_DIR=${env.DSTROOT}"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="assemble-product">
|
||||
<mkdir dir="${product.jarfile.dir}"/>
|
||||
<jar jarfile="${product.jarfile}" level="9" index="true">
|
||||
<fileset dir="${core.bin}"/>
|
||||
<fileset dir="${generated.bin}"/>
|
||||
<fileset dir="${additions.bin}"/>
|
||||
</jar>
|
||||
|
||||
<mkdir dir="${dst}/${product.target_path}"/>
|
||||
<copy file="${product.jarfile}" toDir="${dst}/${product.target_path}" failonerror="true" verbose="true"/>
|
||||
<copy file="${nativelib.file}" toDir="${dst}/${product.target_path}" failonerror="true" verbose="true"/>
|
||||
</target>
|
||||
|
||||
<target name="doc-core">
|
||||
<mkdir dir="${gendoc}"/>
|
||||
<javadoc destdir="${gendoc}" access="protected">
|
||||
<fileset dir="${src}/src" includes="**/*.java"/>
|
||||
</javadoc>
|
||||
</target>
|
||||
|
||||
<target name="build-test" description="compile unit tests">
|
||||
<mkdir dir="${test.bin}"/>
|
||||
<javac srcdir="${test.src}" destdir="${test.bin}" debug="false" includeantruntime="false">
|
||||
<classpath>
|
||||
<pathelement location="${core.bin}"/>
|
||||
<pathelement location="${generator.bin}"/>
|
||||
<pathelement location="${generated.bin}"/>
|
||||
<pathelement location="${additions.bin}"/>
|
||||
</classpath>
|
||||
<classpath refid="test.lib.path.id"/>
|
||||
<compilerarg value="-version"/>
|
||||
</javac>
|
||||
|
||||
<exec executable="/usr/bin/perl" outputproperty="test.classes" failonerror="true">
|
||||
<arg value="${src}/extract_classes.pl"/>
|
||||
<arg path="${test.bin}"/>
|
||||
</exec>
|
||||
|
||||
<mkdir dir="${test.jniheaders}"/>
|
||||
<javah destdir="${test.jniheaders}" class="${test.classes}">
|
||||
<classpath>
|
||||
<path location="${core.bin}"/>
|
||||
<path location="${generated.bin}"/>
|
||||
<path location="${additions.bin}"/>
|
||||
<path location="${test.bin}"/>
|
||||
</classpath>
|
||||
<classpath refid="test.lib.path.id"/>
|
||||
</javah>
|
||||
</target>
|
||||
|
||||
<target name="build-test-installed" description="compile unit tests">
|
||||
<mkdir dir="${test.bin}"/>
|
||||
<javac srcdir="${test.src}" destdir="${test.bin}" debug="false" includeantruntime="false">
|
||||
<compilerarg value="-verbose"/>
|
||||
<classpath>
|
||||
<pathelement location="${generator.bin}"/>
|
||||
<pathelement location="${generated.bin}"/>
|
||||
<pathelement location="${additions.bin}"/>
|
||||
</classpath>
|
||||
<classpath refid="test.lib.path.id"/>
|
||||
<compilerarg value="-version"/>
|
||||
</javac>
|
||||
|
||||
<exec executable="/usr/bin/perl" outputproperty="test.classes" failonerror="true">
|
||||
<arg value="${src}/extract_classes.pl"/>
|
||||
<arg path="${test.bin}"/>
|
||||
</exec>
|
||||
|
||||
<mkdir dir="${test.jniheaders}"/>
|
||||
<javah destdir="${test.jniheaders}" class="${test.classes}">
|
||||
<classpath>
|
||||
<path location="${generated.bin}"/>
|
||||
<path location="${additions.bin}"/>
|
||||
<path location="${test.bin}"/>
|
||||
</classpath>
|
||||
<classpath refid="test.lib.path.id"/>
|
||||
</javah>
|
||||
</target>
|
||||
|
||||
<target name="build-test-native" depends="build-test">
|
||||
<exec executable="xcodebuild" failonerror="true">
|
||||
<env key="CC" value=""/>
|
||||
<env key="CXX" value=""/>
|
||||
<arg value="-configuration"/>
|
||||
<arg value="${cfg}"/>
|
||||
<arg value="-target"/>
|
||||
<arg value="build-test-native"/>
|
||||
<arg value="SRCROOT=${src}"/>
|
||||
<arg value="OBJROOT=${obj}"/>
|
||||
<arg value="DSTROOT=${dst}"/>
|
||||
<arg value="TARGET_TEMP_DIR=${env.DSTROOT}"/>
|
||||
<arg value="PROJECT_TEMP_DIR=${env.DSTROOT}"/>
|
||||
<arg value="BUILD_DIR=${env.DSTROOT}"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="build-test-native-installed" depends="build-test-installed">
|
||||
<exec executable="xcodebuild" failonerror="true">
|
||||
<env key="CC" value=""/>
|
||||
<env key="CXX" value=""/>
|
||||
<arg value="-configuration"/>
|
||||
<arg value="${cfg}"/>
|
||||
<arg value="-target"/>
|
||||
<arg value="build-test-native"/>
|
||||
<arg value="SRCROOT=${src}"/>
|
||||
<arg value="OBJROOT=${obj}"/>
|
||||
<arg value="DSTROOT=${dst}"/>
|
||||
<arg value="TARGET_TEMP_DIR=${env.DSTROOT}"/>
|
||||
<arg value="PROJECT_TEMP_DIR=${env.DSTROOT}"/>
|
||||
<arg value="BUILD_DIR=${env.DSTROOT}"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="test" depends="build-test-native" description="run unit tests">
|
||||
<mkdir dir="${test.reports}"/>
|
||||
<junit fork="yes" printsummary="yes">
|
||||
<assertions>
|
||||
<enable/>
|
||||
</assertions>
|
||||
<jvmarg value="-server" />
|
||||
|
||||
<sysproperty key="java.library.path" value="${nativelib.dir}" />
|
||||
<classpath>
|
||||
<pathelement location="${core.bin}"/>
|
||||
<pathelement location="${generator.bin}"/>
|
||||
<pathelement location="${generated.bin}"/>
|
||||
<pathelement location="${additions.bin}"/>
|
||||
<pathelement location="${test.bin}"/>
|
||||
</classpath>
|
||||
<classpath refid="test.lib.path.id"/>
|
||||
|
||||
<formatter type="plain"/>
|
||||
|
||||
<batchtest fork="yes" todir="${test.reports}">
|
||||
<fileset dir="${test.src}">
|
||||
<include name="**/*Test.java"/>
|
||||
<exclude name="**/AllTests.java"/>
|
||||
</fileset>
|
||||
</batchtest>
|
||||
</junit>
|
||||
</target>
|
||||
|
||||
<target name="test-installed" depends="build-test-native-installed" description="run unit tests">
|
||||
<mkdir dir="${test.reports}"/>
|
||||
<junit fork="yes" printsummary="yes">
|
||||
<assertions>
|
||||
<enable/>
|
||||
</assertions>
|
||||
<jvmarg value="-server" />
|
||||
|
||||
<sysproperty key="java.library.path" value="${nativelib.dir}" />
|
||||
<classpath>
|
||||
<pathelement location="${generator.bin}"/>
|
||||
<pathelement location="${generated.bin}"/>
|
||||
<pathelement location="${additions.bin}"/>
|
||||
<pathelement location="${test.bin}"/>
|
||||
</classpath>
|
||||
<classpath refid="test.lib.path.id"/>
|
||||
|
||||
<formatter type="plain"/>
|
||||
|
||||
<batchtest fork="yes" todir="${test.reports}">
|
||||
<fileset dir="${test.src}">
|
||||
<include name="**/*Test.java"/>
|
||||
<exclude name="**/AllTests.java"/>
|
||||
</fileset>
|
||||
</batchtest>
|
||||
</junit>
|
||||
</target>
|
||||
|
||||
|
||||
<condition property="bench_match" value="*" else="${env.BENCH_MATCH}">
|
||||
<not><isset property="env.BENCH_MATCH"/></not>
|
||||
</condition>
|
||||
|
||||
<target name="bench" depends="build-test-native" description="run benchmarks">
|
||||
<mkdir dir="${test.reports}"/>
|
||||
<junit fork="yes" printsummary="yes">
|
||||
<sysproperty key="java.library.path" value="${nativelib.dir}" />
|
||||
<classpath>
|
||||
<pathelement location="${core.bin}"/>
|
||||
<pathelement location="${generator.bin}"/>
|
||||
<pathelement location="${generated.bin}"/>
|
||||
<pathelement location="${additions.bin}"/>
|
||||
<pathelement location="${test.bin}"/>
|
||||
</classpath>
|
||||
<classpath refid="test.lib.path.id"/>
|
||||
|
||||
<jvmarg value="-Xms256m" />
|
||||
<jvmarg value="-Xmx1024m" />
|
||||
<jvmarg value="-server" />
|
||||
|
||||
<formatter type="plain"/>
|
||||
|
||||
<batchtest fork="yes" todir="${test.reports}">
|
||||
<fileset dir="${test.src}">
|
||||
<include name="**/Bench*${bench_match}*.java"/>
|
||||
</fileset>
|
||||
</batchtest>
|
||||
</junit>
|
||||
</target>
|
||||
|
||||
<target name="bench-installed" depends="build-test-native-installed" description="run benchmarks">
|
||||
<mkdir dir="${test.reports}"/>
|
||||
<junit fork="yes" printsummary="yes">
|
||||
<sysproperty key="java.library.path" value="${nativelib.dir}" />
|
||||
<classpath>
|
||||
<pathelement location="${generator.bin}"/>
|
||||
<pathelement location="${generated.bin}"/>
|
||||
<pathelement location="${additions.bin}"/>
|
||||
<pathelement location="${test.bin}"/>
|
||||
</classpath>
|
||||
<classpath refid="test.lib.path.id"/>
|
||||
|
||||
<jvmarg value="-Xms256m" />
|
||||
<jvmarg value="-Xmx1024m" />
|
||||
<jvmarg value="-server" />
|
||||
|
||||
<formatter type="plain"/>
|
||||
|
||||
<batchtest fork="yes" todir="${test.reports}">
|
||||
<fileset dir="${test.src}">
|
||||
<include name="**/Bench*${bench_match}*.java"/>
|
||||
</fileset>
|
||||
</batchtest>
|
||||
</junit>
|
||||
</target>
|
||||
|
||||
<target name="clean">
|
||||
<delete dir="build"/>
|
||||
<delete dir="${obj}"/>
|
||||
<delete dir="${dst}"/>
|
||||
<delete dir="${gendoc}"/>
|
||||
<delete dir="${test.reports}"/>
|
||||
</target>
|
||||
|
||||
|
||||
<target name="clean-all" depends="clean,build-core,build-core-native,build-generator,run-generator,build-generated,build-additions,build-additions-native,assemble-product">
|
||||
</target>
|
||||
<target name="all" depends="build-core,build-core-native,build-generator,run-generator,build-generated,build-additions,build-additions-native,assemble-product">
|
||||
</target>
|
||||
<target name="all-test" depends="build-core,build-core-native,build-generator,run-generator,build-generated,build-additions,build-additions-native,assemble-product,test-installed">
|
||||
</target>
|
||||
<target name="clean-all-test" depends="clean,build-core,build-core-native,build-generator,run-generator,build-generated,build-additions,build-additions-native,assemble-product,test-installed">
|
||||
</target>
|
||||
<target name="all-but-gen" depends="clean,build-core,build-core-native,build-generator,build-generated,build-additions,build-additions-native,assemble-product">
|
||||
</target>
|
||||
</project>
|
||||
@ -1,39 +0,0 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
# 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.
|
||||
##
|
||||
|
||||
$file_dir = $ARGV[0];
|
||||
@file_list = qx("/usr/bin/find" "$file_dir");
|
||||
|
||||
foreach $file (@file_list) {
|
||||
if ($file =~ s/\.class//) {
|
||||
if ($file !~ s/\$[0-9]//) {
|
||||
$file =~ s/$file_dir\///g;
|
||||
$file =~ s/\//\./g;
|
||||
chomp($file);
|
||||
print "$file,";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,48 +0,0 @@
|
||||
#!/usr/bin/env ruby
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
|
||||
if ARGV.length < 2
|
||||
puts <<EOF
|
||||
Expects two args: EXEC and OUTPATH. First, it runs and prints
|
||||
`EXEC 2>&1`. If it returns successfully, it writes the output to OUTPATH.
|
||||
This script will return successfully unless writing the output fails.
|
||||
EOF
|
||||
exit
|
||||
end
|
||||
|
||||
EXECPATH = ARGV[0]
|
||||
OUTPATH = ARGV[1]
|
||||
|
||||
output = `#{EXECPATH}`
|
||||
puts output
|
||||
|
||||
if $?.to_i == 0
|
||||
puts "Writing output of #{EXECPATH} to #{OUTPATH}"
|
||||
File.open(OUTPATH, 'w') {|f| f.write(output) }
|
||||
else
|
||||
puts "#{EXECPATH} failed to run trial. Ignoring."
|
||||
end
|
||||
@ -1,67 +0,0 @@
|
||||
#!/usr/bin/env ruby
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
|
||||
xcodeAction = ARGV[0]
|
||||
|
||||
exit unless xcodeAction == "install"
|
||||
|
||||
JOBJC_JAR = ARGV[1]
|
||||
LIBPATH = ARGV[2]
|
||||
OBJROOT = ARGV[3]
|
||||
ARCHS = ARGV[4]
|
||||
STABLE_GEN_DIR = ARGV[5]
|
||||
|
||||
ourJavaHome = ENV['JAVA_HOME']
|
||||
ourJavaVersion = `java -fullversion 2>&1`
|
||||
$stderr.puts "ENV['JAVA_HOME'] = #{ourJavaHome}"
|
||||
$stderr.puts "java -fullversion = #{ourJavaVersion}"
|
||||
|
||||
$stderr.puts "jobjc_jar = #{JOBJC_JAR}"
|
||||
$stderr.puts "libpath = #{LIBPATH}"
|
||||
$stderr.puts "objroot = #{OBJROOT}"
|
||||
$stderr.puts "ARCHS = #{ARCHS}"
|
||||
$stderr.puts "STABLE_GEN_DIR = #{STABLE_GEN_DIR}"
|
||||
|
||||
jarch = if ARCHS =~ /x86_64/ then "-d64" else "-d32" end
|
||||
|
||||
# compute the boot class path, but remove the JObjC jar file that may have been installed in the boot jdk
|
||||
|
||||
bootclasspathcmd = "java -classpath #{OBJROOT}/bin/core:#{OBJROOT}/bin/generator com.apple.internal.jobjc.generator.BootClassPathMinus #{JOBJC_JAR}"
|
||||
$stderr.puts bootclasspathcmd
|
||||
bootclasspath = `#{bootclasspathcmd}`
|
||||
|
||||
$stderr.puts "bootclasspath is: "
|
||||
$stderr.puts bootclasspath
|
||||
|
||||
# we run the generator with our newly created JObjC. The installed version (if available) has been removed from
|
||||
# the boot class path, so we are building with everything newly created.
|
||||
cmd = "java #{jarch} -Xms128m -Xmx512m -Djava.library.path=#{LIBPATH} -Xbootclasspath:#{bootclasspath.chomp} -classpath #{OBJROOT}/bin/core:#{OBJROOT}/bin/generator -ea com.apple.internal.jobjc.generator.Generator dst=#{OBJROOT}/src/jobjc frameworks=#{STABLE_GEN_DIR}"
|
||||
|
||||
$stderr.puts cmd
|
||||
puts `#{cmd} 2>&1`
|
||||
|
||||
raise $?.to_i if $?.to_i != 0
|
||||
@ -1,27 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
java -ea -classpath "lib/junit-4.4.jar:build/JObjC.build/Debug/bin/core:build/JObjC.build/Debug/bin/generator:build/JObjC.build/Debug/bin/additions:build/JObjC.build/Debug/bin/test:build/JObjC.build/Debug/bin/generated" -Djava.library.path=build/Debug $@
|
||||
@ -1,275 +0,0 @@
|
||||
#!/usr/bin/env runhaskell
|
||||
|
||||
{-
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
-}
|
||||
{-
|
||||
The simplest way to get Haskell is through MacPorts: sudo port install ghc
|
||||
|
||||
Otherwise, see http://www.haskell.org/ghc/
|
||||
-}
|
||||
|
||||
import Data.List
|
||||
import Data.Maybe
|
||||
import Data.Char
|
||||
|
||||
data Width = W32 | W64
|
||||
deriving (Show, Eq, Bounded, Enum)
|
||||
|
||||
data NType = NBOOL | Nschar | Nuchar | Nsshort | Nushort | Nsint | Nuint
|
||||
| Nslong | Nulong | Nslonglong | Nulonglong | Nfloat | Ndouble
|
||||
deriving (Show, Eq, Bounded, Enum)
|
||||
|
||||
data JPrim = Jboolean | Jbyte | Jchar | Jshort | Jint | Jlong | Jfloat | Jdouble
|
||||
deriving (Show, Eq, Bounded, Enum)
|
||||
|
||||
data JClass = JBoolean | JByte | JCharacter | JShort | JInteger | JLong
|
||||
| JFloat | JDouble
|
||||
deriving (Show, Eq, Bounded, Enum)
|
||||
|
||||
data FFIType = SINT8 | UINT8 | SINT16 | UINT16 | SINT32 | UINT32
|
||||
| SINT64 | UINT64 | FLOAT | DOUBLE
|
||||
deriving (Show, Eq, Bounded, Enum)
|
||||
|
||||
widths = [minBound..maxBound] :: [Width]
|
||||
ntypes = [minBound..maxBound] :: [NType]
|
||||
jprims = [minBound..maxBound] :: [JPrim]
|
||||
jclasses = [minBound..maxBound] :: [JClass]
|
||||
ffitypes = [minBound..maxBound] :: [FFIType]
|
||||
|
||||
-- What's the FFIType for a given Width and NType? For example: W32 NBOOL -> SINT8
|
||||
ffitype :: Width -> NType -> FFIType
|
||||
ffitype _ NBOOL = SINT8
|
||||
ffitype _ Nschar = SINT8
|
||||
ffitype _ Nuchar = UINT8
|
||||
ffitype _ Nsshort = SINT16
|
||||
ffitype _ Nushort = UINT16
|
||||
ffitype _ Nsint = SINT32
|
||||
ffitype _ Nuint = UINT32
|
||||
ffitype W32 Nslong = SINT32
|
||||
ffitype W64 Nslong = SINT64
|
||||
ffitype W32 Nulong = UINT32
|
||||
ffitype W64 Nulong = UINT64
|
||||
ffitype _ Nslonglong = SINT64
|
||||
ffitype _ Nulonglong = UINT64
|
||||
ffitype _ Nfloat = FLOAT
|
||||
ffitype _ Ndouble = DOUBLE
|
||||
|
||||
sizeof :: FFIType -> Int
|
||||
sizeof SINT8 = 1
|
||||
sizeof UINT8 = 1
|
||||
sizeof SINT16 = 2
|
||||
sizeof UINT16 = 2
|
||||
sizeof SINT32 = 4
|
||||
sizeof UINT32 = 4
|
||||
sizeof SINT64 = 8
|
||||
sizeof UINT64 = 8
|
||||
sizeof FLOAT = 4
|
||||
sizeof DOUBLE = 8
|
||||
|
||||
-- What's the Obj-C encoding for a given NType? For example: unsigned char -> 'C'
|
||||
encoding nt = fromJust $ lookup nt $
|
||||
[(NBOOL, 'B'), (Nschar, 'c'), (Nuchar, 'C'), (Nsshort, 's'),
|
||||
(Nushort, 'S'), (Nsint, 'i'), (Nuint, 'I'), (Nslong, 'l'),
|
||||
(Nulong, 'L'), (Nslonglong, 'q'), (Nulonglong, 'Q'),
|
||||
(Nfloat, 'f'), (Ndouble, 'd')]
|
||||
|
||||
-- What's the JPrim for a given NType? For example: native signed long long -> java long
|
||||
ntype2jprim nt = fromJust $ lookup nt $
|
||||
[(NBOOL, Jboolean), (Nschar, Jbyte), (Nuchar, Jbyte),
|
||||
(Nsshort, Jshort), (Nushort, Jshort), (Nsint, Jint), (Nuint, Jint),
|
||||
(Nslong, Jlong), (Nulong, Jlong),
|
||||
(Nslonglong, Jlong), (Nulonglong, Jlong),
|
||||
(Nfloat, Jfloat), (Ndouble, Jdouble)]
|
||||
|
||||
-- What's the JClass for a given JPrim? For example: int -> Integer
|
||||
jprim2jclass jp = fromJust $ lookup jp $
|
||||
[(Jboolean, JBoolean), (Jbyte, JByte), (Jchar, JCharacter),
|
||||
(Jshort, JShort), (Jint, JInteger), (Jlong, JLong),
|
||||
(Jfloat, JFloat), (Jdouble, JDouble)]
|
||||
|
||||
-- Convert a type to something suitable for Java code. For example: Jboolean -> boolean
|
||||
ntype2js nt = tail $ show nt
|
||||
jclass2js t = tail $ show t
|
||||
jprim2js p = tail $ show p
|
||||
ffitype2js f = "FFI_" ++ (show f)
|
||||
|
||||
-- Capitalize the first letter of a String
|
||||
capitalize [] = []
|
||||
capitalize s = [toUpper $ head s] ++ tail s
|
||||
|
||||
-- Given an Width and NType, return the Java code for reading said NType from memory.
|
||||
popAddr :: Width -> NType -> String
|
||||
popAddr _ NBOOL = "rt.unsafe.getByte(addr) != 0"
|
||||
popAddr _ Nschar = "rt.unsafe.getByte(addr)"
|
||||
popAddr _ Nuchar = "rt.unsafe.getByte(addr)"
|
||||
popAddr W32 Nslong = "rt.unsafe.getInt(addr)"
|
||||
popAddr W32 Nulong = "rt.unsafe.getInt(addr)"
|
||||
popAddr _ ntype = "rt.unsafe.get" ++ (capitalize.jprim2js.ntype2jprim $ ntype) ++ "(addr)"
|
||||
|
||||
-- Given an Width and NType, return the Java code for writing said NType to memory.
|
||||
pushAddr :: Width -> NType -> String
|
||||
pushAddr _ NBOOL = "rt.unsafe.putByte(addr, (byte) (x ? 1 : 0));"
|
||||
pushAddr _ Nschar = "rt.unsafe.putByte(addr, x);"
|
||||
pushAddr _ Nuchar = "rt.unsafe.putByte(addr, x);"
|
||||
pushAddr W32 Nslong = "rt.unsafe.putInt(addr, (int) x);"
|
||||
pushAddr W32 Nulong = "rt.unsafe.putInt(addr, (int) x);"
|
||||
pushAddr _ ntype = "rt.unsafe.put" ++ (capitalize jprimS) ++ "(addr, (" ++ jprimS ++ ") x);"
|
||||
where jprimS = jprim2js.ntype2jprim $ ntype
|
||||
|
||||
-- Helpers for generating Java ternarnies and conditionals.
|
||||
archExpr x32 x64 = if x32 /= x64 then retdiff else x32
|
||||
where retdiff = "(JObjCRuntime.IS64 ? (" ++ x64 ++ ") : (" ++ x32 ++ "))"
|
||||
|
||||
archStmt x32 x64 = if x32 /= x64 then retdiff else x32
|
||||
where retdiff = "if(JObjCRuntime.IS64){ " ++ x64 ++ " }else{ " ++ x32 ++ " }"
|
||||
|
||||
-- Get a Java expression for the correct FFIType at runtime. For example: (JObjCRuntime.IS64 ? FFI_SINT64 : FFI_SINT32)
|
||||
ffitypeVal nt = archExpr (ffitype2js $ ffitype W32 nt)
|
||||
(ffitype2js $ ffitype W64 nt)
|
||||
|
||||
-- Similar to ffiTypeVal. Get the correct pop expression and push statement.
|
||||
popAddrVal nt = archExpr (popAddr W32 nt) (popAddr W64 nt)
|
||||
pushAddrVal nt = archStmt (pushAddr W32 nt) (pushAddr W64 nt)
|
||||
|
||||
-- What's the Coder class name we're using for a given NType?
|
||||
coderName nt = aux nt ++ "Coder"
|
||||
where
|
||||
aux NBOOL = "Bool"
|
||||
aux Nschar = "SChar"
|
||||
aux Nuchar = "UChar"
|
||||
aux Nsshort = "SShort"
|
||||
aux Nushort = "UShort"
|
||||
aux Nsint = "SInt"
|
||||
aux Nuint = "UInt"
|
||||
aux Nslong = "SLong"
|
||||
aux Nulong = "ULong"
|
||||
aux Nslonglong = "SLongLong"
|
||||
aux Nulonglong = "ULongLong"
|
||||
aux Nfloat = "Float"
|
||||
aux Ndouble = "Double"
|
||||
|
||||
-- Operation for converting between primitives. Usually it just casts, but booleans are special.
|
||||
jconvertPrims sym Jboolean Jboolean = sym
|
||||
jconvertPrims sym Jboolean b = "((" ++ jprim2js b ++ ")(" ++ sym ++ " ? 1 : 0))"
|
||||
jconvertPrims sym a Jboolean = "(" ++ sym ++ " != 0)"
|
||||
jconvertPrims sym a b = if a == b then sym else "((" ++ jprim2js b ++ ")" ++ sym ++ ")"
|
||||
|
||||
sizeofRet nt =
|
||||
let ffitypes = map (\w -> ffitype w nt) widths
|
||||
sizes = map sizeof ffitypes in
|
||||
if (length $ nub sizes) == 1
|
||||
then "\t\treturn " ++ (show.head $ sizes) ++ ";"
|
||||
else unlines [
|
||||
"\t\tswitch(w){",
|
||||
(unlines $ map casestmt widths),
|
||||
"\t\tdefault: return -1;",
|
||||
"\t\t}"]
|
||||
where
|
||||
casestmt w = "\t\t\tcase " ++ (show w) ++ ": return " ++
|
||||
(show.sizeof $ ffitype w nt) ++ ";"
|
||||
|
||||
-- Generate a coder class for a given NType.
|
||||
c2java ntype =
|
||||
unlines [
|
||||
"// native " ++ ntypeS ++ " -> java " ++ jprimS,
|
||||
"public static final class " ++ className ++ " extends PrimitiveCoder<" ++ jclassS ++ ">{",
|
||||
"\tpublic static final " ++ className ++ " INST = new " ++ className ++ "();",
|
||||
"\tpublic " ++ className ++ "(){ super("++ffitypeVal ntype++", \"" ++ [encoding ntype] ++ "\", "++jclassS++".class, "++jprimS++".class); }",
|
||||
"\t// compile time",
|
||||
"\t@Override public void push(JObjCRuntime rt, long addr, " ++ jprimS ++ " x){",
|
||||
"\t\t" ++ pushAddrVal ntype,
|
||||
"\t}",
|
||||
"\t@Override public " ++ jprimS ++ " pop" ++ capitalize jprimS ++ "(JObjCRuntime rt, long addr){",
|
||||
"\t\treturn " ++ popAddrVal ntype ++ ";",
|
||||
"\t}",
|
||||
"\t// for runtime coding",
|
||||
"\t@Override public int sizeof(Width w){",
|
||||
sizeofRet ntype,
|
||||
"\t}",
|
||||
"\t@Override public void push(JObjCRuntime rt, long addr, " ++ jclassS ++ " x){ " ++
|
||||
"push(rt, addr, (" ++ jprimS ++ ") x); }",
|
||||
"\t@Override public " ++ jclassS ++ " pop(JObjCRuntime rt, long addr){ " ++
|
||||
"return pop" ++ capitalize jprimS ++ "(rt, addr); }",
|
||||
"\t// proxies for mixed encoding",
|
||||
makeProxyMethods ntype,
|
||||
"}"
|
||||
]
|
||||
where
|
||||
jprim = ntype2jprim ntype
|
||||
jclass = jprim2jclass jprim
|
||||
jprimS = jprim2js jprim
|
||||
jclassS = jclass2js jclass
|
||||
ntypeS = ntype2js ntype
|
||||
className = coderName ntype
|
||||
|
||||
-- Generate push and pop methods that convert and proxy to actual implementation.
|
||||
makeProxyMethods nt = unlines $ map aux jprims
|
||||
where
|
||||
targetJPrim = ntype2jprim nt
|
||||
targetJPrimS = jprim2js targetJPrim
|
||||
aux jprim = if targetJPrim == jprim then "" else unlines [
|
||||
"\t@Override public void push(JObjCRuntime rt, long addr, " ++ jprimS ++ " x){ " ++
|
||||
"push(rt, addr, " ++ pushConversion "x" ++ "); }",
|
||||
"\t@Override public " ++ jprimS ++ " pop" ++ capitalize jprimS ++ "(JObjCRuntime rt, long addr){ " ++
|
||||
"return " ++ (popConversion ("pop" ++ capitalize targetJPrimS ++ "(rt, addr)")) ++ "; }"
|
||||
]
|
||||
where
|
||||
jprimS = jprim2js jprim
|
||||
pushConversion sym = jconvertPrims sym jprim targetJPrim
|
||||
popConversion sym = jconvertPrims sym targetJPrim jprim
|
||||
|
||||
main = do
|
||||
putStrLn "package com.apple.jobjc;"
|
||||
|
||||
putStrLn "import com.apple.jobjc.JObjCRuntime.Width;"
|
||||
|
||||
putStrLn "// Auto generated by PrimitiveCoder.hs"
|
||||
putStrLn "// Do not edit by hand."
|
||||
|
||||
putStrLn "public abstract class PrimitiveCoder<T> extends Coder<T>{"
|
||||
|
||||
putStrLn "\tpublic PrimitiveCoder(int ffiTypeCode, String objCEncoding, Class jclass, Class jprim){"
|
||||
putStrLn "\t\tsuper(ffiTypeCode, objCEncoding, jclass, jprim);"
|
||||
putStrLn "\t}"
|
||||
|
||||
mapM_ (\p -> putStrLn $ unlines [makePopI p, makePushI p]) jprims
|
||||
|
||||
mapM_ (putStrLn . c2java) ntypes
|
||||
|
||||
putStrLn "}"
|
||||
where
|
||||
makePopI jprim = unlines ["\tpublic final " ++ jprim2js jprim ++ " pop" ++ (capitalize.jprim2js $ jprim)
|
||||
++ "(NativeArgumentBuffer args){\n"
|
||||
++ "\t\treturn pop" ++ (capitalize.jprim2js $ jprim) ++ "(args.runtime, args.retValPtr);\n"
|
||||
++ "\t}",
|
||||
"\tpublic abstract " ++ jprim2js jprim ++ " pop" ++ (capitalize.jprim2js $ jprim) ++ "(JObjCRuntime runtime, long addr);"]
|
||||
makePushI jprim = unlines ["\tpublic final void push"
|
||||
++ "(NativeArgumentBuffer args, " ++ jprim2js jprim ++ " x){\n"
|
||||
++ "\t\tpush(args.runtime, args.argValuesPtr, x);\n"
|
||||
++ "\t\targs.didPutArgValue(sizeof());\n"
|
||||
++ "\t}",
|
||||
"\tpublic abstract void push(JObjCRuntime runtime, long addr, " ++ jprim2js jprim ++ " x);"]
|
||||
@ -1,63 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.apple.jobjc;
|
||||
|
||||
import com.apple.jobjc.Coder.PrimitivePointerCoder;
|
||||
|
||||
class CIF {
|
||||
private static native int getSizeofCIF();
|
||||
private static final int SIZEOF = getSizeofCIF();
|
||||
private static native boolean prepCIF(long cifPtr, int nargs, long retFFITypePtr, long argsPtr);
|
||||
|
||||
public static CIF createCIFFor(final NativeArgumentBuffer args, final Coder returnCoder, final Coder ... argCoders) {
|
||||
NativeBuffer cifBuf = new NativeBuffer(SIZEOF + (argCoders.length * JObjCRuntime.PTR_LEN));
|
||||
final long argsPtr = cifBuf.bufferPtr + SIZEOF;
|
||||
|
||||
{
|
||||
long argsIterPtr = argsPtr;
|
||||
for(final Coder coder : argCoders){
|
||||
PrimitivePointerCoder.INST.push(args.runtime, argsIterPtr, coder.getFFITypePtr());
|
||||
argsIterPtr += JObjCRuntime.PTR_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
boolean ok = prepCIF(cifBuf.bufferPtr, argCoders.length, returnCoder.getFFITypePtr(), argsPtr);
|
||||
if(!ok)
|
||||
throw new RuntimeException("ffi_prep_cif failed.");
|
||||
|
||||
return new CIF(cifBuf, returnCoder, argCoders);
|
||||
}
|
||||
|
||||
final NativeBuffer cif;
|
||||
// CIF needs to keep refs to the Coders, so they don't get finalized and their FFITypes freed.
|
||||
final Coder returnCoder;
|
||||
final Coder[] argCoders;
|
||||
|
||||
private CIF(final NativeBuffer cif, Coder returnCoder, Coder... argCoders) {
|
||||
this.cif = cif;
|
||||
this.returnCoder = returnCoder;
|
||||
this.argCoders = argCoders;
|
||||
}
|
||||
}
|
||||
@ -1,289 +0,0 @@
|
||||
/*
|
||||
* 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 com.apple.jobjc;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import com.apple.jobjc.JObjCRuntime.Width;
|
||||
import com.apple.jobjc.PrimitiveCoder.BoolCoder;
|
||||
import com.apple.jobjc.PrimitiveCoder.DoubleCoder;
|
||||
import com.apple.jobjc.PrimitiveCoder.FloatCoder;
|
||||
import com.apple.jobjc.PrimitiveCoder.SCharCoder;
|
||||
import com.apple.jobjc.PrimitiveCoder.SIntCoder;
|
||||
import com.apple.jobjc.PrimitiveCoder.SLongLongCoder;
|
||||
import com.apple.jobjc.PrimitiveCoder.SShortCoder;
|
||||
|
||||
public abstract class Coder<T> {
|
||||
private static native long getNativeFFITypePtrForCode(final int code);
|
||||
|
||||
static final int FFI_VOID = 0;
|
||||
static final int FFI_PTR = FFI_VOID+1;
|
||||
|
||||
static final int FFI_SINT8 = FFI_PTR+1;
|
||||
static final int FFI_UINT8 = FFI_SINT8+1;
|
||||
static final int FFI_SINT16 = FFI_UINT8+1;
|
||||
static final int FFI_UINT16 = FFI_SINT16+1;
|
||||
static final int FFI_SINT32 = FFI_UINT16+1;
|
||||
static final int FFI_UINT32 = FFI_SINT32+1;
|
||||
static final int FFI_SINT64 = FFI_UINT32+1;
|
||||
static final int FFI_UINT64 = FFI_SINT64+1;
|
||||
|
||||
static final int FFI_FLOAT = FFI_UINT64+1;
|
||||
static final int FFI_DOUBLE = FFI_FLOAT+1;
|
||||
static final int FFI_LONGDOUBLE = FFI_DOUBLE+1;
|
||||
|
||||
private static long[] ffiCodesToFFITypePtrs;
|
||||
static{
|
||||
System.loadLibrary("JObjC");
|
||||
ffiCodesToFFITypePtrs = new long[FFI_LONGDOUBLE + 1];
|
||||
for (int i = 0; i < FFI_LONGDOUBLE + 1; i++) ffiCodesToFFITypePtrs[i] = getNativeFFITypePtrForCode(i);
|
||||
}
|
||||
|
||||
long getFFITypePtr() {
|
||||
return ffiCodesToFFITypePtrs[getTypeCode()];
|
||||
}
|
||||
|
||||
// runtime coding
|
||||
public abstract void push(final JObjCRuntime runtime, final long addr, final T x);
|
||||
public abstract T pop(final JObjCRuntime runtime, final long addr);
|
||||
|
||||
public void push(final NativeArgumentBuffer args, final T x){
|
||||
push(args.runtime, args.argValuesPtr, x);
|
||||
args.didPutArgValue(sizeof());
|
||||
}
|
||||
|
||||
public T pop(final NativeArgumentBuffer args){
|
||||
return pop(args.runtime, args.retValPtr);
|
||||
}
|
||||
|
||||
public abstract int sizeof(Width w);
|
||||
final public int sizeof(){ return sizeof(JObjCRuntime.WIDTH); }
|
||||
|
||||
//
|
||||
|
||||
public Coder(int ffiTypeCode, String objCEncoding, Class jclass, Class jprim) {
|
||||
this.ffiTypeCode = ffiTypeCode;
|
||||
this.objCEncoding = objCEncoding;
|
||||
this.jclass = jclass;
|
||||
this.jprim = jprim;
|
||||
}
|
||||
|
||||
public Coder(int ffiTypeCode, String objCEncoding, Class jclass) {
|
||||
this(ffiTypeCode, objCEncoding, jclass, null);
|
||||
}
|
||||
|
||||
private final int ffiTypeCode;
|
||||
private final String objCEncoding;
|
||||
private final Class jclass;
|
||||
private final Class jprim;
|
||||
|
||||
final int getTypeCode() { return ffiTypeCode; }
|
||||
final String getObjCEncoding(){ return objCEncoding; }
|
||||
public final Class getJavaClass() { return jclass; }
|
||||
public final Class getJavaPrimitive() { return jprim; }
|
||||
|
||||
// runtime coding
|
||||
|
||||
private static Coder[] runtimeCoders;
|
||||
static public Coder getCoderAtRuntimeForType(Class cls){
|
||||
if(runtimeCoders == null) runtimeCoders = new Coder[]{
|
||||
NSClassCoder.INST, IDCoder.INST, PointerCoder.INST,
|
||||
DoubleCoder.INST, FloatCoder.INST, SLongLongCoder.INST,
|
||||
SIntCoder.INST, SShortCoder.INST, SCharCoder.INST, BoolCoder.INST,
|
||||
VoidCoder.INST
|
||||
};
|
||||
|
||||
for(Coder c : runtimeCoders)
|
||||
if((c.getJavaClass() != null && c.getJavaClass().isAssignableFrom(cls)) ||
|
||||
(c.getJavaPrimitive() != null && c.getJavaPrimitive().isAssignableFrom(cls)))
|
||||
return c;
|
||||
|
||||
if(Struct.class.isAssignableFrom(cls)){
|
||||
try {
|
||||
Method m = cls.getDeclaredMethod("getStructCoder");
|
||||
m.setAccessible(true);
|
||||
return (Coder) m.invoke(null);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
throw new RuntimeException("Could not find suitable coder for " + cls);
|
||||
}
|
||||
|
||||
static public Coder getCoderAtRuntime(Object inst){
|
||||
if(inst == null) return PointerCoder.INST;
|
||||
if(inst instanceof Struct) return ((Struct) inst).getCoder();
|
||||
return getCoderAtRuntimeForType(inst.getClass());
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
public static final class VoidCoder extends Coder<Object>{
|
||||
public static final VoidCoder INST = new VoidCoder();
|
||||
public VoidCoder(){ super(FFI_VOID, "v", Void.class, void.class); }
|
||||
@Override public int sizeof(Width w) { return -1; }
|
||||
@Override public Object pop(JObjCRuntime runtime, long addr) { throw new RuntimeException("Trying to pop a Void."); }
|
||||
@Override public void push(JObjCRuntime runtime, long addr, Object x) { throw new RuntimeException("Trying to push a Void."); }
|
||||
}
|
||||
|
||||
public static final class UnknownCoder extends Coder<Object> {
|
||||
public static final UnknownCoder INST = new UnknownCoder();
|
||||
public UnknownCoder(){ super(-1, "?", null, null); }
|
||||
@Override public int sizeof(Width w) { return -1; }
|
||||
@Override public void push(JObjCRuntime runtime, long addr, Object x) { throw new RuntimeException("Coder not implemented");}
|
||||
@Override public Object pop(JObjCRuntime runtime, long addr) { throw new RuntimeException("Coder not implemented"); }
|
||||
}
|
||||
|
||||
public static final class PrimitivePointerCoder extends Coder<Long> {
|
||||
public static final PrimitivePointerCoder INST = new PrimitivePointerCoder();
|
||||
public PrimitivePointerCoder(){ super(Coder.FFI_PTR, "^?", Long.class, long.class); }
|
||||
@Override public int sizeof(Width w) { return JObjCRuntime.PTR_LEN; }
|
||||
|
||||
public void push(JObjCRuntime runtime, long addr, long x) {
|
||||
if(JObjCRuntime.IS64)
|
||||
runtime.unsafe.putLong(addr, x);
|
||||
else
|
||||
runtime.unsafe.putInt(addr, (int) x);
|
||||
}
|
||||
|
||||
public void push(final JObjCRuntime runtime, final NativeArgumentBuffer argBuf, final long ptr) {
|
||||
push(runtime, argBuf.argValuesPtr, ptr);
|
||||
argBuf.didPutArgValue(sizeof());
|
||||
}
|
||||
|
||||
public long popPtr(final JObjCRuntime runtime, final long addr) {
|
||||
return JObjCRuntime.IS64 ? runtime.unsafe.getLong(addr) : runtime.unsafe.getInt(addr);
|
||||
}
|
||||
|
||||
public long popPtr(final JObjCRuntime runtime, final NativeArgumentBuffer argBuf) {
|
||||
return popPtr(runtime, argBuf.retValPtr);
|
||||
}
|
||||
|
||||
@Override public Long pop(JObjCRuntime runtime, long addr) { return popPtr(runtime, addr); }
|
||||
@Override public void push(JObjCRuntime runtime, long addr, Long x) { push(runtime, addr, (long) x); }
|
||||
}
|
||||
|
||||
public static final class PointerCoder extends Coder<Pointer> {
|
||||
public static final PointerCoder INST = new PointerCoder();
|
||||
public PointerCoder(){ super(FFI_PTR, "^?", Pointer.class); }
|
||||
@Override public int sizeof(Width w) { return PrimitivePointerCoder.INST.sizeof(w); }
|
||||
|
||||
@Override public Pointer pop(JObjCRuntime runtime, long addr) {
|
||||
return new Pointer(PrimitivePointerCoder.INST.popPtr(runtime, addr));
|
||||
}
|
||||
@Override public void push(JObjCRuntime runtime, long addr, Pointer x) {
|
||||
PrimitivePointerCoder.INST.push(runtime, addr, x == null ? 0 : x.ptr);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class SELCoder extends Coder<SEL> {
|
||||
public static final SELCoder INST = new SELCoder();
|
||||
public SELCoder(){ super(FFI_PTR, ":", SEL.class); }
|
||||
@Override public int sizeof(Width w) { return PrimitivePointerCoder.INST.sizeof(w); }
|
||||
|
||||
@Override public void push(JObjCRuntime runtime, long addr, SEL x) {
|
||||
PrimitivePointerCoder.INST.push(runtime, addr, x == null ? 0 : x.selPtr);
|
||||
}
|
||||
@Override public SEL pop(JObjCRuntime runtime, long addr) {
|
||||
return new SEL(PrimitivePointerCoder.INST.popPtr(runtime, addr));
|
||||
}
|
||||
}
|
||||
|
||||
public static abstract class StructCoder extends Coder<Struct> {
|
||||
private final FFIType ffiType;
|
||||
final int sizeof;
|
||||
|
||||
public StructCoder(final int sizeof, final Coder... elementCoders){
|
||||
super(-1, objCEncoding(elementCoders), null);
|
||||
this.ffiType = new FFIType(elementCoders);
|
||||
this.sizeof = sizeof;
|
||||
}
|
||||
|
||||
@Override public int sizeof(Width w) { return sizeof; }
|
||||
|
||||
private static String objCEncoding(final Coder[] elementCoders) {
|
||||
StringWriter str = new StringWriter();
|
||||
str.append("{?=");
|
||||
for(Coder c : elementCoders)
|
||||
str.append(c.getObjCEncoding());
|
||||
str.append("}");
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
@Override long getFFITypePtr() { return ffiType.getPtr(); }
|
||||
|
||||
@Override public void push(NativeArgumentBuffer argBuf, Struct x) {
|
||||
// Just point to the instance on the heap instead of copying it onto the arg buf.
|
||||
argBuf.doPutArgPtr(x.raw.bufferPtr);
|
||||
}
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, Struct x) {
|
||||
rt.unsafe.copyMemory(x.raw.bufferPtr, addr, sizeof);
|
||||
}
|
||||
|
||||
protected abstract Struct newInstance(JObjCRuntime runtime);
|
||||
|
||||
@Override public Struct pop(final JObjCRuntime runtime, final long addr) {
|
||||
Struct s = newInstance(runtime);
|
||||
runtime.unsafe.copyMemory(addr, s.raw.bufferPtr, sizeof);
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class IDCoder extends Coder<ID>{
|
||||
public static final IDCoder INST = new IDCoder();
|
||||
public IDCoder(){ super(FFI_PTR, "@", ID.class); }
|
||||
@Override public int sizeof(Width w) { return PrimitivePointerCoder.INST.sizeof(w); }
|
||||
|
||||
public <T extends ID> T newID(final JObjCRuntime runtime, final long objPtr) {
|
||||
return (T) ID.getObjCObjectFor(runtime, objPtr);
|
||||
}
|
||||
|
||||
@Override public ID pop(final JObjCRuntime runtime, final long addr) {
|
||||
return newID(runtime, PrimitivePointerCoder.INST.popPtr(runtime, addr));
|
||||
}
|
||||
|
||||
@Override public void push(final JObjCRuntime runtime, final long addr, final ID x) {
|
||||
PointerCoder.INST.push(runtime, addr, x);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class NSClassCoder extends Coder<NSClass>{
|
||||
public static final NSClassCoder INST = new NSClassCoder();
|
||||
public NSClassCoder(){ super(FFI_PTR, "#", NSClass.class); }
|
||||
@Override public int sizeof(Width w) { return PrimitivePointerCoder.INST.sizeof(w); }
|
||||
|
||||
@Override public NSClass pop(JObjCRuntime runtime, long addr) {
|
||||
final long clsPtr = PrimitivePointerCoder.INST.popPtr(runtime, addr);
|
||||
if (clsPtr == 0) return null;
|
||||
return NSClass.getObjCClassFor(runtime, clsPtr);
|
||||
}
|
||||
@Override public void push(JObjCRuntime runtime, long addr, NSClass x) {
|
||||
PointerCoder.INST.push(runtime, addr, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,57 +0,0 @@
|
||||
/*
|
||||
* 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 com.apple.jobjc;
|
||||
|
||||
import com.apple.jobjc.Coder.PrimitivePointerCoder;
|
||||
|
||||
|
||||
class FFIType{
|
||||
private static native void makeFFIType(long ffi_type_buf, long elements_buf);
|
||||
private static native int getFFITypeSizeof();
|
||||
private static int FFI_TYPE_SIZEOF = getFFITypeSizeof();
|
||||
final NativeBuffer ffi_type;
|
||||
final NativeBuffer elements;
|
||||
final Coder[] elementCoders;
|
||||
|
||||
public FFIType(final Coder... elementCoders){
|
||||
final JObjCRuntime runtime = JObjCRuntime.inst();
|
||||
this.elementCoders = elementCoders;
|
||||
this.ffi_type = new NativeBuffer(FFI_TYPE_SIZEOF);
|
||||
this.elements = new NativeBuffer(JObjCRuntime.PTR_LEN * (elementCoders.length + 1));
|
||||
|
||||
long elIterPtr = elements.bufferPtr;
|
||||
for(Coder c : elementCoders){
|
||||
PrimitivePointerCoder.INST.push(runtime, elIterPtr, c.getFFITypePtr());
|
||||
elIterPtr += PrimitivePointerCoder.INST.sizeof();
|
||||
}
|
||||
PrimitivePointerCoder.INST.push(runtime, elIterPtr, 0);
|
||||
|
||||
makeFFIType(ffi_type.bufferPtr, elements.bufferPtr);
|
||||
}
|
||||
|
||||
public long getPtr(){
|
||||
return ffi_type.bufferPtr;
|
||||
}
|
||||
}
|
||||
@ -1,60 +0,0 @@
|
||||
/*
|
||||
* 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 com.apple.jobjc;
|
||||
|
||||
|
||||
public class Function {
|
||||
private static native long getFxnPtrForFunctionName(final String functionName);
|
||||
private static native long getFxnPtrForFunctionNameAndLib(final long libPtr, final String functionName);
|
||||
|
||||
final long fxnPtr;
|
||||
|
||||
Function(final long fxnPtr) {
|
||||
this.fxnPtr = fxnPtr;
|
||||
}
|
||||
|
||||
public Function(final String name) {
|
||||
this(getFxnPtr(name));
|
||||
}
|
||||
|
||||
public Function(final MacOSXFramework framework, final String name) {
|
||||
this(getFxnPtr(name, framework));
|
||||
}
|
||||
|
||||
static long getFxnPtr(final String name){
|
||||
long fxnPtr = getFxnPtrForFunctionName(name);
|
||||
if(fxnPtr == 0) throw new RuntimeException("Function pointer for " + name + " not found in runtime.");
|
||||
return fxnPtr;
|
||||
}
|
||||
|
||||
static long getFxnPtr(final String name, final MacOSXFramework framework){
|
||||
long fxnPtr = 0;
|
||||
for(int i = 0; fxnPtr == 0 && i < framework.nativeLibPtrs.length; i++){
|
||||
fxnPtr = getFxnPtrForFunctionNameAndLib(framework.nativeLibPtrs[i], name);
|
||||
if(fxnPtr != 0) return fxnPtr;
|
||||
}
|
||||
throw new RuntimeException("Function pointer for " + name + " not found in framework " + framework + ".");
|
||||
}
|
||||
}
|
||||
@ -1,163 +0,0 @@
|
||||
/*
|
||||
* 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 com.apple.jobjc;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class ID extends Pointer<Void>{
|
||||
static native String getNativeDescription(final long objPtr);
|
||||
|
||||
final JObjCRuntime runtime;
|
||||
|
||||
static final Class[] CTOR_ARGS = { long.class, JObjCRuntime.class };
|
||||
protected ID(final long objPtr, final JObjCRuntime runtime) {
|
||||
super(objPtr);
|
||||
runtime.assertOK();
|
||||
this.runtime = runtime;
|
||||
}
|
||||
|
||||
protected ID(final ID obj, final JObjCRuntime runtime) {
|
||||
this(obj.ptr, runtime);
|
||||
}
|
||||
|
||||
@Override protected NativeObjectLifecycleManager getNativeObjectLifecycleManager() {
|
||||
return NativeObjectLifecycleManager.CFRetainRelease.INST;
|
||||
}
|
||||
|
||||
protected final JObjCRuntime getRuntime() { return runtime; }
|
||||
|
||||
@Override public String toString(){
|
||||
String s = super.toString();
|
||||
return s + " (ObjC: " + ptr + " / " + Long.toHexString(ptr) + ")";
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
public static <T extends ID> T getInstance(final long ptr, final JObjCRuntime runtime){
|
||||
return (T) getObjCObjectFor(runtime, ptr);
|
||||
}
|
||||
|
||||
static <T extends ID> T getObjCObjectFor(final JObjCRuntime runtime, final long objPtr){
|
||||
if (objPtr == 0) return null;
|
||||
|
||||
final WeakReference cachedObj = objectCache.get().get(objPtr);
|
||||
if(cachedObj != null && cachedObj.get() != null) return (T) cachedObj.get();
|
||||
|
||||
final long clsPtr = NSClass.getClass(objPtr);
|
||||
|
||||
final T newObj = (T) (runtime.subclassing.isUserClass(clsPtr) ?
|
||||
Subclassing.getJObjectFromIVar(objPtr)
|
||||
: createNewObjCObjectFor(runtime, objPtr, clsPtr));
|
||||
|
||||
objectCache.get().put(objPtr, new WeakReference(newObj));
|
||||
return newObj;
|
||||
}
|
||||
|
||||
static <T extends ID> T createNewObjCObjectFor(final JObjCRuntime runtime, final long objPtr, final long clsPtr) {
|
||||
final Constructor<T> ctor = getConstructorForClassPtr(runtime, clsPtr);
|
||||
return (T) createNewObjCObjectForConstructor(ctor, objPtr, runtime);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static <T extends ID> Constructor<T> getConstructorForClassPtr(final JObjCRuntime runtime, final long clazzPtr){
|
||||
final Constructor<T> cachedCtor = (Constructor<T>) constructorCache.get().get(clazzPtr);
|
||||
if(cachedCtor != null) return cachedCtor;
|
||||
|
||||
final Class<T> clazz = getClassForClassPtr(runtime, clazzPtr);
|
||||
Constructor<T> ctor;
|
||||
try {
|
||||
ctor = clazz.getDeclaredConstructor(CTOR_ARGS);
|
||||
} catch (SecurityException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
ctor.setAccessible(true);
|
||||
constructorCache.get().put(clazzPtr, (Constructor<ID>) ctor);
|
||||
return ctor;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static <T extends ID> Class<T> getClassForClassPtr(final JObjCRuntime runtime, final long clazzPtr){
|
||||
final String className = NSClass.getClassNameOfClass(clazzPtr);
|
||||
final Class<T> clazz = (Class<T>) runtime.getClassForNativeClassName(className);
|
||||
if(clazz == null){
|
||||
final long superClazzPtr = NSClass.getSuperClassOfClass(clazzPtr);
|
||||
if(superClazzPtr != 0)
|
||||
return getClassForClassPtr(runtime, superClazzPtr);
|
||||
}
|
||||
return clazz;
|
||||
}
|
||||
|
||||
static <T extends ID> T createNewObjCObjectForConstructor(final Constructor ctor, final long objPtr, final JObjCRuntime runtime) {
|
||||
try {
|
||||
final T newInstance = (T) ctor.newInstance(new Object[] { Long.valueOf(objPtr), runtime });
|
||||
objectCache.get().put(objPtr, new WeakReference(newInstance));
|
||||
return newInstance;
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
static <T extends ID> T createNewObjCObjectForClass(final Class<T> clazz, final long objPtr, final JObjCRuntime runtime) {
|
||||
try {
|
||||
final Constructor<T> constructor = clazz.getDeclaredConstructor(CTOR_ARGS);
|
||||
constructor.setAccessible(true);
|
||||
return (T) createNewObjCObjectForConstructor(constructor, objPtr, runtime);
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
static final ThreadLocal<LinkedHashMap<Long, Constructor>> constructorCache = new ThreadLocal<LinkedHashMap<Long, Constructor>>(){
|
||||
@Override protected LinkedHashMap<Long, Constructor> initialValue(){
|
||||
final int MAX_ENTRIES = 1000;
|
||||
final float LOAD_FACTOR = 0.75f;
|
||||
return new LinkedHashMap<Long, Constructor>((int) (MAX_ENTRIES/LOAD_FACTOR), LOAD_FACTOR, true) {
|
||||
@Override protected boolean removeEldestEntry(Map.Entry<Long, Constructor> eldest) {
|
||||
return size() > MAX_ENTRIES;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
static final ThreadLocal<LinkedHashMap<Long, WeakReference>> objectCache = new ThreadLocal<LinkedHashMap<Long, WeakReference>>(){
|
||||
@Override protected LinkedHashMap<Long, WeakReference> initialValue(){
|
||||
final int MAX_ENTRIES = 1000;
|
||||
final float LOAD_FACTOR = 0.75f;
|
||||
return new LinkedHashMap<Long, WeakReference>((int) (MAX_ENTRIES/LOAD_FACTOR), LOAD_FACTOR, true) {
|
||||
@Override protected boolean removeEldestEntry(Map.Entry<Long, WeakReference> eldest) {
|
||||
return size() > MAX_ENTRIES || eldest.getValue().get() == null;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -1,224 +0,0 @@
|
||||
/*
|
||||
* 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 com.apple.jobjc;
|
||||
|
||||
import com.apple.jobjc.Coder.IDCoder;
|
||||
import com.apple.jobjc.Coder.NSClassCoder;
|
||||
import com.apple.jobjc.Coder.PrimitivePointerCoder;
|
||||
import com.apple.jobjc.Coder.SELCoder;
|
||||
import com.apple.jobjc.Coder.StructCoder;
|
||||
|
||||
|
||||
public abstract class Invoke {
|
||||
public abstract void invoke(NativeArgumentBuffer argBuf);
|
||||
public abstract void invoke(NativeArgumentBuffer buffer, Struct retvalStruct);
|
||||
|
||||
//
|
||||
|
||||
public static final class FunCall extends Invoke{
|
||||
static native void invoke(long cifPtr, long fxnPtr, long retValPtr, long argsPtr);
|
||||
|
||||
final long fxnPtr;
|
||||
final CIF cif;
|
||||
|
||||
FunCall(long fxnPtr, CIF cif) {
|
||||
this.fxnPtr = fxnPtr;
|
||||
this.cif = cif;
|
||||
}
|
||||
|
||||
public FunCall(final JObjCRuntime runtime, final String name, final Coder returnCoder, final Coder ... argCoders) {
|
||||
this(Function.getFxnPtr(name), CIF.createCIFFor(runtime.getThreadLocalState(), returnCoder, argCoders));
|
||||
}
|
||||
|
||||
public FunCall(final MacOSXFramework framework, final String name, final Coder returnCoder, final Coder ... argCoders) {
|
||||
this(Function.getFxnPtr(name, framework), CIF.createCIFFor(framework.getRuntime().getThreadLocalState(), returnCoder, argCoders));
|
||||
}
|
||||
|
||||
public void init(final NativeArgumentBuffer argBuf) {
|
||||
argBuf.reset();
|
||||
}
|
||||
|
||||
@Override public void invoke(final NativeArgumentBuffer argBuf) {
|
||||
invoke(argBuf, argBuf.retValPtr);
|
||||
}
|
||||
|
||||
@Override public void invoke(final NativeArgumentBuffer buffer, final Struct retvalStruct) {
|
||||
invoke(buffer, retvalStruct.raw.bufferPtr);
|
||||
}
|
||||
|
||||
void invoke(final NativeArgumentBuffer argBuf, final long retValPtr) {
|
||||
invoke(cif.cif.bufferPtr, fxnPtr, retValPtr, argBuf.buffer.bufferPtr);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class MsgSend extends Invoke{
|
||||
static{ System.load("/usr/lib/libobjc.dylib"); }
|
||||
|
||||
private static final long OBJC_MSG_SEND_FXN_PTR = new Function("objc_msgSend").fxnPtr;
|
||||
private static final long OBJC_MSG_SEND_FPRET_FXN_PTR = new Function("objc_msgSend_fpret").fxnPtr;
|
||||
private static final long OBJC_MSG_SEND_STRET_FXN_PTR = new Function("objc_msgSend_stret").fxnPtr;
|
||||
|
||||
final FunCall funCall;
|
||||
final long selPtr;
|
||||
|
||||
public MsgSend(final JObjCRuntime runtime, final String name, final Coder returnCoder, final Coder ... argCoders) {
|
||||
this.funCall = new FunCall(getMsgSendFxnPtr(returnCoder),
|
||||
CIF.createCIFFor(runtime.getThreadLocalState(), returnCoder, getSelCoders(argCoders)));
|
||||
this.selPtr = SEL.getSelectorPtr(name);
|
||||
}
|
||||
|
||||
public void init(final NativeArgumentBuffer nativeBuffer, final ID obj) {
|
||||
funCall.init(nativeBuffer);
|
||||
IDCoder.INST.push(nativeBuffer, obj);
|
||||
PrimitivePointerCoder.INST.push(nativeBuffer.runtime, nativeBuffer, selPtr);
|
||||
}
|
||||
|
||||
@Override public void invoke(final NativeArgumentBuffer argBuf) {
|
||||
funCall.invoke(argBuf);
|
||||
}
|
||||
|
||||
@Override public void invoke(final NativeArgumentBuffer buffer, final Struct retvalStruct) {
|
||||
funCall.invoke(buffer, retvalStruct);
|
||||
}
|
||||
|
||||
// support
|
||||
|
||||
static Coder[] getSelCoders(final Coder[] argCoders) {
|
||||
final Coder[] selArgCoders = new Coder[argCoders.length + 2];
|
||||
selArgCoders[0] = IDCoder.INST;
|
||||
selArgCoders[1] = SELCoder.INST;
|
||||
for (int i = 0; i < argCoders.length; i++)
|
||||
selArgCoders[i + 2] = argCoders[i];
|
||||
return selArgCoders;
|
||||
}
|
||||
|
||||
static long getMsgSendFxnPtr(final Coder returnCoder) {
|
||||
if(returnCoder instanceof StructCoder){
|
||||
StructCoder scoder = (StructCoder) returnCoder;
|
||||
|
||||
switch(JObjCRuntime.ARCH){
|
||||
case ppc:
|
||||
return OBJC_MSG_SEND_STRET_FXN_PTR;
|
||||
case i386:
|
||||
switch(scoder.sizeof){
|
||||
case 1: case 2: case 4: case 8:
|
||||
return OBJC_MSG_SEND_FXN_PTR;
|
||||
}
|
||||
return OBJC_MSG_SEND_STRET_FXN_PTR;
|
||||
case x86_64:
|
||||
if(scoder.sizeof > 16)
|
||||
return OBJC_MSG_SEND_STRET_FXN_PTR;
|
||||
else
|
||||
return OBJC_MSG_SEND_FXN_PTR;
|
||||
default:
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
final int typeCode = returnCoder.getTypeCode();
|
||||
|
||||
switch(JObjCRuntime.ARCH){
|
||||
case ppc:
|
||||
return OBJC_MSG_SEND_FXN_PTR;
|
||||
case i386:
|
||||
switch(typeCode) {
|
||||
case Coder.FFI_FLOAT: case Coder.FFI_DOUBLE: case Coder.FFI_LONGDOUBLE:
|
||||
return OBJC_MSG_SEND_FPRET_FXN_PTR;
|
||||
}
|
||||
return OBJC_MSG_SEND_FXN_PTR;
|
||||
case x86_64:
|
||||
if(typeCode == Coder.FFI_LONGDOUBLE)
|
||||
return OBJC_MSG_SEND_FPRET_FXN_PTR;
|
||||
return OBJC_MSG_SEND_FXN_PTR;
|
||||
default:
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final class MsgSendSuper extends Invoke{
|
||||
static{ System.load("/usr/lib/libobjc.dylib"); }
|
||||
|
||||
private static final long OBJC_MSG_SEND_SUPER_FXN_PTR = new Function("objc_msgSendSuper").fxnPtr;
|
||||
private static final long OBJC_MSG_SEND_SUPER_STRET_FXN_PTR = new Function("objc_msgSendSuper_stret").fxnPtr;
|
||||
|
||||
final FunCall funCall;
|
||||
final long selPtr;
|
||||
|
||||
public MsgSendSuper(final JObjCRuntime runtime, final String name, final Coder returnCoder, final Coder ... argCoders) {
|
||||
this.funCall = new FunCall(getMsgSendSuperFxnPtr(returnCoder),
|
||||
CIF.createCIFFor(runtime.getThreadLocalState(), returnCoder, getSuperSelCoders(argCoders)));
|
||||
this.selPtr = SEL.getSelectorPtr(name);
|
||||
}
|
||||
|
||||
public void init(final NativeArgumentBuffer argBuf, final ID obj, final NSClass cls) {
|
||||
funCall.init(argBuf);
|
||||
|
||||
// Instead of mallocing a struct, or keeping another thread local,
|
||||
// let's write objc_super out to the argbuf, and then point an argument
|
||||
// to the data.
|
||||
|
||||
final long valPtr = argBuf.argValuesPtr;
|
||||
final int ptrLen = JObjCRuntime.PTR_LEN;
|
||||
|
||||
IDCoder .INST.push(argBuf.runtime, valPtr, obj);
|
||||
NSClassCoder.INST.push(argBuf.runtime, valPtr + ptrLen, cls);
|
||||
argBuf.argValuesPtr += ptrLen + ptrLen;
|
||||
|
||||
PrimitivePointerCoder.INST.push(argBuf.runtime, argBuf, valPtr);
|
||||
PrimitivePointerCoder.INST.push(argBuf.runtime, argBuf, selPtr);
|
||||
}
|
||||
|
||||
@Override public void invoke(final NativeArgumentBuffer argBuf) {
|
||||
funCall.invoke(argBuf);
|
||||
}
|
||||
|
||||
@Override public void invoke(final NativeArgumentBuffer buffer, final Struct retvalStruct) {
|
||||
funCall.invoke(buffer, retvalStruct);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
private final static StructCoder objc_super_coder = new StructCoder(JObjCRuntime.PTR_LEN*2, IDCoder.INST, NSClassCoder.INST){
|
||||
@Override protected Struct newInstance(JObjCRuntime runtime) { return null; }};
|
||||
|
||||
static Coder[] getSuperSelCoders(final Coder[] argCoders) {
|
||||
final Coder[] selArgCoders = new Coder[argCoders.length + 2];
|
||||
selArgCoders[0] = objc_super_coder;
|
||||
selArgCoders[1] = SELCoder.INST;
|
||||
for (int i = 0; i < argCoders.length; i++)
|
||||
selArgCoders[i + 2] = argCoders[i];
|
||||
return selArgCoders;
|
||||
}
|
||||
|
||||
static long getMsgSendSuperFxnPtr(final Coder returnCoder){
|
||||
long normal = MsgSend.getMsgSendFxnPtr(returnCoder);
|
||||
if(normal == MsgSend.OBJC_MSG_SEND_STRET_FXN_PTR)
|
||||
return OBJC_MSG_SEND_SUPER_STRET_FXN_PTR;
|
||||
else
|
||||
return OBJC_MSG_SEND_SUPER_FXN_PTR;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,139 +0,0 @@
|
||||
/*
|
||||
* 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 com.apple.jobjc;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
|
||||
public final class JObjCRuntime {
|
||||
static { System.loadLibrary("JObjC"); }
|
||||
|
||||
public static enum Arch{ ppc, i386, x86_64 };
|
||||
public static enum Width{ W32, W64 };
|
||||
|
||||
public static final Arch ARCH = getArch();
|
||||
public static final Width WIDTH = getWidth();
|
||||
|
||||
private static Arch getArch(){
|
||||
String arch = System.getProperty("os.arch");
|
||||
if("ppc".equals(arch)) return Arch.ppc;
|
||||
if("i386".equals(arch)) return Arch.i386;
|
||||
if("x86_64".equals(arch)) return Arch.x86_64;
|
||||
if("amd64".equals(arch)) return Arch.x86_64;
|
||||
if("universal".equals(arch)) return Arch.x86_64;
|
||||
throw new RuntimeException("Did not recognize os.arch system property: '" + arch + "'");
|
||||
}
|
||||
|
||||
private static Width getWidth(){
|
||||
String width = System.getProperty("sun.arch.data.model");
|
||||
if("32".equals(width)) return Width.W32;
|
||||
if("64".equals(width)) return Width.W64;
|
||||
throw new RuntimeException("Did not recognize sun.arch.data.model system property: '" + width + "'");
|
||||
}
|
||||
|
||||
public static final boolean IS32 = System.getProperty("sun.arch.data.model").equals("32");
|
||||
public static final boolean IS64 = System.getProperty("sun.arch.data.model").equals("64");
|
||||
public static final int PTR_LEN = IS64 ? 8 : 4;
|
||||
public static final boolean IS_BIG_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
|
||||
static final boolean DEBUG = Boolean.parseBoolean(System.getProperty("JObjC.debug"));
|
||||
|
||||
static void checkPermission(){
|
||||
final SecurityManager security = System.getSecurityManager();
|
||||
if (security != null) security.checkPermission(new RuntimePermission("canProcessApplicationEvents"));
|
||||
}
|
||||
|
||||
public final void assertOK(){
|
||||
if(this != instance)
|
||||
throw new SecurityException("runtime");
|
||||
}
|
||||
|
||||
private JObjCRuntime(){}
|
||||
|
||||
private static JObjCRuntime instance;
|
||||
static JObjCRuntime inst() {
|
||||
if (instance == null) instance = new JObjCRuntime();
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static JObjCRuntime getInstance() {
|
||||
checkPermission();
|
||||
return inst();
|
||||
}
|
||||
|
||||
public final NativeArgumentBuffer getThreadLocalState() {
|
||||
return NativeArgumentBuffer.getThreadLocalBuffer(this);
|
||||
}
|
||||
|
||||
final Unsafe unsafe = getUnsafe();
|
||||
final Subclassing subclassing = new Subclassing(this);
|
||||
final List<String> registeredPackages = new ArrayList<String>();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends ID> getClassForNativeClassName(final String className) {
|
||||
for (final String pkg : registeredPackages) {
|
||||
try {
|
||||
final Class<?> clazz = Class.forName(pkg + "." + className);
|
||||
if (clazz != null) return (Class<? extends ID>)clazz;
|
||||
} catch (final ClassNotFoundException e) { }
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private final static Unsafe getUnsafe() {
|
||||
Unsafe inst = null;
|
||||
try {
|
||||
Field f = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
f.setAccessible(true);
|
||||
inst = (Unsafe) f.get(null);
|
||||
if(inst == null) throw new NullPointerException("Unsafe.theUnsafe == null");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Unable to get instance of Unsafe.", e);
|
||||
}
|
||||
return inst;
|
||||
}
|
||||
|
||||
public void registerPackage(final String pkg) {
|
||||
registeredPackages.add(pkg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a subclass of NSObject to allow the native side to send
|
||||
* messages which in turn call java methods declared on the class.
|
||||
* If a native class by the same name already exists, registerClass
|
||||
* will simply return without doing anything.
|
||||
*
|
||||
* For a usage example, see the SubclassingTest.
|
||||
*/
|
||||
public boolean registerUserClass(Class<? extends ID> clazz, Class<? extends NSClass> clazzClazz) {
|
||||
return subclassing.registerUserClass(clazz, clazzClazz);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,74 +0,0 @@
|
||||
/*
|
||||
* 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 com.apple.jobjc;
|
||||
|
||||
|
||||
|
||||
public class MacOSXFramework {
|
||||
private static native long retainFramework(final String frameworkName);
|
||||
private static native void releaseFramework(final long frameworkPtr);
|
||||
private static native void getConstant(final long frameworkPtr, String symbol, final long bufferPtr, final int size);
|
||||
|
||||
private final JObjCRuntime runtime;
|
||||
protected final long[] nativeLibPtrs;
|
||||
|
||||
final long getFrameworkPtr() { return nativeLibPtrs.length > 0 ? nativeLibPtrs[0] : 0; }
|
||||
|
||||
private static long[] createFrameworkPtrsFromPaths(final String[] frameworkLibPaths) {
|
||||
final long[] libPtrs = new long[frameworkLibPaths.length];
|
||||
for(int i = 0; i < libPtrs.length; i++){
|
||||
libPtrs[i] = retainFramework(frameworkLibPaths[i]);
|
||||
if(libPtrs[i] == 0) throw new RuntimeException("Could not open library at " + frameworkLibPaths[i]);
|
||||
}
|
||||
return libPtrs;
|
||||
}
|
||||
|
||||
protected MacOSXFramework(final JObjCRuntime runtime, final String[] nativeLibPaths) {
|
||||
runtime.assertOK();
|
||||
this.runtime = runtime;
|
||||
this.nativeLibPtrs = createFrameworkPtrsFromPaths(nativeLibPaths);
|
||||
}
|
||||
|
||||
@Override protected final synchronized void finalize() throws Throwable {
|
||||
for(long lib : nativeLibPtrs)
|
||||
if(lib != 0) releaseFramework(lib);
|
||||
}
|
||||
|
||||
protected final JObjCRuntime getRuntime(){ return runtime; }
|
||||
|
||||
protected void getConstant(final String symbol, final long retValPtr, final int size){
|
||||
assert size >= 0;
|
||||
assert retValPtr != 0;
|
||||
getConstant(getFrameworkPtr(), symbol, retValPtr, size);
|
||||
}
|
||||
|
||||
protected void getConstant(final String symbol, final NativeArgumentBuffer out, final int size){
|
||||
getConstant(symbol, out.retValPtr, size);
|
||||
}
|
||||
|
||||
protected void getConstant(final String symbol, final Struct out, final int size){
|
||||
getConstant(symbol, out.raw.bufferPtr, size);
|
||||
}
|
||||
}
|
||||
@ -1,117 +0,0 @@
|
||||
/*
|
||||
* 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 com.apple.jobjc;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
|
||||
public class NSClass<T extends ID> extends ID {
|
||||
public static class NSClassNotFoundException extends RuntimeException{
|
||||
public NSClassNotFoundException(String m){ super(m); }
|
||||
public NSClassNotFoundException(String m, Throwable cause){ super(m, cause); }
|
||||
}
|
||||
|
||||
static native long getNativeClassByName(String name);
|
||||
static native long getSuperClassOfClass(long classPtr);
|
||||
static native String getClassNameOfClass(long classPtr);
|
||||
static native long getClass(long objPtr);
|
||||
|
||||
public NSClass(final long ptr, final JObjCRuntime runtime) {
|
||||
super(ptr, runtime);
|
||||
}
|
||||
|
||||
public NSClass(final String name, final JObjCRuntime runtime) {
|
||||
this(getNativeClassByName(name), runtime);
|
||||
if(ptr == 0) throw new NSClassNotFoundException("NSClass pointer is 0. Found no class named " + name);
|
||||
}
|
||||
|
||||
protected NSClass(final JObjCRuntime runtime){
|
||||
super(0, runtime);
|
||||
final String sn = getClass().getSimpleName();
|
||||
final String name = sn.substring(0, sn.lastIndexOf("Class"));
|
||||
ptr = getNativeClassByName(name);
|
||||
if(ptr == 0) throw new NSClassNotFoundException("NSClass pointer is 0. Found no class named " + name);
|
||||
}
|
||||
|
||||
NSClass<? super T> getSuperClass() {
|
||||
return new NSClass<T>(getSuperClassOfClass(ptr), runtime);
|
||||
}
|
||||
|
||||
String getClassName() { return getClassNameOfClass(ptr); }
|
||||
|
||||
@Override protected NativeObjectLifecycleManager getNativeObjectLifecycleManager() {
|
||||
return NativeObjectLifecycleManager.Nothing.INST;
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object o){
|
||||
return (o instanceof NSClass) && (this.ptr == ((NSClass) o).ptr);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
static <T extends NSClass> T getObjCClassFor(final JObjCRuntime runtime, final long clsPtr){
|
||||
if (clsPtr == 0) return null;
|
||||
|
||||
final WeakReference cachedObj = objectCache.get().get(clsPtr);
|
||||
if(cachedObj != null && cachedObj.get() != null) return (T) cachedObj.get();
|
||||
|
||||
final T newObj = (T) createNewObjCClassFor(runtime, clsPtr);
|
||||
objectCache.get().put(clsPtr, new WeakReference(newObj));
|
||||
return newObj;
|
||||
}
|
||||
|
||||
static <T extends NSClass> T createNewObjCClassFor(final JObjCRuntime runtime, final long clsPtr) {
|
||||
final Constructor<T> ctor = getNSClassConstructorForClassPtr(runtime, clsPtr);
|
||||
return (T) createNewObjCObjectForConstructor(ctor, clsPtr, runtime);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static <T extends NSClass> Constructor<T> getNSClassConstructorForClassPtr(final JObjCRuntime runtime, final long clazzPtr){
|
||||
final Class<T> clazz = getNSClassForClassPtr(runtime, clazzPtr);
|
||||
Constructor<T> ctor;
|
||||
try {
|
||||
ctor = clazz.getDeclaredConstructor(CTOR_ARGS);
|
||||
} catch (SecurityException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
ctor.setAccessible(true);
|
||||
return ctor;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static <T extends ID> Class<T> getNSClassForClassPtr(final JObjCRuntime runtime, final long clazzPtr){
|
||||
final String className = NSClass.getClassNameOfClass(clazzPtr);
|
||||
final Class<T> clazz = (Class<T>) runtime.getClassForNativeClassName(className + "Class");
|
||||
if(clazz == null){
|
||||
final long superClazzPtr = NSClass.getSuperClassOfClass(clazzPtr);
|
||||
if(superClazzPtr != 0)
|
||||
return getNSClassForClassPtr(runtime, superClazzPtr);
|
||||
}
|
||||
return clazz;
|
||||
}
|
||||
}
|
||||
@ -1,112 +0,0 @@
|
||||
/*
|
||||
* 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 com.apple.jobjc;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import com.apple.jobjc.Coder.PrimitivePointerCoder;
|
||||
|
||||
|
||||
public final class NativeArgumentBuffer{
|
||||
private static final ThreadLocal<NativeArgumentBuffer> threadLocal = new ThreadLocal<NativeArgumentBuffer>();
|
||||
|
||||
static NativeArgumentBuffer getThreadLocalBuffer(final JObjCRuntime runtime) {
|
||||
runtime.assertOK();
|
||||
final NativeArgumentBuffer alreadyCreated = threadLocal.get();
|
||||
if (alreadyCreated != null) return alreadyCreated;
|
||||
|
||||
final NativeArgumentBuffer newThreadLocalState = new NativeArgumentBuffer(runtime);
|
||||
threadLocal.set(newThreadLocalState);
|
||||
return newThreadLocalState;
|
||||
}
|
||||
|
||||
final JObjCRuntime runtime;
|
||||
|
||||
final NativeBuffer buffer;
|
||||
|
||||
long argPtrsPtr;
|
||||
long argValuesPtr;
|
||||
final long retValPtr;
|
||||
|
||||
private static final int MAX_ARGS = 512;
|
||||
private static final int BUF_SIZE = MAX_ARGS * 8 * 2;
|
||||
private static final int ARG_VALS_OFFSET = BUF_SIZE/2;
|
||||
|
||||
private NativeArgumentBuffer(final JObjCRuntime runtime) {
|
||||
runtime.assertOK();
|
||||
this.runtime = runtime;
|
||||
this.buffer = new NativeBuffer(BUF_SIZE);
|
||||
this.buffer.buffer.order(ByteOrder.nativeOrder());
|
||||
|
||||
reset();
|
||||
this.retValPtr = buffer.bufferPtr;
|
||||
}
|
||||
|
||||
|
||||
// Call before each new call
|
||||
public void reset() {
|
||||
argPtrsPtr = buffer.bufferPtr;
|
||||
argValuesPtr = buffer.bufferPtr + ARG_VALS_OFFSET;
|
||||
assert buffer.ptrInBounds(argValuesPtr);
|
||||
}
|
||||
|
||||
// Push a pointer to a block of memory
|
||||
public void doPutArgPtr(long ptr) {
|
||||
assert buffer.ptrInBounds(argPtrsPtr);
|
||||
PrimitivePointerCoder.INST.push(runtime, argPtrsPtr, ptr);
|
||||
argPtrsPtr += JObjCRuntime.PTR_LEN;
|
||||
}
|
||||
|
||||
// Call this after having written a value of size `sizeof` to `argValuesPtr`.
|
||||
public void didPutArgValue(int sizeof) {
|
||||
assert buffer.ptrInBounds(argValuesPtr);
|
||||
doPutArgPtr(argValuesPtr);
|
||||
argValuesPtr += sizeof;
|
||||
}
|
||||
|
||||
|
||||
@Override public String toString() {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
final long bptr = buffer.bufferPtr;
|
||||
|
||||
for(long i = bptr; i < bptr + ARG_VALS_OFFSET; i += JObjCRuntime.PTR_LEN){
|
||||
if(argPtrsPtr == i)
|
||||
builder.append("*");
|
||||
builder.append(PrimitivePointerCoder.INST.popPtr(JObjCRuntime.inst(), i));
|
||||
builder.append(" ");
|
||||
}
|
||||
|
||||
builder.append("\n");
|
||||
|
||||
for(long i = bptr + ARG_VALS_OFFSET; i < bptr + BUF_SIZE; i += JObjCRuntime.PTR_LEN){
|
||||
if(argValuesPtr == i)
|
||||
builder.append("*");
|
||||
builder.append(PrimitivePointerCoder.INST.popPtr(JObjCRuntime.inst(), i));
|
||||
builder.append(" ");
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
@ -1,109 +0,0 @@
|
||||
/*
|
||||
* 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 com.apple.jobjc;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
|
||||
/**
|
||||
* A wrapper around a direct ByteBuffer and its native pointer. For documentation, @see java.nio.ByteBuffer
|
||||
*/
|
||||
public class NativeBuffer {
|
||||
static native long getPtrOfBuffer(final ByteBuffer byteBuffer);
|
||||
|
||||
public final ByteBuffer buffer;
|
||||
public final long bufferPtr;
|
||||
|
||||
public NativeBuffer(final int capacity){
|
||||
this(ByteBuffer.allocateDirect(capacity));
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a ByteBuffer and set the ByteOrder to nativeOrder.
|
||||
*/
|
||||
public NativeBuffer(ByteBuffer buffer){
|
||||
this.buffer = buffer;
|
||||
this.bufferPtr = getPtrOfBuffer(buffer);
|
||||
assert buffer != null;
|
||||
assert bufferPtr != 0;
|
||||
this.buffer.order(ByteOrder.nativeOrder());
|
||||
}
|
||||
|
||||
public byte get() { return buffer.get(); }
|
||||
public char getChar() { return buffer.getChar(); }
|
||||
public double getDouble() { return buffer.getDouble(); }
|
||||
public float getFloat() { return buffer.getFloat(); }
|
||||
public int getInt() { return buffer.getInt(); }
|
||||
public long getLong() { return buffer.getLong(); }
|
||||
public short getShort() { return buffer.getShort(); }
|
||||
public NativeBuffer put(byte b) { buffer.put(b); return this; }
|
||||
public NativeBuffer put(NativeBuffer src) { buffer.put(src.buffer); return this; }
|
||||
public NativeBuffer putChar(char c) { buffer.putChar(c); return this; }
|
||||
public NativeBuffer putDouble(double d) { buffer.putDouble(d); return this; }
|
||||
public NativeBuffer putFloat(float f) { buffer.putFloat(f); return this; }
|
||||
public NativeBuffer putInt(int i) { buffer.putInt(i); return this; }
|
||||
public NativeBuffer putLong(long l) { buffer.putLong(l); return this; }
|
||||
public NativeBuffer putShort(short s) { buffer.putShort(s); return this; }
|
||||
|
||||
public int capacity() { return buffer.capacity(); }
|
||||
public int position() { return buffer.position(); }
|
||||
public NativeBuffer position(int newPosition) { buffer.position(newPosition); return this; }
|
||||
public NativeBuffer rewind(){ buffer.rewind(); return this; }
|
||||
|
||||
public int limit() { return buffer.limit(); }
|
||||
public NativeBuffer limit(final int sizeof) { buffer.limit(sizeof); return this; }
|
||||
|
||||
public int remaining() { return buffer.remaining(); }
|
||||
|
||||
public NativeBuffer slice(){ return new NativeBuffer(buffer.slice()); }
|
||||
|
||||
@Override public String toString() {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
|
||||
for(int i = 0; i < limit(); i += JObjCRuntime.PTR_LEN){
|
||||
if(position() == i)
|
||||
builder.append("*");
|
||||
if(JObjCRuntime.IS32)
|
||||
builder.append(buffer.getInt(i));
|
||||
else
|
||||
builder.append(buffer.getLong(i));
|
||||
builder.append(" ");
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public long positionPtr() {
|
||||
return bufferPtr + position();
|
||||
}
|
||||
|
||||
/**
|
||||
* bufferPtr <= ptr && ptr < bufferPtr + capacity();
|
||||
*/
|
||||
public boolean ptrInBounds(final long ptr){
|
||||
return bufferPtr <= ptr && ptr < bufferPtr + capacity();
|
||||
}
|
||||
}
|
||||
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* 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 com.apple.jobjc;
|
||||
|
||||
|
||||
public abstract class NativeObjectLifecycleManager {
|
||||
private static native void retainNativeObject(final long ptr);
|
||||
private static native void releaseNativeObject(final long ptr);
|
||||
private static native void freeNativeObject(final long ptr);
|
||||
|
||||
abstract void begin(final long ptr);
|
||||
abstract void end(final long ptr);
|
||||
boolean shouldPreRetain() { return false; }
|
||||
|
||||
public static class CFRetainRelease extends NativeObjectLifecycleManager {
|
||||
public static final NativeObjectLifecycleManager INST = new CFRetainRelease();
|
||||
@Override void begin(final long ptr) { retainNativeObject(ptr); }
|
||||
@Override void end(final long ptr) { releaseNativeObject(ptr); }
|
||||
@Override boolean shouldPreRetain() { return true; }
|
||||
}
|
||||
|
||||
public static class Free extends NativeObjectLifecycleManager {
|
||||
public static final NativeObjectLifecycleManager INST = new Free();
|
||||
@Override void begin(final long ptr) { }
|
||||
@Override void end(final long ptr) { freeNativeObject(ptr); }
|
||||
}
|
||||
|
||||
public static class Nothing extends NativeObjectLifecycleManager {
|
||||
public static final NativeObjectLifecycleManager INST = new Nothing();
|
||||
@Override void begin(final long ptr) { }
|
||||
@Override void end(final long ptr) { }
|
||||
}
|
||||
}
|
||||
@ -1,57 +0,0 @@
|
||||
/*
|
||||
* 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 com.apple.jobjc;
|
||||
|
||||
|
||||
public class Pointer <T> implements Comparable<Pointer<T>>{
|
||||
long ptr;
|
||||
|
||||
protected Pointer(final long ptr) {
|
||||
this.ptr = ptr;
|
||||
getNativeObjectLifecycleManager().begin(ptr);
|
||||
}
|
||||
|
||||
@Override protected final synchronized void finalize() throws Throwable {
|
||||
long pptr = ptr;
|
||||
ptr = 0;
|
||||
if (pptr != 0) getNativeObjectLifecycleManager().end(pptr);
|
||||
}
|
||||
|
||||
protected NativeObjectLifecycleManager getNativeObjectLifecycleManager() {
|
||||
return NativeObjectLifecycleManager.Nothing.INST;
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object o) {
|
||||
return o instanceof Pointer && ptr == ((Pointer) o).ptr;
|
||||
}
|
||||
|
||||
@Override public int hashCode() { return (int)(ptr^(ptr>>>32)); }
|
||||
|
||||
public int compareTo(Pointer<T> o) {
|
||||
if(this==o || ptr==o.ptr) return 0;
|
||||
if(ptr < o.ptr) return -1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -1,700 +0,0 @@
|
||||
/*
|
||||
* 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 com.apple.jobjc;
|
||||
import com.apple.jobjc.JObjCRuntime.Width;
|
||||
// Auto generated by PrimitiveCoder.hs
|
||||
// Do not edit by hand.
|
||||
public abstract class PrimitiveCoder<T> extends Coder<T>{
|
||||
public PrimitiveCoder(int ffiTypeCode, String objCEncoding, Class jclass, Class jprim){
|
||||
super(ffiTypeCode, objCEncoding, jclass, jprim);
|
||||
}
|
||||
public final boolean popBoolean(NativeArgumentBuffer args){
|
||||
return popBoolean(args.runtime, args.retValPtr);
|
||||
}
|
||||
public abstract boolean popBoolean(JObjCRuntime runtime, long addr);
|
||||
|
||||
public final void push(NativeArgumentBuffer args, boolean x){
|
||||
push(args.runtime, args.argValuesPtr, x);
|
||||
args.didPutArgValue(sizeof());
|
||||
}
|
||||
public abstract void push(JObjCRuntime runtime, long addr, boolean x);
|
||||
|
||||
|
||||
public final byte popByte(NativeArgumentBuffer args){
|
||||
return popByte(args.runtime, args.retValPtr);
|
||||
}
|
||||
public abstract byte popByte(JObjCRuntime runtime, long addr);
|
||||
|
||||
public final void push(NativeArgumentBuffer args, byte x){
|
||||
push(args.runtime, args.argValuesPtr, x);
|
||||
args.didPutArgValue(sizeof());
|
||||
}
|
||||
public abstract void push(JObjCRuntime runtime, long addr, byte x);
|
||||
|
||||
|
||||
public final char popChar(NativeArgumentBuffer args){
|
||||
return popChar(args.runtime, args.retValPtr);
|
||||
}
|
||||
public abstract char popChar(JObjCRuntime runtime, long addr);
|
||||
|
||||
public final void push(NativeArgumentBuffer args, char x){
|
||||
push(args.runtime, args.argValuesPtr, x);
|
||||
args.didPutArgValue(sizeof());
|
||||
}
|
||||
public abstract void push(JObjCRuntime runtime, long addr, char x);
|
||||
|
||||
|
||||
public final short popShort(NativeArgumentBuffer args){
|
||||
return popShort(args.runtime, args.retValPtr);
|
||||
}
|
||||
public abstract short popShort(JObjCRuntime runtime, long addr);
|
||||
|
||||
public final void push(NativeArgumentBuffer args, short x){
|
||||
push(args.runtime, args.argValuesPtr, x);
|
||||
args.didPutArgValue(sizeof());
|
||||
}
|
||||
public abstract void push(JObjCRuntime runtime, long addr, short x);
|
||||
|
||||
|
||||
public final int popInt(NativeArgumentBuffer args){
|
||||
return popInt(args.runtime, args.retValPtr);
|
||||
}
|
||||
public abstract int popInt(JObjCRuntime runtime, long addr);
|
||||
|
||||
public final void push(NativeArgumentBuffer args, int x){
|
||||
push(args.runtime, args.argValuesPtr, x);
|
||||
args.didPutArgValue(sizeof());
|
||||
}
|
||||
public abstract void push(JObjCRuntime runtime, long addr, int x);
|
||||
|
||||
|
||||
public final long popLong(NativeArgumentBuffer args){
|
||||
return popLong(args.runtime, args.retValPtr);
|
||||
}
|
||||
public abstract long popLong(JObjCRuntime runtime, long addr);
|
||||
|
||||
public final void push(NativeArgumentBuffer args, long x){
|
||||
push(args.runtime, args.argValuesPtr, x);
|
||||
args.didPutArgValue(sizeof());
|
||||
}
|
||||
public abstract void push(JObjCRuntime runtime, long addr, long x);
|
||||
|
||||
|
||||
public final float popFloat(NativeArgumentBuffer args){
|
||||
return popFloat(args.runtime, args.retValPtr);
|
||||
}
|
||||
public abstract float popFloat(JObjCRuntime runtime, long addr);
|
||||
|
||||
public final void push(NativeArgumentBuffer args, float x){
|
||||
push(args.runtime, args.argValuesPtr, x);
|
||||
args.didPutArgValue(sizeof());
|
||||
}
|
||||
public abstract void push(JObjCRuntime runtime, long addr, float x);
|
||||
|
||||
|
||||
public final double popDouble(NativeArgumentBuffer args){
|
||||
return popDouble(args.runtime, args.retValPtr);
|
||||
}
|
||||
public abstract double popDouble(JObjCRuntime runtime, long addr);
|
||||
|
||||
public final void push(NativeArgumentBuffer args, double x){
|
||||
push(args.runtime, args.argValuesPtr, x);
|
||||
args.didPutArgValue(sizeof());
|
||||
}
|
||||
public abstract void push(JObjCRuntime runtime, long addr, double x);
|
||||
|
||||
|
||||
// native BOOL -> java boolean
|
||||
public static final class BoolCoder extends PrimitiveCoder<Boolean>{
|
||||
public static final BoolCoder INST = new BoolCoder();
|
||||
public BoolCoder(){ super(FFI_SINT8, "B", Boolean.class, boolean.class); }
|
||||
// compile time
|
||||
@Override public void push(JObjCRuntime rt, long addr, boolean x){
|
||||
rt.unsafe.putByte(addr, (byte) (x ? 1 : 0));
|
||||
}
|
||||
@Override public boolean popBoolean(JObjCRuntime rt, long addr){
|
||||
return rt.unsafe.getByte(addr) != 0;
|
||||
}
|
||||
// for runtime coding
|
||||
@Override public int sizeof(Width w){
|
||||
return 1;
|
||||
}
|
||||
@Override public void push(JObjCRuntime rt, long addr, Boolean x){ push(rt, addr, (boolean) x); }
|
||||
@Override public Boolean pop(JObjCRuntime rt, long addr){ return popBoolean(rt, addr); }
|
||||
// proxies for mixed encoding
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, byte x){ push(rt, addr, (x != 0)); }
|
||||
@Override public byte popByte(JObjCRuntime rt, long addr){ return ((byte)(popBoolean(rt, addr) ? 1 : 0)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, char x){ push(rt, addr, (x != 0)); }
|
||||
@Override public char popChar(JObjCRuntime rt, long addr){ return ((char)(popBoolean(rt, addr) ? 1 : 0)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, short x){ push(rt, addr, (x != 0)); }
|
||||
@Override public short popShort(JObjCRuntime rt, long addr){ return ((short)(popBoolean(rt, addr) ? 1 : 0)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, int x){ push(rt, addr, (x != 0)); }
|
||||
@Override public int popInt(JObjCRuntime rt, long addr){ return ((int)(popBoolean(rt, addr) ? 1 : 0)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, long x){ push(rt, addr, (x != 0)); }
|
||||
@Override public long popLong(JObjCRuntime rt, long addr){ return ((long)(popBoolean(rt, addr) ? 1 : 0)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, float x){ push(rt, addr, (x != 0)); }
|
||||
@Override public float popFloat(JObjCRuntime rt, long addr){ return ((float)(popBoolean(rt, addr) ? 1 : 0)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, double x){ push(rt, addr, (x != 0)); }
|
||||
@Override public double popDouble(JObjCRuntime rt, long addr){ return ((double)(popBoolean(rt, addr) ? 1 : 0)); }
|
||||
|
||||
|
||||
}
|
||||
|
||||
// native schar -> java byte
|
||||
public static final class SCharCoder extends PrimitiveCoder<Byte>{
|
||||
public static final SCharCoder INST = new SCharCoder();
|
||||
public SCharCoder(){ super(FFI_SINT8, "c", Byte.class, byte.class); }
|
||||
// compile time
|
||||
@Override public void push(JObjCRuntime rt, long addr, byte x){
|
||||
rt.unsafe.putByte(addr, x);
|
||||
}
|
||||
@Override public byte popByte(JObjCRuntime rt, long addr){
|
||||
return rt.unsafe.getByte(addr);
|
||||
}
|
||||
// for runtime coding
|
||||
@Override public int sizeof(Width w){
|
||||
return 1;
|
||||
}
|
||||
@Override public void push(JObjCRuntime rt, long addr, Byte x){ push(rt, addr, (byte) x); }
|
||||
@Override public Byte pop(JObjCRuntime rt, long addr){ return popByte(rt, addr); }
|
||||
// proxies for mixed encoding
|
||||
@Override public void push(JObjCRuntime rt, long addr, boolean x){ push(rt, addr, ((byte)(x ? 1 : 0))); }
|
||||
@Override public boolean popBoolean(JObjCRuntime rt, long addr){ return (popByte(rt, addr) != 0); }
|
||||
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, char x){ push(rt, addr, ((byte)x)); }
|
||||
@Override public char popChar(JObjCRuntime rt, long addr){ return ((char)popByte(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, short x){ push(rt, addr, ((byte)x)); }
|
||||
@Override public short popShort(JObjCRuntime rt, long addr){ return ((short)popByte(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, int x){ push(rt, addr, ((byte)x)); }
|
||||
@Override public int popInt(JObjCRuntime rt, long addr){ return ((int)popByte(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, long x){ push(rt, addr, ((byte)x)); }
|
||||
@Override public long popLong(JObjCRuntime rt, long addr){ return ((long)popByte(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, float x){ push(rt, addr, ((byte)x)); }
|
||||
@Override public float popFloat(JObjCRuntime rt, long addr){ return ((float)popByte(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, double x){ push(rt, addr, ((byte)x)); }
|
||||
@Override public double popDouble(JObjCRuntime rt, long addr){ return ((double)popByte(rt, addr)); }
|
||||
|
||||
|
||||
}
|
||||
|
||||
// native uchar -> java byte
|
||||
public static final class UCharCoder extends PrimitiveCoder<Byte>{
|
||||
public static final UCharCoder INST = new UCharCoder();
|
||||
public UCharCoder(){ super(FFI_UINT8, "C", Byte.class, byte.class); }
|
||||
// compile time
|
||||
@Override public void push(JObjCRuntime rt, long addr, byte x){
|
||||
rt.unsafe.putByte(addr, x);
|
||||
}
|
||||
@Override public byte popByte(JObjCRuntime rt, long addr){
|
||||
return rt.unsafe.getByte(addr);
|
||||
}
|
||||
// for runtime coding
|
||||
@Override public int sizeof(Width w){
|
||||
return 1;
|
||||
}
|
||||
@Override public void push(JObjCRuntime rt, long addr, Byte x){ push(rt, addr, (byte) x); }
|
||||
@Override public Byte pop(JObjCRuntime rt, long addr){ return popByte(rt, addr); }
|
||||
// proxies for mixed encoding
|
||||
@Override public void push(JObjCRuntime rt, long addr, boolean x){ push(rt, addr, ((byte)(x ? 1 : 0))); }
|
||||
@Override public boolean popBoolean(JObjCRuntime rt, long addr){ return (popByte(rt, addr) != 0); }
|
||||
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, char x){ push(rt, addr, ((byte)x)); }
|
||||
@Override public char popChar(JObjCRuntime rt, long addr){ return ((char)popByte(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, short x){ push(rt, addr, ((byte)x)); }
|
||||
@Override public short popShort(JObjCRuntime rt, long addr){ return ((short)popByte(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, int x){ push(rt, addr, ((byte)x)); }
|
||||
@Override public int popInt(JObjCRuntime rt, long addr){ return ((int)popByte(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, long x){ push(rt, addr, ((byte)x)); }
|
||||
@Override public long popLong(JObjCRuntime rt, long addr){ return ((long)popByte(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, float x){ push(rt, addr, ((byte)x)); }
|
||||
@Override public float popFloat(JObjCRuntime rt, long addr){ return ((float)popByte(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, double x){ push(rt, addr, ((byte)x)); }
|
||||
@Override public double popDouble(JObjCRuntime rt, long addr){ return ((double)popByte(rt, addr)); }
|
||||
|
||||
|
||||
}
|
||||
|
||||
// native sshort -> java short
|
||||
public static final class SShortCoder extends PrimitiveCoder<Short>{
|
||||
public static final SShortCoder INST = new SShortCoder();
|
||||
public SShortCoder(){ super(FFI_SINT16, "s", Short.class, short.class); }
|
||||
// compile time
|
||||
@Override public void push(JObjCRuntime rt, long addr, short x){
|
||||
rt.unsafe.putShort(addr, (short) x);
|
||||
}
|
||||
@Override public short popShort(JObjCRuntime rt, long addr){
|
||||
return rt.unsafe.getShort(addr);
|
||||
}
|
||||
// for runtime coding
|
||||
@Override public int sizeof(Width w){
|
||||
return 2;
|
||||
}
|
||||
@Override public void push(JObjCRuntime rt, long addr, Short x){ push(rt, addr, (short) x); }
|
||||
@Override public Short pop(JObjCRuntime rt, long addr){ return popShort(rt, addr); }
|
||||
// proxies for mixed encoding
|
||||
@Override public void push(JObjCRuntime rt, long addr, boolean x){ push(rt, addr, ((short)(x ? 1 : 0))); }
|
||||
@Override public boolean popBoolean(JObjCRuntime rt, long addr){ return (popShort(rt, addr) != 0); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, byte x){ push(rt, addr, ((short)x)); }
|
||||
@Override public byte popByte(JObjCRuntime rt, long addr){ return ((byte)popShort(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, char x){ push(rt, addr, ((short)x)); }
|
||||
@Override public char popChar(JObjCRuntime rt, long addr){ return ((char)popShort(rt, addr)); }
|
||||
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, int x){ push(rt, addr, ((short)x)); }
|
||||
@Override public int popInt(JObjCRuntime rt, long addr){ return ((int)popShort(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, long x){ push(rt, addr, ((short)x)); }
|
||||
@Override public long popLong(JObjCRuntime rt, long addr){ return ((long)popShort(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, float x){ push(rt, addr, ((short)x)); }
|
||||
@Override public float popFloat(JObjCRuntime rt, long addr){ return ((float)popShort(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, double x){ push(rt, addr, ((short)x)); }
|
||||
@Override public double popDouble(JObjCRuntime rt, long addr){ return ((double)popShort(rt, addr)); }
|
||||
|
||||
|
||||
}
|
||||
|
||||
// native ushort -> java short
|
||||
public static final class UShortCoder extends PrimitiveCoder<Short>{
|
||||
public static final UShortCoder INST = new UShortCoder();
|
||||
public UShortCoder(){ super(FFI_UINT16, "S", Short.class, short.class); }
|
||||
// compile time
|
||||
@Override public void push(JObjCRuntime rt, long addr, short x){
|
||||
rt.unsafe.putShort(addr, (short) x);
|
||||
}
|
||||
@Override public short popShort(JObjCRuntime rt, long addr){
|
||||
return rt.unsafe.getShort(addr);
|
||||
}
|
||||
// for runtime coding
|
||||
@Override public int sizeof(Width w){
|
||||
return 2;
|
||||
}
|
||||
@Override public void push(JObjCRuntime rt, long addr, Short x){ push(rt, addr, (short) x); }
|
||||
@Override public Short pop(JObjCRuntime rt, long addr){ return popShort(rt, addr); }
|
||||
// proxies for mixed encoding
|
||||
@Override public void push(JObjCRuntime rt, long addr, boolean x){ push(rt, addr, ((short)(x ? 1 : 0))); }
|
||||
@Override public boolean popBoolean(JObjCRuntime rt, long addr){ return (popShort(rt, addr) != 0); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, byte x){ push(rt, addr, ((short)x)); }
|
||||
@Override public byte popByte(JObjCRuntime rt, long addr){ return ((byte)popShort(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, char x){ push(rt, addr, ((short)x)); }
|
||||
@Override public char popChar(JObjCRuntime rt, long addr){ return ((char)popShort(rt, addr)); }
|
||||
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, int x){ push(rt, addr, ((short)x)); }
|
||||
@Override public int popInt(JObjCRuntime rt, long addr){ return ((int)popShort(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, long x){ push(rt, addr, ((short)x)); }
|
||||
@Override public long popLong(JObjCRuntime rt, long addr){ return ((long)popShort(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, float x){ push(rt, addr, ((short)x)); }
|
||||
@Override public float popFloat(JObjCRuntime rt, long addr){ return ((float)popShort(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, double x){ push(rt, addr, ((short)x)); }
|
||||
@Override public double popDouble(JObjCRuntime rt, long addr){ return ((double)popShort(rt, addr)); }
|
||||
|
||||
|
||||
}
|
||||
|
||||
// native sint -> java int
|
||||
public static final class SIntCoder extends PrimitiveCoder<Integer>{
|
||||
public static final SIntCoder INST = new SIntCoder();
|
||||
public SIntCoder(){ super(FFI_SINT32, "i", Integer.class, int.class); }
|
||||
// compile time
|
||||
@Override public void push(JObjCRuntime rt, long addr, int x){
|
||||
rt.unsafe.putInt(addr, (int) x);
|
||||
}
|
||||
@Override public int popInt(JObjCRuntime rt, long addr){
|
||||
return rt.unsafe.getInt(addr);
|
||||
}
|
||||
// for runtime coding
|
||||
@Override public int sizeof(Width w){
|
||||
return 4;
|
||||
}
|
||||
@Override public void push(JObjCRuntime rt, long addr, Integer x){ push(rt, addr, (int) x); }
|
||||
@Override public Integer pop(JObjCRuntime rt, long addr){ return popInt(rt, addr); }
|
||||
// proxies for mixed encoding
|
||||
@Override public void push(JObjCRuntime rt, long addr, boolean x){ push(rt, addr, ((int)(x ? 1 : 0))); }
|
||||
@Override public boolean popBoolean(JObjCRuntime rt, long addr){ return (popInt(rt, addr) != 0); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, byte x){ push(rt, addr, ((int)x)); }
|
||||
@Override public byte popByte(JObjCRuntime rt, long addr){ return ((byte)popInt(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, char x){ push(rt, addr, ((int)x)); }
|
||||
@Override public char popChar(JObjCRuntime rt, long addr){ return ((char)popInt(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, short x){ push(rt, addr, ((int)x)); }
|
||||
@Override public short popShort(JObjCRuntime rt, long addr){ return ((short)popInt(rt, addr)); }
|
||||
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, long x){ push(rt, addr, ((int)x)); }
|
||||
@Override public long popLong(JObjCRuntime rt, long addr){ return ((long)popInt(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, float x){ push(rt, addr, ((int)x)); }
|
||||
@Override public float popFloat(JObjCRuntime rt, long addr){ return ((float)popInt(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, double x){ push(rt, addr, ((int)x)); }
|
||||
@Override public double popDouble(JObjCRuntime rt, long addr){ return ((double)popInt(rt, addr)); }
|
||||
|
||||
|
||||
}
|
||||
|
||||
// native uint -> java int
|
||||
public static final class UIntCoder extends PrimitiveCoder<Integer>{
|
||||
public static final UIntCoder INST = new UIntCoder();
|
||||
public UIntCoder(){ super(FFI_UINT32, "I", Integer.class, int.class); }
|
||||
// compile time
|
||||
@Override public void push(JObjCRuntime rt, long addr, int x){
|
||||
rt.unsafe.putInt(addr, (int) x);
|
||||
}
|
||||
@Override public int popInt(JObjCRuntime rt, long addr){
|
||||
return rt.unsafe.getInt(addr);
|
||||
}
|
||||
// for runtime coding
|
||||
@Override public int sizeof(Width w){
|
||||
return 4;
|
||||
}
|
||||
@Override public void push(JObjCRuntime rt, long addr, Integer x){ push(rt, addr, (int) x); }
|
||||
@Override public Integer pop(JObjCRuntime rt, long addr){ return popInt(rt, addr); }
|
||||
// proxies for mixed encoding
|
||||
@Override public void push(JObjCRuntime rt, long addr, boolean x){ push(rt, addr, ((int)(x ? 1 : 0))); }
|
||||
@Override public boolean popBoolean(JObjCRuntime rt, long addr){ return (popInt(rt, addr) != 0); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, byte x){ push(rt, addr, ((int)x)); }
|
||||
@Override public byte popByte(JObjCRuntime rt, long addr){ return ((byte)popInt(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, char x){ push(rt, addr, ((int)x)); }
|
||||
@Override public char popChar(JObjCRuntime rt, long addr){ return ((char)popInt(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, short x){ push(rt, addr, ((int)x)); }
|
||||
@Override public short popShort(JObjCRuntime rt, long addr){ return ((short)popInt(rt, addr)); }
|
||||
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, long x){ push(rt, addr, ((int)x)); }
|
||||
@Override public long popLong(JObjCRuntime rt, long addr){ return ((long)popInt(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, float x){ push(rt, addr, ((int)x)); }
|
||||
@Override public float popFloat(JObjCRuntime rt, long addr){ return ((float)popInt(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, double x){ push(rt, addr, ((int)x)); }
|
||||
@Override public double popDouble(JObjCRuntime rt, long addr){ return ((double)popInt(rt, addr)); }
|
||||
|
||||
|
||||
}
|
||||
|
||||
// native slong -> java long
|
||||
public static final class SLongCoder extends PrimitiveCoder<Long>{
|
||||
public static final SLongCoder INST = new SLongCoder();
|
||||
public SLongCoder(){ super((JObjCRuntime.IS64 ? (FFI_SINT64) : (FFI_SINT32)), "l", Long.class, long.class); }
|
||||
// compile time
|
||||
@Override public void push(JObjCRuntime rt, long addr, long x){
|
||||
if(JObjCRuntime.IS64){ rt.unsafe.putLong(addr, (long) x); }else{ rt.unsafe.putInt(addr, (int) x); }
|
||||
}
|
||||
@Override public long popLong(JObjCRuntime rt, long addr){
|
||||
return (JObjCRuntime.IS64 ? (rt.unsafe.getLong(addr)) : (rt.unsafe.getInt(addr)));
|
||||
}
|
||||
// for runtime coding
|
||||
@Override public int sizeof(Width w){
|
||||
switch(w){
|
||||
case W32: return 4;
|
||||
case W64: return 8;
|
||||
|
||||
default: return -1;
|
||||
}
|
||||
|
||||
}
|
||||
@Override public void push(JObjCRuntime rt, long addr, Long x){ push(rt, addr, (long) x); }
|
||||
@Override public Long pop(JObjCRuntime rt, long addr){ return popLong(rt, addr); }
|
||||
// proxies for mixed encoding
|
||||
@Override public void push(JObjCRuntime rt, long addr, boolean x){ push(rt, addr, ((long)(x ? 1 : 0))); }
|
||||
@Override public boolean popBoolean(JObjCRuntime rt, long addr){ return (popLong(rt, addr) != 0); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, byte x){ push(rt, addr, ((long)x)); }
|
||||
@Override public byte popByte(JObjCRuntime rt, long addr){ return ((byte)popLong(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, char x){ push(rt, addr, ((long)x)); }
|
||||
@Override public char popChar(JObjCRuntime rt, long addr){ return ((char)popLong(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, short x){ push(rt, addr, ((long)x)); }
|
||||
@Override public short popShort(JObjCRuntime rt, long addr){ return ((short)popLong(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, int x){ push(rt, addr, ((long)x)); }
|
||||
@Override public int popInt(JObjCRuntime rt, long addr){ return ((int)popLong(rt, addr)); }
|
||||
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, float x){ push(rt, addr, ((long)x)); }
|
||||
@Override public float popFloat(JObjCRuntime rt, long addr){ return ((float)popLong(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, double x){ push(rt, addr, ((long)x)); }
|
||||
@Override public double popDouble(JObjCRuntime rt, long addr){ return ((double)popLong(rt, addr)); }
|
||||
|
||||
|
||||
}
|
||||
|
||||
// native ulong -> java long
|
||||
public static final class ULongCoder extends PrimitiveCoder<Long>{
|
||||
public static final ULongCoder INST = new ULongCoder();
|
||||
public ULongCoder(){ super((JObjCRuntime.IS64 ? (FFI_UINT64) : (FFI_UINT32)), "L", Long.class, long.class); }
|
||||
// compile time
|
||||
@Override public void push(JObjCRuntime rt, long addr, long x){
|
||||
if(JObjCRuntime.IS64){ rt.unsafe.putLong(addr, (long) x); }else{ rt.unsafe.putInt(addr, (int) x); }
|
||||
}
|
||||
@Override public long popLong(JObjCRuntime rt, long addr){
|
||||
return (JObjCRuntime.IS64 ? (rt.unsafe.getLong(addr)) : (rt.unsafe.getInt(addr)));
|
||||
}
|
||||
// for runtime coding
|
||||
@Override public int sizeof(Width w){
|
||||
switch(w){
|
||||
case W32: return 4;
|
||||
case W64: return 8;
|
||||
|
||||
default: return -1;
|
||||
}
|
||||
|
||||
}
|
||||
@Override public void push(JObjCRuntime rt, long addr, Long x){ push(rt, addr, (long) x); }
|
||||
@Override public Long pop(JObjCRuntime rt, long addr){ return popLong(rt, addr); }
|
||||
// proxies for mixed encoding
|
||||
@Override public void push(JObjCRuntime rt, long addr, boolean x){ push(rt, addr, ((long)(x ? 1 : 0))); }
|
||||
@Override public boolean popBoolean(JObjCRuntime rt, long addr){ return (popLong(rt, addr) != 0); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, byte x){ push(rt, addr, ((long)x)); }
|
||||
@Override public byte popByte(JObjCRuntime rt, long addr){ return ((byte)popLong(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, char x){ push(rt, addr, ((long)x)); }
|
||||
@Override public char popChar(JObjCRuntime rt, long addr){ return ((char)popLong(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, short x){ push(rt, addr, ((long)x)); }
|
||||
@Override public short popShort(JObjCRuntime rt, long addr){ return ((short)popLong(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, int x){ push(rt, addr, ((long)x)); }
|
||||
@Override public int popInt(JObjCRuntime rt, long addr){ return ((int)popLong(rt, addr)); }
|
||||
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, float x){ push(rt, addr, ((long)x)); }
|
||||
@Override public float popFloat(JObjCRuntime rt, long addr){ return ((float)popLong(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, double x){ push(rt, addr, ((long)x)); }
|
||||
@Override public double popDouble(JObjCRuntime rt, long addr){ return ((double)popLong(rt, addr)); }
|
||||
|
||||
|
||||
}
|
||||
|
||||
// native slonglong -> java long
|
||||
public static final class SLongLongCoder extends PrimitiveCoder<Long>{
|
||||
public static final SLongLongCoder INST = new SLongLongCoder();
|
||||
public SLongLongCoder(){ super(FFI_SINT64, "q", Long.class, long.class); }
|
||||
// compile time
|
||||
@Override public void push(JObjCRuntime rt, long addr, long x){
|
||||
rt.unsafe.putLong(addr, (long) x);
|
||||
}
|
||||
@Override public long popLong(JObjCRuntime rt, long addr){
|
||||
return rt.unsafe.getLong(addr);
|
||||
}
|
||||
// for runtime coding
|
||||
@Override public int sizeof(Width w){
|
||||
return 8;
|
||||
}
|
||||
@Override public void push(JObjCRuntime rt, long addr, Long x){ push(rt, addr, (long) x); }
|
||||
@Override public Long pop(JObjCRuntime rt, long addr){ return popLong(rt, addr); }
|
||||
// proxies for mixed encoding
|
||||
@Override public void push(JObjCRuntime rt, long addr, boolean x){ push(rt, addr, ((long)(x ? 1 : 0))); }
|
||||
@Override public boolean popBoolean(JObjCRuntime rt, long addr){ return (popLong(rt, addr) != 0); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, byte x){ push(rt, addr, ((long)x)); }
|
||||
@Override public byte popByte(JObjCRuntime rt, long addr){ return ((byte)popLong(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, char x){ push(rt, addr, ((long)x)); }
|
||||
@Override public char popChar(JObjCRuntime rt, long addr){ return ((char)popLong(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, short x){ push(rt, addr, ((long)x)); }
|
||||
@Override public short popShort(JObjCRuntime rt, long addr){ return ((short)popLong(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, int x){ push(rt, addr, ((long)x)); }
|
||||
@Override public int popInt(JObjCRuntime rt, long addr){ return ((int)popLong(rt, addr)); }
|
||||
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, float x){ push(rt, addr, ((long)x)); }
|
||||
@Override public float popFloat(JObjCRuntime rt, long addr){ return ((float)popLong(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, double x){ push(rt, addr, ((long)x)); }
|
||||
@Override public double popDouble(JObjCRuntime rt, long addr){ return ((double)popLong(rt, addr)); }
|
||||
|
||||
|
||||
}
|
||||
|
||||
// native ulonglong -> java long
|
||||
public static final class ULongLongCoder extends PrimitiveCoder<Long>{
|
||||
public static final ULongLongCoder INST = new ULongLongCoder();
|
||||
public ULongLongCoder(){ super(FFI_UINT64, "Q", Long.class, long.class); }
|
||||
// compile time
|
||||
@Override public void push(JObjCRuntime rt, long addr, long x){
|
||||
rt.unsafe.putLong(addr, (long) x);
|
||||
}
|
||||
@Override public long popLong(JObjCRuntime rt, long addr){
|
||||
return rt.unsafe.getLong(addr);
|
||||
}
|
||||
// for runtime coding
|
||||
@Override public int sizeof(Width w){
|
||||
return 8;
|
||||
}
|
||||
@Override public void push(JObjCRuntime rt, long addr, Long x){ push(rt, addr, (long) x); }
|
||||
@Override public Long pop(JObjCRuntime rt, long addr){ return popLong(rt, addr); }
|
||||
// proxies for mixed encoding
|
||||
@Override public void push(JObjCRuntime rt, long addr, boolean x){ push(rt, addr, ((long)(x ? 1 : 0))); }
|
||||
@Override public boolean popBoolean(JObjCRuntime rt, long addr){ return (popLong(rt, addr) != 0); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, byte x){ push(rt, addr, ((long)x)); }
|
||||
@Override public byte popByte(JObjCRuntime rt, long addr){ return ((byte)popLong(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, char x){ push(rt, addr, ((long)x)); }
|
||||
@Override public char popChar(JObjCRuntime rt, long addr){ return ((char)popLong(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, short x){ push(rt, addr, ((long)x)); }
|
||||
@Override public short popShort(JObjCRuntime rt, long addr){ return ((short)popLong(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, int x){ push(rt, addr, ((long)x)); }
|
||||
@Override public int popInt(JObjCRuntime rt, long addr){ return ((int)popLong(rt, addr)); }
|
||||
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, float x){ push(rt, addr, ((long)x)); }
|
||||
@Override public float popFloat(JObjCRuntime rt, long addr){ return ((float)popLong(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, double x){ push(rt, addr, ((long)x)); }
|
||||
@Override public double popDouble(JObjCRuntime rt, long addr){ return ((double)popLong(rt, addr)); }
|
||||
|
||||
|
||||
}
|
||||
|
||||
// native float -> java float
|
||||
public static final class FloatCoder extends PrimitiveCoder<Float>{
|
||||
public static final FloatCoder INST = new FloatCoder();
|
||||
public FloatCoder(){ super(FFI_FLOAT, "f", Float.class, float.class); }
|
||||
// compile time
|
||||
@Override public void push(JObjCRuntime rt, long addr, float x){
|
||||
rt.unsafe.putFloat(addr, (float) x);
|
||||
}
|
||||
@Override public float popFloat(JObjCRuntime rt, long addr){
|
||||
return rt.unsafe.getFloat(addr);
|
||||
}
|
||||
// for runtime coding
|
||||
@Override public int sizeof(Width w){
|
||||
return 4;
|
||||
}
|
||||
@Override public void push(JObjCRuntime rt, long addr, Float x){ push(rt, addr, (float) x); }
|
||||
@Override public Float pop(JObjCRuntime rt, long addr){ return popFloat(rt, addr); }
|
||||
// proxies for mixed encoding
|
||||
@Override public void push(JObjCRuntime rt, long addr, boolean x){ push(rt, addr, ((float)(x ? 1 : 0))); }
|
||||
@Override public boolean popBoolean(JObjCRuntime rt, long addr){ return (popFloat(rt, addr) != 0); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, byte x){ push(rt, addr, ((float)x)); }
|
||||
@Override public byte popByte(JObjCRuntime rt, long addr){ return ((byte)popFloat(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, char x){ push(rt, addr, ((float)x)); }
|
||||
@Override public char popChar(JObjCRuntime rt, long addr){ return ((char)popFloat(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, short x){ push(rt, addr, ((float)x)); }
|
||||
@Override public short popShort(JObjCRuntime rt, long addr){ return ((short)popFloat(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, int x){ push(rt, addr, ((float)x)); }
|
||||
@Override public int popInt(JObjCRuntime rt, long addr){ return ((int)popFloat(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, long x){ push(rt, addr, ((float)x)); }
|
||||
@Override public long popLong(JObjCRuntime rt, long addr){ return ((long)popFloat(rt, addr)); }
|
||||
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, double x){ push(rt, addr, ((float)x)); }
|
||||
@Override public double popDouble(JObjCRuntime rt, long addr){ return ((double)popFloat(rt, addr)); }
|
||||
|
||||
|
||||
}
|
||||
|
||||
// native double -> java double
|
||||
public static final class DoubleCoder extends PrimitiveCoder<Double>{
|
||||
public static final DoubleCoder INST = new DoubleCoder();
|
||||
public DoubleCoder(){ super(FFI_DOUBLE, "d", Double.class, double.class); }
|
||||
// compile time
|
||||
@Override public void push(JObjCRuntime rt, long addr, double x){
|
||||
rt.unsafe.putDouble(addr, (double) x);
|
||||
}
|
||||
@Override public double popDouble(JObjCRuntime rt, long addr){
|
||||
return rt.unsafe.getDouble(addr);
|
||||
}
|
||||
// for runtime coding
|
||||
@Override public int sizeof(Width w){
|
||||
return 8;
|
||||
}
|
||||
@Override public void push(JObjCRuntime rt, long addr, Double x){ push(rt, addr, (double) x); }
|
||||
@Override public Double pop(JObjCRuntime rt, long addr){ return popDouble(rt, addr); }
|
||||
// proxies for mixed encoding
|
||||
@Override public void push(JObjCRuntime rt, long addr, boolean x){ push(rt, addr, ((double)(x ? 1 : 0))); }
|
||||
@Override public boolean popBoolean(JObjCRuntime rt, long addr){ return (popDouble(rt, addr) != 0); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, byte x){ push(rt, addr, ((double)x)); }
|
||||
@Override public byte popByte(JObjCRuntime rt, long addr){ return ((byte)popDouble(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, char x){ push(rt, addr, ((double)x)); }
|
||||
@Override public char popChar(JObjCRuntime rt, long addr){ return ((char)popDouble(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, short x){ push(rt, addr, ((double)x)); }
|
||||
@Override public short popShort(JObjCRuntime rt, long addr){ return ((short)popDouble(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, int x){ push(rt, addr, ((double)x)); }
|
||||
@Override public int popInt(JObjCRuntime rt, long addr){ return ((int)popDouble(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, long x){ push(rt, addr, ((double)x)); }
|
||||
@Override public long popLong(JObjCRuntime rt, long addr){ return ((long)popDouble(rt, addr)); }
|
||||
|
||||
@Override public void push(JObjCRuntime rt, long addr, float x){ push(rt, addr, ((double)x)); }
|
||||
@Override public float popFloat(JObjCRuntime rt, long addr){ return ((float)popDouble(rt, addr)); }
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,62 +0,0 @@
|
||||
/*
|
||||
* 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 com.apple.jobjc;
|
||||
|
||||
|
||||
public class SEL {
|
||||
static native long getSelectorPtr(String selectorName);
|
||||
static native String getSelectorName(long ptr);
|
||||
|
||||
final long selPtr;
|
||||
|
||||
SEL(long ptr) {
|
||||
this.selPtr = ptr;
|
||||
}
|
||||
|
||||
public SEL(final String name) {
|
||||
this(getSelectorPtr(name));
|
||||
}
|
||||
|
||||
@Override public String toString(){
|
||||
return ((int)selPtr) + " / " + selPtr + " : " + getSelectorName(selPtr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts something like "performSelectorOnMainThread_withObject_wait"
|
||||
* to "performSelectorOnMainThread:withObject:wait:"
|
||||
*/
|
||||
public static String selectorName(String jMethodName, boolean hasArgs){
|
||||
String b = jMethodName.replaceAll("_", ":");
|
||||
return hasArgs ? b + ":" : b;
|
||||
}
|
||||
|
||||
public static String jMethodName(String selectorName){
|
||||
return selectorName.replaceAll(":", "_").replaceAll("_$", "");
|
||||
}
|
||||
|
||||
public static boolean validName(String selectorName){
|
||||
return selectorName.matches("^[a-zA-Z_][a-zA-Z0-9_:]*$");
|
||||
}
|
||||
}
|
||||
@ -1,56 +0,0 @@
|
||||
/*
|
||||
* 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 com.apple.jobjc;
|
||||
|
||||
|
||||
/**
|
||||
* A struct is malloced on the C heap and accessed in Java through a ByteBuffer.
|
||||
*/
|
||||
public abstract class Struct{
|
||||
protected final NativeBuffer raw;
|
||||
private final JObjCRuntime runtime;
|
||||
protected final JObjCRuntime getRuntime(){ return runtime; }
|
||||
|
||||
/**
|
||||
* Create a brand new struct from nothing.
|
||||
*/
|
||||
protected Struct(final JObjCRuntime runtime, final int SIZEOF){
|
||||
this(runtime, new NativeBuffer(SIZEOF), SIZEOF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a struct by taking ownership of an existing buffer.
|
||||
* Used for struct fields of type struct. For example, the origin and size fields
|
||||
* in NSRect would be initialized with this constructor.
|
||||
*/
|
||||
protected Struct(final JObjCRuntime runtime, final NativeBuffer buffer, final int SIZEOF){
|
||||
if(runtime == null) throw new NullPointerException("runtime");
|
||||
this.runtime = runtime;
|
||||
this.raw = buffer;
|
||||
this.raw.limit(SIZEOF);
|
||||
}
|
||||
|
||||
abstract public Coder getCoder();
|
||||
}
|
||||
@ -1,167 +0,0 @@
|
||||
/*
|
||||
* 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 com.apple.jobjc;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.apple.jobjc.Coder.PrimitivePointerCoder;
|
||||
import com.apple.jobjc.Coder.VoidCoder;
|
||||
import com.apple.jobjc.Invoke.MsgSend;
|
||||
|
||||
|
||||
final class Subclassing {
|
||||
static native long allocateClassPair(long superClass, String name);
|
||||
static native boolean addIVarForJObj(long clazz);
|
||||
static native boolean patchAlloc(long classPtr);
|
||||
static native boolean addMethod(long cls, String name, Method jMethod, CIF cif, long cifPtr, String objCEncodedType);
|
||||
static native void registerClassPair(long clazz);
|
||||
|
||||
static native <T extends ID> T getJObjectFromIVar(long objPtr);
|
||||
static native void initJObjectToIVar(long objPtr, ID object);
|
||||
|
||||
final Set<Long> registeredUserSubclasses = new HashSet<Long>();
|
||||
final JObjCRuntime runtime;
|
||||
|
||||
Subclassing(JObjCRuntime runtime){
|
||||
this.runtime = runtime;
|
||||
}
|
||||
|
||||
boolean registerUserClass(final Class<? extends ID> clazz, final Class<? extends NSClass> clazzClazz) {
|
||||
final String nativeClassName = clazz.getSimpleName();
|
||||
// Is it already registered?
|
||||
if(0 != NSClass.getNativeClassByName(nativeClassName))
|
||||
return false;
|
||||
|
||||
if(clazz.isAnonymousClass())
|
||||
throw new RuntimeException("JObjC cannot register anonymous classes.");
|
||||
|
||||
// Verify superclass
|
||||
long superClass = NSClass.getNativeClassByName(clazz.getSuperclass().getSimpleName());
|
||||
if(0 == superClass)
|
||||
throw new RuntimeException(clazz.getSuperclass() + ", the superclass of " + clazz + ", must be a registered class.");
|
||||
|
||||
runtime.registerPackage(clazz.getPackage().getName());
|
||||
|
||||
// Create class
|
||||
long classPtr = Subclassing.allocateClassPair(superClass, nativeClassName);
|
||||
if(classPtr == 0) throw new RuntimeException("objc_allocateClassPair returned 0.");
|
||||
|
||||
// Add ivar to hold jobject
|
||||
boolean addedI = Subclassing.addIVarForJObj(classPtr);
|
||||
if(!addedI) throw new RuntimeException("class_addIvar returned false.");
|
||||
|
||||
// Verify constructor
|
||||
try {
|
||||
clazz.getConstructor(ID.CTOR_ARGS);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Could not access required constructor: " + ID.CTOR_ARGS, e);
|
||||
}
|
||||
|
||||
// Patch alloc to create corresponding jobject on invoke
|
||||
patchAlloc(classPtr);
|
||||
|
||||
// Add methods
|
||||
Set<String> takenSelNames = new HashSet<String>();
|
||||
for(Method method : clazz.getDeclaredMethods()){
|
||||
// No overloading
|
||||
String selName = SEL.selectorName(method.getName(), method.getParameterTypes().length > 0);
|
||||
if(takenSelNames.contains(selName))
|
||||
throw new RuntimeException("Obj-C does not allow method overloading. The Objective-C selector '"
|
||||
+ selName + "' appears more than once in class " + clazz.getCanonicalName() + " / " + nativeClassName + ".");
|
||||
|
||||
method.setAccessible(true);
|
||||
|
||||
// Divine CIF
|
||||
Coder returnCoder = Coder.getCoderAtRuntimeForType(method.getReturnType());
|
||||
Class[] paramTypes = method.getParameterTypes();
|
||||
Coder[] argCoders = new Coder[paramTypes.length];
|
||||
for(int i = 0; i < paramTypes.length; i++)
|
||||
argCoders[i] = Coder.getCoderAtRuntimeForType(paramTypes[i]);
|
||||
|
||||
CIF cif = new MsgSend(runtime, selName, returnCoder, argCoders).funCall.cif;
|
||||
|
||||
// .. and objc encoding
|
||||
StringWriter encType = new StringWriter();
|
||||
encType.append(returnCoder.getObjCEncoding());
|
||||
encType.append("@:");
|
||||
for(int i = 0; i < argCoders.length; i++)
|
||||
encType.append(argCoders[i].getObjCEncoding());
|
||||
|
||||
// Add it!
|
||||
boolean addedM = Subclassing.addMethod(classPtr, selName, method, cif, cif.cif.bufferPtr, encType.toString());
|
||||
if(!addedM) throw new RuntimeException("Failed to add method.");
|
||||
takenSelNames.add(selName);
|
||||
}
|
||||
|
||||
// Seal it
|
||||
Subclassing.registerClassPair(classPtr);
|
||||
registeredUserSubclasses.add(classPtr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean isUserClass(long clsPtr) {
|
||||
return registeredUserSubclasses.contains(clsPtr);
|
||||
}
|
||||
|
||||
// Called from JNI
|
||||
|
||||
private static void initJObject(final long objPtr){
|
||||
// System.err.println("initJObject " + objPtr + " / " + Long.toHexString(objPtr));
|
||||
ID newObj = ID.createNewObjCObjectFor(JObjCRuntime.inst(), objPtr, NSClass.getClass(objPtr));
|
||||
// System.err.println("... " + newObj);
|
||||
initJObjectToIVar(objPtr, newObj);
|
||||
}
|
||||
|
||||
private static void invokeFromJNI(ID obj, Method method, CIF cif, long result, long args){
|
||||
assert obj != null;
|
||||
assert obj.getClass().equals(method.getDeclaringClass()) :
|
||||
obj.getClass().toString() + " != " + method.getDeclaringClass().toString();
|
||||
|
||||
final int argCount = method.getParameterTypes().length;
|
||||
|
||||
// The first two args & coders are for objc id and sel. Skip them.
|
||||
final Object[] argObjects = new Object[argCount];
|
||||
for(int i = 0; i < argCount; i++){
|
||||
final long argAddrAddr = args + ((i+2) * JObjCRuntime.PTR_LEN);
|
||||
final long argAddr = PrimitivePointerCoder.INST.popPtr(obj.runtime, argAddrAddr);
|
||||
argObjects[i] = cif.argCoders[i + 2].pop(obj.runtime, argAddr);
|
||||
}
|
||||
|
||||
Object retVal;
|
||||
try {
|
||||
retVal = method.invoke(obj, argObjects);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
if(!(cif.returnCoder instanceof VoidCoder))
|
||||
cif.returnCoder.push(obj.runtime, result, retVal);
|
||||
}
|
||||
}
|
||||
@ -1,50 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "com_apple_jobjc_CIF.h"
|
||||
|
||||
#define MACOSX
|
||||
#include <ffi/ffi.h>
|
||||
#include <JavaNativeFoundation/JavaNativeFoundation.h>
|
||||
|
||||
#include "NativeBuffer.h"
|
||||
|
||||
JNIEXPORT jint JNICALL Java_com_apple_jobjc_CIF_getSizeofCIF
|
||||
(JNIEnv *env, jclass clazz)
|
||||
{
|
||||
return (jint) sizeof(ffi_cif);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_com_apple_jobjc_CIF_prepCIF
|
||||
(JNIEnv *env, jclass clazz, jlong jCIFPtr, jint jNargs, jlong jRetTypePtr, jlong jArgsPtr)
|
||||
{
|
||||
ffi_cif *cif = jlong_to_ptr(jCIFPtr);
|
||||
unsigned int nargs = jNargs;
|
||||
ffi_type *rtype = jlong_to_ptr(jRetTypePtr);
|
||||
ffi_type **atypes = jlong_to_ptr(jArgsPtr);
|
||||
|
||||
// NSLog(@"rtype->(size: %d, alignment: %d, type: %d)", rtype->size, rtype->alignment, rtype->type);
|
||||
return (jboolean) (FFI_OK == ffi_prep_cif(cif, FFI_DEFAULT_ABI, nargs, rtype, atypes));
|
||||
}
|
||||
@ -1,58 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "com_apple_jobjc_Coder.h"
|
||||
|
||||
#include <JavaNativeFoundation/JavaNativeFoundation.h>
|
||||
#define MACOSX
|
||||
#include <ffi/ffi.h>
|
||||
#include <AppKit/AppKit.h>
|
||||
|
||||
/*
|
||||
* Class: com_apple_jobjc_Coder
|
||||
* Method: getNativeFFITypeCodeForCode
|
||||
* Signature: (I)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_com_apple_jobjc_Coder_getNativeFFITypePtrForCode
|
||||
(JNIEnv *env, jclass clazz, jint code)
|
||||
{
|
||||
switch ((long)code) {
|
||||
case com_apple_jobjc_Coder_FFI_VOID: return ptr_to_jlong(&ffi_type_void);
|
||||
case com_apple_jobjc_Coder_FFI_PTR: return ptr_to_jlong(&ffi_type_pointer);
|
||||
case com_apple_jobjc_Coder_FFI_SINT8: return ptr_to_jlong(&ffi_type_sint8);
|
||||
case com_apple_jobjc_Coder_FFI_UINT8: return ptr_to_jlong(&ffi_type_uint8);
|
||||
case com_apple_jobjc_Coder_FFI_SINT16: return ptr_to_jlong(&ffi_type_sint16);
|
||||
case com_apple_jobjc_Coder_FFI_UINT16: return ptr_to_jlong(&ffi_type_uint16);
|
||||
case com_apple_jobjc_Coder_FFI_SINT32: return ptr_to_jlong(&ffi_type_sint32);
|
||||
case com_apple_jobjc_Coder_FFI_UINT32: return ptr_to_jlong(&ffi_type_uint32);
|
||||
case com_apple_jobjc_Coder_FFI_SINT64: return ptr_to_jlong(&ffi_type_sint64);
|
||||
case com_apple_jobjc_Coder_FFI_UINT64: return ptr_to_jlong(&ffi_type_uint64);
|
||||
case com_apple_jobjc_Coder_FFI_FLOAT: return ptr_to_jlong(&ffi_type_float);
|
||||
case com_apple_jobjc_Coder_FFI_DOUBLE: return ptr_to_jlong(&ffi_type_double);
|
||||
case com_apple_jobjc_Coder_FFI_LONGDOUBLE: return ptr_to_jlong(&ffi_type_longdouble);
|
||||
}
|
||||
|
||||
return ptr_to_jlong(NULL);
|
||||
}
|
||||
@ -1,43 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
#include <JavaNativeFoundation/JavaNativeFoundation.h>
|
||||
#include <ffi/ffi.h>
|
||||
|
||||
#include "com_apple_jobjc_FFIType.h"
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_apple_jobjc_FFIType_makeFFIType
|
||||
(JNIEnv *env, jclass clazz, jlong ffi_type_jlong, jlong ffi_type_elements_jlong)
|
||||
{
|
||||
ffi_type *type = jlong_to_ptr(ffi_type_jlong);
|
||||
type->elements = jlong_to_ptr(ffi_type_elements_jlong);
|
||||
type->type = FFI_TYPE_STRUCT;
|
||||
type->size = type->alignment = 0;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_com_apple_jobjc_FFIType_getFFITypeSizeof
|
||||
(JNIEnv *env, jclass clazz)
|
||||
{
|
||||
return (jint) sizeof(ffi_type);
|
||||
}
|
||||
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "com_apple_jobjc_Function.h"
|
||||
|
||||
#define MACOSX
|
||||
#include <dlfcn.h>
|
||||
#include <JavaNativeFoundation/JavaNativeFoundation.h>
|
||||
|
||||
JNIEXPORT jlong JNICALL Java_com_apple_jobjc_Function_getFxnPtrForFunctionName
|
||||
(JNIEnv *env, jclass clazz, jstring fxnName)
|
||||
{
|
||||
const char *functionName = (*env)->GetStringUTFChars(env, fxnName, NULL);
|
||||
void *fxnPtr = dlsym(RTLD_SELF, functionName);
|
||||
(*env)->ReleaseStringUTFChars(env, fxnName, functionName);
|
||||
return ptr_to_jlong(fxnPtr);
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL Java_com_apple_jobjc_Function_getFxnPtrForFunctionNameAndLib
|
||||
(JNIEnv *env, jclass clazz, jlong frameworkPtr, jstring fxnName)
|
||||
{
|
||||
void *frameworkHandle = jlong_to_ptr(frameworkPtr);
|
||||
|
||||
const char *functionName = (*env)->GetStringUTFChars(env, fxnName, NULL);
|
||||
void *fxnPtr = dlsym(frameworkHandle, functionName);
|
||||
(*env)->ReleaseStringUTFChars(env, fxnName, functionName);
|
||||
|
||||
return ptr_to_jlong(fxnPtr);
|
||||
}
|
||||
@ -1,40 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "com_apple_jobjc_Invoke_FunCall.h"
|
||||
#include <ffi/ffi.h>
|
||||
#include <objc/message.h>
|
||||
#include <JavaNativeFoundation/JavaNativeFoundation.h>
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_apple_jobjc_Invoke_00024FunCall_invoke
|
||||
(JNIEnv *env, jclass clazz, jlong cifPtr, jlong fxnPtr, jlong retValPtr, jlong argsPtr)
|
||||
{
|
||||
ffi_cif *cif = jlong_to_ptr(cifPtr);
|
||||
void *fxn = jlong_to_ptr(fxnPtr);
|
||||
void *retVal = jlong_to_ptr(retValPtr);
|
||||
void **args = jlong_to_ptr(argsPtr);
|
||||
|
||||
ffi_call(cif, fxn, retVal, args);
|
||||
}
|
||||
@ -1,69 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "com_apple_jobjc_MacOSXFramework.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <JavaNativeFoundation/JavaNativeFoundation.h>
|
||||
|
||||
/*
|
||||
* Class: com_apple_jobjc_MacOSXFramework
|
||||
* Method: retainFramework
|
||||
* Signature: (Ljava/lang/String;)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_com_apple_jobjc_MacOSXFramework_retainFramework
|
||||
(JNIEnv *env, jclass clazz, jstring frameworkName)
|
||||
{
|
||||
if (frameworkName == NULL) return ptr_to_jlong(NULL);
|
||||
const char *frameworkNameCStr = (*env)->GetStringUTFChars(env, frameworkName, JNI_FALSE);
|
||||
const void *library = dlopen(frameworkNameCStr, RTLD_LOCAL);
|
||||
(*env)->ReleaseStringUTFChars(env, frameworkName, frameworkNameCStr);
|
||||
return ptr_to_jlong(library);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: com_apple_jobjc_MacOSXFramework
|
||||
* Method: releaseFramework
|
||||
* Signature: (J)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_apple_jobjc_MacOSXFramework_releaseFramework
|
||||
(JNIEnv *env, jclass clazz, jlong frameworkPtr)
|
||||
{
|
||||
dlclose(jlong_to_ptr(frameworkPtr));
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_apple_jobjc_MacOSXFramework_getConstant
|
||||
(JNIEnv *env, jclass clazz, jlong frameworkPtr, jstring constSymbol, jlong retBuffer, jint size)
|
||||
{
|
||||
const char *symbol = (*env)->GetStringUTFChars(env, constSymbol, JNI_FALSE);
|
||||
void *handle = frameworkPtr ? jlong_to_ptr(frameworkPtr) : RTLD_DEFAULT;
|
||||
void *data = dlsym(handle, symbol);
|
||||
(*env)->ReleaseStringUTFChars(env, constSymbol, symbol);
|
||||
|
||||
if(!data)
|
||||
(*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/RuntimeException"), dlerror());
|
||||
else
|
||||
memcpy(jlong_to_ptr(retBuffer), data, (size_t) size);
|
||||
}
|
||||
@ -1,78 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "com_apple_jobjc_NSClass.h"
|
||||
#include <objc/runtime.h>
|
||||
|
||||
#include <JavaNativeFoundation/JavaNativeFoundation.h>
|
||||
|
||||
/*
|
||||
* Class: com_apple_jobjc_NSClass
|
||||
* Method: getNativeClassByName
|
||||
* Signature: (JLjava/lang/String;)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_com_apple_jobjc_NSClass_getNativeClassByName
|
||||
(JNIEnv *env, jclass clazz, jstring className)
|
||||
{
|
||||
if (className == NULL) return ptr_to_jlong(NULL);
|
||||
const char *classNameCStr = (*env)->GetStringUTFChars(env, className, JNI_FALSE);
|
||||
const id obj = objc_getClass(classNameCStr);
|
||||
(*env)->ReleaseStringUTFChars(env, className, classNameCStr);
|
||||
|
||||
if (obj == nil) return ptr_to_jlong(NULL);
|
||||
return ptr_to_jlong(obj);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: com_apple_jobjc_NSClass
|
||||
* Method: getSuperClass
|
||||
* Signature: (J)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_com_apple_jobjc_NSClass_getSuperClassOfClass
|
||||
(JNIEnv *env, jclass clazz, jlong clazzPtr)
|
||||
{
|
||||
if (clazzPtr == 0L) return ptr_to_jlong(NULL);
|
||||
const Class objClazz = (Class)jlong_to_ptr(clazzPtr);
|
||||
return ptr_to_jlong(class_getSuperclass(objClazz));
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: com_apple_jobjc_NSClass
|
||||
* Method: getClassName
|
||||
* Signature: (J)Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_com_apple_jobjc_NSClass_getClassNameOfClass
|
||||
(JNIEnv *env, jclass clazz, jlong clazzPtr)
|
||||
{
|
||||
const char *clazzName = (char *)class_getName((Class)jlong_to_ptr(clazzPtr));
|
||||
return (*env)->NewStringUTF(env, clazzName);
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL Java_com_apple_jobjc_NSClass_getClass
|
||||
(JNIEnv *env, jclass clazz, jlong objPtr)
|
||||
{
|
||||
id obj = (id)jlong_to_ptr(objPtr);
|
||||
return ptr_to_jlong(object_getClass(obj));
|
||||
}
|
||||
@ -1,40 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* NativeBuffer.h
|
||||
* Copyright 2007 Apple Inc. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#define BUFFER_AT(buffer, offset) (((UInt8 *)buffer) + offset)
|
||||
#define GET_VALUE(type, buffer, offset) (*((type *)BUFFER_AT(buffer, offset)))
|
||||
#define PUT_VALUE(type, buffer, offset, value) (*((type *)BUFFER_AT(buffer, offset)) = value)
|
||||
|
||||
#define GET_INT_AT(buffer, offset) GET_VALUE(jint, buffer, offset)
|
||||
#define GET_LONG_AT(buffer, offset) GET_VALUE(jlong, buffer, offset)
|
||||
|
||||
#define PUT_INT_AT(buffer, offset, value) PUT_VALUE(jint, buffer, offset, value)
|
||||
#define PUT_LONG_AT(buffer, offset, value) PUT_VALUE(jlong, buffer, offset, value)
|
||||
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "com_apple_jobjc_NativeBuffer.h"
|
||||
|
||||
#define MACOSX
|
||||
#include <ffi/ffi.h>
|
||||
#include <JavaNativeFoundation/JavaNativeFoundation.h>
|
||||
|
||||
JNIEXPORT jlong JNICALL Java_com_apple_jobjc_NativeBuffer_getPtrOfBuffer
|
||||
(JNIEnv *env, jclass clazz, jobject buffer)
|
||||
{
|
||||
if (buffer == NULL) return ptr_to_jlong(0);
|
||||
return ptr_to_jlong((*env)->GetDirectBufferAddress(env, buffer));
|
||||
}
|
||||
@ -1,65 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "com_apple_jobjc_NativeObjectLifecycleManager.h"
|
||||
|
||||
#include <JavaNativeFoundation/JavaNativeFoundation.h>
|
||||
|
||||
|
||||
/*
|
||||
* Class: com_apple_jobjc_NativeObjectLifecycleManager
|
||||
* Method: retainNativeObject
|
||||
* Signature: (J)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_apple_jobjc_NativeObjectLifecycleManager_retainNativeObject
|
||||
(JNIEnv *env, jclass clazz, jlong ptr)
|
||||
{
|
||||
if (ptr == 0L) return;
|
||||
CFRetain(jlong_to_ptr(ptr));
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: com_apple_jobjc_NativeObjectLifecycleManager
|
||||
* Method: releaseNativeObject
|
||||
* Signature: (J)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_apple_jobjc_NativeObjectLifecycleManager_releaseNativeObject
|
||||
(JNIEnv *env, jclass clazz, jlong ptr)
|
||||
{
|
||||
if (ptr == 0L) return;
|
||||
CFRelease(jlong_to_ptr(ptr));
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: com_apple_jobjc_NativeObjectLifecycleManager
|
||||
* Method: freeNativeObject
|
||||
* Signature: (J)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_apple_jobjc_NativeObjectLifecycleManager_freeNativeObject
|
||||
(JNIEnv *env, jclass clazz, jlong ptr)
|
||||
{
|
||||
if (ptr == 0L) return;
|
||||
free(jlong_to_ptr(ptr));
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "com_apple_jobjc_SEL.h"
|
||||
|
||||
#include <JavaNativeFoundation/JavaNativeFoundation.h>
|
||||
#include <objc/message.h>
|
||||
|
||||
JNIEXPORT jlong JNICALL Java_com_apple_jobjc_SEL_getSelectorPtr
|
||||
(JNIEnv *env, jclass jclazz, jstring selName)
|
||||
{
|
||||
const char *selNameAsChars = (*env)->GetStringUTFChars(env, selName, JNI_FALSE);
|
||||
const SEL sel = sel_registerName(selNameAsChars);
|
||||
(*env)->ReleaseStringUTFChars(env, selName, selNameAsChars);
|
||||
return ptr_to_jlong((void*)sel);
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL Java_com_apple_jobjc_SEL_getSelectorName
|
||||
(JNIEnv *env, jclass jclazz, jlong selPtr)
|
||||
{
|
||||
return (*env)->NewStringUTF(env, sel_getName(jlong_to_ptr(selPtr)));
|
||||
}
|
||||
@ -1,301 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "com_apple_jobjc_Subclassing.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <objc/runtime.h>
|
||||
#include <objc/message.h>
|
||||
|
||||
#include <ffi/ffi.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <JavaNativeFoundation/JavaNativeFoundation.h>
|
||||
|
||||
// Subclassing of Obj-C classes in Java
|
||||
//
|
||||
// See:
|
||||
// - Objective-C Runtime documentation
|
||||
// - man ffi_prep_closure
|
||||
// - Subclassing.java
|
||||
|
||||
|
||||
#pragma mark Accessing object in IVar
|
||||
|
||||
#define JOBJ_IVAR_NAME "jObjWrapper"
|
||||
static jobject getJObjectFromIVar(id obj);
|
||||
|
||||
jobject getJObjectFromIVar(id obj)
|
||||
{
|
||||
JNFJObjectWrapper *wrapper = NULL;
|
||||
object_getInstanceVariable(obj, JOBJ_IVAR_NAME, (void**) &wrapper);
|
||||
return wrapper ? [wrapper jObject] : NULL;
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL Java_com_apple_jobjc_Subclassing_getJObjectFromIVar
|
||||
(JNIEnv *env, jclass jClass, jlong jPtr)
|
||||
{
|
||||
id obj = (id) jlong_to_ptr(jPtr);
|
||||
if(obj == NULL){
|
||||
(*env)->ThrowNew(env, (*env)->FindClass(env,
|
||||
"java/lang/NullPointerException"), "obj");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JNFJObjectWrapper *wrapper;
|
||||
|
||||
if(!object_getInstanceVariable(obj, JOBJ_IVAR_NAME, (void**) &wrapper)){
|
||||
NSLog(@"IVar '%s' not found. obj: %@", JOBJ_IVAR_NAME, obj);
|
||||
(*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/RuntimeException"),
|
||||
"Could not find instance variable that holds Java object.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return wrapper ? [wrapper jObject] : NULL;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_apple_jobjc_Subclassing_initJObjectToIVar
|
||||
(JNIEnv *env, jclass jClass, jlong jPtr, jobject jObject)
|
||||
{
|
||||
id obj = (id) jlong_to_ptr(jPtr);
|
||||
JNFJObjectWrapper *wrapper = [[JNFJObjectWrapper alloc]
|
||||
initWithJObject:jObject withEnv:env];
|
||||
[wrapper retain];
|
||||
|
||||
if(!object_setInstanceVariable(obj, JOBJ_IVAR_NAME, wrapper)){
|
||||
NSLog(@"IVar '%s' not found. obj: %@", JOBJ_IVAR_NAME, obj);
|
||||
(*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/RuntimeException"),
|
||||
"Could not find instance variable that holds Java object.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Registering class
|
||||
|
||||
JNIEXPORT jlong JNICALL Java_com_apple_jobjc_Subclassing_allocateClassPair
|
||||
(JNIEnv *env, jclass clazz, jlong jSuperClass, jstring jName)
|
||||
{
|
||||
const Class superClass = (Class)jlong_to_ptr(jSuperClass);
|
||||
assert(superClass);
|
||||
|
||||
const char *name = (*env)->GetStringUTFChars(env, jName, JNI_FALSE);
|
||||
const Class newClass = objc_allocateClassPair(superClass, name, 0);
|
||||
(*env)->ReleaseStringUTFChars(env, jName, name);
|
||||
|
||||
return ptr_to_jlong(newClass);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_com_apple_jobjc_Subclassing_addIVarForJObj
|
||||
(JNIEnv *env, jclass clazz, jlong jSynthClass)
|
||||
{
|
||||
return class_addIvar(
|
||||
jlong_to_ptr(jSynthClass),
|
||||
JOBJ_IVAR_NAME,
|
||||
sizeof(id),
|
||||
(uint8_t)log2((double)sizeof(id)),
|
||||
"@");
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_apple_jobjc_Subclassing_registerClassPair
|
||||
(JNIEnv *env, jclass clazz, jlong jClass)
|
||||
{
|
||||
Class c = jlong_to_ptr(jClass);
|
||||
// NSLog(@"Registering class pair %p / %s", c, class_getName(c));
|
||||
objc_registerClassPair(c);
|
||||
}
|
||||
|
||||
|
||||
#pragma mark Patching +alloc
|
||||
|
||||
static id patchedAllocIMP(id obj, SEL sel);
|
||||
static void addJavaInstance(id obj);
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_com_apple_jobjc_Subclassing_patchAlloc
|
||||
(JNIEnv *env, jclass clazz, jlong jNativeClass)
|
||||
{
|
||||
Class metaClass = object_getClass(jlong_to_ptr(jNativeClass));
|
||||
return class_addMethod(metaClass,
|
||||
sel_registerName("alloc"),
|
||||
(IMP) patchedAllocIMP,
|
||||
"@@:");
|
||||
}
|
||||
|
||||
static id patchedAllocIMP(id cls, SEL sel){
|
||||
id inst = class_createInstance(cls, 0);
|
||||
addJavaInstance(inst);
|
||||
return inst;
|
||||
}
|
||||
|
||||
static void addJavaInstance(id obj){
|
||||
// NSLog(@"addJavaInstance %p", obj);
|
||||
// NSLog(@"... calling up to Java");
|
||||
|
||||
static JNF_CLASS_CACHE(jc_Subclassing, "com/apple/jobjc/Subclassing");
|
||||
static JNF_STATIC_MEMBER_CACHE(jm_Subclassing_initJObject,
|
||||
jc_Subclassing,
|
||||
"initJObject",
|
||||
"(J)V");
|
||||
|
||||
JNFThreadContext threadWasAttached = JNFThreadDetachOnThreadDeath;
|
||||
JNIEnv *env = JNFObtainEnv(&threadWasAttached);
|
||||
JNFCallStaticVoidMethod(env, jm_Subclassing_initJObject,
|
||||
ptr_to_jlong(obj));
|
||||
|
||||
JNFReleaseEnv(env, &threadWasAttached);
|
||||
}
|
||||
|
||||
|
||||
#pragma mark Adding methods
|
||||
|
||||
static ffi_closure *make_closure(ffi_cif *cif, void *user_data);
|
||||
static void sel_closure_call(ffi_cif* cif, void* result, void** args, void* user_data);
|
||||
|
||||
typedef struct closure_data_t{
|
||||
JNFJObjectWrapper *jMethod;
|
||||
JNFJObjectWrapper *jCIF;
|
||||
} closure_data_t;
|
||||
|
||||
static ffi_closure *make_closure(ffi_cif *cif, void *user_data){
|
||||
// Allocate a page to hold the closure with read and write permissions.
|
||||
ffi_closure *closure;
|
||||
if ((closure = mmap(NULL, sizeof(ffi_closure), PROT_READ | PROT_WRITE,
|
||||
MAP_ANON | MAP_PRIVATE, -1, (off_t) 0)) == (void*)-1)
|
||||
{
|
||||
fprintf(stderr, "mmap failed with errno: %d", errno);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Prepare the ffi_closure structure.
|
||||
ffi_status status;
|
||||
if ((status = ffi_prep_closure(closure, cif, sel_closure_call, (void *)user_data)) != FFI_OK)
|
||||
{
|
||||
fprintf(stderr, "ffi_prep_closure failed with ffi_status: %d", status);
|
||||
munmap(closure, sizeof(ffi_closure));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Ensure that the closure will execute on all architectures.
|
||||
if (mprotect(closure, sizeof(closure), PROT_READ | PROT_EXEC) == -1)
|
||||
{
|
||||
fprintf(stderr, "mprotect failed with errno: %d", errno);
|
||||
munmap(closure, sizeof(ffi_closure));
|
||||
return NULL;
|
||||
}
|
||||
return closure;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_com_apple_jobjc_Subclassing_addMethod
|
||||
(JNIEnv *env, jclass clazz, jlong jClass, jstring jSelName, jobject jMethod,
|
||||
jobject jCIF, jlong jCIFPtr, jstring jObjCEncodedType)
|
||||
{
|
||||
ffi_cif *cif = jlong_to_ptr(jCIFPtr);
|
||||
|
||||
closure_data_t *user_data = malloc(sizeof(closure_data_t));
|
||||
user_data->jMethod = [[JNFJObjectWrapper alloc] initWithJObject:jMethod withEnv:env];
|
||||
user_data->jCIF = [[JNFJObjectWrapper alloc] initWithJObject:jCIF withEnv:env];
|
||||
|
||||
ffi_closure *closure;;
|
||||
if(!(closure = make_closure(cif, user_data))){
|
||||
[user_data->jMethod release];
|
||||
[user_data->jCIF release];
|
||||
free(user_data);
|
||||
return NO;
|
||||
}
|
||||
|
||||
const Class objcClass = (Class)jlong_to_ptr(jClass);
|
||||
|
||||
const char *selName = (*env)->GetStringUTFChars(env, jSelName, JNI_FALSE);
|
||||
const char *objCEncodedType = (*env)->GetStringUTFChars(env, jObjCEncodedType, JNI_FALSE);
|
||||
|
||||
// NSLog(@"Adding method '%s' :: '%s' to '%s' / %p",
|
||||
// selName,
|
||||
// objCEncodedType,
|
||||
// class_getName(objcClass),
|
||||
// objcClass);
|
||||
|
||||
BOOL ret = class_addMethod(objcClass, sel_registerName(selName), (IMP) closure, objCEncodedType);
|
||||
|
||||
(*env)->ReleaseStringUTFChars(env, jSelName, selName);
|
||||
(*env)->ReleaseStringUTFChars(env, jObjCEncodedType, objCEncodedType);
|
||||
|
||||
if(!ret){
|
||||
NSLog(@"class_addMethod failed");
|
||||
munmap(closure, sizeof(ffi_closure));
|
||||
[user_data->jMethod release];
|
||||
[user_data->jCIF release];
|
||||
free(user_data);
|
||||
return NO;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sel_closure_call(ffi_cif* cif, void* result, void** args, void* user_data)
|
||||
{
|
||||
id obj = *(id*) args[0];
|
||||
// SEL sel = *(SEL*) args[1];
|
||||
|
||||
// NSLog(@"Subclassing: sel_closure_call: %p %p", obj, sel);
|
||||
// NSLog(@"Subclassing: sel_closure_call: obj class: %@ sel name: %s", object_getClass(obj), sel_getName(sel));
|
||||
|
||||
jobject jObj = getJObjectFromIVar(obj);
|
||||
|
||||
if(!jObj){
|
||||
addJavaInstance(obj);
|
||||
jObj = getJObjectFromIVar(obj);
|
||||
}
|
||||
|
||||
closure_data_t *jmeta = user_data;
|
||||
jobject jMethod = [jmeta->jMethod jObject];
|
||||
jobject jCIF = [jmeta->jCIF jObject];
|
||||
|
||||
JNFThreadContext threadWasAttached = JNFThreadDetachOnThreadDeath;
|
||||
JNIEnv *env = JNFObtainEnv(&threadWasAttached);
|
||||
|
||||
if((*env)->ExceptionOccurred(env)) goto bail;
|
||||
|
||||
static JNF_CLASS_CACHE(jc, "com/apple/jobjc/Subclassing");
|
||||
static JNF_STATIC_MEMBER_CACHE(jm_invokeFromJNI, jc, "invokeFromJNI",
|
||||
"(Lcom/apple/jobjc/ID;Ljava/lang/reflect/Method;Lcom/apple/jobjc/CIF;JJ)V");
|
||||
|
||||
JNFCallStaticVoidMethod(env, jm_invokeFromJNI,
|
||||
jObj,
|
||||
jMethod,
|
||||
jCIF,
|
||||
ptr_to_jlong(result),
|
||||
ptr_to_jlong(args));
|
||||
|
||||
bail:
|
||||
JNFReleaseEnv(env, &threadWasAttached);
|
||||
|
||||
if((*env)->ExceptionOccurred(env)){
|
||||
NSLog(@"Exception!");
|
||||
(*env)->ExceptionDescribe(env);
|
||||
}
|
||||
JNFReleaseEnv(env, &threadWasAttached);
|
||||
}
|
||||
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.apple.internal.jobjc.generator;
|
||||
|
||||
public class BootClassPathMinus {
|
||||
|
||||
/*
|
||||
* return the default boot class path with all parts mentioned in arguments removed
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
String bootClassPath = System.getProperty("sun.boot.class.path");
|
||||
StringBuffer newPath = new StringBuffer(bootClassPath.length());
|
||||
String[] bootClassPathParts = bootClassPath.split(java.io.File.pathSeparator, 0);
|
||||
for (String part : bootClassPathParts) {
|
||||
boolean found = false;
|
||||
for (String minus : args) {
|
||||
if (part.endsWith(minus)) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
if (newPath.length() > 0) newPath.append(java.io.File.pathSeparatorChar);
|
||||
newPath.append(part);
|
||||
}
|
||||
}
|
||||
System.out.println(newPath.toString());
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,112 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.apple.internal.jobjc.generator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.apple.internal.jobjc.generator.model.Category;
|
||||
import com.apple.internal.jobjc.generator.model.Clazz;
|
||||
import com.apple.internal.jobjc.generator.model.Framework;
|
||||
|
||||
public class ClassConsolidator {
|
||||
private static String[] PREFERRED_FRAMEWORKS = { "Foundation", "AppKit" };
|
||||
|
||||
static void consolidateClassesForFrameworks(final List<Framework> frameworks) throws Throwable {
|
||||
System.out.println("--2-- Resolving duplicate classes:");
|
||||
final Map<String, List<Clazz>> allClasses = new HashMap<String, List<Clazz>>();
|
||||
|
||||
for (final Framework framework : frameworks) {
|
||||
for (final Clazz clazz : framework.classes) {
|
||||
final List<Clazz> existingClazzList = allClasses.get(clazz.name);
|
||||
if(existingClazzList != null)
|
||||
existingClazzList.add(clazz);
|
||||
else
|
||||
allClasses.put(clazz.name, new ArrayList<Clazz>(Arrays.asList(clazz)));
|
||||
}
|
||||
}
|
||||
|
||||
final Map<String, Clazz> filteredClasses = new HashMap<String, Clazz>();
|
||||
final List<List<Clazz>> dreggs = new ArrayList<List<Clazz>>();
|
||||
|
||||
final Collection<List<Clazz>> clazzLists = allClasses.values();
|
||||
for (final List<Clazz> clazzList : clazzLists) {
|
||||
if (clazzList.size() > 1) {
|
||||
// add to the list for later analysis
|
||||
dreggs.add(clazzList);
|
||||
continue;
|
||||
}
|
||||
|
||||
// if there is only one class definition, go with it!
|
||||
final Clazz clazz = clazzList.get(0);
|
||||
filteredClasses.put(clazz.name, clazz);
|
||||
}
|
||||
|
||||
// figure out which class is the real class, and convert the rest to categories
|
||||
for (final List<Clazz> dreg : dreggs)
|
||||
deriveCategoriesFrom(dreg, filteredClasses);
|
||||
|
||||
// patch up the inheritance hierarchy
|
||||
System.out.println("Determining super classes:");
|
||||
for (final Framework framework : frameworks)
|
||||
framework.resolveSuperClasses(filteredClasses);
|
||||
}
|
||||
|
||||
private static void deriveCategoriesFrom(final List<Clazz> clazzes, final Map<String, Clazz> filteredClasses) {
|
||||
final List<Clazz> clazzesToDerive = new ArrayList<Clazz>(clazzes);
|
||||
|
||||
for (final String preferredFrameworkName : PREFERRED_FRAMEWORKS) {
|
||||
for (final Clazz clazz : clazzesToDerive) {
|
||||
if (!preferredFrameworkName.equals(clazz.parent.name)) continue;
|
||||
|
||||
System.out.print("\t" + clazz.parent.name + " owns \"" + clazz.name + "\", ");
|
||||
addCategoriesAndPatchClasses(clazzes, clazz);
|
||||
filteredClasses.put(clazz.name, clazz);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final List<String> frameworkNameList = new ArrayList<String>(clazzes.size());
|
||||
for (final Clazz clazz : clazzes) frameworkNameList.add(clazz.parent.name);
|
||||
throw new RuntimeException("Could not derived a preferred framework for: " + clazzes.get(0).name + ", from (" + Utils.joinWComma(frameworkNameList) + ")");
|
||||
}
|
||||
|
||||
private static void addCategoriesAndPatchClasses(final List<Clazz> clazzes, final Clazz clazz) {
|
||||
final List<String> fwNames = new ArrayList<String>(clazzes.size());
|
||||
|
||||
for (final Clazz cls : clazzes) {
|
||||
if (cls == clazz) continue;
|
||||
fwNames.add(cls.parent.name);
|
||||
cls.parent.classes.remove(cls);
|
||||
cls.parent.categories.add(new Category(cls, clazz));
|
||||
}
|
||||
|
||||
System.out.println("creating categories in: " + Utils.joinWComma(fwNames));
|
||||
}
|
||||
}
|
||||
@ -1,61 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.apple.internal.jobjc.generator;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
import com.apple.internal.jobjc.generator.classes.*;
|
||||
|
||||
public class FileCopier {
|
||||
public static List<OutputFile> addSourceFilesFrom(final String srcPath) {
|
||||
final List<OutputFile> outputFileList = new ArrayList<OutputFile>();
|
||||
|
||||
final List<File> fileList = getFileList(srcPath);
|
||||
for (final File file : fileList) {
|
||||
outputFileList.add(new CopiedFile(file, ClassGenerator.JOBJC_PACKAGE, file.getName().replace("\\.java", "")));
|
||||
}
|
||||
|
||||
return outputFileList;
|
||||
}
|
||||
|
||||
private static List<File> getFileList(final String srcPath) {
|
||||
final File srcRoot = new File(srcPath);
|
||||
if (!srcRoot.exists()) throw new RuntimeException("Source root " + srcRoot + " does not exist. Nowhere to copy base runtime objects from.");
|
||||
|
||||
final File targetDir = new File(srcRoot, ClassGenerator.JOBJC_PACKAGE.replaceAll("\\.", "\\/"));
|
||||
if (!targetDir.exists() || !targetDir.isDirectory()) throw new RuntimeException("Base runtime object source directory " + targetDir + " does not exist. No runtime class files to copy.");
|
||||
|
||||
final List<File> fileList = new ArrayList<File>();
|
||||
final File[] targetDirFileList = targetDir.listFiles();
|
||||
for (final File file : targetDirFileList) {
|
||||
if (!file.isFile()) continue;
|
||||
if (!file.getName().endsWith(".java")) continue;
|
||||
fileList.add(file);
|
||||
}
|
||||
|
||||
return fileList;
|
||||
}
|
||||
}
|
||||
@ -1,112 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.apple.internal.jobjc.generator;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.apple.internal.jobjc.generator.model.Framework;
|
||||
import com.apple.internal.jobjc.generator.model.Framework.FrameworkDependency;
|
||||
import com.apple.internal.jobjc.generator.utils.Fp;
|
||||
import com.apple.internal.jobjc.generator.utils.StructOffsetResolverBigBang;
|
||||
import com.apple.jobjc.JObjCRuntime;
|
||||
|
||||
public class FrameworkGenerator {
|
||||
private static final String BRIDGESUPPORT_FILE_EXTENSION = "Full.bridgesupport";
|
||||
private static final String FRAMEWORK_MATCH = "^.*Full\\.bridgesupport$";
|
||||
private static final String FRAMEWORK_PRUNE = "^.*(PyObjC|/Versions|\\.lproj|/Headers|/PrivateHeaders).*$";
|
||||
|
||||
static List<File> findFrameworkFilesIn(final File file) throws IOException{
|
||||
final List<File> bridgeSupportFiles = Utils.find(file, FRAMEWORK_MATCH, FRAMEWORK_PRUNE);
|
||||
System.out.println("found " + bridgeSupportFiles.size() + " frameworks");
|
||||
return bridgeSupportFiles;
|
||||
}
|
||||
|
||||
static List<Framework> parseFrameworksFrom(final List<File> bridgeSupportFiles) {
|
||||
final List<Framework> frameworks = new ArrayList<Framework>();
|
||||
|
||||
System.out.println("Parsing XML");
|
||||
for (final File file : bridgeSupportFiles){
|
||||
Framework f = new Framework(extractFrameworkNameFrom(file), file);
|
||||
try{
|
||||
f.load();
|
||||
frameworks.add(f);
|
||||
System.out.println("Generator@" + JObjCRuntime.ARCH + " loaded "
|
||||
+ f.name + " (" + Fp.join(":", f.binaries) + ")");
|
||||
}
|
||||
catch(Exception x){
|
||||
System.out.println("!! Generator@" + JObjCRuntime.ARCH + " failed to load "
|
||||
+ f.name + " (" + Fp.join(":", f.binaries) + "). SKIPPING");
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("Parsing dependencies");
|
||||
for (final Framework f : frameworks) f.parseDependencies(frameworks);
|
||||
|
||||
Set<String> alreadyWarnedDependency = new HashSet<String>();
|
||||
for(final Framework f : frameworks)
|
||||
for(final FrameworkDependency dep : f.dependencies)
|
||||
if(dep.object == null && !alreadyWarnedDependency.contains(dep.name)){
|
||||
System.out.println(String.format("Warning: unresolved dependency: %1$30s -> %2$s", f.name, dep.name));
|
||||
alreadyWarnedDependency.add(dep.name);
|
||||
}
|
||||
if(alreadyWarnedDependency.size() > 0)
|
||||
System.out.println("Unresolved dependencies lead to unresolved types.");
|
||||
|
||||
Utils.topologicalSort(frameworks);
|
||||
List<Framework> cycle = Utils.getDependencyCycle(frameworks);
|
||||
if(cycle != null)
|
||||
System.out.println("Warning: cycle found in framework dependencies: " + Fp.join(" -> ", cycle));
|
||||
|
||||
System.out.println("Parsing types");
|
||||
for (final Framework f : frameworks){
|
||||
f.parseCFTypes();
|
||||
f.parseOpaques();
|
||||
}
|
||||
for (final Framework f : frameworks) f.parseStructs();
|
||||
|
||||
new StructOffsetResolverBigBang().resolve(frameworks);
|
||||
|
||||
System.out.println("Parsing classes");
|
||||
for (final Framework f : frameworks) f.parseClasses();
|
||||
|
||||
System.out.println("Parsing constants");
|
||||
for (final Framework f : frameworks) f.parseConstants();
|
||||
|
||||
System.out.println("Parsing functions");
|
||||
for (final Framework f : frameworks) f.parseFunctions();
|
||||
|
||||
return frameworks;
|
||||
}
|
||||
|
||||
private static String extractFrameworkNameFrom(final File file) {
|
||||
final String fileName = file.getName();
|
||||
return fileName.substring(0, fileName.lastIndexOf(BRIDGESUPPORT_FILE_EXTENSION));
|
||||
}
|
||||
}
|
||||
@ -1,178 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.apple.internal.jobjc.generator;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import com.apple.internal.jobjc.generator.model.Arg;
|
||||
import com.apple.internal.jobjc.generator.model.Function;
|
||||
import com.apple.internal.jobjc.generator.model.Method;
|
||||
import com.apple.internal.jobjc.generator.model.types.JType;
|
||||
import com.apple.internal.jobjc.generator.utils.JavaLang.JLCall;
|
||||
import com.apple.internal.jobjc.generator.utils.JavaLang.JLField;
|
||||
import com.apple.internal.jobjc.generator.utils.JavaLang.JLMethod;
|
||||
import com.apple.internal.jobjc.generator.utils.JavaLang.JLTertiary;
|
||||
import com.apple.jobjc.Coder;
|
||||
import com.apple.jobjc.Invoke;
|
||||
import com.apple.jobjc.Invoke.FunCall;
|
||||
import com.apple.jobjc.Invoke.MsgSend;
|
||||
|
||||
public class FunctionGenerator {
|
||||
private final static String VARARGS_NAME = "varargs";
|
||||
|
||||
private static String createFieldCache(final Class<? extends Invoke> type, final Function fxn) {
|
||||
final String identifier = makeInstanceName(fxn);
|
||||
|
||||
JLField field = new JLField("private static", type.getCanonicalName(), identifier);
|
||||
// It's okay to make it static, because the getter isn't static, so the only way to access it is through an instance.
|
||||
JLMethod getter = new JLMethod("private final", type.getCanonicalName(), "get_" + identifier);
|
||||
|
||||
JLCall createIt = new JLCall("new " + type.getCanonicalName());
|
||||
createIt.args.add(firstArg(fxn));
|
||||
createIt.args.add("\"" + fxn.name + "\"");
|
||||
createIt.args.add(fxn.returnValue.type.getJType().getCoderDescriptor().getCoderInstanceName());
|
||||
for (final Arg arg : fxn.args)
|
||||
createIt.args.add(arg.type.getJType().getCoderDescriptor().getCoderInstanceName());
|
||||
|
||||
getter.body.add("return " + new JLTertiary(identifier + " != null", identifier, identifier + " = " + createIt) + ";");
|
||||
|
||||
return field.toString() + getter.toString();
|
||||
}
|
||||
|
||||
private static String createLocalForward(final Class<? extends Invoke> type, final Function fxn) {
|
||||
final String identifier = makeInstanceName(fxn);
|
||||
return new JLField("final", type.getCanonicalName(), identifier, new JLCall("get_" + identifier)).toString();
|
||||
}
|
||||
|
||||
private static String createLocalNew(final Class<? extends Invoke> type, final Function fxn) {
|
||||
final String identifier = makeInstanceName(fxn);
|
||||
StringWriter out = new StringWriter();
|
||||
|
||||
out.append(String.format("%3$s[] argCoders = new %3$s[%1$d + %2$s.length];\n", fxn.args.size(), VARARGS_NAME, Coder.class.getCanonicalName()));
|
||||
|
||||
for(int i = 0; i < fxn.args.size(); i++)
|
||||
out.append(String.format("argCoders[%1$d] = %2$s;\n", i, fxn.args.get(0).type.getJType().getCoderDescriptor().getCoderInstanceName()));
|
||||
|
||||
if(fxn.variadic){
|
||||
out.append(String.format("for(int i = %1$d; i < (%1$d + %2$s.length); i++)\n", fxn.args.size(), VARARGS_NAME));
|
||||
out.append(String.format("\targCoders[i] = %1$s.getCoderAtRuntime(%2$s[i - %3$s]);\n", Coder.class.getCanonicalName(), VARARGS_NAME, fxn.args.size()));
|
||||
}
|
||||
|
||||
out.append("final " + type.getCanonicalName() + " " + identifier + " = new " + type.getCanonicalName() + "(" + firstArg(fxn) + ", \"" + fxn.name + "\", "
|
||||
+ fxn.returnValue.type.getJType().getCoderDescriptor().getCoderInstanceName() + ", argCoders);");
|
||||
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
private static final String CONTEXT_NAME = "nativeBuffer";
|
||||
|
||||
public static void writeOutFunction(final PrintStream out, final Class<? extends Invoke> type, final Function fxn, final String initWithObj) {
|
||||
final String instName = makeInstanceName(fxn);
|
||||
final JType returnJavaType = fxn.returnValue.type.getJType();
|
||||
|
||||
if(!fxn.variadic){
|
||||
out.print(createFieldCache(type, fxn));
|
||||
out.println();
|
||||
}
|
||||
|
||||
JLMethod meth = new JLMethod("public", returnJavaType.getJavaReturnTypeName(), fxn.getJavaName());
|
||||
|
||||
for(Arg arg : fxn.args)
|
||||
meth.args.add("final " + arg.type.getJType().getTypeNameAsParam() + " " + arg.javaName);
|
||||
|
||||
if(fxn.variadic)
|
||||
meth.args.add("final Object... " + VARARGS_NAME);
|
||||
|
||||
if(fxn instanceof Method && ((Method)fxn).ignore){
|
||||
String suggestion = ((Method)fxn).suggestion == null ? "" : (" Suggested work-around: " + ((Method)fxn).suggestion);
|
||||
meth.jdoc.add("@deprecated The framework recommends that this method be ignored. (It may be deprecated.)" + suggestion);
|
||||
meth.attrs.add("@Deprecated");
|
||||
}
|
||||
|
||||
// type mismatch warning
|
||||
{
|
||||
{
|
||||
String retMsg = fxn.returnValue.type.getJType().getCoderDescriptor().mismatchMessage();
|
||||
if(retMsg != null){
|
||||
meth.jdoc.add("@deprecated Possible type mismatch: (return value) " + retMsg);
|
||||
meth.attrs.add("@Deprecated");
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < fxn.args.size(); i++){
|
||||
final Arg arg = fxn.args.get(i);
|
||||
String argMsg = arg.type.getJType().getCoderDescriptor().mismatchMessage();
|
||||
if(argMsg != null){
|
||||
meth.jdoc.add("@deprecated Possible type mismatch: (arg" + i + ": " + arg.javaName + ") " + argMsg);
|
||||
meth.attrs.add("@Deprecated");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(fxn.variadic)
|
||||
meth.body.add(createLocalNew(coreType(fxn), fxn));
|
||||
else
|
||||
meth.body.add(createLocalForward(coreType(fxn), fxn));
|
||||
|
||||
meth.body.add(returnJavaType.createDeclareBuffer(CONTEXT_NAME));
|
||||
meth.body.add(returnJavaType.createInit(CONTEXT_NAME, instName, initWithObj));
|
||||
|
||||
for(final Arg arg : fxn.args)
|
||||
meth.body.add(arg.type.getJType().getCoderDescriptor().getPushStatementFor(CONTEXT_NAME, arg.javaName));
|
||||
|
||||
if(fxn.variadic){
|
||||
meth.body.add(String.format("for(int i = %1$d; i < (%1$d + %2$s.length); i++)", fxn.args.size(), VARARGS_NAME));
|
||||
meth.body.add(String.format("\targCoders[i].push(%1$s, %2$s[i - %3$d]);", CONTEXT_NAME, VARARGS_NAME, fxn.args.size()));
|
||||
}
|
||||
|
||||
meth.body.add(returnJavaType.createInvoke(CONTEXT_NAME, instName));
|
||||
meth.body.add(returnJavaType.createPop(CONTEXT_NAME));
|
||||
meth.body.add(returnJavaType.createReturn());
|
||||
|
||||
out.print(meth.toString());
|
||||
out.println();
|
||||
}
|
||||
|
||||
private static Class<? extends Invoke> coreType(final Function fxn){
|
||||
return fxn instanceof Method ? MsgSend.class : FunCall.class;
|
||||
}
|
||||
|
||||
private static String firstArg(Function fxn){
|
||||
return fxn instanceof Method ? "getRuntime()" : "this";
|
||||
}
|
||||
|
||||
private static String makeInstanceName(Function fxn){
|
||||
String ext;
|
||||
if(fxn instanceof Method){
|
||||
if(((Method) fxn).isClassMethod) ext = "CMetInst";
|
||||
else ext = "IMetInst";
|
||||
}
|
||||
else
|
||||
ext = "FxnInst";
|
||||
|
||||
return fxn.getJavaName() + "_" + ext;
|
||||
}
|
||||
}
|
||||
@ -1,94 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.apple.internal.jobjc.generator;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.apple.internal.jobjc.generator.classes.MixedPrimitiveCoderClassFile;
|
||||
import com.apple.internal.jobjc.generator.classes.OutputFile;
|
||||
import com.apple.internal.jobjc.generator.model.Framework;
|
||||
import com.apple.internal.jobjc.generator.model.coders.ComplexCoderDescriptor;
|
||||
import com.apple.internal.jobjc.generator.model.types.Type;
|
||||
import com.apple.internal.jobjc.generator.model.types.TypeCache;
|
||||
import com.apple.internal.jobjc.generator.utils.Fp.Pair;
|
||||
|
||||
public class Generator {
|
||||
private static final String DEFAULT_FRAMEWORKS_PATH = "/System/Library/Frameworks";
|
||||
private static final String DEFAULT_OUTPUT_PATH = "/tmp/JObjC";
|
||||
|
||||
public static void main(final String...args) throws Throwable {
|
||||
final Map<String, String> argMap = Utils.getArgs(args);
|
||||
|
||||
final String dst = get(argMap, "dst", DEFAULT_OUTPUT_PATH);
|
||||
System.out.println("Cleaning up: " + dst);
|
||||
final File dstLoc = new File(dst);
|
||||
Utils.recDelete(dstLoc);
|
||||
dstLoc.mkdirs();
|
||||
System.out.println("Outputting classes to: " + dst);
|
||||
|
||||
final String frameworksPath = get(argMap, "frameworks", DEFAULT_FRAMEWORKS_PATH);
|
||||
System.out.println("Searching for bridged frameworks in: " + frameworksPath);
|
||||
|
||||
final List<File> bridgeSupportFiles = FrameworkGenerator.findFrameworkFilesIn(new File(frameworksPath));
|
||||
final List<Framework> frameworks = FrameworkGenerator.parseFrameworksFrom(bridgeSupportFiles);
|
||||
|
||||
System.out.println("--1-- Generator: consolidateClassesForFrameworks");
|
||||
ClassConsolidator.consolidateClassesForFrameworks(frameworks);
|
||||
|
||||
System.out.println("--1-- Generator: TypeCache load");
|
||||
TypeCache.inst().load(frameworks);
|
||||
|
||||
System.out.println("--1-- Generator: disambiguateMethodNames");
|
||||
MethodDisambiguator.disambiguateMethodNames();
|
||||
|
||||
System.out.println("--1-- Generator: disambiguateFunctionsIn");
|
||||
MethodDisambiguator.disambiguateFunctionsIn(frameworks);
|
||||
|
||||
System.out.println("--1-- Generator: generateClasses");
|
||||
final List<OutputFile> sourceFiles = ClassGenerator.generateClasses(frameworks);
|
||||
sourceFiles.add(new MixedPrimitiveCoderClassFile(ComplexCoderDescriptor.getMixedEncoders()));
|
||||
|
||||
System.out.println("--1-- Generator: writing " + sourceFiles.size() + " files");
|
||||
for (final OutputFile sourceFile : sourceFiles) sourceFile.write(dstLoc);
|
||||
|
||||
System.out.println("I have " + TypeCache.inst().getUnknownTypes().size() + " unresolved types.");
|
||||
for (final Type type : TypeCache.inst().getUnknownTypes())
|
||||
System.out.println("[Warning] unknown type: " + type);
|
||||
|
||||
for(Type type : TypeCache.inst().typesByNTypes.values()){
|
||||
if(!type.type32.getClass().equals(type.type64.getClass())){
|
||||
System.out.format("Type with differing NTypes: %1$15s: %2$s\n", type.name, new Pair(type.type32, type.type64));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String get(final Map<String, String> defaults, final String key, final String defaultValue) {
|
||||
final String value = defaults.get(key);
|
||||
if (value != null) return value;
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.apple.internal.jobjc.generator;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.apple.internal.jobjc.generator.model.Clazz;
|
||||
import com.apple.internal.jobjc.generator.model.Framework;
|
||||
import com.apple.internal.jobjc.generator.model.Function;
|
||||
import com.apple.internal.jobjc.generator.model.types.TypeCache;
|
||||
|
||||
public class MethodDisambiguator {
|
||||
static void disambiguateMethodNames() {
|
||||
// link all subclassers off their parents
|
||||
for (final Clazz clazz : TypeCache.inst().getAllClasses()) {
|
||||
final Clazz superClazz = clazz.superClass;
|
||||
if (superClazz != null) superClazz.subClassers.add(clazz);
|
||||
}
|
||||
|
||||
// recursively call all subclassers, starting from NSObject on down
|
||||
disambiguateMethodNamesFor(TypeCache.inst().getClassForName("NSObject"));
|
||||
|
||||
// NSProxy does not appear to subclass from NSObject, but it is still a real full class...?
|
||||
disambiguateMethodNamesFor(TypeCache.inst().getClassForName("NSProxy"));
|
||||
}
|
||||
|
||||
static void disambiguateMethodNamesFor(final Clazz clazz) {
|
||||
clazz.disambiguateMethods();
|
||||
for (final Clazz subClazz : clazz.subClassers) {
|
||||
disambiguateMethodNamesFor(subClazz);
|
||||
}
|
||||
}
|
||||
|
||||
public static void disambiguateFunctionsIn(final List<Framework> frameworks) {
|
||||
for (final Framework framework : frameworks) {
|
||||
disambiguateFunctionsInFramework(framework);
|
||||
}
|
||||
}
|
||||
|
||||
static void disambiguateFunctionsInFramework(final Framework framework) {
|
||||
for (final Function fxn : framework.functions)
|
||||
fxn.disambiguateArgs();
|
||||
}
|
||||
}
|
||||
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.apple.internal.jobjc.generator;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class RestrictedKeywords {
|
||||
static final String[] JAVA_KEYWORD_CONFLICTS = {
|
||||
"wait", "null", "class", "new", "toString", "finalize", "boolean", "interface", "final", "static"
|
||||
};
|
||||
|
||||
static final Set<String> originalRestrictedSet = new HashSet<String>(Arrays.asList(JAVA_KEYWORD_CONFLICTS));
|
||||
|
||||
public static Set<String> getNewRestrictedSet() {
|
||||
return new HashSet<String>(originalRestrictedSet);
|
||||
}
|
||||
|
||||
public static boolean isRestricted(String s){
|
||||
return originalRestrictedSet.contains(s);
|
||||
}
|
||||
}
|
||||
@ -1,186 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.apple.internal.jobjc.generator;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.apple.internal.jobjc.generator.model.Framework;
|
||||
import com.apple.internal.jobjc.generator.model.Framework.FrameworkDependency;
|
||||
import com.apple.internal.jobjc.generator.utils.Fp;
|
||||
|
||||
public class Utils {
|
||||
public static boolean isLeopard = System.getProperty("os.version").startsWith("10.5");
|
||||
public static boolean isSnowLeopard = System.getProperty("os.version").startsWith("10.6");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> List<T> list(final Object...args) {
|
||||
final ArrayList<Object> list = new ArrayList<Object>(args.length);
|
||||
for (final Object arg : args) list.add(arg);
|
||||
return (List<T>)list;
|
||||
}
|
||||
|
||||
/**
|
||||
* A small implementation of UNIX find.
|
||||
* @param matchRegex Only collect paths that match this regex.
|
||||
* @param pruneRegex Don't recurse down a path that matches this regex. May be null.
|
||||
* @throws IOException if File.getCanonicalPath() fails.
|
||||
*/
|
||||
public static List<File> find(final File startpath, final String matchRegex, final String pruneRegex) throws IOException{
|
||||
final Pattern matchPattern = Pattern.compile(matchRegex, Pattern.CASE_INSENSITIVE);
|
||||
final Pattern prunePattern = pruneRegex == null ? null : Pattern.compile(pruneRegex, Pattern.CASE_INSENSITIVE);
|
||||
final Set<String> visited = new HashSet<String>();
|
||||
final List<File> found = new ArrayList<File>();
|
||||
class Search{
|
||||
void search(final File path) throws IOException{
|
||||
if(prunePattern != null && prunePattern.matcher(path.getAbsolutePath()).matches()) return;
|
||||
String cpath = path.getCanonicalPath();
|
||||
if(!visited.add(cpath)) return;
|
||||
if(matchPattern.matcher(path.getAbsolutePath()).matches())
|
||||
found.add(path);
|
||||
if(path.isDirectory())
|
||||
for(File sub : path.listFiles())
|
||||
search(sub);
|
||||
}
|
||||
}
|
||||
new Search().search(startpath);
|
||||
return found;
|
||||
}
|
||||
|
||||
public static String joinWComma(final List<?> list) { return Fp.join(", ", list); }
|
||||
public static String joinWComma(final Object[] list) { return Fp.join(", ", Arrays.asList(list)); }
|
||||
|
||||
public static class Substituter {
|
||||
String str;
|
||||
|
||||
public Substituter(final String str) {
|
||||
this.str = str.replaceAll("\\#", "\t").replaceAll("\\~", "\n");
|
||||
}
|
||||
|
||||
public void replace(final String key, final String value) {
|
||||
str = str.replaceAll("\\$" + key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply String.format first, and then pass through Substituter.
|
||||
*/
|
||||
public static String format(String format, Object... args){
|
||||
return new Substituter(String.format(format, args)).toString();
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
static Map<String, String> getArgs(final String...args) {
|
||||
final Map<String, String> argMap = new HashMap<String, String>();
|
||||
for (final String arg : args) {
|
||||
final String[] splitArg = arg.split("\\=");
|
||||
if (splitArg.length != 2) continue;
|
||||
argMap.put(splitArg[0], splitArg[1]);
|
||||
}
|
||||
return argMap;
|
||||
}
|
||||
|
||||
static void recDelete(final File file) {
|
||||
if (!file.exists()) return;
|
||||
if (file.isDirectory()) for (final File f : file.listFiles()) recDelete(f);
|
||||
file.delete();
|
||||
}
|
||||
|
||||
public static String capitalize(String s){
|
||||
if(s.length() == 0) return s;
|
||||
return Character.toString(Character.toUpperCase(s.charAt(0))) + s.substring(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort frameworks by dependencies. If A is a dependency of B,
|
||||
* then A will come before B in the list.
|
||||
*/
|
||||
public static void topologicalSort(final List<Framework> frameworks) {
|
||||
final Set<Framework> visited = new TreeSet<Framework>();
|
||||
final List<Framework> sorted = new ArrayList<Framework>(frameworks.size());
|
||||
class Rec{
|
||||
void visit(final Framework fw){
|
||||
if(!visited.add(fw)) return;
|
||||
for(FrameworkDependency dep : fw.dependencies)
|
||||
if(dep.object != null)
|
||||
visit(dep.object);
|
||||
sorted.add(fw);
|
||||
}
|
||||
}
|
||||
for(Framework fw : frameworks) new Rec().visit(fw);
|
||||
frameworks.clear();
|
||||
frameworks.addAll(sorted);
|
||||
}
|
||||
|
||||
/**
|
||||
* If there is a cycle it is returned. Otherwise null is returned.
|
||||
*/
|
||||
public static List<Framework> getDependencyCycle(List<Framework> frameworks) {
|
||||
@SuppressWarnings("serial")
|
||||
class FoundCycle extends Throwable{
|
||||
public final List<Framework> cycle;
|
||||
public FoundCycle(List<Framework> cycle){
|
||||
this.cycle = cycle;
|
||||
}
|
||||
};
|
||||
class Rec{
|
||||
void visit(final Framework fw, List<Framework> visited) throws FoundCycle{
|
||||
visited = new LinkedList<Framework>(visited);
|
||||
if(visited.contains(fw)){
|
||||
visited.add(fw);
|
||||
throw new FoundCycle(visited);
|
||||
}
|
||||
visited.add(fw);
|
||||
for(FrameworkDependency dep : fw.dependencies)
|
||||
if(dep.object != null)
|
||||
visit(dep.object, visited);
|
||||
}
|
||||
}
|
||||
try{ for(Framework fw : frameworks){ new Rec().visit(fw, new LinkedList<Framework>()); }}
|
||||
catch(FoundCycle x){ return x.cycle; }
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getCanonicalPath(File file) throws RuntimeException{
|
||||
try {
|
||||
return file.getCanonicalPath();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,59 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.apple.internal.jobjc.generator.classes;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
import com.apple.internal.jobjc.generator.model.CFType;
|
||||
import com.apple.jobjc.Pointer;
|
||||
|
||||
public class CFTypeClassFile extends GeneratedClassFile {
|
||||
final CFType cftype;
|
||||
|
||||
public CFTypeClassFile(final CFType cftype) {
|
||||
super(cftype.parent.pkg, cftype.type.getJType().getJavaClassName(), com.apple.jobjc.CFType.class.getCanonicalName());
|
||||
this.cftype = cftype;
|
||||
}
|
||||
|
||||
@Override public void writeBeginning(PrintStream out){
|
||||
out.println("\tpublic " + className + "(" + Pointer.class.getName() + "<?> ptr){");
|
||||
out.println("\t\tsuper(ptr);");
|
||||
out.println("\t}");
|
||||
out.println("");
|
||||
out.println("\tpublic " + className + "(long ptr){");
|
||||
out.println("\t\tsuper(ptr);");
|
||||
out.println("\t}");
|
||||
}
|
||||
|
||||
@Override public void writeBody(PrintStream out){
|
||||
if(cftype.getTypeIdFunc != null){
|
||||
out.println("\tpublic static long getTypeId(){");
|
||||
out.println("\t\treturn " + RootJObjCClass.runtimeFrameworkInst(cftype.parent.name) + "." + cftype.getTypeIdFunc + "();");
|
||||
out.println("\t}");
|
||||
}
|
||||
else
|
||||
out.println("\t// getTypeIdFunc not found");
|
||||
}
|
||||
}
|
||||
@ -1,64 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.apple.internal.jobjc.generator.classes;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.apple.internal.jobjc.generator.FunctionGenerator;
|
||||
import com.apple.internal.jobjc.generator.model.Category;
|
||||
import com.apple.internal.jobjc.generator.model.Method;
|
||||
import com.apple.jobjc.JObjCRuntime;
|
||||
import com.apple.jobjc.Invoke.MsgSend;
|
||||
|
||||
public class CategoryClassClassFile extends AbstractObjCClassFile {
|
||||
final Category category;
|
||||
|
||||
public CategoryClassClassFile(final Category category) {
|
||||
super(category.category, category.category.name + "Class",
|
||||
category.category.superClass.getFullPath() + "Class");
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
@Override public void writeBeginning(final PrintStream out) {
|
||||
out.format(
|
||||
"\t%1$s(%2$s runtime) {\n" +
|
||||
"\t\tsuper(\"%3$s\", runtime);\n" +
|
||||
"\t}\n",
|
||||
className, JObjCRuntime.class.getCanonicalName(), category.category.superClass.name);
|
||||
}
|
||||
|
||||
@Override public void writeBody(final PrintStream out) {
|
||||
Set<String> written = new HashSet<String>();
|
||||
for(final Method method : this.clazz.classMethods)
|
||||
if(written.add(method.name))
|
||||
FunctionGenerator.writeOutFunction(out, MsgSend.class, method, "this");
|
||||
else
|
||||
System.out.format("Duplicate method: %1$s %2$s -%3$s\n", clazz.parent.name, className, method.name);
|
||||
}
|
||||
|
||||
@Override protected boolean isFinal(){ return true; }
|
||||
}
|
||||
@ -1,48 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.apple.internal.jobjc.generator.classes;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
import com.apple.internal.jobjc.generator.model.Category;
|
||||
import com.apple.jobjc.JObjCRuntime;
|
||||
|
||||
public class CategoryClassFile extends JObjCClassFile {
|
||||
private final Category category;
|
||||
|
||||
public CategoryClassFile(final Category category) {
|
||||
super(category.category);
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
@Override public void writeBeginning(final PrintStream out) {
|
||||
String targetCls = category.category.superClass.getFullPath();
|
||||
out.format("\tpublic %1$s(final %2$s obj, final %3$s runtime) {\n" +
|
||||
"\t\tsuper(obj, runtime);\n" +
|
||||
"\t}\n",
|
||||
className, targetCls, JObjCRuntime.class.getCanonicalName());
|
||||
super.writeBeginning(out);
|
||||
}
|
||||
}
|
||||
@ -1,54 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.apple.internal.jobjc.generator.classes;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class CopiedFile extends OutputFile {
|
||||
final File sourceFile;
|
||||
|
||||
public CopiedFile(final File sourceFile, final String pkg, final String filename) {
|
||||
super(pkg, filename);
|
||||
this.sourceFile = sourceFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(final File parentDir) {
|
||||
try {
|
||||
final PrintStream out = open(parentDir);
|
||||
final InputStream in = new FileInputStream(sourceFile);
|
||||
|
||||
copy(in, out);
|
||||
close(out);
|
||||
} catch (final IOException e) { throw new RuntimeException(e); }
|
||||
}
|
||||
|
||||
private static void copy(final InputStream in, final PrintStream out) throws IOException {
|
||||
int bit;
|
||||
while (-1 != (bit = in.read())) {
|
||||
out.write(bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,160 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.apple.internal.jobjc.generator.classes;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import com.apple.internal.jobjc.generator.FunctionGenerator;
|
||||
import com.apple.internal.jobjc.generator.Utils;
|
||||
import com.apple.internal.jobjc.generator.model.Category;
|
||||
import com.apple.internal.jobjc.generator.model.Clazz;
|
||||
import com.apple.internal.jobjc.generator.model.Constant;
|
||||
import com.apple.internal.jobjc.generator.model.Framework;
|
||||
import com.apple.internal.jobjc.generator.model.Function;
|
||||
import com.apple.internal.jobjc.generator.model.NativeEnum;
|
||||
import com.apple.internal.jobjc.generator.model.StringConstant;
|
||||
import com.apple.internal.jobjc.generator.model.Struct;
|
||||
import com.apple.internal.jobjc.generator.model.types.JType;
|
||||
import com.apple.internal.jobjc.generator.model.types.JType.JStruct;
|
||||
import com.apple.internal.jobjc.generator.utils.Fp;
|
||||
import com.apple.internal.jobjc.generator.utils.JavaLang;
|
||||
import com.apple.internal.jobjc.generator.utils.Fp.Map1;
|
||||
import com.apple.internal.jobjc.generator.utils.JavaLang.JLCall;
|
||||
import com.apple.internal.jobjc.generator.utils.JavaLang.JLField;
|
||||
import com.apple.internal.jobjc.generator.utils.JavaLang.JLMethod;
|
||||
import com.apple.internal.jobjc.generator.utils.JavaLang.JLReturn;
|
||||
import com.apple.jobjc.JObjCRuntime;
|
||||
import com.apple.jobjc.MacOSXFramework;
|
||||
import com.apple.jobjc.Invoke.FunCall;
|
||||
|
||||
public class FrameworkClassFile extends GeneratedClassFile {
|
||||
final Framework framework;
|
||||
|
||||
public FrameworkClassFile(final Framework framework) {
|
||||
super(framework.pkg, framework.name + "Framework", MacOSXFramework.class.getName());
|
||||
this.framework = framework;
|
||||
}
|
||||
|
||||
@Override public void writeBeginning(final PrintStream out) {
|
||||
List<String> binPaths = Fp.map(new Map1<File,String>(){
|
||||
public String apply(File a) { return "\"" + a.getAbsolutePath() + "\""; }},
|
||||
framework.binaries);
|
||||
out.println(new Utils.Substituter(
|
||||
"#public " + className + "(" + JObjCRuntime.class.getName() + " runtime) {~" +
|
||||
"##super(runtime, new String[]{" + Fp.join(", ", binPaths) + "});~" +
|
||||
"#}~"
|
||||
));
|
||||
}
|
||||
|
||||
@Override public void writeBody(final PrintStream out) {
|
||||
for(final Struct struct : new ArrayList<Struct>(framework.structs)){
|
||||
out.println("\tpublic " + struct.name + " make" + struct.name + "(){");
|
||||
out.println("\t\treturn new " + struct.name + "(getRuntime());");
|
||||
out.println("\t}");
|
||||
out.println("\tpublic " + struct.name + " make" + struct.name + "(com.apple.jobjc.NativeBuffer base){");
|
||||
out.println("\t\treturn new " + struct.name + "(getRuntime(), base);");
|
||||
out.println("\t}");
|
||||
}
|
||||
|
||||
for(final NativeEnum nenum : framework.enums){
|
||||
if(nenum.ignore){
|
||||
out.println("\t/**");
|
||||
out.println("\t * @deprecated Suggestion: " + nenum.suggestion);
|
||||
out.println("\t */");
|
||||
out.println("\t@Deprecated");
|
||||
}
|
||||
out.println(String.format("\tpublic final %3$s %1$s(){ return %2$s; }",
|
||||
nenum.name, nenum.valueToString(), nenum.type.getJType().getJavaReturnTypeName()));
|
||||
}
|
||||
|
||||
for(final Constant konst : framework.constants){
|
||||
String cacheName = "_" + konst.name;
|
||||
final JType jtype = konst.type.getJType();
|
||||
final String cast = jtype.getReturnTypeCast() == null ? "" : "(" + jtype.getReturnTypeCast() + ")";
|
||||
out.println();
|
||||
|
||||
out.print(new JLField("private", jtype.getJavaTypeName(), cacheName, jtype.getDefaultReturnValue()));
|
||||
|
||||
JLMethod reader = new JLMethod("public final", jtype.getJavaReturnTypeName(), konst.name);
|
||||
reader.body.add("if(" + cacheName + " != " + jtype.getDefaultReturnValue() + ") return " + cast + cacheName + ";");
|
||||
|
||||
String contextName = jtype instanceof JStruct ? "returnValue" : "nativeBuffer";
|
||||
|
||||
if(jtype instanceof JStruct)
|
||||
reader.body.add(((JStruct)jtype).createReturnValue());
|
||||
else
|
||||
reader.body.add(jtype.createDeclareBuffer(contextName));
|
||||
|
||||
reader.body.add("getConstant(\"" + konst.name + "\", " + contextName + ", " + jtype.getCoderDescriptor().getCoderInstanceName() + ".sizeof());");
|
||||
|
||||
reader.body.add(jtype.createPop(contextName));
|
||||
reader.body.add(cacheName + " = returnValue;");
|
||||
reader.body.add(jtype.createReturn());
|
||||
|
||||
out.print(reader);
|
||||
}
|
||||
|
||||
for(final StringConstant konst : framework.stringConstants){
|
||||
if(Fp.any(new Map1<Constant,Boolean>(){ public Boolean apply(Constant a) {
|
||||
return a.name.equals(konst.name);
|
||||
}}, new ArrayList<Constant>(framework.constants))){
|
||||
System.out.println("Warning: [" + framework.name + "] String constant " + konst.name + " is already defined in constants. Skipping.");
|
||||
}
|
||||
else{
|
||||
out.println("\tpublic final String " + konst.name + "(){ return \"" + escapeQuotes(konst.value) + "\"; }");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Order classes to get stable output
|
||||
*/
|
||||
TreeSet<Clazz> sortedClasses = new TreeSet<Clazz>(framework.classes);
|
||||
for (final Clazz clazz : sortedClasses) {
|
||||
final String classClassName = clazz.name + "Class";
|
||||
out.println(JavaLang.makeSingleton("_" + classClassName, clazz.name, classClassName, "getRuntime()"));
|
||||
}
|
||||
|
||||
for (final Category cat : framework.categories) {
|
||||
final String classClassName = cat.category.name + "Class";
|
||||
out.println(JavaLang.makeSingleton("_" + classClassName, cat.category.name, classClassName, "getRuntime()"));
|
||||
|
||||
JLMethod jlm = new JLMethod("public", cat.category.name, cat.category.name, "final " + cat.category.superClass.getFullPath() + " obj");
|
||||
jlm.body.add(new JLReturn(new JLCall("new " + cat.category.name, "obj", "getRuntime()")));
|
||||
out.println(jlm);
|
||||
}
|
||||
|
||||
for (final Function fxn : framework.functions){
|
||||
FunctionGenerator.writeOutFunction(out, FunCall.class, fxn, null);
|
||||
}
|
||||
}
|
||||
|
||||
private String escapeQuotes(String s){
|
||||
return s.replace("\"", "\\\"");
|
||||
}
|
||||
}
|
||||
@ -1,78 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.apple.internal.jobjc.generator.classes;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
|
||||
public class GeneratedClassFile extends OutputFile {
|
||||
protected final String className;
|
||||
protected final String genericArgs;
|
||||
protected final String superClass;
|
||||
|
||||
public GeneratedClassFile(final String pkg, final String classname, final String superClass) {
|
||||
this(pkg, classname, null, superClass);
|
||||
}
|
||||
|
||||
public GeneratedClassFile(final String pkg, final String classname, final String genericArgs, final String superClass) {
|
||||
super(pkg, classname + ".java");
|
||||
this.className = classname;
|
||||
this.genericArgs = genericArgs;
|
||||
this.superClass = superClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(final File parentDir) {
|
||||
try {
|
||||
final PrintStream out = open(parentDir);
|
||||
out.println("package " + pkg + ";");
|
||||
out.println();
|
||||
out.print("public " + (isFinal() ? "final" : "") + " class " + className);
|
||||
if(genericArgs != null) out.print("<" + genericArgs + ">");
|
||||
if (superClass != null) out.print(" extends " + superClass);
|
||||
out.println(" {");
|
||||
writeBeginning(out);
|
||||
writeBody(out);
|
||||
writeEnd(out);
|
||||
out.println("}");
|
||||
close(out);
|
||||
} catch (final IOException e) { throw new RuntimeException(e); }
|
||||
}
|
||||
|
||||
public void writeBeginning(final PrintStream out) {
|
||||
|
||||
}
|
||||
|
||||
public void writeBody(final PrintStream out) {
|
||||
|
||||
}
|
||||
|
||||
public void writeEnd(final PrintStream out) {
|
||||
|
||||
}
|
||||
|
||||
protected boolean isFinal(){ return false; }
|
||||
}
|
||||
@ -1,69 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.apple.internal.jobjc.generator.classes;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.apple.internal.jobjc.generator.ClassGenerator;
|
||||
import com.apple.internal.jobjc.generator.FunctionGenerator;
|
||||
import com.apple.internal.jobjc.generator.model.Clazz;
|
||||
import com.apple.internal.jobjc.generator.model.Method;
|
||||
import com.apple.jobjc.JObjCRuntime;
|
||||
import com.apple.jobjc.Invoke.MsgSend;
|
||||
|
||||
public class JObjCClassClassFile extends AbstractObjCClassFile {
|
||||
public JObjCClassClassFile(final Clazz clazz) {
|
||||
super(clazz, clazz.name + "Class", clazz.superClass != null ? clazz.superClass.getFullPath() + "Class" : ClassGenerator.JOBJC_PACKAGE + ".NSClass<" + clazz.name + ">");
|
||||
}
|
||||
|
||||
@Override public void writeBeginning(final PrintStream out) {
|
||||
out.format(
|
||||
"\tpublic %1$s(%2$s runtime) {\n" +
|
||||
"\t\tsuper(runtime);\n" +
|
||||
"\t}\n",
|
||||
className, JObjCRuntime.class.getCanonicalName());
|
||||
out.format(
|
||||
"\tpublic %1$s(String name, %2$s runtime) {\n" +
|
||||
"\t\tsuper(name, runtime);\n" +
|
||||
"\t}\n",
|
||||
className, JObjCRuntime.class.getCanonicalName());
|
||||
out.format(
|
||||
"\tpublic %1$s(long ptr, %2$s runtime) {\n" +
|
||||
"\t\tsuper(ptr, runtime);\n" +
|
||||
"\t}\n",
|
||||
className, JObjCRuntime.class.getCanonicalName());
|
||||
}
|
||||
|
||||
@Override public void writeBody(final PrintStream out) {
|
||||
Set<String> written = new HashSet<String>();
|
||||
for(final Method method : this.clazz.classMethods)
|
||||
if(written.add(method.name))
|
||||
FunctionGenerator.writeOutFunction(out, MsgSend.class, method, "this");
|
||||
else
|
||||
System.out.format("Duplicate method: %1$s %2$s -%3$s\n", clazz.parent.name, className, method.name);
|
||||
}
|
||||
}
|
||||
@ -1,81 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.apple.internal.jobjc.generator.classes;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import com.apple.internal.jobjc.generator.FunctionGenerator;
|
||||
import com.apple.internal.jobjc.generator.model.Clazz;
|
||||
import com.apple.internal.jobjc.generator.model.Method;
|
||||
import com.apple.jobjc.JObjCRuntime;
|
||||
import com.apple.jobjc.NativeObjectLifecycleManager;
|
||||
import com.apple.jobjc.Invoke.MsgSend;
|
||||
|
||||
public class JObjCClassFile extends AbstractObjCClassFile {
|
||||
public JObjCClassFile(final Clazz clazz) {
|
||||
super(clazz, clazz.name,
|
||||
clazz.superClass == null ? "com.apple.jobjc.ID"
|
||||
: clazz.superClass.getFullPath());
|
||||
}
|
||||
|
||||
private static Map<String, NativeObjectLifecycleManager> nolmForClass =
|
||||
new TreeMap<String, NativeObjectLifecycleManager>();
|
||||
static{
|
||||
nolmForClass.put("NSAutoreleasePool", NativeObjectLifecycleManager.Nothing.INST);
|
||||
}
|
||||
|
||||
@Override public void writeBeginning(final PrintStream out) {
|
||||
out.format("\tpublic %1$s(final long objPtr, final %2$s runtime) {\n" +
|
||||
"\t\tsuper(objPtr, runtime);\n" +
|
||||
"\t}\n",
|
||||
className, JObjCRuntime.class.getCanonicalName());
|
||||
|
||||
out.format("\tpublic %1$s(final %1$s obj, final %2$s runtime) {\n" +
|
||||
"\t\tsuper(obj, runtime);\n" +
|
||||
"\t}\n",
|
||||
className, JObjCRuntime.class.getCanonicalName());
|
||||
|
||||
NativeObjectLifecycleManager nolm = nolmForClass.get(clazz.name);
|
||||
if(nolm != null)
|
||||
out.format("\t@Override\n"+
|
||||
"\tprotected %1$s getNativeObjectLifecycleManager() {\n" +
|
||||
"\t\treturn %2$s.INST;\n" +
|
||||
"\t}\n",
|
||||
NativeObjectLifecycleManager.class.getCanonicalName(), nolm.getClass().getCanonicalName());
|
||||
}
|
||||
|
||||
@Override public void writeBody(final PrintStream out) {
|
||||
Set<String> written = new HashSet<String>();
|
||||
for(final Method method : this.clazz.instanceMethods)
|
||||
if(written.add(method.name))
|
||||
FunctionGenerator.writeOutFunction(out, MsgSend.class, method, "this");
|
||||
else
|
||||
System.out.format("Duplicate method: %1$s %2$s -%3$s\n", clazz.parent.name, className, method.name);
|
||||
}
|
||||
}
|
||||
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.apple.internal.jobjc.generator.classes;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.Collection;
|
||||
|
||||
import com.apple.internal.jobjc.generator.ClassGenerator;
|
||||
import com.apple.internal.jobjc.generator.model.coders.ComplexCoderDescriptor.MixedEncodingDescriptor;
|
||||
import com.apple.jobjc.PrimitiveCoder;
|
||||
|
||||
public class MixedPrimitiveCoderClassFile extends GeneratedClassFile {
|
||||
private static final String MULTI_CODER_CLASSNAME = "MixedPrimitiveCoder";
|
||||
public static final String FULL_MULTI_CODER_CLASSNAME = ClassGenerator.JOBJC_PACKAGE + "." + MULTI_CODER_CLASSNAME;
|
||||
|
||||
final Collection<MixedEncodingDescriptor> coderDescs;
|
||||
|
||||
public MixedPrimitiveCoderClassFile(final Collection<MixedEncodingDescriptor> coderDescs) {
|
||||
super(ClassGenerator.JOBJC_PACKAGE, MULTI_CODER_CLASSNAME, "java.lang.Object");
|
||||
this.coderDescs = coderDescs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeBody(final PrintStream out) {
|
||||
for (final MixedEncodingDescriptor desc : coderDescs) {
|
||||
out.println("\tpublic static final " + PrimitiveCoder.class.getCanonicalName() + " " + desc.getMixedName() + " = " + desc.getDefinition() + ";");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,53 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.apple.internal.jobjc.generator.classes;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
import com.apple.internal.jobjc.generator.model.Opaque;
|
||||
import com.apple.jobjc.Pointer;
|
||||
|
||||
public class OpaqueClassFile extends GeneratedClassFile {
|
||||
final Opaque opaque;
|
||||
|
||||
public OpaqueClassFile(final Opaque opaque) {
|
||||
super(opaque.parent.pkg, opaque.type.getJType().getJavaClassName(), com.apple.jobjc.Opaque.class.getCanonicalName());
|
||||
this.opaque = opaque;
|
||||
}
|
||||
|
||||
@Override public void writeBeginning(PrintStream out){
|
||||
out.println("\t// " + opaque.type);
|
||||
out.println("\t// " + opaque.type.getJType());
|
||||
out.println("");
|
||||
out.println("\tpublic " + className + "(" + Pointer.class.getName() + "<?> ptr){");
|
||||
out.println("\t\tsuper(ptr);");
|
||||
out.println("\t}");
|
||||
out.println("");
|
||||
out.println("\tpublic " + className + "(long ptr){");
|
||||
out.println("\t\tsuper(ptr);");
|
||||
out.println("\t}");
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,58 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.apple.internal.jobjc.generator.classes;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public abstract class OutputFile {
|
||||
final String pkg;
|
||||
final String fileName;
|
||||
|
||||
public OutputFile(final String pkg, final String filename) {
|
||||
this.pkg = pkg;
|
||||
this.fileName = filename;
|
||||
}
|
||||
|
||||
public PrintStream open(final File parentDir) throws IOException {
|
||||
final File pkgDir = new File(parentDir, pkg.replace('.', '/'));
|
||||
pkgDir.mkdirs();
|
||||
final File classFile = new File(pkgDir, fileName);
|
||||
classFile.createNewFile();
|
||||
return new PrintStream(classFile);
|
||||
}
|
||||
|
||||
public void close(final PrintStream out) {
|
||||
out.close();
|
||||
}
|
||||
|
||||
public abstract void write(final File parentDir);
|
||||
|
||||
public boolean isClass(final Class<?> clazz) {
|
||||
final String pkgName = clazz.getPackage().getName();
|
||||
if (!pkgName.equals(pkg)) return false;
|
||||
|
||||
return fileName.contains(clazz.getSimpleName());
|
||||
}
|
||||
}
|
||||
@ -1,84 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.apple.internal.jobjc.generator.classes;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.List;
|
||||
|
||||
import com.apple.internal.jobjc.generator.ClassGenerator;
|
||||
import com.apple.internal.jobjc.generator.model.Framework;
|
||||
import com.apple.internal.jobjc.generator.utils.JavaLang;
|
||||
import com.apple.internal.jobjc.generator.utils.JavaLang.JLCtor;
|
||||
import com.apple.internal.jobjc.generator.utils.JavaLang.JLField;
|
||||
import com.apple.internal.jobjc.generator.utils.JavaLang.JLMethod;
|
||||
import com.apple.jobjc.JObjCRuntime;
|
||||
|
||||
public class RootJObjCClass extends GeneratedClassFile {
|
||||
private static final String JOBJC_CLASSNAME = "JObjC";
|
||||
public static final String FULL_JOBJC_CLASSNAME = ClassGenerator.JOBJC_PACKAGE + "." + JOBJC_CLASSNAME;
|
||||
public static final String JOBJC_RUNTIME_INST = FULL_JOBJC_CLASSNAME + ".getInstance()";
|
||||
public static final String JOBJC_RUNTIME_INST_R = FULL_JOBJC_CLASSNAME + ".getInstance(getRuntime())";
|
||||
|
||||
public static final String runtimeFrameworkInst(String fwname){
|
||||
return JOBJC_RUNTIME_INST + "." + fwname + "()";
|
||||
}
|
||||
|
||||
public static final String runtimeFrameworkInstR(String fwname){
|
||||
return JOBJC_RUNTIME_INST_R + "." + fwname + "()";
|
||||
}
|
||||
|
||||
final List<Framework> frameworks;
|
||||
|
||||
public RootJObjCClass(final List<Framework> frameworks) {
|
||||
super(ClassGenerator.JOBJC_PACKAGE, JOBJC_CLASSNAME, "java.lang.Object");
|
||||
this.frameworks = frameworks;
|
||||
}
|
||||
|
||||
@Override public void writeBeginning(final PrintStream out) {
|
||||
out.print(new JLField("private static", JOBJC_CLASSNAME, "instance"));
|
||||
out.print(new JLField("private final", JObjCRuntime.class.getName(), "runtime"));
|
||||
|
||||
JLMethod getInstR = new JLMethod("public static", JOBJC_CLASSNAME, "getInstance", "final JObjCRuntime runtime");
|
||||
getInstR.body.add("if(runtime == null) throw new NullPointerException(\"runtime\");");
|
||||
getInstR.body.add("if(instance == null) instance = new JObjC(runtime);");
|
||||
getInstR.body.add("return instance;");
|
||||
out.print(getInstR);
|
||||
|
||||
JLMethod getInst = new JLMethod("public static", JOBJC_CLASSNAME, "getInstance");
|
||||
getInst.body.add("return getInstance(JObjCRuntime.getInstance());");
|
||||
out.print(getInst);
|
||||
|
||||
JLCtor ctor = new JLCtor("private", JOBJC_CLASSNAME, "final JObjCRuntime runtime");
|
||||
ctor.body.add("this.runtime = runtime;");
|
||||
for (final Framework f : frameworks)
|
||||
ctor.body.add("runtime.registerPackage(\"" + f.pkg + "\");");
|
||||
out.print(ctor);
|
||||
}
|
||||
|
||||
@Override public void writeBody(final PrintStream out) {
|
||||
for (final Framework f : frameworks)
|
||||
out.println(JavaLang.makeSingleton("_" + f.name, f.name, f.pkg + "." + f.name + "Framework", "runtime"));
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user