--- old/make/CompileModuleTools.gmk 2020-03-23 19:56:17.827962840 +0100 +++ new/make/CompileModuleTools.gmk 2020-03-23 19:56:17.475962843 +0100 @@ -37,9 +37,7 @@ $(eval $(call SetupJavaCompilation,BUILD_JIGSAW_TOOLS, \ SETUP := GENERATE_USINGJDKBYTECODE, \ SRC := $(TOPDIR)/make/jdk/src/classes, \ - INCLUDES := build/tools/deps \ - build/tools/docs \ - build/tools/jigsaw, \ + INCLUDES := build/tools/jigsaw, \ COPY := .properties .html, \ BIN := $(TOOLS_CLASSES_DIR), \ DISABLED_WARNINGS := fallthrough, \ --- old/make/CompileToolsJdk.gmk 2020-03-23 19:56:18.591962835 +0100 +++ new/make/CompileToolsJdk.gmk 2020-03-23 19:56:18.259962837 +0100 @@ -27,6 +27,7 @@ include $(SPEC) include MakeBase.gmk +include Modules.gmk include JavaCompilation.gmk include SetupJavaCompilers.gmk include TextFileProcessing.gmk @@ -39,6 +40,7 @@ # Use += to be able to add to this from a custom extension BUILD_TOOLS_SRC_DIRS += \ + $(call FindAllToolsDirs) \ $(TOPDIR)/make/jdk/src/classes \ $(BUILDTOOLS_OUTPUTDIR)/interim_tzdb_classes \ # @@ -48,10 +50,9 @@ SRC := $(BUILD_TOOLS_SRC_DIRS), \ EXCLUDES := \ build/tools/classlist \ - build/tools/deps \ - build/tools/docs \ build/tools/jigsaw \ build/tools/depend \ + org/openjdk/buildtools/symbolgenerator \ , \ BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes, \ ADD_JAVAC_FLAGS := \ @@ -62,10 +63,11 @@ TARGETS += $(BUILD_TOOLS_JDK) -$(eval $(call SetupCopyFiles,COPY_NIMBUS_TEMPLATES, \ +$(eval $(call SetupCopyFiles, COPY_NIMBUS_TEMPLATES, \ SRC := $(TOPDIR)/src/java.desktop/share/classes/javax/swing/plaf/nimbus, \ - DEST := $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes/build/tools/generatenimbus/resources, \ - FILES := $(wildcard $(TOPDIR)/src/java.desktop/share/classes/javax/swing/plaf/nimbus/*.template))) + DEST := $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes/org/openjdk/buildtools/generatenimbus/resources, \ + FILES := $(wildcard $(TOPDIR)/src/java.desktop/share/classes/javax/swing/plaf/nimbus/*.template), \ +)) TARGETS += $(COPY_NIMBUS_TEMPLATES) --- old/make/CopyInterimTZDB.gmk 2020-03-23 19:56:19.299962830 +0100 +++ new/make/CopyInterimTZDB.gmk 2020-03-23 19:56:18.959962832 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2019, 2020, 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 @@ -35,15 +35,16 @@ define tzdb_copyfiles $(call MakeTargetDir) $(RM) '$@' - $(SED) -e "s/package java.time.zone/package build.tools.tzdb/" \ + $(SED) -e "s/package java.time.zone/package org.openjdk.buildtools.tzdb/" \ < $(<) > $@ endef -$(eval $(call SetupCopyFiles,COPY_INTERIM_TZDB, \ +$(eval $(call SetupCopyFiles, COPY_INTERIM_TZDB, \ SRC := $(TOPDIR)/src/java.base/share/classes/java/time/zone, \ - DEST := $(BUILDTOOLS_OUTPUTDIR)/interim_tzdb_classes/build/tools/tzdb, \ + DEST := $(BUILDTOOLS_OUTPUTDIR)/interim_tzdb_classes/org/openjdk/buildtools/tzdb, \ FILES := ZoneRules.java ZoneOffsetTransition.java ZoneOffsetTransitionRule.java Ser.java, \ - MACRO := tzdb_copyfiles)) + MACRO := tzdb_copyfiles, \ +)) ########################################################################################## --- old/make/ToolsJdk.gmk 2020-03-23 19:56:20.071962824 +0100 +++ new/make/ToolsJdk.gmk 2020-03-23 19:56:19.739962826 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2020, 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 @@ -40,89 +40,23 @@ ################################################################################ -TOOL_COMPILEFONTCONFIG = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ - --add-exports java.desktop/sun.awt=ALL-UNNAMED \ - build.tools.compilefontconfig.CompileFontConfig - +# used by build system for many modules TOOL_COMPILEPROPERTIES = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ build.tools.compileproperties.CompileProperties -TOOL_GENERATECHARACTER = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ - build.tools.generatecharacter.GenerateCharacter - -TOOL_CHARACTERNAME = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ - build.tools.generatecharacter.CharacterName - -TOOL_DTDBUILDER = $(JAVA_SMALL) -Ddtd_home=$(TOPDIR)/make/data/dtdbuilder \ - -Djava.awt.headless=true \ - -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes build.tools.dtdbuilder.DTDBuilder - -TOOL_GENERATEBREAKITERATORDATA = $(JAVA_SMALL) \ - -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ - build.tools.generatebreakiteratordata.GenerateBreakIteratorData - -TOOL_GENERATECURRENCYDATA = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ - build.tools.generatecurrencydata.GenerateCurrencyData - -TOOL_TZDB = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ - build.tools.tzdb.TzdbZoneRulesCompiler - -TOOL_BLACKLISTED_CERTS = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ - build.tools.blacklistedcertsconverter.BlacklistedCertsConverter - -TOOL_MAKEJAVASECURITY = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ - build.tools.makejavasecurity.MakeJavaSecurity - -TOOL_GENERATECACERTS = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ - build.tools.generatecacerts.GenerateCacerts - -TOOL_GENERATEEMOJIDATA = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ - build.tools.generateemojidata.GenerateEmojiData - - -# TODO: There are references to the jdwpgen.jar in jdk/make/netbeans/jdwpgen/build.xml -# and nbproject/project.properties in the same dir. Needs to be looked at. -TOOL_JDWPGEN = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes build.tools.jdwpgen.Main - -# TODO: Lots of files in jdk/make/tools/CharsetMapping dir +# shared by java.base and jdk.charsets TOOL_CHARSETMAPPING = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ build.tools.charsetmapping.Main $(LOG_INFO) -TOOL_SPP = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes build.tools.spp.Spp - -# Nimbus is used somewhere in the swing build. -TOOL_GENERATENIMBUS = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ - build.tools.generatenimbus.Generator - -TOOL_WRAPPERGENERATOR = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ - build.tools.x11wrappergen.WrapperGenerator - -TOOL_AWT_TOBIN = $(JAVA_SMALL) -Djava.awt.headless=true -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ - build.tools.icondata.awt.ToBin - -TOOL_OSX_TOBIN = $(JAVA_SMALL) -Djava.awt.headless=true -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ - build.tools.icondata.osxapp.ToBin - +# shared by java.base and jdk.localedata TOOL_CLDRCONVERTER = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ build.tools.cldrconverter.CLDRConverter -TOOL_INTPOLY = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ - build.tools.intpoly.FieldGen - -TOOL_GENERATELSREQUIVMAPS = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ - build.tools.generatelsrequivmaps.EquivMapsGenerator - -TOOL_GENMODULEINFOSOURCE = $(JAVA_SMALL) $(INTERIM_LANGTOOLS_BOOTCLASSPATH) \ - -cp $(call PathList, $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes) \ +# used by build system for all modules +TOOL_GENMODULEINFOSOURCE = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ build.tools.module.GenModuleInfoSource -TOOL_GENCLASSLOADERMAP = $(JAVA_SMALL) $(INTERIM_LANGTOOLS_BOOTCLASSPATH) \ - -cp $(call PathList, $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes) \ - build.tools.module.GenModuleLoaderMap - -TOOL_PUBLICSUFFIXLIST = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ - build.tools.publicsuffixlist.GeneratePublicSuffixList - +# used by build system for docs TOOL_FIXUPPANDOC = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ build.tools.fixuppandoc.Main --- old/make/UpdateX11Wrappers.gmk 2020-03-23 19:56:20.843962818 +0100 +++ new/make/UpdateX11Wrappers.gmk 2020-03-23 19:56:20.515962821 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 2020, 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 @@ -47,6 +47,9 @@ $(error It is not possible to update the x11wrappers when cross-compiling) endif +TOOL_WRAPPERGENERATOR = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ + org.openjdk.buildtools.x11wrappergen.WrapperGenerator + X11WRAPPERS_OUTPUT := $(SUPPORT_OUTPUTDIR)/x11wrappers GENERATOR_SOURCE_FILE := $(X11WRAPPERS_OUTPUT)/src/data_generator.c --- old/make/common/Modules.gmk 2020-03-23 19:56:21.595962813 +0100 +++ new/make/common/Modules.gmk 2020-03-23 19:56:21.275962815 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 2020, 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 @@ -203,7 +203,7 @@ # The native dynamic libraries in these modules will also get built into static # libraries for consumption by downstream projects that need to statically link # the JDK libraries. Those static libraries are not part of the main JDK -# distribution. +# distribution. STATIC_LIBS_MODULES := \ java.base \ jdk.crypto.ec \ @@ -274,6 +274,8 @@ MAN_SUBDIRS += share/man +TOOLS_SUBDIRS += share/tools + # Find all module-info.java files for the current build target platform and # configuration. # Param 1 - Module to find for, set to * for finding all @@ -338,6 +340,13 @@ $(strip $(wildcard \ $(foreach sub, $(MAN_SUBDIRS), $(addsuffix /$(strip $1)/$(sub), $(TOP_SRC_DIRS))))) +# Find all tools directories for all modules for the current build target platform and +# configuration. +FindAllToolsDirs = \ + $(sort $(wildcard \ + $(foreach sub, $(TOOLS_SUBDIRS), \ + $(patsubst %,%/*/$(sub), $(TOP_SRC_DIRS))))) + # Construct the complete module source path GetModuleSrcPath = \ $(call PathList, \ --- old/make/data/symbols/symbols 2020-03-23 19:56:22.383962807 +0100 +++ new/make/data/symbols/symbols 2020-03-23 19:56:22.035962809 +0100 @@ -27,7 +27,7 @@ # ########################################################## # #command used to generate this file: -#build.tools.symbolgenerator.CreateSymbols build-description-incremental symbols include.list +#org.openjdk.buildtools.symbolgenerator.CreateSymbols build-description-incremental symbols include.list # generate platforms 7:8:9:A:B:C:D:E platform version 8 files java.activation-8.sym.txt:java.base-8.sym.txt:java.compiler-8.sym.txt:java.corba-8.sym.txt:java.datatransfer-8.sym.txt:java.desktop-8.sym.txt:java.instrument-8.sym.txt:java.logging-8.sym.txt:java.management-8.sym.txt:java.management.rmi-8.sym.txt:java.naming-8.sym.txt:java.prefs-8.sym.txt:java.rmi-8.sym.txt:java.scripting-8.sym.txt:java.security.jgss-8.sym.txt:java.security.sasl-8.sym.txt:java.sql-8.sym.txt:java.sql.rowset-8.sym.txt:java.transaction-8.sym.txt:java.xml-8.sym.txt:java.xml.bind-8.sym.txt:java.xml.crypto-8.sym.txt:java.xml.ws-8.sym.txt:java.xml.ws.annotation-8.sym.txt:jdk.httpserver-8.sym.txt:jdk.management-8.sym.txt:jdk.scripting.nashorn-8.sym.txt:jdk.sctp-8.sym.txt:jdk.security.auth-8.sym.txt:jdk.security.jgss-8.sym.txt --- old/make/gendata/Gendata-java.base.gmk 2020-03-23 19:56:23.131962801 +0100 +++ new/make/gendata/Gendata-java.base.gmk 2020-03-23 19:56:22.815962804 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2020, 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 @@ -40,6 +40,9 @@ ################################################################################ +TOOL_CHARACTERNAME = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ + org.openjdk.buildtools.generatecharacter.CharacterName + GENDATA_UNINAME := $(JDK_OUTPUTDIR)/modules/java.base/java/lang/uniName.dat $(GENDATA_UNINAME): $(TOPDIR)/make/data/unicodedata/UnicodeData.txt $(BUILD_TOOLS_JDK) @@ -52,6 +55,9 @@ GENDATA_CURDATA := $(JDK_OUTPUTDIR)/modules/java.base/java/util/currency.data +TOOL_GENERATECURRENCYDATA = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ + org.openjdk.buildtools.generatecurrencydata.GenerateCurrencyData + $(GENDATA_CURDATA): $(TOPDIR)/make/data/currency/CurrencyData.properties $(BUILD_TOOLS_JDK) $(call MakeDir, $(@D)) $(RM) $@ @@ -63,6 +69,9 @@ ################################################################################ +TOOL_GENERATECACERTS = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ + org.openjdk.buildtools.generatecacerts.GenerateCacerts + GENDATA_CACERTS_SRC := $(TOPDIR)/make/data/cacerts/ GENDATA_CACERTS := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base/security/cacerts @@ -88,6 +97,9 @@ # RESTRICTED_PKGS_SRC is optionally set in custom extension for this makefile +TOOL_MAKEJAVASECURITY = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ + org.openjdk.buildtools.makejavasecurity.MakeJavaSecurity + $(GENDATA_JAVA_SECURITY): $(BUILD_TOOLS_JDK) $(GENDATA_JAVA_SECURITY_SRC) $(RESTRICTED_PKGS_SRC) $(call LogInfo, Generating java.security) $(call MakeTargetDir) --- old/make/gendata/Gendata-jdk.compiler.gmk 2020-03-23 19:56:23.907962796 +0100 +++ new/make/gendata/Gendata-jdk.compiler.gmk 2020-03-23 19:56:23.567962798 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2020, 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 @@ -54,9 +54,9 @@ $(eval $(call SetupJavaCompilation, COMPILE_CREATE_SYMBOLS, \ SETUP := GENERATE_OLDBYTECODE, \ - SRC := $(TOPDIR)/make/langtools/src/classes \ + SRC := $(TOPDIR)/src/jdk.compiler/share/tools \ $(TOPDIR)/src/jdk.jdeps/share/classes, \ - INCLUDES := build/tools/symbolgenerator com/sun/tools/classfile, \ + INCLUDES := org/openjdk/buildtools/symbolgenerator com/sun/tools/classfile, \ BIN := $(BUILDTOOLS_OUTPUTDIR)/create_symbols, \ ADD_JAVAC_FLAGS := $(INTERIM_LANGTOOLS_ARGS) \ --patch-module java.base=$(BUILDTOOLS_OUTPUTDIR)/gensrc/java.base.interim \ @@ -73,14 +73,14 @@ $(JAVA_SMALL) $(INTERIM_LANGTOOLS_ARGS) \ $(COMPILECREATESYMBOLS_ADD_EXPORTS) \ -classpath $(BUILDTOOLS_OUTPUTDIR)/create_symbols \ - build.tools.symbolgenerator.CreateSymbols \ + org.openjdk.buildtools.symbolgenerator.CreateSymbols \ build-ctsym \ $(CT_DATA_DESCRIPTION) \ $(@D) $(JAVA_SMALL) $(INTERIM_LANGTOOLS_ARGS) \ $(COMPILECREATESYMBOLS_ADD_EXPORTS) \ -classpath $(BUILDTOOLS_OUTPUTDIR)/create_symbols \ - build.tools.symbolgenerator.TransitiveDependencies \ + org.openjdk.buildtools.symbolgenerator.TransitiveDependencies \ $(@D) \ $(CT_MODULESOURCEPATH) \ $(CT_MODULES) --- old/make/gendata/GendataBlacklistedCerts.gmk 2020-03-23 19:56:24.687962790 +0100 +++ new/make/gendata/GendataBlacklistedCerts.gmk 2020-03-23 19:56:24.343962792 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 2020, 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 @@ -25,6 +25,9 @@ $(eval $(call IncludeCustomExtension, gendata/GendataBlacklistedCerts.gmk)) +TOOL_BLACKLISTED_CERTS = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ + org.openjdk.buildtools.blacklistedcertsconverter.BlacklistedCertsConverter + GENDATA_BLACKLISTED_CERTS_SRC += $(TOPDIR)/make/data/blacklistedcertsconverter/blacklisted.certs.pem GENDATA_BLACKLISTED_CERTS := $(SUPPORT_OUTPUTDIR)/modules_libs/$(MODULE)/security/blacklisted.certs --- old/make/gendata/GendataBreakIterator.gmk 2020-03-23 19:56:25.427962784 +0100 +++ new/make/gendata/GendataBreakIterator.gmk 2020-03-23 19:56:25.095962787 +0100 @@ -1,5 +1,5 @@ -# Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2020, 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 @@ -72,6 +72,10 @@ # input UNICODEDATA := $(TOPDIR)/make/data/unicodedata/UnicodeData.txt +TOOL_GENERATEBREAKITERATORDATA = $(JAVA_SMALL) \ + -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ + org.openjdk.buildtools.generatebreakiteratordata.GenerateBreakIteratorData + # output BASE_DATA_PKG_DIR := $(JDK_OUTPUTDIR)/modules/java.base/sun/text/resources LD_DATA_PKG_DIR := $(JDK_OUTPUTDIR)/modules/jdk.localedata/sun/text/resources/ext --- old/make/gendata/GendataFontConfig.gmk 2020-03-23 19:56:26.171962779 +0100 +++ new/make/gendata/GendataFontConfig.gmk 2020-03-23 19:56:25.839962781 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2020, 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 @@ -23,6 +23,10 @@ # questions. # +TOOL_COMPILEFONTCONFIG = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ + --add-exports java.desktop/sun.awt=ALL-UNNAMED \ + org.openjdk.buildtools.compilefontconfig.CompileFontConfig + GENDATA_FONT_CONFIG_DST := $(SUPPORT_OUTPUTDIR)/modules_libs/$(MODULE) GENDATA_FONT_CONFIG_DATA_DIR ?= $(TOPDIR)/make/data/fontconfig --- old/make/gendata/GendataHtml32dtd.gmk 2020-03-23 19:56:26.875962774 +0100 +++ new/make/gendata/GendataHtml32dtd.gmk 2020-03-23 19:56:26.555962776 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2020, 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 @@ -23,6 +23,10 @@ # questions. # +TOOL_DTDBUILDER = $(JAVA_SMALL) -Ddtd_home=$(TOPDIR)/make/data/dtdbuilder \ + -Djava.awt.headless=true \ + -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes org.openjdk.buildtools.dtdbuilder.DTDBuilder + GENDATA_HTML32DTD := HTML32DTD = $(JDK_OUTPUTDIR)/modules/java.desktop/javax/swing/text/html/parser/html32.bdtd --- old/make/gendata/GendataPublicSuffixList.gmk 2020-03-23 19:56:27.615962768 +0100 +++ new/make/gendata/GendataPublicSuffixList.gmk 2020-03-23 19:56:27.279962771 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2020, 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 @@ -25,6 +25,9 @@ include $(SPEC) +TOOL_PUBLICSUFFIXLIST = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ + org.openjdk.buildtools.publicsuffixlist.GeneratePublicSuffixList + GENDATA_PUBLICSUFFIXLIST_SRC += $(TOPDIR)/make/data/publicsuffixlist/public_suffix_list.dat GENDATA_PUBLICSUFFIXLIST := $(SUPPORT_OUTPUTDIR)/modules_libs/$(MODULE)/security/public_suffix_list.dat --- old/make/gendata/GendataTZDB.gmk 2020-03-23 19:56:28.383962763 +0100 +++ new/make/gendata/GendataTZDB.gmk 2020-03-23 19:56:28.047962765 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 2020, 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 @@ -25,6 +25,8 @@ GENDATA_TZDB := +TOOL_TZDB = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ + org.openjdk.buildtools.tzdb.TzdbZoneRulesCompiler # # Time zone data file creation # --- old/make/gensrc/Gensrc-java.base.gmk 2020-03-23 19:56:29.139962757 +0100 +++ new/make/gensrc/Gensrc-java.base.gmk 2020-03-23 19:56:28.815962759 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2020, 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 @@ -25,6 +25,10 @@ include GensrcCommonJdk.gmk +# Used by GensrcBuffer.gmk, GensrcCharsetCoder.gmk and GensrcVarHandles.gmk +TOOL_SPP = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ + org.openjdk.buildtools.spp.Spp + include GensrcLocaleData.gmk include GensrcCharacterData.gmk include GensrcMisc.gmk @@ -90,6 +94,9 @@ ################################################################################ +TOOL_GENERATELSREQUIVMAPS = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ + org.openjdk.buildtools.generatelsrequivmaps.EquivMapsGenerator + GENSRC_LSREQUIVMAPS := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/util/locale/LocaleEquivalentMaps.java $(GENSRC_LSREQUIVMAPS): $(TOPDIR)/make/data/lsrdata/language-subtag-registry.txt $(BUILD_TOOLS_JDK) @@ -100,8 +107,11 @@ ################################################################################ +TOOL_INTPOLY = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ + org.openjdk.buildtools.intpoly.FieldGen + INTPOLY_GEN_DONE := $(GENSRC_DIR)/_intpoly-gensrc.marker -INTPOLY_HEADER := $(TOPDIR)/make/jdk/src/classes/build/tools/intpoly/header.txt +INTPOLY_HEADER := $(TOPDIR)/src/java.base/share/tools/org/openjdk/buildtools/intpoly/header.txt $(INTPOLY_GEN_DONE): $(INTPLOY_HEADER) $(BUILD_TOOLS_JDK) $(call MakeDir, $(GENSRC_DIR)) $(call LogInfo, Generating fixed-field math classes for java.base) --- old/make/gensrc/Gensrc-jdk.jdi.gmk 2020-03-23 19:56:29.871962752 +0100 +++ new/make/gensrc/Gensrc-jdk.jdi.gmk 2020-03-23 19:56:29.575962754 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2020, 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 @@ -29,6 +29,9 @@ # Translate the Java debugger wire protocol (jdwp.spec) file into a JDWP.java file # and a JDWPCommands.h C-header file. +TOOL_JDWPGEN = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ + org.openjdk.buildtools.jdwpgen.Main + JDWP_SPEC_FILE := $(TOPDIR)/make/data/jdwp/jdwp.spec HEADER_FILE := $(SUPPORT_OUTPUTDIR)/headers/jdk.jdwp.agent/JDWPCommands.h JAVA_FILE := $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jdi/com/sun/tools/jdi/JDWP.java --- old/make/gensrc/GensrcCharacterData.gmk 2020-03-23 19:56:30.575962746 +0100 +++ new/make/gensrc/GensrcCharacterData.gmk 2020-03-23 19:56:30.279962749 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2020, 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 @@ -27,6 +27,9 @@ # Rules to create $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/lang/CharacterData*.java # +TOOL_GENERATECHARACTER = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ + org.openjdk.buildtools.generatecharacter.GenerateCharacter + GENSRC_CHARACTERDATA := CHARACTERDATA = $(TOPDIR)/make/data/characterdata --- old/make/gensrc/GensrcEmojiData.gmk 2020-03-23 19:56:31.343962741 +0100 +++ new/make/gensrc/GensrcEmojiData.gmk 2020-03-23 19:56:31.011962743 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2019, 2020, 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 @@ -27,6 +27,9 @@ # Rules to create $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/util/regex/EmojiData.java # +TOOL_GENERATEEMOJIDATA = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ + org.openjdk.buildtools.generateemojidata.GenerateEmojiData + GENSRC_EMOJIDATA := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/util/regex/EmojiData.java EMOJIDATATEMP = $(TOPDIR)/src/java.base/share/classes/java/util/regex/EmojiData.java.template --- old/make/gensrc/GensrcIcons.gmk 2020-03-23 19:56:32.103962735 +0100 +++ new/make/gensrc/GensrcIcons.gmk 2020-03-23 19:56:31.779962737 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2020, 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 @@ -70,6 +70,10 @@ ################################################################################ +TOOL_AWT_TOBIN = $(JAVA_SMALL) -Djava.awt.headless=true \ + -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ + org.openjdk.buildtools.icondataawt.ToBin + define SetupGensrcAWTIcon # param 1 is for src-file # param 2 is for src-dir @@ -109,6 +113,9 @@ ################################################################################ ifeq ($(call isTargetOs, macosx), true) + TOOL_OSX_TOBIN = $(JAVA_SMALL) -Djava.awt.headless=true \ + -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ + org.openjdk.buildtools.icondataosx.ToBin GENSRC_OSX_ICONS_DST := $(SUPPORT_OUTPUTDIR)/headers/java.desktop GENSRC_OSX_ICONS := $(GENSRC_OSX_ICONS_DST)/AWTIconData.h --- old/make/gensrc/GensrcModuleLoaderMap.gmk 2020-03-23 19:56:32.871962729 +0100 +++ new/make/gensrc/GensrcModuleLoaderMap.gmk 2020-03-23 19:56:32.535962732 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2020, 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 @@ -41,6 +41,10 @@ VARDEPS_VALUE := $(BOOT_MODULES_LIST) $(PLATFORM_MODULES_LIST) VARDEPS_FILE := $(call DependOnVariable, VARDEPS_VALUE) +TOOL_GENCLASSLOADERMAP = $(JAVA_SMALL) \ + -cp $(call PathList, $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes) \ + org.openjdk.buildtools.moduleloadermap.GenModuleLoaderMap + ############################################################################ $(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/module/ModuleLoaderMap.java: \ --- old/make/gensrc/GensrcSwing.gmk 2020-03-23 19:56:33.603962724 +0100 +++ new/make/gensrc/GensrcSwing.gmk 2020-03-23 19:56:33.303962726 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2020, 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 @@ -26,6 +26,10 @@ # # Generate java files for javax.swing.plaf package # + +TOOL_GENERATENIMBUS = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ + org.openjdk.buildtools.generatenimbus.Generator + NIMBUS_PACKAGE = javax.swing.plaf NIMBUS_GENSRC_DIR = $(SUPPORT_OUTPUTDIR)/gensrc/java.desktop/javax/swing/plaf/nimbus NIMBUS_SKIN_FILE = $(TOPDIR)/src/java.desktop/share/classes/javax/swing/plaf/nimbus/skin.laf --- old/make/gensrc/GensrcX11Wrappers.gmk 2020-03-23 19:56:34.327962719 +0100 +++ new/make/gensrc/GensrcX11Wrappers.gmk 2020-03-23 19:56:34.031962721 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 2020, 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 @@ -26,6 +26,9 @@ # Generate java sources using the X11 offsets that are precalculated in files # make/data/x11wrappergen/sizes-
.txt. +TOOL_WRAPPERGENERATOR = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ + org.openjdk.buildtools.x11wrappergen.WrapperGenerator + # Put the generated Java classes used to interface X11 from awt here. GENSRC_X11WRAPPERS_OUTPUTDIR := $(SUPPORT_OUTPUTDIR)/gensrc/java.desktop/sun/awt/X11 --- old/make/langtools/test/sym/CreateSymbolsTest.java 2020-03-23 19:56:35.071962713 +0100 +++ new/make/langtools/test/sym/CreateSymbolsTest.java 2020-03-23 19:56:34.731962716 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2020, 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 @@ -56,7 +56,7 @@ Path compileDir = testClasses.resolve("data"); deleteRecursively(compileDir); Files.createDirectories(compileDir); - Path createSymbols = findFile("../../make/src/classes/build/tools/symbolgenerator/CreateSymbols.java"); + Path createSymbols = findFile("../../src/jdk.compiler/share/tools/org/openjdk/symbolgenerator/CreateSymbols.java"); if (createSymbols == null) { System.err.println("Warning: cannot find CreateSymbols, skipping."); --- old/make/langtools/test/sym/CreateSymbolsTestImpl.java 2020-03-23 19:56:35.847962707 +0100 +++ new/make/langtools/test/sym/CreateSymbolsTestImpl.java 2020-03-23 19:56:35.507962710 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2020, 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 @@ -41,12 +41,12 @@ import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; -import build.tools.symbolgenerator.CreateSymbols; -import build.tools.symbolgenerator.CreateSymbols.ClassDescription; -import build.tools.symbolgenerator.CreateSymbols.ClassList; -import build.tools.symbolgenerator.CreateSymbols.CtSymKind; -import build.tools.symbolgenerator.CreateSymbols.ExcludeIncludeList; -import build.tools.symbolgenerator.CreateSymbols.VersionDescription; +import org.openjdk.buildtools.symbolgenerator.CreateSymbols; +import org.openjdk.buildtools.symbolgenerator.CreateSymbols.ClassDescription; +import org.openjdk.buildtools.symbolgenerator.CreateSymbols.ClassList; +import org.openjdk.buildtools.symbolgenerator.CreateSymbols.CtSymKind; +import org.openjdk.buildtools.symbolgenerator.CreateSymbols.ExcludeIncludeList; +import org.openjdk.buildtools.symbolgenerator.CreateSymbols.VersionDescription; public class CreateSymbolsTestImpl { --- old/make/scripts/generate-symbol-data.sh 2020-03-23 19:56:36.599962702 +0100 +++ new/make/scripts/generate-symbol-data.sh 2020-03-23 19:56:36.267962704 +0100 @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2019, 2020, 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 @@ -73,5 +73,5 @@ --add-exports jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED \ --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \ --add-modules jdk.jdeps \ - ../../../make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java \ + ../../../src/jdk.compiler/share/tools/org/openjdk/buildtools/symbolgenerator/CreateSymbols.java \ build-description-incremental symbols include.list --- old/make/jdk/src/classes/build/tools/blacklistedcertsconverter/BlacklistedCertsConverter.java 2020-03-23 19:56:37.415962696 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,113 +0,0 @@ -/* - * Copyright (c) 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 build.tools.blacklistedcertsconverter; - -import java.security.MessageDigest; -import java.security.cert.Certificate; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.util.Collection; -import java.util.Set; -import java.util.TreeSet; - - -/** - * Converts blacklisted.certs.pem from System.in to blacklisted.certs in - * System.out. The input must start with a #! line including the fingerprint - * algorithm. The output is sorted and unique. - */ -public class BlacklistedCertsConverter { - - public static void main(String[] args) throws Exception { - - byte[] pattern = "#! java BlacklistedCertsConverter ".getBytes(); - String mdAlg = ""; - - for (int i=0; ; i++) { - int n = System.in.read(); - if (n < 0) { - throw new Exception("Unexpected EOF"); - } - if (i < pattern.length) { - if (n != pattern[i]) { - throw new Exception("The first line must start with \"" - + new String(pattern) + "\""); - } - } else if (i < pattern.length + 100) { - if (n < 32) { - break; - } else { - mdAlg = mdAlg + String.format("%c", n); - } - } - } - - mdAlg = mdAlg.trim(); - System.out.println("Algorithm=" + mdAlg); - - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - Collection certs - = cf.generateCertificates(System.in); - - // Output sorted so that it's easy to locate an entry. - Set fingerprints = new TreeSet<>(); - for (Certificate cert: certs) { - fingerprints.add( - getCertificateFingerPrint(mdAlg, (X509Certificate)cert)); - } - - for (String s: fingerprints) { - System.out.println(s); - } - } - - /** - * Converts a byte to hex digit and writes to the supplied buffer - */ - private static void byte2hex(byte b, StringBuffer buf) { - char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', - '9', 'A', 'B', 'C', 'D', 'E', 'F' }; - int high = ((b & 0xf0) >> 4); - int low = (b & 0x0f); - buf.append(hexChars[high]); - buf.append(hexChars[low]); - } - - /** - * Gets the requested finger print of the certificate. - */ - private static String getCertificateFingerPrint( - String mdAlg, X509Certificate cert) throws Exception { - byte[] encCertInfo = cert.getEncoded(); - MessageDigest md = MessageDigest.getInstance(mdAlg); - byte[] digest = md.digest(encCertInfo); - StringBuffer buf = new StringBuffer(); - for (int i = 0; i < digest.length; i++) { - byte2hex(digest[i], buf); - } - return buf.toString(); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.base/share/tools/org/openjdk/buildtools/blacklistedcertsconverter/BlacklistedCertsConverter.java 2020-03-23 19:56:37.003962699 +0100 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 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 org.openjdk.buildtools.blacklistedcertsconverter; + +import java.security.MessageDigest; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.Set; +import java.util.TreeSet; + + +/** + * Converts blacklisted.certs.pem from System.in to blacklisted.certs in + * System.out. The input must start with a #! line including the fingerprint + * algorithm. The output is sorted and unique. + */ +public class BlacklistedCertsConverter { + + public static void main(String[] args) throws Exception { + + byte[] pattern = "#! java BlacklistedCertsConverter ".getBytes(); + String mdAlg = ""; + + for (int i=0; ; i++) { + int n = System.in.read(); + if (n < 0) { + throw new Exception("Unexpected EOF"); + } + if (i < pattern.length) { + if (n != pattern[i]) { + throw new Exception("The first line must start with \"" + + new String(pattern) + "\""); + } + } else if (i < pattern.length + 100) { + if (n < 32) { + break; + } else { + mdAlg = mdAlg + String.format("%c", n); + } + } + } + + mdAlg = mdAlg.trim(); + System.out.println("Algorithm=" + mdAlg); + + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + Collection certs + = cf.generateCertificates(System.in); + + // Output sorted so that it's easy to locate an entry. + Set fingerprints = new TreeSet<>(); + for (Certificate cert: certs) { + fingerprints.add( + getCertificateFingerPrint(mdAlg, (X509Certificate)cert)); + } + + for (String s: fingerprints) { + System.out.println(s); + } + } + + /** + * Converts a byte to hex digit and writes to the supplied buffer + */ + private static void byte2hex(byte b, StringBuffer buf) { + char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', + '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + int high = ((b & 0xf0) >> 4); + int low = (b & 0x0f); + buf.append(hexChars[high]); + buf.append(hexChars[low]); + } + + /** + * Gets the requested finger print of the certificate. + */ + private static String getCertificateFingerPrint( + String mdAlg, X509Certificate cert) throws Exception { + byte[] encCertInfo = cert.getEncoded(); + MessageDigest md = MessageDigest.getInstance(mdAlg); + byte[] digest = md.digest(encCertInfo); + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < digest.length; i++) { + byte2hex(digest[i], buf); + } + return buf.toString(); + } +} --- old/make/jdk/src/classes/build/tools/generatebreakiteratordata/CharSet.java 2020-03-23 19:56:38.251962690 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,819 +0,0 @@ -/* - * Copyright (c) 2003, 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. - */ - -/* - * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved - * (C) Copyright IBM Corp. 1996 - 2002 - All Rights Reserved - * - * The original version of this source code and documentation - * is copyrighted and owned by Taligent, Inc., a wholly-owned - * subsidiary of IBM. These materials are provided under terms - * of a License Agreement between Taligent and Sun. This technology - * is protected by multiple US and International patents. - * - * This notice and attribution to Taligent may not be removed. - * Taligent is a registered trademark of Taligent, Inc. - */ - -package build.tools.generatebreakiteratordata; - -import java.util.Arrays; -import java.util.Hashtable; - -/** - * An object representing a set of characters. (This is a "set" in the - * mathematical sense: an unduplicated list of characters on which set - * operations such as union and intersection can be performed.) The - * set information is stored in compressed, optimized form: The object - * contains an integer array with an even number of characters. Each - * pair of characters represents a range of characters contained in the set - * (a pair of the same character represents a single character). The - * characters are sorted in increasing order. - */ -class CharSet { - /** - * The structure containing the set information. The characters - * in this array are organized into pairs, each pair representing - * a range of characters contained in the set - */ - private int[] chars; - - //========================================================================== - // parseString() and associated routines - //========================================================================== - /** - * A cache which is used to speed up parseString() whenever it is - * used to parse a description that has been parsed before - */ - private static Hashtable expressionCache = null; - - /** - * Builds a CharSet based on a textual description. For the syntax of - * the description, see the documentation of RuleBasedBreakIterator. - * @see java.text.RuleBasedBreakIterator - */ - public static CharSet parseString(String s) { - CharSet result = null; - - // if "s" is in the expression cache, pull the result out - // of the expresison cache - if (expressionCache != null) { - result = expressionCache.get(s); - } - - // otherwise, use doParseString() to actually parse the string, - // and then add a corresponding entry to the expression cache - if (result == null) { - result = doParseString(s); - if (expressionCache == null) { - expressionCache = new Hashtable<>(); - } - expressionCache.put(s, result); - } - result = (CharSet)(result.clone()); - return result; - } - - /** - * This function is used by parseString() to actually parse the string - */ - private static CharSet doParseString(String s) { - CharSet result = new CharSet(); - int p = 0; - - boolean haveDash = false; - boolean haveTilde = false; - boolean wIsReal = false; - int w = 0x0000; - - // for each character in the description... - while (p < s.length()) { - int c = s.codePointAt(p); - - // if it's an opening bracket... - if (c == '[') { - // flush the single-character cache - if (wIsReal) { - result.internalUnion(new CharSet(w)); - } - - // locate the matching closing bracket - int bracketLevel = 1; - int q = p + 1; - while (bracketLevel != 0) { - // if no matching bracket by end of string then... - if (q >= s.length()) { - throw new IllegalArgumentException("Parse error at position " + p + " in " + s); - } - int ch = s.codePointAt(q); - switch (ch) { - case '\\': // need to step over next character - ch = s.codePointAt(++q); - break; - case '[': - ++bracketLevel; - break; - case ']': - --bracketLevel; - break; - } - q += Character.charCount(ch); - } - --q; - - // call parseString() recursively to parse the text inside - // the brackets, then either add or subtract the result from - // our running result depending on whether or not the [] - // expresison was preceded by a ^ - if (!haveTilde) { - result.internalUnion(CharSet.parseString(s.substring(p + 1, q))); - } - else { - result.internalDifference(CharSet.parseString(s.substring(p + 1, q))); - } - haveTilde = false; - haveDash = false; - wIsReal = false; - p = q + 1; - } - - // if the character is a colon... - else if (c == ':') { - // flush the single-character cache - if (wIsReal) { - result.internalUnion(new CharSet(w)); - } - - // locate the matching colon (and throw an error if there - // isn't one) - int q = s.indexOf(':', p + 1); - if (q == -1) { - throw new IllegalArgumentException("Parse error at position " + p + " in " + s); - } - - // use charSetForCategory() to parse the text in the colons, - // and either add or substract the result from our running - // result depending on whether the :: expression was - // preceded by a ^ - if (!haveTilde) { - result.internalUnion(charSetForCategory(s.substring(p + 1, q))); - } - else { - result.internalDifference(charSetForCategory(s.substring(p + 1, q))); - } - - // reset everything and advance to the next character - haveTilde = false; - haveDash = false; - wIsReal = false; - p = q + 1; - } - - // if the character is a dash, set an appropriate flag - else if (c == '-') { - if (wIsReal) { - haveDash = true; - } - ++p; - } - - // if the character is a caret, flush the single-character - // cache and set an appropriate flag. If the set is empty - // (i.e., if the expression begins with ^), invert the set - // (i.e., set it to include everything). The idea here is - // that a set that includes nothing but ^ expressions - // means "everything but these things". - else if (c == '^') { - if (wIsReal) { - result.internalUnion(new CharSet(w)); - wIsReal = false; - } - haveTilde = true; - ++p; - if (result.empty()) { - result.internalComplement(); - } - } - - // throw an exception on an illegal character - else if (c >= ' ' && c < '\u007f' && !Character.isLetter((char)c) - && !Character.isDigit((char)c) && c != '\\') { - throw new IllegalArgumentException("Parse error at position " + p + " in " + s); - } - - // otherwise, we end up here... - else { - // on a backslash, advance to the next character - if (c == '\\') { - ++p; - } - - // if the preceding character was a dash, this character - // defines the end of a range. Add or subtract that range - // from the running result depending on whether or not it - // was preceded by a ^ - if (haveDash) { - if (s.codePointAt(p) < w) { - throw new IllegalArgumentException("U+" + - Integer.toHexString(s.codePointAt(p)) - + " is less than U+" + Integer.toHexString(w) + ". Dash expressions " - + "can't have their endpoints in reverse order."); - } - - int ch = s.codePointAt(p); - if (!haveTilde) { - result.internalUnion(new CharSet(w, ch)); - } - else { - result.internalDifference(new CharSet(w, ch)); - } - p += Character.charCount(ch); - haveDash = false; - haveTilde = false; - wIsReal = false; - } - - // if the preceding character was a caret, remove this character - // from the running result - else if (haveTilde) { - w = s.codePointAt(p); - result.internalDifference(new CharSet(w)); - p += Character.charCount(w); - haveTilde = false; - wIsReal = false; - } - - // otherwise, flush the single-character cache and then - // put this character into the cache - else if (wIsReal) { - result.internalUnion(new CharSet(w)); - w = s.codePointAt(p); - p += Character.charCount(w); - wIsReal = true; - } else { - w = s.codePointAt(p); - p += Character.charCount(w); - wIsReal = true; - } - } - } - - // finally, flush the single-character cache one last time - if (wIsReal) { - result.internalUnion(new CharSet(w)); - } - - return result; - } - - /** - * Creates a CharSet containing all the characters in a particular - * Unicode category. The text is either a two-character code from - * the Unicode database or a single character that begins one or more - * two-character codes. - */ - private static CharSet charSetForCategory(String category) { - // throw an exception if we have anything other than one or two - // characters inside the colons - if (category.length() == 0 || category.length() >= 3) { - throw new IllegalArgumentException("Invalid character category: " + category); - } - - // if we have two characters, search the category map for that code - // and either construct and return a CharSet from the data in the - // category map or throw an exception - if (category.length() == 2) { - for (int i = 0; i < CharacterCategory.categoryNames.length; i++) { - if (CharacterCategory.categoryNames[i].equals(category)) { - return new CharSet(CharacterCategory.getCategoryMap(i)); - } - } - throw new IllegalArgumentException("Invalid character category: " + category); - } - - // if we have one character, search the category map for codes beginning - // with that letter, and union together all of the matching sets that - // we find (or throw an exception if there are no matches) - else if (category.length() == 1) { - CharSet result = new CharSet(); - for (int i = 0; i < CharacterCategory.categoryNames.length; i++) { - if (CharacterCategory.categoryNames[i].startsWith(category)) { - result = result.union(new CharSet(CharacterCategory.getCategoryMap(i))); - } - } - if (result.empty()) { - throw new IllegalArgumentException("Invalid character category: " + category); - } - else { - return result; - } - } - return new CharSet(); // should never get here, but to make the compiler happy... - } - - /** - * Returns a copy of CharSet's expression cache and sets CharSet's - * expression cache to empty. - */ - public static Hashtable releaseExpressionCache() { - Hashtable result = expressionCache; - expressionCache = null; - return result; - } - - //========================================================================== - // CharSet manipulation - //========================================================================== - /** - * Creates an empty CharSet. - */ - public CharSet() { - chars = new int[0]; - } - - /** - * Creates a CharSet containing a single character. - * @param c The character to put into the CharSet - */ - public CharSet(int c) { - chars = new int[2]; - chars[0] = c; - chars[1] = c; - } - - /** - * Creates a CharSet containing a range of characters. - * @param lo The lowest-numbered character to include in the range - * @param hi The highest-numbered character to include in the range - */ - public CharSet(int lo, int hi) { - chars = new int[2]; - if (lo <= hi) { - chars[0] = lo; - chars[1] = hi; - } - else { - chars[0] = hi; - chars[1] = lo; - } - } - - /** - * Creates a CharSet, initializing it from the internal storage - * of another CharSet (this function performs no error checking - * on "chars", so if it's malformed, undefined behavior will result) - */ - private CharSet(int[] chars) { - this.chars = chars; - } - - /** - * Returns a CharSet representing the union of two CharSets. - */ - public CharSet union(CharSet that) { - return new CharSet(doUnion(that.chars)); - } - - /** - * Adds the characters in "that" to this CharSet - */ - private void internalUnion(CharSet that) { - chars = doUnion(that.chars); - } - - /** - * The actual implementation of the union functions - */ - private int[] doUnion(int[] c2) { - int[] result = new int[chars.length+c2.length]; - - int i = 0; - int j = 0; - int index = 0; - - // consider all the characters in both strings - while (i < chars.length && j < c2.length) { - int ub; - - // the first character in the result is the lower of the - // starting characters of the two strings, and "ub" gets - // set to the upper bound of that range - if (chars[i] < c2[j]) { - result[index++] = chars[i]; - ub = chars[++i]; - } - else { - result[index++] = c2[j]; - ub = c2[++j]; - } - - // for as long as one of our two pointers is pointing to a range's - // end point, or i is pointing to a character that is less than - // "ub" plus one (the "plus one" stitches touching ranges together)... - while (i % 2 == 1 || - j % 2 == 1 || - (i < chars.length && chars[i] <= ub + 1)) { - - // advance i to the first character that is greater than - // "ub" plus one - while (i < chars.length && chars[i] <= ub + 1) { - ++i; - } - - // if i points to the endpoint of a range, update "ub" - // to that character, or if i points to the start of - // a range and the endpoint of the preceding range is - // greater than "ub", update "up" to _that_ character - if (i % 2 == 1) { - ub = chars[i]; - } - else if (i > 0 && chars[i - 1] > ub) { - ub = chars[i - 1]; - } - - // now advance j to the first character that is greater - // that "ub" plus one - while (j < c2.length && c2[j] <= ub + 1) { - ++j; - } - - // if j points to the endpoint of a range, update "ub" - // to that character, or if j points to the start of - // a range and the endpoint of the preceding range is - // greater than "ub", update "up" to _that_ character - if (j % 2 == 1) { - ub = c2[j]; - } - else if (j > 0 && c2[j - 1] > ub) { - ub = c2[j - 1]; - } - } - // when we finally fall out of this loop, we will have stitched - // together a series of ranges that overlap or touch, i and j - // will both point to starting points of ranges, and "ub" will - // be the endpoint of the range we're working on. Write "ub" - // to the result - result[index++] = ub; - - // loop back around to create the next range in the result - } - - // we fall out to here when we've exhausted all the characters in - // one of the operands. We can append all of the remaining characters - // in the other operand without doing any extra work. - if (i < chars.length) { - for (int k = i; k < chars.length; k++) { - result[index++] = chars[k]; - } - } - if (j < c2.length) { - for (int k = j; k < c2.length; k++) { - result[index++] = c2[k]; - } - } - - if (result.length > index) { - int[] tmpbuf = new int[index]; - System.arraycopy(result, 0, tmpbuf, 0, index); - return tmpbuf; - } - - return result; - } - - /** - * Returns the intersection of two CharSets. - */ - public CharSet intersection(CharSet that) { - return new CharSet(doIntersection(that.chars)); - } - - /** - * Removes from this CharSet any characters that aren't also in "that" - */ - private void internalIntersection(CharSet that) { - chars = doIntersection(that.chars); - } - - /** - * The internal implementation of the two intersection functions - */ - private int[] doIntersection(int[] c2) { - int[] result = new int[chars.length+c2.length]; - - int i = 0; - int j = 0; - int oldI; - int oldJ; - int index = 0; - - // iterate until we've exhausted one of the operands - while (i < chars.length && j < c2.length) { - - // advance j until it points to a character that is larger than - // the one i points to. If this is the beginning of a one- - // character range, advance j to point to the end - if (i < chars.length && i % 2 == 0) { - while (j < c2.length && c2[j] < chars[i]) { - ++j; - } - if (j < c2.length && j % 2 == 0 && c2[j] == chars[i]) { - ++j; - } - } - - // if j points to the endpoint of a range, save the current - // value of i, then advance i until it reaches a character - // which is larger than the character pointed at - // by j. All of the characters we've advanced over (except - // the one currently pointed to by i) are added to the result - oldI = i; - while (j % 2 == 1 && i < chars.length && chars[i] <= c2[j]) { - ++i; - } - for (int k = oldI; k < i; k++) { - result[index++] = chars[k]; - } - - // if i points to the endpoint of a range, save the current - // value of j, then advance j until it reaches a character - // which is larger than the character pointed at - // by i. All of the characters we've advanced over (except - // the one currently pointed to by i) are added to the result - oldJ = j; - while (i % 2 == 1 && j < c2.length && c2[j] <= chars[i]) { - ++j; - } - for (int k = oldJ; k < j; k++) { - result[index++] = c2[k]; - } - - // advance i until it points to a character larger than j - // If it points at the beginning of a one-character range, - // advance it to the end of that range - if (j < c2.length && j % 2 == 0) { - while (i < chars.length && chars[i] < c2[j]) { - ++i; - } - if (i < chars.length && i % 2 == 0 && c2[j] == chars[i]) { - ++i; - } - } - } - - if (result.length > index) { - int[] tmpbuf = new int[index]; - System.arraycopy(result, 0, tmpbuf, 0, index); - return tmpbuf; - } - - return result; - } - - /** - * Returns a CharSet containing all the characters in "this" that - * aren't also in "that" - */ - public CharSet difference(CharSet that) { - return new CharSet(doIntersection(that.doComplement())); - } - - /** - * Removes from "this" all the characters that are also in "that" - */ - private void internalDifference(CharSet that) { - chars = doIntersection(that.doComplement()); - } - - /** - * Returns a CharSet containing all the characters which are not - * in "this" - */ - public CharSet complement() { - return new CharSet(doComplement()); - } - - /** - * Complements "this". All the characters it contains are removed, - * and all the characters it doesn't contain are added. - */ - private void internalComplement() { - chars = doComplement(); - } - - /** - * The internal implementation function for the complement routines - */ - private int[] doComplement() { - // the complement of an empty CharSet is one containing everything - if (empty()) { - int[] result = new int[2]; - result[0] = 0x0000; - result[1] = 0x10FFFF; - return result; - } - - int[] result = new int[chars.length+2]; - - int i = 0; - int index = 0; - - // the result begins with \u0000 unless the original CharSet does - if (chars[0] != 0x0000) { - result[index++] = 0x0000; - } - - // walk through the characters in this CharSet. Append a pair of - // characters the first of which is one less than the first - // character we see and the second of which is one plus the second - // character we see (don't write the first character if it's \u0000, - // and don't write the second character if it's \uffff. - while (i < chars.length) { - if (chars[i] != 0x0000) { - result[index++] = chars[i] - 1; - } - if (chars[i + 1] != 0x10FFFF) { - result[index++] = chars[i + 1] + 1; - } - i += 2; - } - - // add 0x10ffff to the end of the result, unless it was in - // the original set - if (chars[i-1] != 0x10FFFF) { - result[index++] = 0x10FFFF; - } - - if (result.length > index) { - int[] tmpbuf = new int[index]; - System.arraycopy(result, 0, tmpbuf, 0, index); - return tmpbuf; - } - - return result; - } - - /** - * Returns true if this CharSet contains the specified character - * @param c The character we're testing for set membership - */ - public boolean contains(int c) { - // search for the first range endpoint that is greater than or - // equal to c - int i = 1; - while (i < chars.length && chars[i] < c) { - i += 2; - } - - // if we've walked off the end, we don't contain c - if (i == chars.length) { - return false; - } - - // otherwise, we contain c if the beginning of the range is less - // than or equal to c - return chars[i - 1] <= c; - } - - /** - * Returns true if "that" is another instance of CharSet containing - * the exact same characters as this one - */ - public boolean equals(Object that) { - return (that instanceof CharSet) && Arrays.equals(chars, ((CharSet)that).chars); - } - - /** - * Returns the hash code for this set of characters - */ - public int hashCode() { - return Arrays.hashCode(chars); - } - - /** - * Creates a new CharSet that is equal to this one - */ - public Object clone() { - return new CharSet(chars); - } - - /** - * Returns true if this CharSet contains no characters - */ - public boolean empty() { - return chars.length == 0; - } - - /** - * Returns a textual representation of this CharSet. If the result - * of calling this function is passed to CharSet.parseString(), it - * will produce another CharSet that is equal to this one. - */ - public String toString() { - StringBuffer result = new StringBuffer(); - - // the result begins with an opening bracket - result.append('['); - - // iterate through the ranges in the CharSet - for (int i = 0; i < chars.length; i += 2) { - // for a range with the same beginning and ending point, - // output that character - if (chars[i] == chars[i + 1]) { - result.append("0x"); - result.append(Integer.toHexString(chars[i])); - } - - // otherwise, output the start and end points of the range - // separated by a dash - else { - result.append("0x"); - result.append(Integer.toHexString(chars[i])); - result.append("-0x"); - result.append(Integer.toHexString(chars[i + 1])); - } - } - - // the result ends with a closing bracket - result.append(']'); - return result.toString(); - } - - /** - * Returns an integer array representing the contents of this CharSet - * in the same form in which they're stored internally: as pairs - * of characters representing the start and end points of ranges - */ - public int[] getRanges() { - return chars; - } - - /** - * Returns an Enumeration that will return the ranges of characters - * contained in this CharSet one at a time - */ - public Enumeration getChars() { - return new Enumeration(this); - } - - //========================================================================== - // CharSet.Enumeration - //========================================================================== - - /** - * An Enumeration that can be used to extract the character ranges - * from a CharSet one at a time - */ - public class Enumeration implements java.util.Enumeration { - /** - * Initializes a CharSet.Enumeration - */ - Enumeration(CharSet cs) { - this.chars = cs.chars; - p = 0; - } - - /** - * Returns true if the enumeration hasn't yet returned - * all the ranges in the CharSet - */ - public boolean hasMoreElements() { - return p < chars.length; - } - - /** - * Returns the next range in the CarSet - */ - public int[] nextElement() { - int[] result = new int[2]; - result[0] = chars[p++]; - result[1] = chars[p++]; - return result; - } - - int p; - int[] chars; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.base/share/tools/org/openjdk/buildtools/generatebreakiteratordata/CharSet.java 2020-03-23 19:56:37.823962693 +0100 @@ -0,0 +1,819 @@ +/* + * Copyright (c) 2003, 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. + */ + +/* + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved + * (C) Copyright IBM Corp. 1996 - 2002 - All Rights Reserved + * + * The original version of this source code and documentation + * is copyrighted and owned by Taligent, Inc., a wholly-owned + * subsidiary of IBM. These materials are provided under terms + * of a License Agreement between Taligent and Sun. This technology + * is protected by multiple US and International patents. + * + * This notice and attribution to Taligent may not be removed. + * Taligent is a registered trademark of Taligent, Inc. + */ + +package org.openjdk.buildtools.generatebreakiteratordata; + +import java.util.Arrays; +import java.util.Hashtable; + +/** + * An object representing a set of characters. (This is a "set" in the + * mathematical sense: an unduplicated list of characters on which set + * operations such as union and intersection can be performed.) The + * set information is stored in compressed, optimized form: The object + * contains an integer array with an even number of characters. Each + * pair of characters represents a range of characters contained in the set + * (a pair of the same character represents a single character). The + * characters are sorted in increasing order. + */ +class CharSet { + /** + * The structure containing the set information. The characters + * in this array are organized into pairs, each pair representing + * a range of characters contained in the set + */ + private int[] chars; + + //========================================================================== + // parseString() and associated routines + //========================================================================== + /** + * A cache which is used to speed up parseString() whenever it is + * used to parse a description that has been parsed before + */ + private static Hashtable expressionCache = null; + + /** + * Builds a CharSet based on a textual description. For the syntax of + * the description, see the documentation of RuleBasedBreakIterator. + * @see java.text.RuleBasedBreakIterator + */ + public static CharSet parseString(String s) { + CharSet result = null; + + // if "s" is in the expression cache, pull the result out + // of the expresison cache + if (expressionCache != null) { + result = expressionCache.get(s); + } + + // otherwise, use doParseString() to actually parse the string, + // and then add a corresponding entry to the expression cache + if (result == null) { + result = doParseString(s); + if (expressionCache == null) { + expressionCache = new Hashtable<>(); + } + expressionCache.put(s, result); + } + result = (CharSet)(result.clone()); + return result; + } + + /** + * This function is used by parseString() to actually parse the string + */ + private static CharSet doParseString(String s) { + CharSet result = new CharSet(); + int p = 0; + + boolean haveDash = false; + boolean haveTilde = false; + boolean wIsReal = false; + int w = 0x0000; + + // for each character in the description... + while (p < s.length()) { + int c = s.codePointAt(p); + + // if it's an opening bracket... + if (c == '[') { + // flush the single-character cache + if (wIsReal) { + result.internalUnion(new CharSet(w)); + } + + // locate the matching closing bracket + int bracketLevel = 1; + int q = p + 1; + while (bracketLevel != 0) { + // if no matching bracket by end of string then... + if (q >= s.length()) { + throw new IllegalArgumentException("Parse error at position " + p + " in " + s); + } + int ch = s.codePointAt(q); + switch (ch) { + case '\\': // need to step over next character + ch = s.codePointAt(++q); + break; + case '[': + ++bracketLevel; + break; + case ']': + --bracketLevel; + break; + } + q += Character.charCount(ch); + } + --q; + + // call parseString() recursively to parse the text inside + // the brackets, then either add or subtract the result from + // our running result depending on whether or not the [] + // expresison was preceded by a ^ + if (!haveTilde) { + result.internalUnion(CharSet.parseString(s.substring(p + 1, q))); + } + else { + result.internalDifference(CharSet.parseString(s.substring(p + 1, q))); + } + haveTilde = false; + haveDash = false; + wIsReal = false; + p = q + 1; + } + + // if the character is a colon... + else if (c == ':') { + // flush the single-character cache + if (wIsReal) { + result.internalUnion(new CharSet(w)); + } + + // locate the matching colon (and throw an error if there + // isn't one) + int q = s.indexOf(':', p + 1); + if (q == -1) { + throw new IllegalArgumentException("Parse error at position " + p + " in " + s); + } + + // use charSetForCategory() to parse the text in the colons, + // and either add or substract the result from our running + // result depending on whether the :: expression was + // preceded by a ^ + if (!haveTilde) { + result.internalUnion(charSetForCategory(s.substring(p + 1, q))); + } + else { + result.internalDifference(charSetForCategory(s.substring(p + 1, q))); + } + + // reset everything and advance to the next character + haveTilde = false; + haveDash = false; + wIsReal = false; + p = q + 1; + } + + // if the character is a dash, set an appropriate flag + else if (c == '-') { + if (wIsReal) { + haveDash = true; + } + ++p; + } + + // if the character is a caret, flush the single-character + // cache and set an appropriate flag. If the set is empty + // (i.e., if the expression begins with ^), invert the set + // (i.e., set it to include everything). The idea here is + // that a set that includes nothing but ^ expressions + // means "everything but these things". + else if (c == '^') { + if (wIsReal) { + result.internalUnion(new CharSet(w)); + wIsReal = false; + } + haveTilde = true; + ++p; + if (result.empty()) { + result.internalComplement(); + } + } + + // throw an exception on an illegal character + else if (c >= ' ' && c < '\u007f' && !Character.isLetter((char)c) + && !Character.isDigit((char)c) && c != '\\') { + throw new IllegalArgumentException("Parse error at position " + p + " in " + s); + } + + // otherwise, we end up here... + else { + // on a backslash, advance to the next character + if (c == '\\') { + ++p; + } + + // if the preceding character was a dash, this character + // defines the end of a range. Add or subtract that range + // from the running result depending on whether or not it + // was preceded by a ^ + if (haveDash) { + if (s.codePointAt(p) < w) { + throw new IllegalArgumentException("U+" + + Integer.toHexString(s.codePointAt(p)) + + " is less than U+" + Integer.toHexString(w) + ". Dash expressions " + + "can't have their endpoints in reverse order."); + } + + int ch = s.codePointAt(p); + if (!haveTilde) { + result.internalUnion(new CharSet(w, ch)); + } + else { + result.internalDifference(new CharSet(w, ch)); + } + p += Character.charCount(ch); + haveDash = false; + haveTilde = false; + wIsReal = false; + } + + // if the preceding character was a caret, remove this character + // from the running result + else if (haveTilde) { + w = s.codePointAt(p); + result.internalDifference(new CharSet(w)); + p += Character.charCount(w); + haveTilde = false; + wIsReal = false; + } + + // otherwise, flush the single-character cache and then + // put this character into the cache + else if (wIsReal) { + result.internalUnion(new CharSet(w)); + w = s.codePointAt(p); + p += Character.charCount(w); + wIsReal = true; + } else { + w = s.codePointAt(p); + p += Character.charCount(w); + wIsReal = true; + } + } + } + + // finally, flush the single-character cache one last time + if (wIsReal) { + result.internalUnion(new CharSet(w)); + } + + return result; + } + + /** + * Creates a CharSet containing all the characters in a particular + * Unicode category. The text is either a two-character code from + * the Unicode database or a single character that begins one or more + * two-character codes. + */ + private static CharSet charSetForCategory(String category) { + // throw an exception if we have anything other than one or two + // characters inside the colons + if (category.length() == 0 || category.length() >= 3) { + throw new IllegalArgumentException("Invalid character category: " + category); + } + + // if we have two characters, search the category map for that code + // and either construct and return a CharSet from the data in the + // category map or throw an exception + if (category.length() == 2) { + for (int i = 0; i < CharacterCategory.categoryNames.length; i++) { + if (CharacterCategory.categoryNames[i].equals(category)) { + return new CharSet(CharacterCategory.getCategoryMap(i)); + } + } + throw new IllegalArgumentException("Invalid character category: " + category); + } + + // if we have one character, search the category map for codes beginning + // with that letter, and union together all of the matching sets that + // we find (or throw an exception if there are no matches) + else if (category.length() == 1) { + CharSet result = new CharSet(); + for (int i = 0; i < CharacterCategory.categoryNames.length; i++) { + if (CharacterCategory.categoryNames[i].startsWith(category)) { + result = result.union(new CharSet(CharacterCategory.getCategoryMap(i))); + } + } + if (result.empty()) { + throw new IllegalArgumentException("Invalid character category: " + category); + } + else { + return result; + } + } + return new CharSet(); // should never get here, but to make the compiler happy... + } + + /** + * Returns a copy of CharSet's expression cache and sets CharSet's + * expression cache to empty. + */ + public static Hashtable releaseExpressionCache() { + Hashtable result = expressionCache; + expressionCache = null; + return result; + } + + //========================================================================== + // CharSet manipulation + //========================================================================== + /** + * Creates an empty CharSet. + */ + public CharSet() { + chars = new int[0]; + } + + /** + * Creates a CharSet containing a single character. + * @param c The character to put into the CharSet + */ + public CharSet(int c) { + chars = new int[2]; + chars[0] = c; + chars[1] = c; + } + + /** + * Creates a CharSet containing a range of characters. + * @param lo The lowest-numbered character to include in the range + * @param hi The highest-numbered character to include in the range + */ + public CharSet(int lo, int hi) { + chars = new int[2]; + if (lo <= hi) { + chars[0] = lo; + chars[1] = hi; + } + else { + chars[0] = hi; + chars[1] = lo; + } + } + + /** + * Creates a CharSet, initializing it from the internal storage + * of another CharSet (this function performs no error checking + * on "chars", so if it's malformed, undefined behavior will result) + */ + private CharSet(int[] chars) { + this.chars = chars; + } + + /** + * Returns a CharSet representing the union of two CharSets. + */ + public CharSet union(CharSet that) { + return new CharSet(doUnion(that.chars)); + } + + /** + * Adds the characters in "that" to this CharSet + */ + private void internalUnion(CharSet that) { + chars = doUnion(that.chars); + } + + /** + * The actual implementation of the union functions + */ + private int[] doUnion(int[] c2) { + int[] result = new int[chars.length+c2.length]; + + int i = 0; + int j = 0; + int index = 0; + + // consider all the characters in both strings + while (i < chars.length && j < c2.length) { + int ub; + + // the first character in the result is the lower of the + // starting characters of the two strings, and "ub" gets + // set to the upper bound of that range + if (chars[i] < c2[j]) { + result[index++] = chars[i]; + ub = chars[++i]; + } + else { + result[index++] = c2[j]; + ub = c2[++j]; + } + + // for as long as one of our two pointers is pointing to a range's + // end point, or i is pointing to a character that is less than + // "ub" plus one (the "plus one" stitches touching ranges together)... + while (i % 2 == 1 || + j % 2 == 1 || + (i < chars.length && chars[i] <= ub + 1)) { + + // advance i to the first character that is greater than + // "ub" plus one + while (i < chars.length && chars[i] <= ub + 1) { + ++i; + } + + // if i points to the endpoint of a range, update "ub" + // to that character, or if i points to the start of + // a range and the endpoint of the preceding range is + // greater than "ub", update "up" to _that_ character + if (i % 2 == 1) { + ub = chars[i]; + } + else if (i > 0 && chars[i - 1] > ub) { + ub = chars[i - 1]; + } + + // now advance j to the first character that is greater + // that "ub" plus one + while (j < c2.length && c2[j] <= ub + 1) { + ++j; + } + + // if j points to the endpoint of a range, update "ub" + // to that character, or if j points to the start of + // a range and the endpoint of the preceding range is + // greater than "ub", update "up" to _that_ character + if (j % 2 == 1) { + ub = c2[j]; + } + else if (j > 0 && c2[j - 1] > ub) { + ub = c2[j - 1]; + } + } + // when we finally fall out of this loop, we will have stitched + // together a series of ranges that overlap or touch, i and j + // will both point to starting points of ranges, and "ub" will + // be the endpoint of the range we're working on. Write "ub" + // to the result + result[index++] = ub; + + // loop back around to create the next range in the result + } + + // we fall out to here when we've exhausted all the characters in + // one of the operands. We can append all of the remaining characters + // in the other operand without doing any extra work. + if (i < chars.length) { + for (int k = i; k < chars.length; k++) { + result[index++] = chars[k]; + } + } + if (j < c2.length) { + for (int k = j; k < c2.length; k++) { + result[index++] = c2[k]; + } + } + + if (result.length > index) { + int[] tmpbuf = new int[index]; + System.arraycopy(result, 0, tmpbuf, 0, index); + return tmpbuf; + } + + return result; + } + + /** + * Returns the intersection of two CharSets. + */ + public CharSet intersection(CharSet that) { + return new CharSet(doIntersection(that.chars)); + } + + /** + * Removes from this CharSet any characters that aren't also in "that" + */ + private void internalIntersection(CharSet that) { + chars = doIntersection(that.chars); + } + + /** + * The internal implementation of the two intersection functions + */ + private int[] doIntersection(int[] c2) { + int[] result = new int[chars.length+c2.length]; + + int i = 0; + int j = 0; + int oldI; + int oldJ; + int index = 0; + + // iterate until we've exhausted one of the operands + while (i < chars.length && j < c2.length) { + + // advance j until it points to a character that is larger than + // the one i points to. If this is the beginning of a one- + // character range, advance j to point to the end + if (i < chars.length && i % 2 == 0) { + while (j < c2.length && c2[j] < chars[i]) { + ++j; + } + if (j < c2.length && j % 2 == 0 && c2[j] == chars[i]) { + ++j; + } + } + + // if j points to the endpoint of a range, save the current + // value of i, then advance i until it reaches a character + // which is larger than the character pointed at + // by j. All of the characters we've advanced over (except + // the one currently pointed to by i) are added to the result + oldI = i; + while (j % 2 == 1 && i < chars.length && chars[i] <= c2[j]) { + ++i; + } + for (int k = oldI; k < i; k++) { + result[index++] = chars[k]; + } + + // if i points to the endpoint of a range, save the current + // value of j, then advance j until it reaches a character + // which is larger than the character pointed at + // by i. All of the characters we've advanced over (except + // the one currently pointed to by i) are added to the result + oldJ = j; + while (i % 2 == 1 && j < c2.length && c2[j] <= chars[i]) { + ++j; + } + for (int k = oldJ; k < j; k++) { + result[index++] = c2[k]; + } + + // advance i until it points to a character larger than j + // If it points at the beginning of a one-character range, + // advance it to the end of that range + if (j < c2.length && j % 2 == 0) { + while (i < chars.length && chars[i] < c2[j]) { + ++i; + } + if (i < chars.length && i % 2 == 0 && c2[j] == chars[i]) { + ++i; + } + } + } + + if (result.length > index) { + int[] tmpbuf = new int[index]; + System.arraycopy(result, 0, tmpbuf, 0, index); + return tmpbuf; + } + + return result; + } + + /** + * Returns a CharSet containing all the characters in "this" that + * aren't also in "that" + */ + public CharSet difference(CharSet that) { + return new CharSet(doIntersection(that.doComplement())); + } + + /** + * Removes from "this" all the characters that are also in "that" + */ + private void internalDifference(CharSet that) { + chars = doIntersection(that.doComplement()); + } + + /** + * Returns a CharSet containing all the characters which are not + * in "this" + */ + public CharSet complement() { + return new CharSet(doComplement()); + } + + /** + * Complements "this". All the characters it contains are removed, + * and all the characters it doesn't contain are added. + */ + private void internalComplement() { + chars = doComplement(); + } + + /** + * The internal implementation function for the complement routines + */ + private int[] doComplement() { + // the complement of an empty CharSet is one containing everything + if (empty()) { + int[] result = new int[2]; + result[0] = 0x0000; + result[1] = 0x10FFFF; + return result; + } + + int[] result = new int[chars.length+2]; + + int i = 0; + int index = 0; + + // the result begins with \u0000 unless the original CharSet does + if (chars[0] != 0x0000) { + result[index++] = 0x0000; + } + + // walk through the characters in this CharSet. Append a pair of + // characters the first of which is one less than the first + // character we see and the second of which is one plus the second + // character we see (don't write the first character if it's \u0000, + // and don't write the second character if it's \uffff. + while (i < chars.length) { + if (chars[i] != 0x0000) { + result[index++] = chars[i] - 1; + } + if (chars[i + 1] != 0x10FFFF) { + result[index++] = chars[i + 1] + 1; + } + i += 2; + } + + // add 0x10ffff to the end of the result, unless it was in + // the original set + if (chars[i-1] != 0x10FFFF) { + result[index++] = 0x10FFFF; + } + + if (result.length > index) { + int[] tmpbuf = new int[index]; + System.arraycopy(result, 0, tmpbuf, 0, index); + return tmpbuf; + } + + return result; + } + + /** + * Returns true if this CharSet contains the specified character + * @param c The character we're testing for set membership + */ + public boolean contains(int c) { + // search for the first range endpoint that is greater than or + // equal to c + int i = 1; + while (i < chars.length && chars[i] < c) { + i += 2; + } + + // if we've walked off the end, we don't contain c + if (i == chars.length) { + return false; + } + + // otherwise, we contain c if the beginning of the range is less + // than or equal to c + return chars[i - 1] <= c; + } + + /** + * Returns true if "that" is another instance of CharSet containing + * the exact same characters as this one + */ + public boolean equals(Object that) { + return (that instanceof CharSet) && Arrays.equals(chars, ((CharSet)that).chars); + } + + /** + * Returns the hash code for this set of characters + */ + public int hashCode() { + return Arrays.hashCode(chars); + } + + /** + * Creates a new CharSet that is equal to this one + */ + public Object clone() { + return new CharSet(chars); + } + + /** + * Returns true if this CharSet contains no characters + */ + public boolean empty() { + return chars.length == 0; + } + + /** + * Returns a textual representation of this CharSet. If the result + * of calling this function is passed to CharSet.parseString(), it + * will produce another CharSet that is equal to this one. + */ + public String toString() { + StringBuffer result = new StringBuffer(); + + // the result begins with an opening bracket + result.append('['); + + // iterate through the ranges in the CharSet + for (int i = 0; i < chars.length; i += 2) { + // for a range with the same beginning and ending point, + // output that character + if (chars[i] == chars[i + 1]) { + result.append("0x"); + result.append(Integer.toHexString(chars[i])); + } + + // otherwise, output the start and end points of the range + // separated by a dash + else { + result.append("0x"); + result.append(Integer.toHexString(chars[i])); + result.append("-0x"); + result.append(Integer.toHexString(chars[i + 1])); + } + } + + // the result ends with a closing bracket + result.append(']'); + return result.toString(); + } + + /** + * Returns an integer array representing the contents of this CharSet + * in the same form in which they're stored internally: as pairs + * of characters representing the start and end points of ranges + */ + public int[] getRanges() { + return chars; + } + + /** + * Returns an Enumeration that will return the ranges of characters + * contained in this CharSet one at a time + */ + public Enumeration getChars() { + return new Enumeration(this); + } + + //========================================================================== + // CharSet.Enumeration + //========================================================================== + + /** + * An Enumeration that can be used to extract the character ranges + * from a CharSet one at a time + */ + public class Enumeration implements java.util.Enumeration { + /** + * Initializes a CharSet.Enumeration + */ + Enumeration(CharSet cs) { + this.chars = cs.chars; + p = 0; + } + + /** + * Returns true if the enumeration hasn't yet returned + * all the ranges in the CharSet + */ + public boolean hasMoreElements() { + return p < chars.length; + } + + /** + * Returns the next range in the CarSet + */ + public int[] nextElement() { + int[] result = new int[2]; + result[0] = chars[p++]; + result[1] = chars[p++]; + return result; + } + + int p; + int[] chars; + } +} --- old/make/jdk/src/classes/build/tools/generatebreakiteratordata/CharacterCategory.java 2020-03-23 19:56:39.091962684 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,697 +0,0 @@ -/* - * Copyright (c) 2003, 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 is a tool to generate categoryNames and categoryMap which are used in - * CharSet.java. - */ - -package build.tools.generatebreakiteratordata; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.FileReader; -import java.io.FileWriter; -import java.util.StringTokenizer; - -class CharacterCategory { - - /** - * A list of Unicode category names. - */ - static final String[] categoryNames = { - "Ll", /* Letter, Lowercase */ - "Lu", /* Letter, Uppercase */ - "Lt", /* Letter, Titlecase */ - "Lo", /* Letter, Other */ - "Lm", /* Letter, Modifier */ - "Nd", /* Number, Decimal Digit */ - "Nl", /* Number, Letter */ - "No", /* Number, Other */ - "Ps", /* Punctuation, Open */ - "Pe", /* Punctuation, Close */ - "Pi", /* Punctuation, Initial quote */ - "Pf", /* Punctuation, Final quote */ - "Pd", /* Punctuation, Dash */ - "Pc", /* Punctuation, Connector */ - "Po", /* Punctuation, Other */ - "Sc", /* Symbol, Currency */ - "Sm", /* Symbol, Math */ - "So", /* Symbol, Other */ - "Mn", /* Mark, Non-Spacing */ - "Mc", /* Mark, Spacing Combining */ - "Me", /* Mark, Enclosing */ - "Zl", /* Separator, Line */ - "Zp", /* Separator, Paragraph */ - "Zs", /* Separator, Space */ - "Cc", /* Other, Control */ - "Cf", /* Other, Format */ - "--", /* Dummy, ignored */ - // Don't add anything after the Dummy entry!! - }; - - /** - * A array of Unicode code points for each category. - */ - private static int[][] categoryMap; - - - /** - * Generates CategoryMap for GenerateBreakIteratorData. - */ - static void makeCategoryMap(String filename) { - /* Overwrite specfile name */ - specfile = filename; - - /* Generate data in current format (1.5.0) */ - generateNewData(); - - /* Copy generated data to cateogyMap */ - categoryMap = new int[categoryNames.length-1][]; - for (int i = 0; i < categoryNames.length-1; i++) { - int len = newListCount[BMP][i] + newListCount[nonBMP][i]; - categoryMap[i] = new int[len]; - System.arraycopy(newList[i], 0, categoryMap[i], 0, len); - } - } - - /** - * Returns categoryMap for the given category. - */ - static int[] getCategoryMap(int category) { - return categoryMap[category]; - } - - - /** - * Only used for debugging and generating a test program. - */ - public static void main(String[] args) { - /* Parses command-line options */ - processArgs(args); - - /* Generates data in current format (1.5.0) */ - generateNewData(); - - /* - * Generates data in older format (1.4.X and earlier) and creates - * the old CategoryMap if "oldFilename" is not null. - */ - if (!oldDatafile.equals("")) { - generateOldData(); - generateOldDatafile(); - } - - /* Displays summary of generated data */ - showSummary(); - - /* - * Generates a test program which compares the new data and the return - * values of Character.getType(). - * and the old data and the new data. - */ - generateTestProgram(); - } - - - /** - * Spec (Unicode data file) - */ - private static String specfile = "UnicodeData.txt"; - - /** - * Output directory - */ - private static String outputDir = ""; - - /** - * Old data filename - */ - private static String oldDatafile = ""; - - /** - * Parses the specified arguments and sets up the variables. - */ - private static void processArgs(String[] args) { - for (int i = 0; i < args.length; i++) { - String arg =args[i]; - if (arg.equals("-spec")) { - specfile = args[++i]; - } else if (arg.equals("-old")) { - oldDatafile = args[++i]; - } else if (arg.equals("-o")) { - outputDir = args[++i]; - } else { - System.err.println("Usage: java CharacterCategory [-spec specfile]"); - System.exit(1); - } - } - } - - - /** - * Displays summary of generated data - */ - private static void showSummary() { - int oldSum = 0; - int newSum = 0; - int oldSuppSum = 0; - int newSuppSum = 0; - - for (int i = 0; i < categoryNames.length-1; i++) { - int newNum = newListCount[BMP][i] + newListCount[nonBMP][i]; - - if (oldTotalCount[i] != newNum) { - System.err.println("Error: The number of generated data is different between the new approach and the old approach."); - } - if (oldListCount[SURROGATE][i] != newListCount[nonBMP][i]) { - System.err.println("Error: The number of generated supplementarycharacters is different between the new approach and the old approach."); - } - - System.out.println(" " + categoryNames[i] + ": " + - oldTotalCount[i] + - "(" + oldListCount[BEFORE][i] + - " + " + oldListCount[SURROGATE][i] + - " + " + oldListCount[AFTER][i] + ")" + - " --- " + newNum + - "(" + newListCount[BMP][i] + - " + " + newListCount[nonBMP][i] + ")"); - - oldSum += oldListCount[BEFORE][i] * 2 + - oldListCount[SURROGATE][i] * 4 + - oldListCount[AFTER][i] * 2; - newSum += newNum * 4 ; - oldSuppSum += oldListCount[SURROGATE][i] * 4; - newSuppSum += newListCount[nonBMP][i] * 4; - } - - System.out.println("\nTotal buffer sizes are:\n " + - oldSum + "bytes(Including " + oldSuppSum + - "bytes for supplementary characters)\n " + - newSum + "bytes(Including " + newSuppSum + - "bytes for supplementary characters)"); - - if (!ignoredOld.toString().equals(ignoredNew.toString())) { - System.err.println("Ignored categories: Error: List mismatch: " + - ignoredOld + " vs. " + ignoredNew); - } else { - System.out.println("\nIgnored categories: " + ignoredOld); - System.out.println("Please confirm that they aren't used in BreakIteratorRules."); - } - } - - - private static final int HighSurrogate_CodeUnit_Start = 0xD800; - private static final int LowSurrogate_CodeUnit_Start = 0xDC00; - private static final int Supplementary_CodePoint_Start = 0x10000; - - - private static StringBuffer ignoredOld = new StringBuffer(); - private static int[] oldTotalCount = new int[categoryNames.length]; - private static int[][] oldListCount = new int[3][categoryNames.length]; - private static int[][] oldListLen = new int[3][categoryNames.length]; - private static StringBuffer[][] oldList = new StringBuffer[3][categoryNames.length]; - - private static final int BEFORE = 0; - private static final int SURROGATE = 1; - private static final int AFTER = 2; - - /** - * Makes CategoryMap in ordler format which had been used by JDK 1.4.X and - * earlier versions. - */ - private static void generateOldData() { - /* Initialize arrays. */ - for (int i = 0; i")) { - setFirst = false; - } else { - appendOldChar(prevIndex, prevCodeValue, prevCode); - appendOldChar(index, curCodeValue, code); - } - } - prevCodeValue = curCodeValue; - prevCode = code; - if (characterName.endsWith(" First>")) { - setFirst = true; - } - } else { - if (ignoredOld.indexOf(category) == -1) { - ignoredOld.append(category); - ignoredOld.append(' '); - } - } - } - appendOldChar(prevIndex, prevCodeValue, prevCode); - - bin.close(); - fin.close(); - } - catch (Exception e) { - throw new InternalError(e.toString()); - } - } - - private static void appendOldChar(int index, int code, String s) { - int range; - if (code < HighSurrogate_CodeUnit_Start) { - range = BEFORE; - } else if (code < Supplementary_CodePoint_Start) { - range = AFTER; - } else { - range = SURROGATE; - } - - if (oldListLen[range][index] > 64) { - oldList[range][index].append("\"\n + \""); - oldListLen[range][index] = 19; - } - - if (code == 0x22 || code == 0x5c) { - oldList[range][index].append('\\'); - oldList[range][index].append((char)code); - oldListLen[range][index] += 2; - } else if (code > 0x20 && code < 0x7F) { - oldList[range][index].append((char)code); - oldListLen[range][index] ++; - } else { - if (range == SURROGATE) {// Need to convert code point to code unit - oldList[range][index].append(toCodeUnit(code)); - oldListLen[range][index] += 12; - } else { - oldList[range][index].append("\\u"); - oldList[range][index].append(s); - oldListLen[range][index] += 6; - } - } - oldListCount[range][index] ++; - oldTotalCount[index]++; - } - - private static String toCodeUnit(int i) { - StringBuffer sb = new StringBuffer(); - sb.append("\\u"); - sb.append(Integer.toString((i - Supplementary_CodePoint_Start) / 0x400 + HighSurrogate_CodeUnit_Start, 16).toUpperCase()); - sb.append("\\u"); - sb.append(Integer.toString(i % 0x400 + LowSurrogate_CodeUnit_Start, 16).toUpperCase()); - return sb.toString(); - } - - private static int toCodePoint(String s) { - char c1 = s.charAt(0); - - if (s.length() == 1 || !Character.isHighSurrogate(c1)) { - return (int)c1; - } else { - char c2 = s.charAt(1); - if (s.length() != 2 || !Character.isLowSurrogate(c2)) { - return -1; - } - return Character.toCodePoint(c1, c2); - } - } - - - private static StringBuffer ignoredNew = new StringBuffer(); - private static int[] newTotalCount = new int[categoryNames.length]; - private static int[][] newListCount = new int[2][categoryNames.length]; - private static int[][] newList = new int[categoryNames.length][]; - - private static final int BMP = 0; - private static final int nonBMP = 1; - - /** - * Makes CategoryMap in newer format which is used by JDK 1.5.0. - */ - private static void generateNewData() { - /* Initialize arrays. */ - for (int i = 0; i")) { - setFirst = false; - } else { - System.err.println("*** Error 1 at " + code); - } - } else { - if (characterName.endsWith(" First>")) { - setFirst = true; - } else if (characterName.endsWith(" Last>")) { - System.err.println("*** Error 2 at " + code); - } else { - if (prevCodeValue != curCodeValue - 1) { - appendNewChar(prevIndex, prevCodeValue); - appendNewChar(index, curCodeValue); - } - } - } - } else { - if (setFirst) { - System.err.println("*** Error 3 at " + code); - } else if (characterName.endsWith(" First>")) { - setFirst = true; - } else if (characterName.endsWith(" Last>")) { - System.err.println("*** Error 4 at " + code); - } - appendNewChar(prevIndex, prevCodeValue); - appendNewChar(index, curCodeValue); - prevIndex = index; - } - prevCodeValue = curCodeValue; - } else { - if (ignoredNew.indexOf(category) == -1) { - ignoredNew.append(category); - ignoredNew.append(' '); - } - } - } - appendNewChar(prevIndex, prevCodeValue); - - bin.close(); - fin.close(); - } - catch (Exception e) { - System.err.println("Error occurred on accessing " + specfile); - e.printStackTrace(); - System.exit(1); - } - } - - private static void appendNewChar(int index, int code) { - int bufLen = newList[index].length; - if (newTotalCount[index] == bufLen) { - int[] tmpBuf = new int[bufLen + 10]; - System.arraycopy(newList[index], 0, tmpBuf, 0, bufLen); - newList[index] = tmpBuf; - } - - newList[index][newTotalCount[index]++] = code; - if (code < 0x10000) { - newListCount[BMP][index]++; - } else { - newListCount[nonBMP][index]++; - } - } - - - /* Generates the old CategoryMap. */ - private static void generateOldDatafile() { - try { - FileWriter fout = new FileWriter(oldDatafile); - BufferedWriter bout = new BufferedWriter(fout); - - bout.write("\n //\n // The following String[][] can be used in CharSet.java as is.\n //\n\n private static final String[][] categoryMap = {\n"); - for (int i = 0; i < categoryNames.length - 1; i++) { - if (oldTotalCount[i] != 0) { - bout.write(" { \"" + categoryNames[i] + "\","); - - /* 0x0000-0xD7FF */ - if (oldListCount[BEFORE][i] != 0) { - bout.write(" \""); - - bout.write(oldList[BEFORE][i].toString() + "\"\n"); - } - - /* 0xD800-0xFFFF */ - if (oldListCount[AFTER][i] != 0) { - if (oldListCount[BEFORE][i] != 0) { - bout.write(" + \""); - } else { - bout.write(" \""); - } - bout.write(oldList[AFTER][i].toString() + "\"\n"); - } - - /* 0xD800DC00(0x10000)-0xDBFF0xDFFFF(0x10FFFF) */ - if (oldListCount[SURROGATE][i] != 0) { - if (oldListCount[BEFORE][i] != 0 || oldListCount[AFTER][i] != 0) { - bout.write(" + \""); - } else { - bout.write(" \""); - } - bout.write(oldList[SURROGATE][i].toString() + "\"\n"); - } - bout.write(" },\n"); - - } - } - bout.write(" };\n\n"); - bout.close(); - fout.close(); - } - catch (Exception e) { - System.err.println("Error occurred on accessing " + oldDatafile); - e.printStackTrace(); - System.exit(1); - } - - System.out.println("\n" + oldDatafile + " has been generated."); - } - - - /** - * Test program to be generated - */ - private static final String outfile = "CharacterCategoryTest.java"; - - /* - * Generates a test program which compare the generated date (newer one) - * with the return values of Characger.getType(). - */ - private static void generateTestProgram() { - try { - FileWriter fout = new FileWriter(outfile); - BufferedWriter bout = new BufferedWriter(fout); - - bout.write(collationMethod); - bout.write("\n //\n // The following arrays can be used in CharSet.java as is.\n //\n\n"); - - bout.write(" private static final String[] categoryNames = {"); - for (int i = 0; i < categoryNames.length - 1; i++) { - if (i % 10 == 0) { - bout.write("\n "); - } - bout.write("\"" + categoryNames[i] + "\", "); - } - bout.write("\n };\n\n"); - - bout.write(" private static final int[][] categoryMap = {\n"); - - for (int i = 0; i < categoryNames.length - 1; i++) { - StringBuffer sb = new StringBuffer(" { /* Data for \"" + categoryNames[i] + "\" category */"); - - for (int j = 0; j < newTotalCount[i]; j++) { - if (j % 8 == 0) { - sb.append("\n "); - } - sb.append(" 0x"); - sb.append(Integer.toString(newList[i][j], 16).toUpperCase()); - sb.append(','); - } - sb.append("\n },\n"); - bout.write(sb.toString()); - } - - bout.write(" };\n"); - - bout.write("\n}\n"); - - bout.close(); - fout.close(); - } - catch (Exception e) { - System.err.println("Error occurred on accessing " + outfile); - e.printStackTrace(); - System.exit(1); - } - - System.out.println("\n" + outfile + " has been generated."); - } - - static String collationMethod = -"public class CharacterCategoryTest {\n\n" + -" static final int SIZE = 0x110000;\n" + -" static final String[] category = {\n" + -" \"Cn\", \"Lu\", \"Ll\", \"Lt\", \"Lm\", \"Lo\", \"Mn\", \"Me\",\n" + -" \"Mc\", \"Nd\", \"Nl\", \"No\", \"Zs\", \"Zl\", \"Zp\", \"Cc\",\n" + -" \"Cf\", \"\", \"Co\", \"Cs\", \"Pd\", \"Ps\", \"Pe\", \"Pc\",\n" + -" \"Po\", \"Sm\", \"Sc\", \"Sk\", \"So\", \"Pi\", \"Pf\"\n" + -" };\n\n" + -" public static void main(String[] args) {\n" + -" boolean err = false;\n" + -" byte[] b = new byte[SIZE];\n" + -" for (int i = 0; i < SIZE; i++) {\n" + -" b[i] = 0;\n" + -" }\n" + -" for (int i = 0; i < categoryMap.length; i++) {\n" + -" byte categoryNum = 0;\n" + -" String categoryName = categoryNames[i];\n" + -" for (int j = 0; j < category.length; j++) {\n" + -" if (categoryName.equals(category[j])) {\n" + -" categoryNum = (byte)j;\n" + -" break;\n" + -" }\n" + -" }\n" + -" int[] values = categoryMap[i];\n" + -" for (int j = 0; j < values.length;) {\n" + -" int firstChar = values[j++];\n" + -" int lastChar = values[j++];\n" + -" for (int k = firstChar; k <= lastChar; k++) {\n" + -" b[k] = categoryNum;\n" + -" }\n" + -" }\n" + -" }\n" + -" for (int i = 0; i < SIZE; i++) {\n" + -" int characterType = Character.getType(i);\n" + -" if (b[i] != characterType) {\n" + -" /* Co, Cs and Sk categories are ignored in CharacterCategory. */\n" + -" if (characterType == Character.PRIVATE_USE ||\n" + -" characterType == Character.SURROGATE ||\n" + -" characterType == Character.MODIFIER_SYMBOL) {\n" + -" continue;\n" + -" }\n" + -" err = true;\n" + -" System.err.println(\"Category conflict for a character(0x\" +\n" + -" Integer.toHexString(i) +\n" + -" \"). CharSet.categoryMap:\" +\n" + -" category[b[i]] +\n" + -" \" Character.getType():\" +\n" + -" category[characterType]);\n" + -" }\n" + -" }\n\n" + -" if (err) {\n" + -" throw new RuntimeException(\"Conflict occurred between Charset.categoryMap and Character.getType()\");\n" + -" }\n" + -" }\n"; - -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.base/share/tools/org/openjdk/buildtools/generatebreakiteratordata/CharacterCategory.java 2020-03-23 19:56:38.643962687 +0100 @@ -0,0 +1,697 @@ +/* + * Copyright (c) 2003, 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 is a tool to generate categoryNames and categoryMap which are used in + * CharSet.java. + */ + +package org.openjdk.buildtools.generatebreakiteratordata; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.FileReader; +import java.io.FileWriter; +import java.util.StringTokenizer; + +class CharacterCategory { + + /** + * A list of Unicode category names. + */ + static final String[] categoryNames = { + "Ll", /* Letter, Lowercase */ + "Lu", /* Letter, Uppercase */ + "Lt", /* Letter, Titlecase */ + "Lo", /* Letter, Other */ + "Lm", /* Letter, Modifier */ + "Nd", /* Number, Decimal Digit */ + "Nl", /* Number, Letter */ + "No", /* Number, Other */ + "Ps", /* Punctuation, Open */ + "Pe", /* Punctuation, Close */ + "Pi", /* Punctuation, Initial quote */ + "Pf", /* Punctuation, Final quote */ + "Pd", /* Punctuation, Dash */ + "Pc", /* Punctuation, Connector */ + "Po", /* Punctuation, Other */ + "Sc", /* Symbol, Currency */ + "Sm", /* Symbol, Math */ + "So", /* Symbol, Other */ + "Mn", /* Mark, Non-Spacing */ + "Mc", /* Mark, Spacing Combining */ + "Me", /* Mark, Enclosing */ + "Zl", /* Separator, Line */ + "Zp", /* Separator, Paragraph */ + "Zs", /* Separator, Space */ + "Cc", /* Other, Control */ + "Cf", /* Other, Format */ + "--", /* Dummy, ignored */ + // Don't add anything after the Dummy entry!! + }; + + /** + * A array of Unicode code points for each category. + */ + private static int[][] categoryMap; + + + /** + * Generates CategoryMap for GenerateBreakIteratorData. + */ + static void makeCategoryMap(String filename) { + /* Overwrite specfile name */ + specfile = filename; + + /* Generate data in current format (1.5.0) */ + generateNewData(); + + /* Copy generated data to cateogyMap */ + categoryMap = new int[categoryNames.length-1][]; + for (int i = 0; i < categoryNames.length-1; i++) { + int len = newListCount[BMP][i] + newListCount[nonBMP][i]; + categoryMap[i] = new int[len]; + System.arraycopy(newList[i], 0, categoryMap[i], 0, len); + } + } + + /** + * Returns categoryMap for the given category. + */ + static int[] getCategoryMap(int category) { + return categoryMap[category]; + } + + + /** + * Only used for debugging and generating a test program. + */ + public static void main(String[] args) { + /* Parses command-line options */ + processArgs(args); + + /* Generates data in current format (1.5.0) */ + generateNewData(); + + /* + * Generates data in older format (1.4.X and earlier) and creates + * the old CategoryMap if "oldFilename" is not null. + */ + if (!oldDatafile.equals("")) { + generateOldData(); + generateOldDatafile(); + } + + /* Displays summary of generated data */ + showSummary(); + + /* + * Generates a test program which compares the new data and the return + * values of Character.getType(). + * and the old data and the new data. + */ + generateTestProgram(); + } + + + /** + * Spec (Unicode data file) + */ + private static String specfile = "UnicodeData.txt"; + + /** + * Output directory + */ + private static String outputDir = ""; + + /** + * Old data filename + */ + private static String oldDatafile = ""; + + /** + * Parses the specified arguments and sets up the variables. + */ + private static void processArgs(String[] args) { + for (int i = 0; i < args.length; i++) { + String arg =args[i]; + if (arg.equals("-spec")) { + specfile = args[++i]; + } else if (arg.equals("-old")) { + oldDatafile = args[++i]; + } else if (arg.equals("-o")) { + outputDir = args[++i]; + } else { + System.err.println("Usage: java CharacterCategory [-spec specfile]"); + System.exit(1); + } + } + } + + + /** + * Displays summary of generated data + */ + private static void showSummary() { + int oldSum = 0; + int newSum = 0; + int oldSuppSum = 0; + int newSuppSum = 0; + + for (int i = 0; i < categoryNames.length-1; i++) { + int newNum = newListCount[BMP][i] + newListCount[nonBMP][i]; + + if (oldTotalCount[i] != newNum) { + System.err.println("Error: The number of generated data is different between the new approach and the old approach."); + } + if (oldListCount[SURROGATE][i] != newListCount[nonBMP][i]) { + System.err.println("Error: The number of generated supplementarycharacters is different between the new approach and the old approach."); + } + + System.out.println(" " + categoryNames[i] + ": " + + oldTotalCount[i] + + "(" + oldListCount[BEFORE][i] + + " + " + oldListCount[SURROGATE][i] + + " + " + oldListCount[AFTER][i] + ")" + + " --- " + newNum + + "(" + newListCount[BMP][i] + + " + " + newListCount[nonBMP][i] + ")"); + + oldSum += oldListCount[BEFORE][i] * 2 + + oldListCount[SURROGATE][i] * 4 + + oldListCount[AFTER][i] * 2; + newSum += newNum * 4 ; + oldSuppSum += oldListCount[SURROGATE][i] * 4; + newSuppSum += newListCount[nonBMP][i] * 4; + } + + System.out.println("\nTotal buffer sizes are:\n " + + oldSum + "bytes(Including " + oldSuppSum + + "bytes for supplementary characters)\n " + + newSum + "bytes(Including " + newSuppSum + + "bytes for supplementary characters)"); + + if (!ignoredOld.toString().equals(ignoredNew.toString())) { + System.err.println("Ignored categories: Error: List mismatch: " + + ignoredOld + " vs. " + ignoredNew); + } else { + System.out.println("\nIgnored categories: " + ignoredOld); + System.out.println("Please confirm that they aren't used in BreakIteratorRules."); + } + } + + + private static final int HighSurrogate_CodeUnit_Start = 0xD800; + private static final int LowSurrogate_CodeUnit_Start = 0xDC00; + private static final int Supplementary_CodePoint_Start = 0x10000; + + + private static StringBuffer ignoredOld = new StringBuffer(); + private static int[] oldTotalCount = new int[categoryNames.length]; + private static int[][] oldListCount = new int[3][categoryNames.length]; + private static int[][] oldListLen = new int[3][categoryNames.length]; + private static StringBuffer[][] oldList = new StringBuffer[3][categoryNames.length]; + + private static final int BEFORE = 0; + private static final int SURROGATE = 1; + private static final int AFTER = 2; + + /** + * Makes CategoryMap in ordler format which had been used by JDK 1.4.X and + * earlier versions. + */ + private static void generateOldData() { + /* Initialize arrays. */ + for (int i = 0; i")) { + setFirst = false; + } else { + appendOldChar(prevIndex, prevCodeValue, prevCode); + appendOldChar(index, curCodeValue, code); + } + } + prevCodeValue = curCodeValue; + prevCode = code; + if (characterName.endsWith(" First>")) { + setFirst = true; + } + } else { + if (ignoredOld.indexOf(category) == -1) { + ignoredOld.append(category); + ignoredOld.append(' '); + } + } + } + appendOldChar(prevIndex, prevCodeValue, prevCode); + + bin.close(); + fin.close(); + } + catch (Exception e) { + throw new InternalError(e.toString()); + } + } + + private static void appendOldChar(int index, int code, String s) { + int range; + if (code < HighSurrogate_CodeUnit_Start) { + range = BEFORE; + } else if (code < Supplementary_CodePoint_Start) { + range = AFTER; + } else { + range = SURROGATE; + } + + if (oldListLen[range][index] > 64) { + oldList[range][index].append("\"\n + \""); + oldListLen[range][index] = 19; + } + + if (code == 0x22 || code == 0x5c) { + oldList[range][index].append('\\'); + oldList[range][index].append((char)code); + oldListLen[range][index] += 2; + } else if (code > 0x20 && code < 0x7F) { + oldList[range][index].append((char)code); + oldListLen[range][index] ++; + } else { + if (range == SURROGATE) {// Need to convert code point to code unit + oldList[range][index].append(toCodeUnit(code)); + oldListLen[range][index] += 12; + } else { + oldList[range][index].append("\\u"); + oldList[range][index].append(s); + oldListLen[range][index] += 6; + } + } + oldListCount[range][index] ++; + oldTotalCount[index]++; + } + + private static String toCodeUnit(int i) { + StringBuffer sb = new StringBuffer(); + sb.append("\\u"); + sb.append(Integer.toString((i - Supplementary_CodePoint_Start) / 0x400 + HighSurrogate_CodeUnit_Start, 16).toUpperCase()); + sb.append("\\u"); + sb.append(Integer.toString(i % 0x400 + LowSurrogate_CodeUnit_Start, 16).toUpperCase()); + return sb.toString(); + } + + private static int toCodePoint(String s) { + char c1 = s.charAt(0); + + if (s.length() == 1 || !Character.isHighSurrogate(c1)) { + return (int)c1; + } else { + char c2 = s.charAt(1); + if (s.length() != 2 || !Character.isLowSurrogate(c2)) { + return -1; + } + return Character.toCodePoint(c1, c2); + } + } + + + private static StringBuffer ignoredNew = new StringBuffer(); + private static int[] newTotalCount = new int[categoryNames.length]; + private static int[][] newListCount = new int[2][categoryNames.length]; + private static int[][] newList = new int[categoryNames.length][]; + + private static final int BMP = 0; + private static final int nonBMP = 1; + + /** + * Makes CategoryMap in newer format which is used by JDK 1.5.0. + */ + private static void generateNewData() { + /* Initialize arrays. */ + for (int i = 0; i")) { + setFirst = false; + } else { + System.err.println("*** Error 1 at " + code); + } + } else { + if (characterName.endsWith(" First>")) { + setFirst = true; + } else if (characterName.endsWith(" Last>")) { + System.err.println("*** Error 2 at " + code); + } else { + if (prevCodeValue != curCodeValue - 1) { + appendNewChar(prevIndex, prevCodeValue); + appendNewChar(index, curCodeValue); + } + } + } + } else { + if (setFirst) { + System.err.println("*** Error 3 at " + code); + } else if (characterName.endsWith(" First>")) { + setFirst = true; + } else if (characterName.endsWith(" Last>")) { + System.err.println("*** Error 4 at " + code); + } + appendNewChar(prevIndex, prevCodeValue); + appendNewChar(index, curCodeValue); + prevIndex = index; + } + prevCodeValue = curCodeValue; + } else { + if (ignoredNew.indexOf(category) == -1) { + ignoredNew.append(category); + ignoredNew.append(' '); + } + } + } + appendNewChar(prevIndex, prevCodeValue); + + bin.close(); + fin.close(); + } + catch (Exception e) { + System.err.println("Error occurred on accessing " + specfile); + e.printStackTrace(); + System.exit(1); + } + } + + private static void appendNewChar(int index, int code) { + int bufLen = newList[index].length; + if (newTotalCount[index] == bufLen) { + int[] tmpBuf = new int[bufLen + 10]; + System.arraycopy(newList[index], 0, tmpBuf, 0, bufLen); + newList[index] = tmpBuf; + } + + newList[index][newTotalCount[index]++] = code; + if (code < 0x10000) { + newListCount[BMP][index]++; + } else { + newListCount[nonBMP][index]++; + } + } + + + /* Generates the old CategoryMap. */ + private static void generateOldDatafile() { + try { + FileWriter fout = new FileWriter(oldDatafile); + BufferedWriter bout = new BufferedWriter(fout); + + bout.write("\n //\n // The following String[][] can be used in CharSet.java as is.\n //\n\n private static final String[][] categoryMap = {\n"); + for (int i = 0; i < categoryNames.length - 1; i++) { + if (oldTotalCount[i] != 0) { + bout.write(" { \"" + categoryNames[i] + "\","); + + /* 0x0000-0xD7FF */ + if (oldListCount[BEFORE][i] != 0) { + bout.write(" \""); + + bout.write(oldList[BEFORE][i].toString() + "\"\n"); + } + + /* 0xD800-0xFFFF */ + if (oldListCount[AFTER][i] != 0) { + if (oldListCount[BEFORE][i] != 0) { + bout.write(" + \""); + } else { + bout.write(" \""); + } + bout.write(oldList[AFTER][i].toString() + "\"\n"); + } + + /* 0xD800DC00(0x10000)-0xDBFF0xDFFFF(0x10FFFF) */ + if (oldListCount[SURROGATE][i] != 0) { + if (oldListCount[BEFORE][i] != 0 || oldListCount[AFTER][i] != 0) { + bout.write(" + \""); + } else { + bout.write(" \""); + } + bout.write(oldList[SURROGATE][i].toString() + "\"\n"); + } + bout.write(" },\n"); + + } + } + bout.write(" };\n\n"); + bout.close(); + fout.close(); + } + catch (Exception e) { + System.err.println("Error occurred on accessing " + oldDatafile); + e.printStackTrace(); + System.exit(1); + } + + System.out.println("\n" + oldDatafile + " has been generated."); + } + + + /** + * Test program to be generated + */ + private static final String outfile = "CharacterCategoryTest.java"; + + /* + * Generates a test program which compare the generated date (newer one) + * with the return values of Characger.getType(). + */ + private static void generateTestProgram() { + try { + FileWriter fout = new FileWriter(outfile); + BufferedWriter bout = new BufferedWriter(fout); + + bout.write(collationMethod); + bout.write("\n //\n // The following arrays can be used in CharSet.java as is.\n //\n\n"); + + bout.write(" private static final String[] categoryNames = {"); + for (int i = 0; i < categoryNames.length - 1; i++) { + if (i % 10 == 0) { + bout.write("\n "); + } + bout.write("\"" + categoryNames[i] + "\", "); + } + bout.write("\n };\n\n"); + + bout.write(" private static final int[][] categoryMap = {\n"); + + for (int i = 0; i < categoryNames.length - 1; i++) { + StringBuffer sb = new StringBuffer(" { /* Data for \"" + categoryNames[i] + "\" category */"); + + for (int j = 0; j < newTotalCount[i]; j++) { + if (j % 8 == 0) { + sb.append("\n "); + } + sb.append(" 0x"); + sb.append(Integer.toString(newList[i][j], 16).toUpperCase()); + sb.append(','); + } + sb.append("\n },\n"); + bout.write(sb.toString()); + } + + bout.write(" };\n"); + + bout.write("\n}\n"); + + bout.close(); + fout.close(); + } + catch (Exception e) { + System.err.println("Error occurred on accessing " + outfile); + e.printStackTrace(); + System.exit(1); + } + + System.out.println("\n" + outfile + " has been generated."); + } + + static String collationMethod = +"public class CharacterCategoryTest {\n\n" + +" static final int SIZE = 0x110000;\n" + +" static final String[] category = {\n" + +" \"Cn\", \"Lu\", \"Ll\", \"Lt\", \"Lm\", \"Lo\", \"Mn\", \"Me\",\n" + +" \"Mc\", \"Nd\", \"Nl\", \"No\", \"Zs\", \"Zl\", \"Zp\", \"Cc\",\n" + +" \"Cf\", \"\", \"Co\", \"Cs\", \"Pd\", \"Ps\", \"Pe\", \"Pc\",\n" + +" \"Po\", \"Sm\", \"Sc\", \"Sk\", \"So\", \"Pi\", \"Pf\"\n" + +" };\n\n" + +" public static void main(String[] args) {\n" + +" boolean err = false;\n" + +" byte[] b = new byte[SIZE];\n" + +" for (int i = 0; i < SIZE; i++) {\n" + +" b[i] = 0;\n" + +" }\n" + +" for (int i = 0; i < categoryMap.length; i++) {\n" + +" byte categoryNum = 0;\n" + +" String categoryName = categoryNames[i];\n" + +" for (int j = 0; j < category.length; j++) {\n" + +" if (categoryName.equals(category[j])) {\n" + +" categoryNum = (byte)j;\n" + +" break;\n" + +" }\n" + +" }\n" + +" int[] values = categoryMap[i];\n" + +" for (int j = 0; j < values.length;) {\n" + +" int firstChar = values[j++];\n" + +" int lastChar = values[j++];\n" + +" for (int k = firstChar; k <= lastChar; k++) {\n" + +" b[k] = categoryNum;\n" + +" }\n" + +" }\n" + +" }\n" + +" for (int i = 0; i < SIZE; i++) {\n" + +" int characterType = Character.getType(i);\n" + +" if (b[i] != characterType) {\n" + +" /* Co, Cs and Sk categories are ignored in CharacterCategory. */\n" + +" if (characterType == Character.PRIVATE_USE ||\n" + +" characterType == Character.SURROGATE ||\n" + +" characterType == Character.MODIFIER_SYMBOL) {\n" + +" continue;\n" + +" }\n" + +" err = true;\n" + +" System.err.println(\"Category conflict for a character(0x\" +\n" + +" Integer.toHexString(i) +\n" + +" \"). CharSet.categoryMap:\" +\n" + +" category[b[i]] +\n" + +" \" Character.getType():\" +\n" + +" category[characterType]);\n" + +" }\n" + +" }\n\n" + +" if (err) {\n" + +" throw new RuntimeException(\"Conflict occurred between Charset.categoryMap and Character.getType()\");\n" + +" }\n" + +" }\n"; + +} --- old/make/jdk/src/classes/build/tools/generatebreakiteratordata/DictionaryBasedBreakIteratorBuilder.java 2020-03-23 19:56:39.895962678 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2003, 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 build.tools.generatebreakiteratordata; - -import java.util.Hashtable; -import java.util.Vector; - -/** - * The Builder class for DictionaryBasedBreakIterator inherits almost all of - * its functionality from RuleBasedBreakIteratorBuilder, but extends it with - * extra logic to handle the "" token. - */ -class DictionaryBasedBreakIteratorBuilder extends RuleBasedBreakIteratorBuilder { - - /** - * A list of flags indicating which character categories are contained in - * the dictionary file (this is used to determine which ranges of characters - * to apply the dictionary to) - */ - private boolean[] categoryFlags; - - /** - * A CharSet that contains all the characters represented in the dictionary - */ - private CharSet dictionaryChars = new CharSet(); - private String dictionaryExpression = ""; - - public DictionaryBasedBreakIteratorBuilder(String description) { - super(description); - } - - /** - * We override handleSpecialSubstitution() to add logic to handle - * the tag. If we see a substitution named "", - * parse the substitution expression and store the result in - * dictionaryChars. - */ - protected void handleSpecialSubstitution(String replace, String replaceWith, - int startPos, String description) { - super.handleSpecialSubstitution(replace, replaceWith, startPos, description); - - if (replace.equals("")) { - if (replaceWith.charAt(0) == '(') { - error("Dictionary group can't be enclosed in (", startPos, description); - } - dictionaryExpression = replaceWith; - dictionaryChars = CharSet.parseString(replaceWith); - } - } - - /** - * The other half of the logic to handle the dictionary characters happens - * here. After the inherited builder has derived the real character - * categories, we set up the categoryFlags array in the iterator. This array - * contains "true" for every character category that includes a dictionary - * character. - */ - protected void buildCharCategories(Vector tempRuleList) { - super.buildCharCategories(tempRuleList); - - categoryFlags = new boolean[categories.size()]; - for (int i = 0; i < categories.size(); i++) { - CharSet cs = categories.elementAt(i); - if (!(cs.intersection(dictionaryChars).empty())) { - categoryFlags[i] = true; - } - } - } - - // This function is actually called by - // RuleBasedBreakIteratorBuilder.buildCharCategories(), which is called by - // the function above. This gives us a way to create a separate character - // category for the dictionary characters even when - // RuleBasedBreakIteratorBuilder isn't making a distinction. - protected void mungeExpressionList(Hashtable expressions) { - expressions.put(dictionaryExpression, dictionaryChars); - } - - void makeFile(String filename) { - super.setAdditionalData(super.toByteArray(categoryFlags)); - super.makeFile(filename); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.base/share/tools/org/openjdk/buildtools/generatebreakiteratordata/DictionaryBasedBreakIteratorBuilder.java 2020-03-23 19:56:39.503962680 +0100 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2003, 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 org.openjdk.buildtools.generatebreakiteratordata; + +import java.util.Hashtable; +import java.util.Vector; + +/** + * The Builder class for DictionaryBasedBreakIterator inherits almost all of + * its functionality from RuleBasedBreakIteratorBuilder, but extends it with + * extra logic to handle the "" token. + */ +class DictionaryBasedBreakIteratorBuilder extends RuleBasedBreakIteratorBuilder { + + /** + * A list of flags indicating which character categories are contained in + * the dictionary file (this is used to determine which ranges of characters + * to apply the dictionary to) + */ + private boolean[] categoryFlags; + + /** + * A CharSet that contains all the characters represented in the dictionary + */ + private CharSet dictionaryChars = new CharSet(); + private String dictionaryExpression = ""; + + public DictionaryBasedBreakIteratorBuilder(String description) { + super(description); + } + + /** + * We override handleSpecialSubstitution() to add logic to handle + * the tag. If we see a substitution named "", + * parse the substitution expression and store the result in + * dictionaryChars. + */ + protected void handleSpecialSubstitution(String replace, String replaceWith, + int startPos, String description) { + super.handleSpecialSubstitution(replace, replaceWith, startPos, description); + + if (replace.equals("")) { + if (replaceWith.charAt(0) == '(') { + error("Dictionary group can't be enclosed in (", startPos, description); + } + dictionaryExpression = replaceWith; + dictionaryChars = CharSet.parseString(replaceWith); + } + } + + /** + * The other half of the logic to handle the dictionary characters happens + * here. After the inherited builder has derived the real character + * categories, we set up the categoryFlags array in the iterator. This array + * contains "true" for every character category that includes a dictionary + * character. + */ + protected void buildCharCategories(Vector tempRuleList) { + super.buildCharCategories(tempRuleList); + + categoryFlags = new boolean[categories.size()]; + for (int i = 0; i < categories.size(); i++) { + CharSet cs = categories.elementAt(i); + if (!(cs.intersection(dictionaryChars).empty())) { + categoryFlags[i] = true; + } + } + } + + // This function is actually called by + // RuleBasedBreakIteratorBuilder.buildCharCategories(), which is called by + // the function above. This gives us a way to create a separate character + // category for the dictionary characters even when + // RuleBasedBreakIteratorBuilder isn't making a distinction. + protected void mungeExpressionList(Hashtable expressions) { + expressions.put(dictionaryExpression, dictionaryChars); + } + + void makeFile(String filename) { + super.setAdditionalData(super.toByteArray(categoryFlags)); + super.makeFile(filename); + } +} --- old/make/jdk/src/classes/build/tools/generatebreakiteratordata/GenerateBreakIteratorData.java 2020-03-23 19:56:40.739962671 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,207 +0,0 @@ -/* - * Copyright (c) 2003, 2020, 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.generatebreakiteratordata; - -import java.util.Enumeration; -import java.util.ListResourceBundle; -import java.util.Locale; -import java.util.ResourceBundle; - -/** - * Generates datafile for BreakIterator. - */ -public class GenerateBreakIteratorData { - - /** - * Directory where generated data files are put in. - */ - private static String outputDir = "" ; - - /** - * Unicode data file - */ - private static String unicodeData = "UnicodeData.txt"; - - /** - * Locale data - */ - private static String language = ""; - private static String country = ""; - private static String valiant = ""; - private static String localeName = ""; /* _language_country_valiant */ - - - public static void main(String[] args) { - /* Parse command-line options */ - processArgs(args); - - /* Make categoryMap from Unicode data */ - CharacterCategory.makeCategoryMap(unicodeData); - - /* Generate files */ - try { - generateFiles(); - } catch (Exception e) { - e.printStackTrace(); - System.exit(1); - } - } - - private static String localizedBundleName(String pkg, String clazz) { - if (language.length() > 0) { - return pkg + ".ext." + clazz + '_' + language; - } else { - return pkg + '.' + clazz; - } - } - - /** - * Generate data files whose names are included in - * sun.text.resources.BreakIteratorInfo+ - */ - private static void generateFiles() throws Exception { - String[] classNames; - ResourceBundle rules, info; - - info = (ResourceBundle) Class.forName( - localizedBundleName("sun.text.resources", "BreakIteratorInfo")).getDeclaredConstructor().newInstance(); - - classNames = info.getStringArray("BreakIteratorClasses"); - - rules = (ResourceBundle) Class.forName( - localizedBundleName("sun.text.resources", "BreakIteratorRules")).getDeclaredConstructor().newInstance(); - - if (info.containsKey("CharacterData")) { - generateDataFile(info.getString("CharacterData"), - rules.getString("CharacterBreakRules"), - classNames[0]); - } - if (info.containsKey("WordData")) { - generateDataFile(info.getString("WordData"), - rules.getString("WordBreakRules"), - classNames[1]); - } - if (info.containsKey("LineData")) { - generateDataFile(info.getString("LineData"), - rules.getString("LineBreakRules"), - classNames[2]); - } - if (info.containsKey("SentenceData")) { - generateDataFile(info.getString("SentenceData"), - rules.getString("SentenceBreakRules"), - classNames[3]); - } - } - - /** - * Generate a data file for break-iterator - */ - private static void generateDataFile(String datafile, String rule, String builder) { - RuleBasedBreakIteratorBuilder bld; - if (builder.equals("RuleBasedBreakIterator")) { - bld = new RuleBasedBreakIteratorBuilder(rule); - } else if (builder.equals("DictionaryBasedBreakIterator")) { - bld = new DictionaryBasedBreakIteratorBuilder(rule); - } else { - throw new IllegalArgumentException("Invalid break iterator class \"" + builder + "\""); - } - - bld.makeFile(datafile); - } - - /** - * Parses the specified arguments and sets up the variables. - */ - private static void processArgs(String[] args) { - for (int i = 0; i < args.length; i++) { - String arg = args[i]; - if (arg.equals("-o")) { - outputDir = args[++i]; - } else if (arg.equals("-spec")) { - unicodeData = args[++i]; - } else if (arg.equals("-language")) { - language = args[++i]; - } else if (arg.equals("-country")) { - country = args[++i]; - } else if (arg.equals("-valiant")) { - valiant = args[++i]; - } else { - usage(); - } - } - - // Set locale name - localeName = getLocaleName(); - } - - /** - * Make locale name ("_language_country_valiant") - */ - private static String getLocaleName() { - if (language.equals("")) { - if (!country.equals("") || !valiant.equals("")) { - language = "en"; - } else { - return ""; - } - } - - StringBuffer sb = new StringBuffer(); - sb.append('_'); - sb.append(language); - if (!country.equals("") || !valiant.equals("")) { - sb.append('_'); - sb.append(country); - if (!valiant.equals("")) { - sb.append('_'); - sb.append(valiant); - } - } - - return sb.toString(); - } - - /** - * Usage: Displayed when an invalid command-line option is specified. - */ - private static void usage() { - System.err.println("Usage: GenerateBreakIteratorData [options]\n" + - " -o outputDir output directory name\n" + - " -spec specname unicode text filename\n" + - " and locale data:\n" + - " -lang language target language name\n" + - " -country country target country name\n" + - " -valiant valiant target valiant name\n" - ); - } - - /** - * Return the path of output directory - */ - static String getOutputDirectory() { - return outputDir; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.base/share/tools/org/openjdk/buildtools/generatebreakiteratordata/GenerateBreakIteratorData.java 2020-03-23 19:56:40.303962675 +0100 @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatebreakiteratordata; + +import java.util.Enumeration; +import java.util.ListResourceBundle; +import java.util.Locale; +import java.util.ResourceBundle; + +/** + * Generates datafile for BreakIterator. + */ +public class GenerateBreakIteratorData { + + /** + * Directory where generated data files are put in. + */ + private static String outputDir = "" ; + + /** + * Unicode data file + */ + private static String unicodeData = "UnicodeData.txt"; + + /** + * Locale data + */ + private static String language = ""; + private static String country = ""; + private static String valiant = ""; + private static String localeName = ""; /* _language_country_valiant */ + + + public static void main(String[] args) { + /* Parse command-line options */ + processArgs(args); + + /* Make categoryMap from Unicode data */ + CharacterCategory.makeCategoryMap(unicodeData); + + /* Generate files */ + try { + generateFiles(); + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + } + + private static String localizedBundleName(String pkg, String clazz) { + if (language.length() > 0) { + return pkg + ".ext." + clazz + '_' + language; + } else { + return pkg + '.' + clazz; + } + } + + /** + * Generate data files whose names are included in + * sun.text.resources.BreakIteratorInfo+ + */ + private static void generateFiles() throws Exception { + String[] classNames; + ResourceBundle rules, info; + + info = (ResourceBundle) Class.forName( + localizedBundleName("sun.text.resources", "BreakIteratorInfo")).getDeclaredConstructor().newInstance(); + + classNames = info.getStringArray("BreakIteratorClasses"); + + rules = (ResourceBundle) Class.forName( + localizedBundleName("sun.text.resources", "BreakIteratorRules")).getDeclaredConstructor().newInstance(); + + if (info.containsKey("CharacterData")) { + generateDataFile(info.getString("CharacterData"), + rules.getString("CharacterBreakRules"), + classNames[0]); + } + if (info.containsKey("WordData")) { + generateDataFile(info.getString("WordData"), + rules.getString("WordBreakRules"), + classNames[1]); + } + if (info.containsKey("LineData")) { + generateDataFile(info.getString("LineData"), + rules.getString("LineBreakRules"), + classNames[2]); + } + if (info.containsKey("SentenceData")) { + generateDataFile(info.getString("SentenceData"), + rules.getString("SentenceBreakRules"), + classNames[3]); + } + } + + /** + * Generate a data file for break-iterator + */ + private static void generateDataFile(String datafile, String rule, String builder) { + RuleBasedBreakIteratorBuilder bld; + if (builder.equals("RuleBasedBreakIterator")) { + bld = new RuleBasedBreakIteratorBuilder(rule); + } else if (builder.equals("DictionaryBasedBreakIterator")) { + bld = new DictionaryBasedBreakIteratorBuilder(rule); + } else { + throw new IllegalArgumentException("Invalid break iterator class \"" + builder + "\""); + } + + bld.makeFile(datafile); + } + + /** + * Parses the specified arguments and sets up the variables. + */ + private static void processArgs(String[] args) { + for (int i = 0; i < args.length; i++) { + String arg = args[i]; + if (arg.equals("-o")) { + outputDir = args[++i]; + } else if (arg.equals("-spec")) { + unicodeData = args[++i]; + } else if (arg.equals("-language")) { + language = args[++i]; + } else if (arg.equals("-country")) { + country = args[++i]; + } else if (arg.equals("-valiant")) { + valiant = args[++i]; + } else { + usage(); + } + } + + // Set locale name + localeName = getLocaleName(); + } + + /** + * Make locale name ("_language_country_valiant") + */ + private static String getLocaleName() { + if (language.equals("")) { + if (!country.equals("") || !valiant.equals("")) { + language = "en"; + } else { + return ""; + } + } + + StringBuffer sb = new StringBuffer(); + sb.append('_'); + sb.append(language); + if (!country.equals("") || !valiant.equals("")) { + sb.append('_'); + sb.append(country); + if (!valiant.equals("")) { + sb.append('_'); + sb.append(valiant); + } + } + + return sb.toString(); + } + + /** + * Usage: Displayed when an invalid command-line option is specified. + */ + private static void usage() { + System.err.println("Usage: GenerateBreakIteratorData [options]\n" + + " -o outputDir output directory name\n" + + " -spec specname unicode text filename\n" + + " and locale data:\n" + + " -lang language target language name\n" + + " -country country target country name\n" + + " -valiant valiant target valiant name\n" + ); + } + + /** + * Return the path of output directory + */ + static String getOutputDirectory() { + return outputDir; + } +} --- old/make/jdk/src/classes/build/tools/generatebreakiteratordata/RuleBasedBreakIteratorBuilder.java 2020-03-23 19:56:41.539962665 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,2198 +0,0 @@ -/* - * Copyright (c) 2003, 2020, 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.generatebreakiteratordata; - -import java.io.*; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.Stack; -import java.util.Vector; -import java.util.zip.CRC32; -import sun.text.CompactByteArray; - -/** - * This class has the job of constructing a RuleBasedBreakIterator from a - * textual description. A Builder is constructed by GenerateBreakIteratorData, - * which uses it to construct the iterator itself and then throws it away. - *

The construction logic is separated out into its own class for two primary - * reasons: - *

    - *
  • The construction logic is quite sophisticated and large. Separating - * it out into its own class means the code must only be loaded into memory - * while a RuleBasedBreakIterator is being constructed, and can be purged after - * that. - *
  • There is a fair amount of state that must be maintained throughout the - * construction process that is not needed by the iterator after construction. - * Separating this state out into another class prevents all of the functions - * that construct the iterator from having to have really long parameter lists, - * (hopefully) contributing to readability and maintainability. - *
- *

- * It'd be really nice if this could be an independent class rather than an - * inner class, because that would shorten the source file considerably, but - * making Builder an inner class of RuleBasedBreakIterator allows it direct - * access to RuleBasedBreakIterator's private members, which saves us from - * having to provide some kind of "back door" to the Builder class that could - * then also be used by other classes. - */ -class RuleBasedBreakIteratorBuilder { - - /** - * A token used as a character-category value to identify ignore characters - */ - protected static final byte IGNORE = -1; - - /** - * Tables that indexes from character values to character category numbers - */ - private CompactByteArray charCategoryTable = null; - private SupplementaryCharacterData supplementaryCharCategoryTable = null; - - /** - * The table of state transitions used for forward iteration - */ - private short[] stateTable = null; - - /** - * The table of state transitions used to sync up the iterator with the - * text in backwards and random-access iteration - */ - private short[] backwardsStateTable = null; - - /** - * A list of flags indicating which states in the state table are accepting - * ("end") states - */ - private boolean[] endStates = null; - - /** - * A list of flags indicating which states in the state table are - * lookahead states (states which turn lookahead on and off) - */ - private boolean[] lookaheadStates = null; - - /** - * A table for additional data. May be used by a subclass of - * RuleBasedBreakIterator. - */ - private byte[] additionalData = null; - - /** - * The number of character categories (and, thus, the number of columns in - * the state tables) - */ - private int numCategories; - - /** - * A temporary holding place used for calculating the character categories. - * This object contains CharSet objects. - */ - protected Vector categories = null; - - /** - * A table used to map parts of regexp text to lists of character - * categories, rather than having to figure them out from scratch each time - */ - protected Hashtable expressions = null; - - /** - * A temporary holding place for the list of ignore characters - */ - protected CharSet ignoreChars = null; - - /** - * A temporary holding place where the forward state table is built - */ - protected Vector tempStateTable = null; - - /** - * A list of all the states that have to be filled in with transitions to - * the next state that is created. Used when building the state table from - * the regular expressions. - */ - protected Vector decisionPointList = null; - - /** - * A stack for holding decision point lists. This is used to handle nested - * parentheses and braces in regexps. - */ - protected Stack> decisionPointStack = null; - - /** - * A list of states that loop back on themselves. Used to handle .*? - */ - protected Vector loopingStates = null; - - /** - * Looping states actually have to be backfilled later in the process - * than everything else. This is where a the list of states to backfill - * is accumulated. This is also used to handle .*? - */ - protected Vector statesToBackfill = null; - - /** - * A list mapping pairs of state numbers for states that are to be combined - * to the state number of the state representing their combination. Used - * in the process of making the state table deterministic to prevent - * infinite recursion. - */ - protected Vector mergeList = null; - - /** - * A flag that is used to indicate when the list of looping states can - * be reset. - */ - protected boolean clearLoopingStates = false; - - /** - * A bit mask used to indicate a bit in the table's flags column that marks - * a state as an accepting state. - */ - protected static final int END_STATE_FLAG = 0x8000; - - /** - * A bit mask used to indicate a bit in the table's flags column that marks - * a state as one the builder shouldn't loop to any looping states - */ - protected static final int DONT_LOOP_FLAG = 0x4000; - - /** - * A bit mask used to indicate a bit in the table's flags column that marks - * a state as a lookahead state. - */ - protected static final int LOOKAHEAD_STATE_FLAG = 0x2000; - - /** - * A bit mask representing the union of the mask values listed above. - * Used for clearing or masking off the flag bits. - */ - protected static final int ALL_FLAGS = END_STATE_FLAG - | LOOKAHEAD_STATE_FLAG - | DONT_LOOP_FLAG; - - /** - * This is the main function for setting up the BreakIterator's tables. It - * just vectors different parts of the job off to other functions. - */ - public RuleBasedBreakIteratorBuilder(String description) { - Vector tempRuleList = buildRuleList(description); - buildCharCategories(tempRuleList); - buildStateTable(tempRuleList); - buildBackwardsStateTable(tempRuleList); - } - - /** - * Thus function has three main purposes: - *

  • Perform general syntax checking on the description, so the rest - * of the build code can assume that it's parsing a legal description. - *
  • Split the description into separate rules - *
  • Perform variable-name substitutions (so that no one else sees - * variable names) - *
- */ - private Vector buildRuleList(String description) { - // invariants: - // - parentheses must be balanced: ()[]{}<> - // - nothing can be nested inside <> - // - nothing can be nested inside [] except more []s - // - pairs of ()[]{}<> must not be empty - // - ; can only occur at the outer level - // - | can only appear inside () - // - only one = or / can occur in a single rule - // - = and / cannot both occur in the same rule - // - <> can only occur on the left side of a = expression - // (because we'll perform substitutions to eliminate them other places) - // - the left-hand side of a = expression can only be a single character - // (possibly with \) or text inside <> - // - the right-hand side of a = expression must be enclosed in [] or () - // - * may not occur at the beginning of a rule, nor may it follow - // =, /, (, (, |, }, ;, or * - // - ? may only follow * - // - the rule list must contain at least one / rule - // - no rule may be empty - // - all printing characters in the ASCII range except letters and digits - // are reserved and must be preceded by \ - // - ! may only occur at the beginning of a rule - - // set up a vector to contain the broken-up description (each entry in the - // vector is a separate rule) and a stack for keeping track of opening - // punctuation - Vector tempRuleList = new Vector<>(); - Stack parenStack = new Stack<>(); - - int p = 0; - int ruleStart = 0; - int c = '\u0000'; - int lastC = '\u0000'; - int lastOpen = '\u0000'; - boolean haveEquals = false; - boolean havePipe = false; - boolean sawVarName = false; - final String charsThatCantPrecedeAsterisk = "=/{(|}*;\u0000"; - - // if the description doesn't end with a semicolon, tack a semicolon onto the end - if (description.length() != 0 && - description.codePointAt(description.length() - 1) != ';') { - description = description + ";"; - } - - // for each character, do... - while (p < description.length()) { - c = description.codePointAt(p); - - switch (c) { - // if the character is a backslash, skip the character that follows it - // (it'll get treated as a literal character) - case '\\': - ++p; - break; - - // if the character is opening punctuation, verify that no nesting - // rules are broken, and push the character onto the stack - case '{': - case '<': - case '[': - case '(': - if (lastOpen == '<') { - error("Can't nest brackets inside <>", p, description); - } - if (lastOpen == '[' && c != '[') { - error("Can't nest anything in [] but []", p, description); - } - - // if we see < anywhere except on the left-hand side of =, - // we must be seeing a variable name that was never defined - if (c == '<' && (haveEquals || havePipe)) { - error("Unknown variable name", p, description); - } - - lastOpen = c; - parenStack.push(Character.valueOf((char)c)); - if (c == '<') { - sawVarName = true; - } - break; - - // if the character is closing punctuation, verify that it matches the - // last opening punctuation we saw, and that the brackets contain - // something, then pop the stack - case '}': - case '>': - case ']': - case ')': - char expectedClose = '\u0000'; - switch (lastOpen) { - case '{': - expectedClose = '}'; - break; - case '[': - expectedClose = ']'; - break; - case '(': - expectedClose = ')'; - break; - case '<': - expectedClose = '>'; - break; - } - if (c != expectedClose) { - error("Unbalanced parentheses", p, description); - } - if (lastC == lastOpen) { - error("Parens don't contain anything", p, description); - } - parenStack.pop(); - if (!parenStack.empty()) { - lastOpen = parenStack.peek().charValue(); - } - else { - lastOpen = '\u0000'; - } - - break; - - // if the character is an asterisk, make sure it occurs in a place - // where an asterisk can legally go - case '*': - if (charsThatCantPrecedeAsterisk.indexOf(lastC) != -1) { - error("Misplaced asterisk", p, description); - } - break; - - // if the character is a question mark, make sure it follows an asterisk - case '?': - if (lastC != '*') { - error("Misplaced ?", p, description); - } - break; - - // if the character is an equals sign, make sure we haven't seen another - // equals sign or a slash yet - case '=': - if (haveEquals || havePipe) { - error("More than one = or / in rule", p, description); - } - haveEquals = true; - break; - - // if the character is a slash, make sure we haven't seen another slash - // or an equals sign yet - case '/': - if (haveEquals || havePipe) { - error("More than one = or / in rule", p, description); - } - if (sawVarName) { - error("Unknown variable name", p, description); - } - havePipe = true; - break; - - // if the character is an exclamation point, make sure it occurs only - // at the beginning of a rule - case '!': - if (lastC != ';' && lastC != '\u0000') { - error("! can only occur at the beginning of a rule", p, description); - } - break; - - // we don't have to do anything special on a period - case '.': - break; - - // if the character is a syntax character that can only occur - // inside [], make sure that it does in fact only occur inside []. - case '^': - case '-': - case ':': - if (lastOpen != '[' && lastOpen != '<') { - error("Illegal character", p, description); - } - break; - - // if the character is a semicolon, do the following... - case ';': - // make sure the rule contains something and that there are no - // unbalanced parentheses or brackets - if (lastC == ';' || lastC == '\u0000') { - error("Empty rule", p, description); - } - if (!parenStack.empty()) { - error("Unbalanced parenheses", p, description); - } - - if (parenStack.empty()) { - // if the rule contained an = sign, call processSubstitution() - // to replace the substitution name with the substitution text - // wherever it appears in the description - if (haveEquals) { - description = processSubstitution(description.substring(ruleStart, - p), description, p + 1); - } - else { - // otherwise, check to make sure the rule doesn't reference - // any undefined substitutions - if (sawVarName) { - error("Unknown variable name", p, description); - } - - // then add it to tempRuleList - tempRuleList.addElement(description.substring(ruleStart, p)); - } - - // and reset everything to process the next rule - ruleStart = p + 1; - haveEquals = havePipe = sawVarName = false; - } - break; - - // if the character is a vertical bar, check to make sure that it - // occurs inside a () expression and that the character that precedes - // it isn't also a vertical bar - case '|': - if (lastC == '|') { - error("Empty alternative", p, description); - } - if (parenStack.empty() || lastOpen != '(') { - error("Misplaced |", p, description); - } - break; - - // if the character is anything else (escaped characters are - // skipped and don't make it here), it's an error - default: - if (c >= ' ' && c < '\u007f' && !Character.isLetter((char)c) - && !Character.isDigit((char)c)) { - error("Illegal character", p, description); - } - if (c >= Character.MIN_SUPPLEMENTARY_CODE_POINT) { - ++p; - } - break; - } - lastC = c; - ++p; - } - if (tempRuleList.size() == 0) { - error("No valid rules in description", p, description); - } - return tempRuleList; - } - - /** - * This function performs variable-name substitutions. First it does syntax - * checking on the variable-name definition. If it's syntactically valid, it - * then goes through the remainder of the description and does a simple - * find-and-replace of the variable name with its text. (The variable text - * must be enclosed in either [] or () for this to work.) - */ - protected String processSubstitution(String substitutionRule, String description, - int startPos) { - // isolate out the text on either side of the equals sign - String replace; - String replaceWith; - int equalPos = substitutionRule.indexOf('='); - replace = substitutionRule.substring(0, equalPos); - replaceWith = substitutionRule.substring(equalPos + 1); - - // check to see whether the substitution name is something we've declared - // to be "special". For RuleBasedBreakIterator itself, this is "". - // This function takes care of any extra processing that has to be done - // with "special" substitution names. - handleSpecialSubstitution(replace, replaceWith, startPos, description); - - // perform various other syntax checks on the rule - if (replaceWith.length() == 0) { - error("Nothing on right-hand side of =", startPos, description); - } - if (replace.length() == 0) { - error("Nothing on left-hand side of =", startPos, description); - } - if (replace.length() == 2 && replace.charAt(0) != '\\') { - error("Illegal left-hand side for =", startPos, description); - } - if (replace.length() >= 3 && replace.charAt(0) != '<' && - replace.codePointBefore(equalPos) != '>') { - error("Illegal left-hand side for =", startPos, description); - } - if (!(replaceWith.charAt(0) == '[' && - replaceWith.charAt(replaceWith.length() - 1) == ']') && - !(replaceWith.charAt(0) == '(' && - replaceWith.charAt(replaceWith.length() - 1) == ')')) { - error("Illegal right-hand side for =", startPos, description); - } - - // now go through the rest of the description (which hasn't been broken up - // into separate rules yet) and replace every occurrence of the - // substitution name with the substitution body - StringBuffer result = new StringBuffer(); - result.append(description.substring(0, startPos)); - int lastPos = startPos; - int pos = description.indexOf(replace, startPos); - while (pos != -1) { - result.append(description.substring(lastPos, pos)); - result.append(replaceWith); - lastPos = pos + replace.length(); - pos = description.indexOf(replace, lastPos); - } - result.append(description.substring(lastPos)); - return result.toString(); - } - - /** - * This function defines a protocol for handling substitution names that - * are "special," i.e., that have some property beyond just being - * substitutions. At the RuleBasedBreakIterator level, we have one - * special substitution name, "". Subclasses can override this - * function to add more. Any special processing that has to go on beyond - * that which is done by the normal substitution-processing code is done - * here. - */ - protected void handleSpecialSubstitution(String replace, String replaceWith, - int startPos, String description) { - // if we get a definition for a substitution called "ignore", it defines - // the ignore characters for the iterator. Check to make sure the expression - // is a [] expression, and if it is, parse it and store the characters off - // to the side. - if (replace.equals("")) { - if (replaceWith.charAt(0) == '(') { - error("Ignore group can't be enclosed in (", startPos, description); - } - ignoreChars = CharSet.parseString(replaceWith); - } - } - - /** - * This function builds the character category table. On entry, - * tempRuleList is a vector of break rules that has had variable names substituted. - * On exit, the charCategoryTable data member has been initialized to hold the - * character category table, and tempRuleList's rules have been munged to contain - * character category numbers everywhere a literal character or a [] expression - * originally occurred. - */ - @SuppressWarnings("fallthrough") - protected void buildCharCategories(Vector tempRuleList) { - int bracketLevel = 0; - int p = 0; - int lineNum = 0; - - // build hash table of every literal character or [] expression in the rule list - // and use CharSet.parseString() to derive a CharSet object representing the - // characters each refers to - expressions = new Hashtable<>(); - while (lineNum < tempRuleList.size()) { - String line = tempRuleList.elementAt(lineNum); - p = 0; - while (p < line.length()) { - int c = line.codePointAt(p); - switch (c) { - // skip over all syntax characters except [ - case '{': case '}': case '(': case ')': case '*': case '.': - case '/': case '|': case ';': case '?': case '!': - break; - - // for [, find the matching ] (taking nested [] pairs into account) - // and add the whole expression to the expression list - case '[': - int q = p + 1; - ++bracketLevel; - while (q < line.length() && bracketLevel != 0) { - c = line.codePointAt(q); - switch (c) { - case '\\': - q++; - break; - case '[': - ++bracketLevel; - break; - case ']': - --bracketLevel; - break; - } - q = q + Character.charCount(c); - } - if (expressions.get(line.substring(p, q)) == null) { - expressions.put(line.substring(p, q), CharSet.parseString(line.substring(p, q))); - } - p = q - 1; - break; - - // for \ sequences, just move to the next character and treat - // it as a single character - case '\\': - ++p; - c = line.codePointAt(p); - // DON'T break; fall through into "default" clause - - // for an isolated single character, add it to the expression list - default: - expressions.put(line.substring(p, p + 1), CharSet.parseString(line.substring(p, p + 1))); - break; - } - p += Character.charCount(line.codePointAt(p)); - } - ++lineNum; - } - // dump CharSet's internal expression cache - CharSet.releaseExpressionCache(); - - // create the temporary category table (which is a vector of CharSet objects) - categories = new Vector<>(); - if (ignoreChars != null) { - categories.addElement(ignoreChars); - } - else { - categories.addElement(new CharSet()); - } - ignoreChars = null; - - // this is a hook to allow subclasses to add categories on their own - mungeExpressionList(expressions); - - // Derive the character categories. Go through the existing character categories - // looking for overlap. Any time there's overlap, we create a new character - // category for the characters that overlapped and remove them from their original - // category. At the end, any characters that are left in the expression haven't - // been mentioned in any category, so another new category is created for them. - // For example, if the first expression is [abc], then a, b, and c will be placed - // into a single character category. If the next expression is [bcd], we will first - // remove b and c from their existing category (leaving a behind), create a new - // category for b and c, and then create another new category for d (which hadn't - // been mentioned in the previous expression). - // At no time should a character ever occur in more than one character category. - - // for each expression in the expressions list, do... - for (Enumeration iter = expressions.elements(); iter.hasMoreElements(); ) { - // initialize the working char set to the chars in the current expression - CharSet e = (CharSet)iter.nextElement(); - - // for each category in the category list, do... - for (int j = categories.size() - 1; !e.empty() && j > 0; j--) { - - // if there's overlap between the current working set of chars - // and the current category... - CharSet that = categories.elementAt(j); - if (!that.intersection(e).empty()) { - - // add a new category for the characters that were in the - // current category but not in the working char set - CharSet temp = that.difference(e); - if (!temp.empty()) { - categories.addElement(temp); - } - - // remove those characters from the working char set and replace - // the current category with the characters that it did - // have in common with the current working char set - temp = e.intersection(that); - e = e.difference(that); - if (!temp.equals(that)) { - categories.setElementAt(temp, j); - } - } - } - - // if there are still characters left in the working char set, - // add a new category containing them - if (!e.empty()) { - categories.addElement(e); - } - } - - // we have the ignore characters stored in position 0. Make an extra pass through - // the character category list and remove anything from the ignore list that shows - // up in some other category - CharSet allChars = new CharSet(); - for (int i = 1; i < categories.size(); i++) { - allChars = allChars.union(categories.elementAt(i)); - } - CharSet ignoreChars = categories.elementAt(0); - ignoreChars = ignoreChars.difference(allChars); - categories.setElementAt(ignoreChars, 0); - - // now that we've derived the character categories, go back through the expression - // list and replace each CharSet object with a String that represents the - // character categories that expression refers to. The String is encoded: each - // character is a character category number (plus 0x100 to avoid confusing them - // with syntax characters in the rule grammar) - - for (Enumeration iter = expressions.keys(); iter.hasMoreElements(); ) { - String key = iter.nextElement(); - CharSet cs = (CharSet)expressions.get(key); - StringBuffer cats = new StringBuffer(); - - // for each category... - for (int j = 0; j < categories.size(); j++) { - - // if the current expression contains characters in that category... - CharSet temp = cs.intersection(categories.elementAt(j)); - if (!temp.empty()) { - - // then add the encoded category number to the String for this - // expression - cats.append((char)(0x100 + j)); - if (temp.equals(cs)) { - break; - } - } - } - - // once we've finished building the encoded String for this expression, - // replace the CharSet object with it - expressions.put(key, cats.toString()); - } - - // and finally, we turn the temporary category table into a permanent category - // table, which is a CompactByteArray. (we skip category 0, which by definition - // refers to all characters not mentioned specifically in the rules) - charCategoryTable = new CompactByteArray((byte)0); - supplementaryCharCategoryTable = new SupplementaryCharacterData((byte)0); - - // for each category... - for (int i = 0; i < categories.size(); i++) { - CharSet chars = categories.elementAt(i); - - // go through the character ranges in the category one by one... - Enumeration enum_ = chars.getChars(); - while (enum_.hasMoreElements()) { - int[] range = enum_.nextElement(); - - // and set the corresponding elements in the CompactArray accordingly - if (i != 0) { - if (range[0] < Character.MIN_SUPPLEMENTARY_CODE_POINT) { - if (range[1] < Character.MIN_SUPPLEMENTARY_CODE_POINT) { - charCategoryTable.setElementAt((char)range[0], (char)range[1], (byte)i); - } else { - charCategoryTable.setElementAt((char)range[0], (char)0xFFFF, (byte)i); - supplementaryCharCategoryTable.appendElement(Character.MIN_SUPPLEMENTARY_CODE_POINT, range[1], (byte)i); - } - } else { - supplementaryCharCategoryTable.appendElement(range[0], range[1], (byte)i); - } - } - - // (category 0 is special-- it's the hiding place for the ignore - // characters, whose real category number in the CompactArray is - // -1 [this is because category 0 contains all characters not - // specifically mentioned anywhere in the rules] ) - else { - if (range[0] < Character.MIN_SUPPLEMENTARY_CODE_POINT) { - if (range[1] < Character.MIN_SUPPLEMENTARY_CODE_POINT) { - charCategoryTable.setElementAt((char)range[0], (char)range[1], IGNORE); - } else { - charCategoryTable.setElementAt((char)range[0], (char)0xFFFF, IGNORE); - supplementaryCharCategoryTable.appendElement(Character.MIN_SUPPLEMENTARY_CODE_POINT, range[1], IGNORE); - } - } else { - supplementaryCharCategoryTable.appendElement(range[0], range[1], IGNORE); - } - } - } - } - - // once we've populated the CompactArray, compact it - charCategoryTable.compact(); - - // And, complete the category table for supplementary characters - supplementaryCharCategoryTable.complete(); - - // initialize numCategories - numCategories = categories.size(); - } - - protected void mungeExpressionList(Hashtable expressions) { - // empty in the parent class. This function provides a hook for subclasses - // to mess with the character category table. - } - - /** - * This is the function that builds the forward state table. Most of the real - * work is done in parseRule(), which is called once for each rule in the - * description. - */ - private void buildStateTable(Vector tempRuleList) { - // initialize our temporary state table, and fill it with two states: - // state 0 is a dummy state that allows state 1 to be the starting state - // and 0 to represent "stop". State 1 is added here to seed things - // before we start parsing - tempStateTable = new Vector<>(); - tempStateTable.addElement(new short[numCategories + 1]); - tempStateTable.addElement(new short[numCategories + 1]); - - // call parseRule() for every rule in the rule list (except those which - // start with !, which are actually backwards-iteration rules) - for (int i = 0; i < tempRuleList.size(); i++) { - String rule = tempRuleList.elementAt(i); - if (rule.charAt(0) != '!') { - parseRule(rule, true); - } - } - - // finally, use finishBuildingStateTable() to minimize the number of - // states in the table and perform some other cleanup work - finishBuildingStateTable(true); - } - - /** - * This is where most of the work really happens. This routine parses a single - * rule in the rule description, adding and modifying states in the state - * table according to the new expression. The state table is kept deterministic - * throughout the whole operation, although some ugly postprocessing is needed - * to handle the *? token. - */ - private void parseRule(String rule, boolean forward) { - // algorithm notes: - // - The basic idea here is to read successive character-category groups - // from the input string. For each group, you create a state and point - // the appropriate entries in the previous state to it. This produces a - // straight line from the start state to the end state. The {}, *, and (|) - // idioms produce branches in this straight line. These branches (states - // that can transition to more than one other state) are called "decision - // points." A list of decision points is kept. This contains a list of - // all states that can transition to the next state to be created. For a - // straight line progression, the only thing in the decision-point list is - // the current state. But if there's a branch, the decision-point list - // will contain all of the beginning points of the branch when the next - // state to be created represents the end point of the branch. A stack is - // used to save decision point lists in the presence of nested parentheses - // and the like. For example, when a { is encountered, the current decision - // point list is saved on the stack and restored when the corresponding } - // is encountered. This way, after the } is read, the decision point list - // will contain both the state right before the } _and_ the state before - // the whole {} expression. Both of these states can transition to the next - // state after the {} expression. - // - one complication arises when we have to stamp a transition value into - // an array cell that already contains one. The updateStateTable() and - // mergeStates() functions handle this case. Their basic approach is to - // create a new state that combines the two states that conflict and point - // at it when necessary. This happens recursively, so if the merged states - // also conflict, they're resolved in the same way, and so on. There are - // a number of tests aimed at preventing infinite recursion. - // - another complication arises with repeating characters. It's somewhat - // ambiguous whether the user wants a greedy or non-greedy match in these cases. - // (e.g., whether "[a-z]*abc" means the SHORTEST sequence of letters ending in - // "abc" or the LONGEST sequence of letters ending in "abc". We've adopted - // the *? to mean "shortest" and * by itself to mean "longest". (You get the - // same result with both if there's no overlap between the repeating character - // group and the group immediately following it.) Handling the *? token is - // rather complicated and involves keeping track of whether a state needs to - // be merged (as described above) or merely overwritten when you update one of - // its cells, and copying the contents of a state that loops with a *? token - // into some of the states that follow it after the rest of the table-building - // process is complete ("backfilling"). - // implementation notes: - // - This function assumes syntax checking has been performed on the input string - // prior to its being passed in here. It assumes that parentheses are - // balanced, all literal characters are enclosed in [] and turned into category - // numbers, that there are no illegal characters or character sequences, and so - // on. Violation of these invariants will lead to undefined behavior. - // - It'd probably be better to use linked lists rather than Vector and Stack - // to maintain the decision point list and stack. I went for simplicity in - // this initial implementation. If performance is critical enough, we can go - // back and fix this later. - // -There are a number of important limitations on the *? token. It does not work - // right when followed by a repeating character sequence (e.g., ".*?(abc)*") - // (although it does work right when followed by a single repeating character). - // It will not always work right when nested in parentheses or braces (although - // sometimes it will). It also will not work right if the group of repeating - // characters and the group of characters that follows overlap partially - // (e.g., "[a-g]*?[e-j]"). None of these capabilites was deemed necessary for - // describing breaking rules we know about, so we left them out for - // expeditiousness. - // - Rules such as "[a-z]*?abc;" will be treated the same as "[a-z]*?aa*bc;"-- - // that is, if the string ends in "aaaabc", the break will go before the first - // "a" rather than the last one. Both of these are limitations in the design - // of RuleBasedBreakIterator and not limitations of the rule parser. - - int p = 0; - int currentState = 1; // don't use state number 0; 0 means "stop" - int lastState = currentState; - String pendingChars = ""; - - decisionPointStack = new Stack<>(); - decisionPointList = new Vector<>(); - loopingStates = new Vector<>(); - statesToBackfill = new Vector<>(); - - short[] state; - boolean sawEarlyBreak = false; - - // if we're adding rules to the backward state table, mark the initial state - // as a looping state - if (!forward) { - loopingStates.addElement(Integer.valueOf(1)); - } - - // put the current state on the decision point list before we start - decisionPointList.addElement(Integer.valueOf(currentState)); // we want currentState to - // be 1 here... - currentState = tempStateTable.size() - 1; // but after that, we want it to be - // 1 less than the state number of the next state - while (p < rule.length()) { - int c = rule.codePointAt(p); - clearLoopingStates = false; - - // this section handles literal characters, escaped characters (which are - // effectively literal characters too), the . token, and [] expressions - if (c == '[' - || c == '\\' - || Character.isLetter(c) - || Character.isDigit(c) - || c < ' ' - || c == '.' - || c >= '\u007f') { - - // if we're not on a period, isolate the expression and look up - // the corresponding category list - if (c != '.') { - int q = p; - - // if we're on a backslash, the expression is the character - // after the backslash - if (c == '\\') { - q = p + 2; - ++p; - } - - // if we're on an opening bracket, scan to the closing bracket - // to isolate the expression - else if (c == '[') { - int bracketLevel = 1; - - q += Character.charCount(rule.codePointAt(q)); - while (bracketLevel > 0) { - c = rule.codePointAt(q); - if (c == '[') { - ++bracketLevel; - } - else if (c == ']') { - --bracketLevel; - } - else if (c == '\\') { - c = rule.codePointAt(++q); - } - q += Character.charCount(c); - } - } - - // otherwise, the expression is just the character itself - else { - q = p + Character.charCount(c); - } - - // look up the category list for the expression and store it - // in pendingChars - pendingChars = (String)expressions.get(rule.substring(p, q)); - - // advance the current position past the expression - p = q - Character.charCount(rule.codePointBefore(q)); - } - - // if the character we're on is a period, we end up down here - else { - int rowNum = decisionPointList.lastElement().intValue(); - state = tempStateTable.elementAt(rowNum); - - // if the period is followed by an asterisk, then just set the current - // state to loop back on itself - if (p + 1 < rule.length() && rule.charAt(p + 1) == '*' && state[0] != 0) { - decisionPointList.addElement(Integer.valueOf(state[0])); - pendingChars = ""; - ++p; - } - - // otherwise, fabricate a category list ("pendingChars") with - // every category in it - else { - StringBuffer temp = new StringBuffer(); - for (int i = 0; i < numCategories; i++) - temp.append((char)(i + 0x100)); - pendingChars = temp.toString(); - } - } - - // we'll end up in here for all expressions except for .*, which is - // special-cased above - if (pendingChars.length() != 0) { - - // if the expression is followed by an asterisk, then push a copy - // of the current desicion point list onto the stack (this is - // the same thing we do on an opening brace) - if (p + 1 < rule.length() && rule.charAt(p + 1) == '*') { - @SuppressWarnings("unchecked") - Vector clone = (Vector)decisionPointList.clone(); - decisionPointStack.push(clone); - } - - // create a new state, add it to the list of states to backfill - // if we have looping states to worry about, set its "don't make - // me an accepting state" flag if we've seen a slash, and add - // it to the end of the state table - int newState = tempStateTable.size(); - if (loopingStates.size() != 0) { - statesToBackfill.addElement(Integer.valueOf(newState)); - } - state = new short[numCategories + 1]; - if (sawEarlyBreak) { - state[numCategories] = DONT_LOOP_FLAG; - } - tempStateTable.addElement(state); - - // update everybody in the decision point list to point to - // the new state (this also performs all the reconciliation - // needed to make the table deterministic), then clear the - // decision point list - updateStateTable(decisionPointList, pendingChars, (short)newState); - decisionPointList.removeAllElements(); - - // add all states created since the last literal character we've - // seen to the decision point list - lastState = currentState; - do { - ++currentState; - decisionPointList.addElement(Integer.valueOf(currentState)); - } while (currentState + 1 < tempStateTable.size()); - } - } - - // a { marks the beginning of an optional run of characters. Push a - // copy of the current decision point list onto the stack. This saves - // it, preventing it from being affected by whatever's inside the parentheses. - // This decision point list is restored when a } is encountered. - else if (c == '{') { - @SuppressWarnings("unchecked") - Vector clone = (Vector)decisionPointList.clone(); - decisionPointStack.push(clone); - } - - // a } marks the end of an optional run of characters. Pop the last decision - // point list off the stack and merge it with the current decision point list. - // a * denotes a repeating character or group (* after () is handled separately - // below). In addition to restoring the decision point list, modify the - // current state to point to itself on the appropriate character categories. - else if (c == '}' || c == '*') { - // when there's a *, update the current state to loop back on itself - // on the character categories that caused us to enter this state - if (c == '*') { - for (int i = lastState + 1; i < tempStateTable.size(); i++) { - Vector temp = new Vector<>(); - temp.addElement(Integer.valueOf(i)); - updateStateTable(temp, pendingChars, (short)(lastState + 1)); - } - } - - // pop the top element off the decision point stack and merge - // it with the current decision point list (this causes the divergent - // paths through the state table to come together again on the next - // new state) - Vector temp = decisionPointStack.pop(); - for (int i = 0; i < decisionPointList.size(); i++) - temp.addElement(decisionPointList.elementAt(i)); - decisionPointList = temp; - } - - // a ? after a * modifies the behavior of * in cases where there is overlap - // between the set of characters that repeat and the characters which follow. - // Without the ?, all states following the repeating state, up to a state which - // is reached by a character that doesn't overlap, will loop back into the - // repeating state. With the ?, the mark states following the *? DON'T loop - // back into the repeating state. Thus, "[a-z]*xyz" will match the longest - // sequence of letters that ends in "xyz," while "[a-z]*? will match the - // _shortest_ sequence of letters that ends in "xyz". - // We use extra bookkeeping to achieve this effect, since everything else works - // according to the "longest possible match" principle. The basic principle - // is that transitions out of a looping state are written in over the looping - // value instead of being reconciled, and that we copy the contents of the - // looping state into empty cells of all non-terminal states that follow the - // looping state. - else if (c == '?') { - setLoopingStates(decisionPointList, decisionPointList); - } - - // a ( marks the beginning of a sequence of characters. Parentheses can either - // contain several alternative character sequences (i.e., "(ab|cd|ef)"), or - // they can contain a sequence of characters that can repeat (i.e., "(abc)*"). Thus, - // A () group can have multiple entry and exit points. To keep track of this, - // we reserve TWO spots on the decision-point stack. The top of the stack is - // the list of exit points, which becomes the current decision point list when - // the ) is reached. The next entry down is the decision point list at the - // beginning of the (), which becomes the current decision point list at every - // entry point. - // In addition to keeping track of the exit points and the active decision - // points before the ( (i.e., the places from which the () can be entered), - // we need to keep track of the entry points in case the expression loops - // (i.e., is followed by *). We do that by creating a dummy state in the - // state table and adding it to the decision point list (BEFORE it's duplicated - // on the stack). Nobody points to this state, so it'll get optimized out - // at the end. It exists only to hold the entry points in case the () - // expression loops. - else if (c == '(') { - - // add a new state to the state table to hold the entry points into - // the () expression - tempStateTable.addElement(new short[numCategories + 1]); - - // we have to adjust lastState and currentState to account for the - // new dummy state - lastState = currentState; - ++currentState; - - // add the current state to the decision point list (add it at the - // BEGINNING so we can find it later) - decisionPointList.insertElementAt(Integer.valueOf(currentState), 0); - - // finally, push a copy of the current decision point list onto the - // stack (this keeps track of the active decision point list before - // the () expression), followed by an empty decision point list - // (this will hold the exit points) - @SuppressWarnings("unchecked") - Vector clone = (Vector)decisionPointList.clone(); - decisionPointStack.push(clone); - decisionPointStack.push(new Vector()); - } - - // a | separates alternative character sequences in a () expression. When - // a | is encountered, we add the current decision point list to the exit-point - // list, and restore the decision point list to its state prior to the (. - else if (c == '|') { - - // pick out the top two decision point lists on the stack - Vector oneDown = decisionPointStack.pop(); - Vector twoDown = decisionPointStack.peek(); - decisionPointStack.push(oneDown); - - // append the current decision point list to the list below it - // on the stack (the list of exit points), and restore the - // current decision point list to its state before the () expression - for (int i = 0; i < decisionPointList.size(); i++) - oneDown.addElement(decisionPointList.elementAt(i)); - @SuppressWarnings("unchecked") - Vector clone = (Vector)twoDown.clone(); - decisionPointList = clone; - } - - // a ) marks the end of a sequence of characters. We do one of two things - // depending on whether the sequence repeats (i.e., whether the ) is followed - // by *): If the sequence doesn't repeat, then the exit-point list is merged - // with the current decision point list and the decision point list from before - // the () is thrown away. If the sequence does repeat, then we fish out the - // state we were in before the ( and copy all of its forward transitions - // (i.e., every transition added by the () expression) into every state in the - // exit-point list and the current decision point list. The current decision - // point list is then merged with both the exit-point list AND the saved version - // of the decision point list from before the (). Then we throw out the *. - else if (c == ')') { - - // pull the exit point list off the stack, merge it with the current - // decision point list, and make the merged version the current - // decision point list - Vector exitPoints = decisionPointStack.pop(); - for (int i = 0; i < decisionPointList.size(); i++) - exitPoints.addElement(decisionPointList.elementAt(i)); - decisionPointList = exitPoints; - - // if the ) isn't followed by a *, then all we have to do is throw - // away the other list on the decision point stack, and we're done - if (p + 1 >= rule.length() || rule.charAt(p + 1) != '*') { - decisionPointStack.pop(); - } - - // but if the sequence repeats, we have a lot more work to do... - else { - - // now exitPoints and decisionPointList have to point to equivalent - // vectors, but not the SAME vector - @SuppressWarnings("unchecked") - Vector clone = (Vector)decisionPointList.clone(); - exitPoints = clone; - - // pop the original decision point list off the stack - Vector temp = decisionPointStack.pop(); - - // we squirreled away the row number of our entry point list - // at the beginning of the original decision point list. Fish - // that state number out and retrieve the entry point list - int tempStateNum = temp.firstElement().intValue(); - short[] tempState = tempStateTable.elementAt(tempStateNum); - - // merge the original decision point list with the current - // decision point list - for (int i = 0; i < decisionPointList.size(); i++) - temp.addElement(decisionPointList.elementAt(i)); - decisionPointList = temp; - - // finally, copy every forward reference from the entry point - // list into every state in the new decision point list - for (int i = 0; i < tempState.length; i++) { - if (tempState[i] > tempStateNum) { - updateStateTable(exitPoints, - Character.valueOf((char)(i + 0x100)).toString(), - tempState[i]); - } - } - - // update lastState and currentState, and throw away the * - lastState = currentState; - currentState = tempStateTable.size() - 1; - ++p; - } - } - - // a / marks the position where the break is to go if the character sequence - // matches this rule. We update the flag word of every state on the decision - // point list to mark them as ending states, and take note of the fact that - // we've seen the slash - else if (c == '/') { - sawEarlyBreak = true; - for (int i = 0; i < decisionPointList.size(); i++) { - state = tempStateTable.elementAt(decisionPointList. - elementAt(i).intValue()); - state[numCategories] |= LOOKAHEAD_STATE_FLAG; - } - } - - // if we get here without executing any of the above clauses, we have a - // syntax error. However, for now we just ignore the offending character - // and move on - - // clearLoopingStates is a signal back from updateStateTable() that we've - // transitioned to a state that won't loop back to the current looping - // state. (In other words, we've gotten to a point where we can no longer - // go back into a *? we saw earlier.) Clear out the list of looping states - // and backfill any states that need to be backfilled. - if (clearLoopingStates) { - setLoopingStates(null, decisionPointList); - } - - // advance to the next character, now that we've processed the current - // character - p += Character.charCount(c); - } - - // this takes care of backfilling any states that still need to be backfilled - setLoopingStates(null, decisionPointList); - - // when we reach the end of the string, we do a postprocessing step to mark the - // end states. The decision point list contains every state that can transition - // to the end state-- that is, every state that is the last state in a sequence - // that matches the rule. All of these states are considered "mark states" - // or "accepting states"-- that is, states that cause the position returned from - // next() to be updated. A mark state represents a possible break position. - // This allows us to look ahead and remember how far the rule matched - // before following the new branch (see next() for more information). - // The temporary state table has an extra "flag column" at the end where this - // information is stored. We mark the end states by setting a flag in their - // flag column. - // Now if we saw the / in the rule, then everything after it is lookahead - // material and the break really goes where the slash is. In this case, - // we mark these states as BOTH accepting states and lookahead states. This - // signals that these states cause the break position to be updated to the - // position of the slash rather than the current break position. - for (int i = 0; i < decisionPointList.size(); i++) { - int rowNum = decisionPointList.elementAt(i).intValue(); - state = tempStateTable.elementAt(rowNum); - state[numCategories] |= END_STATE_FLAG; - if (sawEarlyBreak) { - state[numCategories] |= LOOKAHEAD_STATE_FLAG; - } - } - } - - - /** - * Update entries in the state table, and merge states when necessary to keep - * the table deterministic. - * @param rows The list of rows that need updating (the decision point list) - * @param pendingChars A character category list, encoded in a String. This is the - * list of the columns that need updating. - * @param newValue Update the cells specfied above to contain this value - */ - private void updateStateTable(Vector rows, - String pendingChars, - short newValue) { - // create a dummy state that has the specified row number (newValue) in - // the cells that need to be updated (those specified by pendingChars) - // and 0 in the other cells - short[] newValues = new short[numCategories + 1]; - for (int i = 0; i < pendingChars.length(); i++) - newValues[(int)(pendingChars.charAt(i)) - 0x100] = newValue; - - // go through the list of rows to update, and update them by calling - // mergeStates() to merge them the the dummy state we created - for (int i = 0; i < rows.size(); i++) { - mergeStates(rows.elementAt(i).intValue(), newValues, rows); - } - } - - /** - * The real work of making the state table deterministic happens here. This function - * merges a state in the state table (specified by rowNum) with a state that is - * passed in (newValues). The basic process is to copy the nonzero cells in newStates - * into the state in the state table (we'll call that oldValues). If there's a - * collision (i.e., if the same cell has a nonzero value in both states, and it's - * not the SAME value), then we have to reconcile the collision. We do this by - * creating a new state, adding it to the end of the state table, and using this - * function recursively to merge the original two states into a single, combined - * state. This process may happen recursively (i.e., each successive level may - * involve collisions). To prevent infinite recursion, we keep a log of merge - * operations. Any time we're merging two states we've merged before, we can just - * supply the row number for the result of that merge operation rather than creating - * a new state just like it. - * @param rowNum The row number in the state table of the state to be updated - * @param newValues The state to merge it with. - * @param rowsBeingUpdated A copy of the list of rows passed to updateStateTable() - * (itself a copy of the decision point list from parseRule()). Newly-created - * states get added to the decision point list if their "parents" were on it. - */ - private void mergeStates(int rowNum, - short[] newValues, - Vector rowsBeingUpdated) { - short[] oldValues = tempStateTable.elementAt(rowNum); - boolean isLoopingState = loopingStates.contains(Integer.valueOf(rowNum)); - - // for each of the cells in the rows we're reconciling, do... - for (int i = 0; i < oldValues.length; i++) { - - // if they contain the same value, we don't have to do anything - if (oldValues[i] == newValues[i]) { - continue; - } - - // if oldValues is a looping state and the state the current cell points to - // is too, then we can just stomp over the current value of that cell (and - // set the clear-looping-states flag if necessary) - else if (isLoopingState && loopingStates.contains(Integer.valueOf(oldValues[i]))) { - if (newValues[i] != 0) { - if (oldValues[i] == 0) { - clearLoopingStates = true; - } - oldValues[i] = newValues[i]; - } - } - - // if the current cell in oldValues is 0, copy in the corresponding value - // from newValues - else if (oldValues[i] == 0) { - oldValues[i] = newValues[i]; - } - - // the last column of each row is the flag column. Take care to merge the - // flag words correctly - else if (i == numCategories) { - oldValues[i] = (short)((newValues[i] & ALL_FLAGS) | oldValues[i]); - } - - // if both newValues and oldValues have a nonzero value in the current - // cell, and it isn't the same value both places... - else if (oldValues[i] != 0 && newValues[i] != 0) { - - // look up this pair of cell values in the merge list. If it's - // found, update the cell in oldValues to point to the merged state - int combinedRowNum = searchMergeList(oldValues[i], newValues[i]); - if (combinedRowNum != 0) { - oldValues[i] = (short)combinedRowNum; - } - - // otherwise, we have to reconcile them... - else { - // copy our row numbers into variables to make things easier - int oldRowNum = oldValues[i]; - int newRowNum = newValues[i]; - combinedRowNum = tempStateTable.size(); - - // add this pair of row numbers to the merge list (create it first - // if we haven't created the merge list yet) - if (mergeList == null) { - mergeList = new Vector<>(); - } - mergeList.addElement(new int[] { oldRowNum, newRowNum, combinedRowNum }); - - // create a new row to represent the merged state, and copy the - // contents of oldRow into it, then add it to the end of the - // state table and update the original row (oldValues) to point - // to the new, merged, state - short[] newRow = new short[numCategories + 1]; - short[] oldRow = tempStateTable.elementAt(oldRowNum); - System.arraycopy(oldRow, 0, newRow, 0, numCategories + 1); - tempStateTable.addElement(newRow); - oldValues[i] = (short)combinedRowNum; - - // if the decision point list contains either of the parent rows, - // update it to include the new row as well - if ((decisionPointList.contains(Integer.valueOf(oldRowNum)) - || decisionPointList.contains(Integer.valueOf(newRowNum))) - && !decisionPointList.contains(Integer.valueOf(combinedRowNum)) - ) { - decisionPointList.addElement(Integer.valueOf(combinedRowNum)); - } - - // do the same thing with the list of rows being updated - if ((rowsBeingUpdated.contains(Integer.valueOf(oldRowNum)) - || rowsBeingUpdated.contains(Integer.valueOf(newRowNum))) - && !rowsBeingUpdated.contains(Integer.valueOf(combinedRowNum)) - ) { - decisionPointList.addElement(Integer.valueOf(combinedRowNum)); - } - // now (groan) do the same thing for all the entries on the - // decision point stack - for (int k = 0; k < decisionPointStack.size(); k++) { - Vector dpl = decisionPointStack.elementAt(k); - if ((dpl.contains(Integer.valueOf(oldRowNum)) - || dpl.contains(Integer.valueOf(newRowNum))) - && !dpl.contains(Integer.valueOf(combinedRowNum)) - ) { - dpl.addElement(Integer.valueOf(combinedRowNum)); - } - } - - // FINALLY (puff puff puff), call mergeStates() recursively to copy - // the row referred to by newValues into the new row and resolve any - // conflicts that come up at that level - mergeStates(combinedRowNum, tempStateTable.elementAt( - newValues[i]), rowsBeingUpdated); - } - } - } - return; - } - - /** - * The merge list is a list of pairs of rows that have been merged somewhere in - * the process of building this state table, along with the row number of the - * row containing the merged state. This function looks up a pair of row numbers - * and returns the row number of the row they combine into. (It returns 0 if - * this pair of rows isn't in the merge list.) - */ - private int searchMergeList(int a, int b) { - // if there is no merge list, there obviously isn't anything in it - if (mergeList == null) { - return 0; - } - - // otherwise, for each element in the merge list... - else { - int[] entry; - for (int i = 0; i < mergeList.size(); i++) { - entry = mergeList.elementAt(i); - - // we have a hit if the two row numbers match the two row numbers - // in the beginning of the entry (the two that combine), in either - // order - if ((entry[0] == a && entry[1] == b) || (entry[0] == b && entry[1] == a)) { - return entry[2]; - } - - // we also have a hit if one of the two row numbers matches the marged - // row number and the other one matches one of the original row numbers - if ((entry[2] == a && (entry[0] == b || entry[1] == b))) { - return entry[2]; - } - if ((entry[2] == b && (entry[0] == a || entry[1] == a))) { - return entry[2]; - } - } - return 0; - } - } - - /** - * This function is used to update the list of current loooping states (i.e., - * states that are controlled by a *? construct). It backfills values from - * the looping states into unpopulated cells of the states that are currently - * marked for backfilling, and then updates the list of looping states to be - * the new list - * @param newLoopingStates The list of new looping states - * @param endStates The list of states to treat as end states (states that - * can exit the loop). - */ - private void setLoopingStates(Vector newLoopingStates, - Vector endStates) { - - // if the current list of looping states isn't empty, we have to backfill - // values from the looping states into the states that are waiting to be - // backfilled - if (!loopingStates.isEmpty()) { - int loopingState = loopingStates.lastElement().intValue(); - int rowNum; - - // don't backfill into an end state OR any state reachable from an end state - // (since the search for reachable states is recursive, it's split out into - // a separate function, eliminateBackfillStates(), below) - for (int i = 0; i < endStates.size(); i++) { - eliminateBackfillStates(endStates.elementAt(i).intValue()); - } - - // we DON'T actually backfill the states that need to be backfilled here. - // Instead, we MARK them for backfilling. The reason for this is that if - // there are multiple rules in the state-table description, the looping - // states may have some of their values changed by a succeeding rule, and - // this wouldn't be reflected in the backfilled states. We mark a state - // for backfilling by putting the row number of the state to copy from - // into the flag cell at the end of the row - for (int i = 0; i < statesToBackfill.size(); i++) { - rowNum = statesToBackfill.elementAt(i).intValue(); - short[] state = tempStateTable.elementAt(rowNum); - state[numCategories] = - (short)((state[numCategories] & ALL_FLAGS) | loopingState); - } - statesToBackfill.removeAllElements(); - loopingStates.removeAllElements(); - } - - if (newLoopingStates != null) { - @SuppressWarnings("unchecked") - Vector clone = (Vector)newLoopingStates.clone(); - loopingStates = clone; - } - } - - /** - * This removes "ending states" and states reachable from them from the - * list of states to backfill. - * @param The row number of the state to remove from the backfill list - */ - private void eliminateBackfillStates(int baseState) { - - // don't do anything unless this state is actually in the backfill list... - if (statesToBackfill.contains(Integer.valueOf(baseState))) { - - // if it is, take it out - statesToBackfill.removeElement(Integer.valueOf(baseState)); - - // then go through and recursively call this function for every - // state that the base state points to - short[] state = tempStateTable.elementAt(baseState); - for (int i = 0; i < numCategories; i++) { - if (state[i] != 0) { - eliminateBackfillStates(state[i]); - } - } - } - } - - /** - * This function completes the backfilling process by actually doing the - * backfilling on the states that are marked for it - */ - private void backfillLoopingStates() { - short[] state; - short[] loopingState = null; - int loopingStateRowNum = 0; - int fromState; - - // for each state in the state table... - for (int i = 0; i < tempStateTable.size(); i++) { - state = tempStateTable.elementAt(i); - - // check the state's flag word to see if it's marked for backfilling - // (it's marked for backfilling if any bits other than the two high-order - // bits are set-- if they are, then the flag word, minus the two high bits, - // is the row number to copy from) - fromState = state[numCategories] & ~ALL_FLAGS; - if (fromState > 0) { - - // load up the state to copy from (if we haven't already) - if (fromState != loopingStateRowNum) { - loopingStateRowNum = fromState; - loopingState = tempStateTable.elementAt(loopingStateRowNum); - } - - // clear out the backfill part of the flag word - state[numCategories] &= ALL_FLAGS; - - // then fill all zero cells in the current state with values - // from the corresponding cells of the fromState - for (int j = 0; j < state.length; j++) { - if (state[j] == 0) { - state[j] = loopingState[j]; - } - else if (state[j] == DONT_LOOP_FLAG) { - state[j] = 0; - } - } - } - } - } - - /** - * This function completes the state-table-building process by doing several - * postprocessing steps and copying everything into its final resting place - * in the iterator itself - * @param forward True if we're working on the forward state table - */ - private void finishBuildingStateTable(boolean forward) { - // start by backfilling the looping states - backfillLoopingStates(); - - int[] rowNumMap = new int[tempStateTable.size()]; - Stack rowsToFollow = new Stack<>(); - rowsToFollow.push(Integer.valueOf(1)); - rowNumMap[1] = 1; - - // determine which states are no longer reachable from the start state - // (the reachable states will have their row numbers in the row number - // map, and the nonreachable states will have zero in the row number map) - while (rowsToFollow.size() != 0) { - int rowNum = rowsToFollow.pop().intValue(); - short[] row = tempStateTable.elementAt(rowNum); - - for (int i = 0; i < numCategories; i++) { - if (row[i] != 0) { - if (rowNumMap[row[i]] == 0) { - rowNumMap[row[i]] = row[i]; - rowsToFollow.push(Integer.valueOf(row[i])); - } - } - } - } - - boolean madeChange; - int newRowNum; - - // algorithm for minimizing the number of states in the table adapted from - // Aho & Ullman, "Principles of Compiler Design" - // The basic idea here is to organize the states into classes. When we're done, - // all states in the same class can be considered identical and all but one eliminated. - - // initially assign states to classes based on the number of populated cells they - // contain (the class number is the number of populated cells) - int[] stateClasses = new int[tempStateTable.size()]; - int nextClass = numCategories + 1; - short[] state1, state2; - for (int i = 1; i < stateClasses.length; i++) { - if (rowNumMap[i] == 0) { - continue; - } - state1 = tempStateTable.elementAt(i); - for (int j = 0; j < numCategories; j++) { - if (state1[j] != 0) { - ++stateClasses[i]; - } - } - if (stateClasses[i] == 0) { - stateClasses[i] = nextClass; - } - } - ++nextClass; - - // then, for each class, elect the first member of that class as that class's - // "representative". For each member of the class, compare it to the "representative." - // If there's a column position where the state being tested transitions to a - // state in a DIFFERENT class from the class where the "representative" transitions, - // then move the state into a new class. Repeat this process until no new classes - // are created. - int currentClass; - int lastClass; - boolean split; - - do { - currentClass = 1; - lastClass = nextClass; - while (currentClass < nextClass) { - split = false; - state1 = state2 = null; - for (int i = 0; i < stateClasses.length; i++) { - if (stateClasses[i] == currentClass) { - if (state1 == null) { - state1 = tempStateTable.elementAt(i); - } - else { - state2 = tempStateTable.elementAt(i); - for (int j = 0; j < state2.length; j++) { - if ((j == numCategories && state1[j] != state2[j] && forward) - || (j != numCategories && stateClasses[state1[j]] - != stateClasses[state2[j]])) { - stateClasses[i] = nextClass; - split = true; - break; - } - } - } - } - } - if (split) { - ++nextClass; - } - ++currentClass; - } - } while (lastClass != nextClass); - - // at this point, all of the states in a class except the first one (the - //"representative") can be eliminated, so update the row-number map accordingly - int[] representatives = new int[nextClass]; - for (int i = 1; i < stateClasses.length; i++) - if (representatives[stateClasses[i]] == 0) { - representatives[stateClasses[i]] = i; - } - else { - rowNumMap[i] = representatives[stateClasses[i]]; - } - - // renumber all remaining rows... - // first drop all that are either unreferenced or not a class representative - for (int i = 1; i < rowNumMap.length; i++) { - if (rowNumMap[i] != i) { - tempStateTable.setElementAt(null, i); - } - } - - // then calculate everybody's new row number and update the row - // number map appropriately (the first pass updates the row numbers - // of all the class representatives [the rows we're keeping], and the - // second pass updates the cross references for all the rows that - // are being deleted) - newRowNum = 1; - for (int i = 1; i < rowNumMap.length; i++) { - if (tempStateTable.elementAt(i) != null) { - rowNumMap[i] = newRowNum++; - } - } - for (int i = 1; i < rowNumMap.length; i++) { - if (tempStateTable.elementAt(i) == null) { - rowNumMap[i] = rowNumMap[rowNumMap[i]]; - } - } - - // allocate the permanent state table, and copy the remaining rows into it - // (adjusting all the cell values, of course) - - // this section does that for the forward state table - if (forward) { - endStates = new boolean[newRowNum]; - lookaheadStates = new boolean[newRowNum]; - stateTable = new short[newRowNum * numCategories]; - int p = 0; - int p2 = 0; - for (int i = 0; i < tempStateTable.size(); i++) { - short[] row = tempStateTable.elementAt(i); - if (row == null) { - continue; - } - for (int j = 0; j < numCategories; j++) { - stateTable[p] = (short)(rowNumMap[row[j]]); - ++p; - } - endStates[p2] = ((row[numCategories] & END_STATE_FLAG) != 0); - lookaheadStates[p2] = ((row[numCategories] & LOOKAHEAD_STATE_FLAG) != 0); - ++p2; - } - } - - // and this section does it for the backward state table - else { - backwardsStateTable = new short[newRowNum * numCategories]; - int p = 0; - for (int i = 0; i < tempStateTable.size(); i++) { - short[] row = tempStateTable.elementAt(i); - if (row == null) { - continue; - } - for (int j = 0; j < numCategories; j++) { - backwardsStateTable[p] = (short)(rowNumMap[row[j]]); - ++p; - } - } - } - } - - /** - * This function builds the backward state table from the forward state - * table and any additional rules (identified by the ! on the front) - * supplied in the description - */ - private void buildBackwardsStateTable(Vector tempRuleList) { - - // create the temporary state table and seed it with two rows (row 0 - // isn't used for anything, and we have to create row 1 (the initial - // state) before we can do anything else - tempStateTable = new Vector<>(); - tempStateTable.addElement(new short[numCategories + 1]); - tempStateTable.addElement(new short[numCategories + 1]); - - // although the backwards state table is built automatically from the forward - // state table, there are some situations (the default sentence-break rules, - // for example) where this doesn't yield enough stop states, causing a dramatic - // drop in performance. To help with these cases, the user may supply - // supplemental rules that are added to the backward state table. These have - // the same syntax as the normal break rules, but begin with '!' to distinguish - // them from normal break rules - for (int i = 0; i < tempRuleList.size(); i++) { - String rule = tempRuleList.elementAt(i); - if (rule.charAt(0) == '!') { - parseRule(rule.substring(1), false); - } - } - backfillLoopingStates(); - - // Backwards iteration is qualitatively different from forwards iteration. - // This is because backwards iteration has to be made to operate from no context - // at all-- the user should be able to ask BreakIterator for the break position - // immediately on either side of some arbitrary offset in the text. The - // forward iteration table doesn't let us do that-- it assumes complete - // information on the context, which means starting from the beginning of the - // document. - // The way we do backward and random-access iteration is to back up from the - // current (or user-specified) position until we see something we're sure is - // a break position (it may not be the last break position immediately - // preceding our starting point, however). Then we roll forward from there to - // locate the actual break position we're after. - // This means that the backwards state table doesn't have to identify every - // break position, allowing the building algorithm to be much simpler. Here, - // we use a "pairs" approach, scanning the forward-iteration state table for - // pairs of character categories we ALWAYS break between, and building a state - // table from that information. No context is required-- all this state table - // looks at is a pair of adjacent characters. - - // It's possible that the user has supplied supplementary rules (see above). - // This has to be done first to keep parseRule() and friends from becoming - // EVEN MORE complicated. The automatically-generated states are appended - // onto the end of the state table, and then the two sets of rules are - // stitched together at the end. Take note of the row number of the - // first row of the auromatically-generated part. - int backTableOffset = tempStateTable.size(); - if (backTableOffset > 2) { - ++backTableOffset; - } - - // the automatically-generated part of the table models a two-dimensional - // array where the two dimensions represent the two characters we're currently - // looking at. To model this as a state table, we actually need one additional - // row to represent the initial state. It gets populated with the row numbers - // of the other rows (in order). - for (int i = 0; i < numCategories + 1; i++) - tempStateTable.addElement(new short[numCategories + 1]); - - short[] state = tempStateTable.elementAt(backTableOffset - 1); - for (int i = 0; i < numCategories; i++) - state[i] = (short)(i + backTableOffset); - - // scavenge the forward state table for pairs of character categories - // that always have a break between them. The algorithm is as follows: - // Look down each column in the state table. For each nonzero cell in - // that column, look up the row it points to. For each nonzero cell in - // that row, populate a cell in the backwards state table: the row number - // of that cell is the number of the column we were scanning (plus the - // offset that locates this sub-table), and the column number of that cell - // is the column number of the nonzero cell we just found. This cell is - // populated with its own column number (adjusted according to the actual - // location of the sub-table). This process will produce a state table - // whose behavior is the same as looking up successive pairs of characters - // in an array of Booleans to determine whether there is a break. - int numRows = stateTable.length / numCategories; - for (int column = 0; column < numCategories; column++) { - for (int row = 0; row < numRows; row++) { - int nextRow = lookupState(row, column); - if (nextRow != 0) { - for (int nextColumn = 0; nextColumn < numCategories; nextColumn++) { - int cellValue = lookupState(nextRow, nextColumn); - if (cellValue != 0) { - state = tempStateTable.elementAt(nextColumn + - backTableOffset); - state[column] = (short)(column + backTableOffset); - } - } - } - } - } - - // if the user specified some backward-iteration rules with the ! token, - // we have to merge the resulting state table with the auto-generated one - // above. First copy the populated cells from row 1 over the populated - // cells in the auto-generated table. Then copy values from row 1 of the - // auto-generated table into all of the the unpopulated cells of the - // rule-based table. - if (backTableOffset > 1) { - - // for every row in the auto-generated sub-table, if a cell is - // populated that is also populated in row 1 of the rule-based - // sub-table, copy the value from row 1 over the value in the - // auto-generated sub-table - state = tempStateTable.elementAt(1); - for (int i = backTableOffset - 1; i < tempStateTable.size(); i++) { - short[] state2 = tempStateTable.elementAt(i); - for (int j = 0; j < numCategories; j++) { - if (state[j] != 0 && state2[j] != 0) { - state2[j] = state[j]; - } - } - } - - // now, for every row in the rule-based sub-table that is not - // an end state, fill in all unpopulated cells with the values - // of the corresponding cells in the first row of the auto- - // generated sub-table. - state = tempStateTable.elementAt(backTableOffset - 1); - for (int i = 1; i < backTableOffset - 1; i++) { - short[] state2 = tempStateTable.elementAt(i); - if ((state2[numCategories] & END_STATE_FLAG) == 0) { - for (int j = 0; j < numCategories; j++) { - if (state2[j] == 0) { - state2[j] = state[j]; - } - } - } - } - } - - // finally, clean everything up and copy it into the actual BreakIterator - // by calling finishBuildingStateTable() - finishBuildingStateTable(false); - } - - /** - * Given a current state and a character category, looks up the - * next state to transition to in the state table. - */ - protected int lookupState(int state, int category) { - return stateTable[state * numCategories + category]; - } - - /** - * Throws an IllegalArgumentException representing a syntax error in the rule - * description. The exception's message contains some debugging information. - * @param message A message describing the problem - * @param position The position in the description where the problem was - * discovered - * @param context The string containing the error - */ - protected void error(String message, int position, String context) { - throw new IllegalArgumentException("Parse error at position (" + position + "): " + message + "\n" + - context.substring(0, position) + " -here- " + context.substring(position)); - } - - void makeFile(String filename) { - writeTables(filename); - } - - /** - * Magic number for the BreakIterator data file format. - */ - private static final byte[] LABEL = { - (byte)'B', (byte)'I', (byte)'d', (byte)'a', (byte)'t', (byte)'a', - (byte)'\0' - }; - - /** - * Version number of the dictionary that was read in. - */ - private static final byte[] supportedVersion = { (byte)1 }; - - /** - * Header size in byte count - */ - private static final int HEADER_LENGTH = 36; - - /** - * Array length of indices for BMP characters - */ - private static final int BMP_INDICES_LENGTH = 512; - - /** - * Read datafile. The datafile's format is as follows: - *
-     *   BreakIteratorData {
-     *       u1           magic[7];
-     *       u1           version;
-     *       u4           totalDataSize;
-     *       header_info  header;
-     *       body         value;
-     *   }
-     * 
- * totalDataSize is the summation of the size of - * header_info and body in byte count. - *

- * In header, each field except for checksum implies the - * length of each field. Since BMPdataLength is a fixed-length - * data(512 entries), its length isn't included in header. - * checksum is a CRC32 value of all in body. - *

-     *   header_info {
-     *       u4           stateTableLength;
-     *       u4           backwardsStateTableLength;
-     *       u4           endStatesLength;
-     *       u4           lookaheadStatesLength;
-     *       u4           BMPdataLength;
-     *       u4           nonBMPdataLength;
-     *       u4           additionalDataLength;
-     *       u8           checksum;
-     *   }
-     * 
- *

- * - * Finally, BMPindices and BMPdata are set to - * charCategoryTable. nonBMPdata is set to - * supplementaryCharCategoryTable. - *

-     *   body {
-     *       u2           stateTable[stateTableLength];
-     *       u2           backwardsStateTable[backwardsStateTableLength];
-     *       u1           endStates[endStatesLength];
-     *       u1           lookaheadStates[lookaheadStatesLength];
-     *       u2           BMPindices[512];
-     *       u1           BMPdata[BMPdataLength];
-     *       u4           nonBMPdata[numNonBMPdataLength];
-     *       u1           additionalData[additionalDataLength];
-     *   }
-     * 
- */ - protected void writeTables(String datafile) { - final String filename; - final String outputDir; - String tmpbuf = GenerateBreakIteratorData.getOutputDirectory(); - - if (tmpbuf.equals("")) { - filename = datafile; - outputDir = ""; - } else { - char sep = File.separatorChar; - if (sep == '/') { - outputDir = tmpbuf; - } else if (sep == '\\') { - outputDir = tmpbuf.replaceAll("/", "\\\\"); - } else { - outputDir = tmpbuf.replaceAll("/", String.valueOf(sep)); - } - - filename = outputDir + sep + datafile; - } - - try { - if (!outputDir.equals("")) { - new File(outputDir).mkdirs(); - } - BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(filename)); - - byte[] BMPdata = charCategoryTable.getStringArray(); - short[] BMPindices = charCategoryTable.getIndexArray(); - int[] nonBMPdata = supplementaryCharCategoryTable.getArray(); - - if (BMPdata.length <= 0) { - throw new InternalError("Wrong BMP data length(" + BMPdata.length + ")"); - } - if (BMPindices.length != BMP_INDICES_LENGTH) { - throw new InternalError("Wrong BMP indices length(" + BMPindices.length + ")"); - } - if (nonBMPdata.length <= 0) { - throw new InternalError("Wrong non-BMP data length(" + nonBMPdata.length + ")"); - } - - int len; - - /* Compute checksum */ - CRC32 crc32 = new CRC32(); - len = stateTable.length; - for (int i = 0; i < len; i++) { - crc32.update(stateTable[i]); - } - len = backwardsStateTable.length; - for (int i = 0; i < len; i++) { - crc32.update(backwardsStateTable[i]); - } - crc32.update(toByteArray(endStates)); - crc32.update(toByteArray(lookaheadStates)); - for (int i = 0; i < BMP_INDICES_LENGTH; i++) { - crc32.update(BMPindices[i]); - } - crc32.update(BMPdata); - len = nonBMPdata.length; - for (int i = 0; i < len; i++) { - crc32.update(nonBMPdata[i]); - } - if (additionalData != null) { - len = additionalData.length; - for (int i = 0; i < len; i++) { - crc32.update(additionalData[i]); - } - } - - /* First, write magic, version, and totalDataSize. */ - len = HEADER_LENGTH + - (stateTable.length + backwardsStateTable.length) * 2 + - endStates.length + lookaheadStates.length + 1024 + - BMPdata.length + nonBMPdata.length * 4 + - ((additionalData == null) ? 0 : additionalData.length); - out.write(LABEL); - out.write(supportedVersion); - out.write(toByteArray(len)); - - /* Write header_info. */ - out.write(toByteArray(stateTable.length)); - out.write(toByteArray(backwardsStateTable.length)); - out.write(toByteArray(endStates.length)); - out.write(toByteArray(lookaheadStates.length)); - out.write(toByteArray(BMPdata.length)); - out.write(toByteArray(nonBMPdata.length)); - if (additionalData == null) { - out.write(toByteArray(0)); - } else { - out.write(toByteArray(additionalData.length)); - } - out.write(toByteArray(crc32.getValue())); - - /* Write stateTable[numCategories * numRows] */ - len = stateTable.length; - for (int i = 0; i < len; i++) { - out.write(toByteArray(stateTable[i])); - } - - /* Write backwardsStateTable[numCategories * numRows] */ - len = backwardsStateTable.length; - for (int i = 0; i < len; i++) { - out.write(toByteArray(backwardsStateTable[i])); - } - - /* Write endStates[numRows] */ - out.write(toByteArray(endStates)); - - /* Write lookaheadStates[numRows] */ - out.write(toByteArray(lookaheadStates)); - - for (int i = 0; i < BMP_INDICES_LENGTH; i++) { - out.write(toByteArray(BMPindices[i])); - } - BMPindices = null; - out.write(BMPdata); - BMPdata = null; - - /* Write a category table for non-BMP characters. */ - len = nonBMPdata.length; - for (int i = 0; i < len; i++) { - out.write(toByteArray(nonBMPdata[i])); - } - nonBMPdata = null; - - /* Write additional data */ - if (additionalData != null) { - out.write(additionalData); - } - - out.close(); - } - catch (Exception e) { - throw new InternalError(e.toString()); - } - } - - byte[] toByteArray(short val) { - byte[] buf = new byte[2]; - buf[0] = (byte)((val>>>8) & 0xFF); - buf[1] = (byte)(val & 0xFF); - return buf; - } - - byte[] toByteArray(int val) { - byte[] buf = new byte[4]; - buf[0] = (byte)((val>>>24) & 0xFF); - buf[1] = (byte)((val>>>16) & 0xFF); - buf[2] = (byte)((val>>>8) & 0xFF); - buf[3] = (byte)(val & 0xFF); - return buf; - } - - byte[] toByteArray(long val) { - byte[] buf = new byte[8]; - buf[0] = (byte)((val>>>56) & 0xff); - buf[1] = (byte)((val>>>48) & 0xff); - buf[2] = (byte)((val>>>40) & 0xff); - buf[3] = (byte)((val>>>32) & 0xff); - buf[4] = (byte)((val>>>24) & 0xff); - buf[5] = (byte)((val>>>16) & 0xff); - buf[6] = (byte)((val>>>8) & 0xff); - buf[7] = (byte)(val & 0xff); - return buf; - } - - byte[] toByteArray(boolean[] data) { - byte[] buf = new byte[data.length]; - for (int i = 0; i < data.length; i++) { - buf[i] = data[i] ? (byte)1 : (byte)0; - } - return buf; - } - - void setAdditionalData(byte[] data) { - additionalData = data; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.base/share/tools/org/openjdk/buildtools/generatebreakiteratordata/RuleBasedBreakIteratorBuilder.java 2020-03-23 19:56:41.123962669 +0100 @@ -0,0 +1,2198 @@ +/* + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatebreakiteratordata; + +import java.io.*; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Stack; +import java.util.Vector; +import java.util.zip.CRC32; +import sun.text.CompactByteArray; + +/** + * This class has the job of constructing a RuleBasedBreakIterator from a + * textual description. A Builder is constructed by GenerateBreakIteratorData, + * which uses it to construct the iterator itself and then throws it away. + *

The construction logic is separated out into its own class for two primary + * reasons: + *

    + *
  • The construction logic is quite sophisticated and large. Separating + * it out into its own class means the code must only be loaded into memory + * while a RuleBasedBreakIterator is being constructed, and can be purged after + * that. + *
  • There is a fair amount of state that must be maintained throughout the + * construction process that is not needed by the iterator after construction. + * Separating this state out into another class prevents all of the functions + * that construct the iterator from having to have really long parameter lists, + * (hopefully) contributing to readability and maintainability. + *
+ *

+ * It'd be really nice if this could be an independent class rather than an + * inner class, because that would shorten the source file considerably, but + * making Builder an inner class of RuleBasedBreakIterator allows it direct + * access to RuleBasedBreakIterator's private members, which saves us from + * having to provide some kind of "back door" to the Builder class that could + * then also be used by other classes. + */ +class RuleBasedBreakIteratorBuilder { + + /** + * A token used as a character-category value to identify ignore characters + */ + protected static final byte IGNORE = -1; + + /** + * Tables that indexes from character values to character category numbers + */ + private CompactByteArray charCategoryTable = null; + private SupplementaryCharacterData supplementaryCharCategoryTable = null; + + /** + * The table of state transitions used for forward iteration + */ + private short[] stateTable = null; + + /** + * The table of state transitions used to sync up the iterator with the + * text in backwards and random-access iteration + */ + private short[] backwardsStateTable = null; + + /** + * A list of flags indicating which states in the state table are accepting + * ("end") states + */ + private boolean[] endStates = null; + + /** + * A list of flags indicating which states in the state table are + * lookahead states (states which turn lookahead on and off) + */ + private boolean[] lookaheadStates = null; + + /** + * A table for additional data. May be used by a subclass of + * RuleBasedBreakIterator. + */ + private byte[] additionalData = null; + + /** + * The number of character categories (and, thus, the number of columns in + * the state tables) + */ + private int numCategories; + + /** + * A temporary holding place used for calculating the character categories. + * This object contains CharSet objects. + */ + protected Vector categories = null; + + /** + * A table used to map parts of regexp text to lists of character + * categories, rather than having to figure them out from scratch each time + */ + protected Hashtable expressions = null; + + /** + * A temporary holding place for the list of ignore characters + */ + protected CharSet ignoreChars = null; + + /** + * A temporary holding place where the forward state table is built + */ + protected Vector tempStateTable = null; + + /** + * A list of all the states that have to be filled in with transitions to + * the next state that is created. Used when building the state table from + * the regular expressions. + */ + protected Vector decisionPointList = null; + + /** + * A stack for holding decision point lists. This is used to handle nested + * parentheses and braces in regexps. + */ + protected Stack> decisionPointStack = null; + + /** + * A list of states that loop back on themselves. Used to handle .*? + */ + protected Vector loopingStates = null; + + /** + * Looping states actually have to be backfilled later in the process + * than everything else. This is where a the list of states to backfill + * is accumulated. This is also used to handle .*? + */ + protected Vector statesToBackfill = null; + + /** + * A list mapping pairs of state numbers for states that are to be combined + * to the state number of the state representing their combination. Used + * in the process of making the state table deterministic to prevent + * infinite recursion. + */ + protected Vector mergeList = null; + + /** + * A flag that is used to indicate when the list of looping states can + * be reset. + */ + protected boolean clearLoopingStates = false; + + /** + * A bit mask used to indicate a bit in the table's flags column that marks + * a state as an accepting state. + */ + protected static final int END_STATE_FLAG = 0x8000; + + /** + * A bit mask used to indicate a bit in the table's flags column that marks + * a state as one the builder shouldn't loop to any looping states + */ + protected static final int DONT_LOOP_FLAG = 0x4000; + + /** + * A bit mask used to indicate a bit in the table's flags column that marks + * a state as a lookahead state. + */ + protected static final int LOOKAHEAD_STATE_FLAG = 0x2000; + + /** + * A bit mask representing the union of the mask values listed above. + * Used for clearing or masking off the flag bits. + */ + protected static final int ALL_FLAGS = END_STATE_FLAG + | LOOKAHEAD_STATE_FLAG + | DONT_LOOP_FLAG; + + /** + * This is the main function for setting up the BreakIterator's tables. It + * just vectors different parts of the job off to other functions. + */ + public RuleBasedBreakIteratorBuilder(String description) { + Vector tempRuleList = buildRuleList(description); + buildCharCategories(tempRuleList); + buildStateTable(tempRuleList); + buildBackwardsStateTable(tempRuleList); + } + + /** + * Thus function has three main purposes: + *

  • Perform general syntax checking on the description, so the rest + * of the build code can assume that it's parsing a legal description. + *
  • Split the description into separate rules + *
  • Perform variable-name substitutions (so that no one else sees + * variable names) + *
+ */ + private Vector buildRuleList(String description) { + // invariants: + // - parentheses must be balanced: ()[]{}<> + // - nothing can be nested inside <> + // - nothing can be nested inside [] except more []s + // - pairs of ()[]{}<> must not be empty + // - ; can only occur at the outer level + // - | can only appear inside () + // - only one = or / can occur in a single rule + // - = and / cannot both occur in the same rule + // - <> can only occur on the left side of a = expression + // (because we'll perform substitutions to eliminate them other places) + // - the left-hand side of a = expression can only be a single character + // (possibly with \) or text inside <> + // - the right-hand side of a = expression must be enclosed in [] or () + // - * may not occur at the beginning of a rule, nor may it follow + // =, /, (, (, |, }, ;, or * + // - ? may only follow * + // - the rule list must contain at least one / rule + // - no rule may be empty + // - all printing characters in the ASCII range except letters and digits + // are reserved and must be preceded by \ + // - ! may only occur at the beginning of a rule + + // set up a vector to contain the broken-up description (each entry in the + // vector is a separate rule) and a stack for keeping track of opening + // punctuation + Vector tempRuleList = new Vector<>(); + Stack parenStack = new Stack<>(); + + int p = 0; + int ruleStart = 0; + int c = '\u0000'; + int lastC = '\u0000'; + int lastOpen = '\u0000'; + boolean haveEquals = false; + boolean havePipe = false; + boolean sawVarName = false; + final String charsThatCantPrecedeAsterisk = "=/{(|}*;\u0000"; + + // if the description doesn't end with a semicolon, tack a semicolon onto the end + if (description.length() != 0 && + description.codePointAt(description.length() - 1) != ';') { + description = description + ";"; + } + + // for each character, do... + while (p < description.length()) { + c = description.codePointAt(p); + + switch (c) { + // if the character is a backslash, skip the character that follows it + // (it'll get treated as a literal character) + case '\\': + ++p; + break; + + // if the character is opening punctuation, verify that no nesting + // rules are broken, and push the character onto the stack + case '{': + case '<': + case '[': + case '(': + if (lastOpen == '<') { + error("Can't nest brackets inside <>", p, description); + } + if (lastOpen == '[' && c != '[') { + error("Can't nest anything in [] but []", p, description); + } + + // if we see < anywhere except on the left-hand side of =, + // we must be seeing a variable name that was never defined + if (c == '<' && (haveEquals || havePipe)) { + error("Unknown variable name", p, description); + } + + lastOpen = c; + parenStack.push(Character.valueOf((char)c)); + if (c == '<') { + sawVarName = true; + } + break; + + // if the character is closing punctuation, verify that it matches the + // last opening punctuation we saw, and that the brackets contain + // something, then pop the stack + case '}': + case '>': + case ']': + case ')': + char expectedClose = '\u0000'; + switch (lastOpen) { + case '{': + expectedClose = '}'; + break; + case '[': + expectedClose = ']'; + break; + case '(': + expectedClose = ')'; + break; + case '<': + expectedClose = '>'; + break; + } + if (c != expectedClose) { + error("Unbalanced parentheses", p, description); + } + if (lastC == lastOpen) { + error("Parens don't contain anything", p, description); + } + parenStack.pop(); + if (!parenStack.empty()) { + lastOpen = parenStack.peek().charValue(); + } + else { + lastOpen = '\u0000'; + } + + break; + + // if the character is an asterisk, make sure it occurs in a place + // where an asterisk can legally go + case '*': + if (charsThatCantPrecedeAsterisk.indexOf(lastC) != -1) { + error("Misplaced asterisk", p, description); + } + break; + + // if the character is a question mark, make sure it follows an asterisk + case '?': + if (lastC != '*') { + error("Misplaced ?", p, description); + } + break; + + // if the character is an equals sign, make sure we haven't seen another + // equals sign or a slash yet + case '=': + if (haveEquals || havePipe) { + error("More than one = or / in rule", p, description); + } + haveEquals = true; + break; + + // if the character is a slash, make sure we haven't seen another slash + // or an equals sign yet + case '/': + if (haveEquals || havePipe) { + error("More than one = or / in rule", p, description); + } + if (sawVarName) { + error("Unknown variable name", p, description); + } + havePipe = true; + break; + + // if the character is an exclamation point, make sure it occurs only + // at the beginning of a rule + case '!': + if (lastC != ';' && lastC != '\u0000') { + error("! can only occur at the beginning of a rule", p, description); + } + break; + + // we don't have to do anything special on a period + case '.': + break; + + // if the character is a syntax character that can only occur + // inside [], make sure that it does in fact only occur inside []. + case '^': + case '-': + case ':': + if (lastOpen != '[' && lastOpen != '<') { + error("Illegal character", p, description); + } + break; + + // if the character is a semicolon, do the following... + case ';': + // make sure the rule contains something and that there are no + // unbalanced parentheses or brackets + if (lastC == ';' || lastC == '\u0000') { + error("Empty rule", p, description); + } + if (!parenStack.empty()) { + error("Unbalanced parenheses", p, description); + } + + if (parenStack.empty()) { + // if the rule contained an = sign, call processSubstitution() + // to replace the substitution name with the substitution text + // wherever it appears in the description + if (haveEquals) { + description = processSubstitution(description.substring(ruleStart, + p), description, p + 1); + } + else { + // otherwise, check to make sure the rule doesn't reference + // any undefined substitutions + if (sawVarName) { + error("Unknown variable name", p, description); + } + + // then add it to tempRuleList + tempRuleList.addElement(description.substring(ruleStart, p)); + } + + // and reset everything to process the next rule + ruleStart = p + 1; + haveEquals = havePipe = sawVarName = false; + } + break; + + // if the character is a vertical bar, check to make sure that it + // occurs inside a () expression and that the character that precedes + // it isn't also a vertical bar + case '|': + if (lastC == '|') { + error("Empty alternative", p, description); + } + if (parenStack.empty() || lastOpen != '(') { + error("Misplaced |", p, description); + } + break; + + // if the character is anything else (escaped characters are + // skipped and don't make it here), it's an error + default: + if (c >= ' ' && c < '\u007f' && !Character.isLetter((char)c) + && !Character.isDigit((char)c)) { + error("Illegal character", p, description); + } + if (c >= Character.MIN_SUPPLEMENTARY_CODE_POINT) { + ++p; + } + break; + } + lastC = c; + ++p; + } + if (tempRuleList.size() == 0) { + error("No valid rules in description", p, description); + } + return tempRuleList; + } + + /** + * This function performs variable-name substitutions. First it does syntax + * checking on the variable-name definition. If it's syntactically valid, it + * then goes through the remainder of the description and does a simple + * find-and-replace of the variable name with its text. (The variable text + * must be enclosed in either [] or () for this to work.) + */ + protected String processSubstitution(String substitutionRule, String description, + int startPos) { + // isolate out the text on either side of the equals sign + String replace; + String replaceWith; + int equalPos = substitutionRule.indexOf('='); + replace = substitutionRule.substring(0, equalPos); + replaceWith = substitutionRule.substring(equalPos + 1); + + // check to see whether the substitution name is something we've declared + // to be "special". For RuleBasedBreakIterator itself, this is "". + // This function takes care of any extra processing that has to be done + // with "special" substitution names. + handleSpecialSubstitution(replace, replaceWith, startPos, description); + + // perform various other syntax checks on the rule + if (replaceWith.length() == 0) { + error("Nothing on right-hand side of =", startPos, description); + } + if (replace.length() == 0) { + error("Nothing on left-hand side of =", startPos, description); + } + if (replace.length() == 2 && replace.charAt(0) != '\\') { + error("Illegal left-hand side for =", startPos, description); + } + if (replace.length() >= 3 && replace.charAt(0) != '<' && + replace.codePointBefore(equalPos) != '>') { + error("Illegal left-hand side for =", startPos, description); + } + if (!(replaceWith.charAt(0) == '[' && + replaceWith.charAt(replaceWith.length() - 1) == ']') && + !(replaceWith.charAt(0) == '(' && + replaceWith.charAt(replaceWith.length() - 1) == ')')) { + error("Illegal right-hand side for =", startPos, description); + } + + // now go through the rest of the description (which hasn't been broken up + // into separate rules yet) and replace every occurrence of the + // substitution name with the substitution body + StringBuffer result = new StringBuffer(); + result.append(description.substring(0, startPos)); + int lastPos = startPos; + int pos = description.indexOf(replace, startPos); + while (pos != -1) { + result.append(description.substring(lastPos, pos)); + result.append(replaceWith); + lastPos = pos + replace.length(); + pos = description.indexOf(replace, lastPos); + } + result.append(description.substring(lastPos)); + return result.toString(); + } + + /** + * This function defines a protocol for handling substitution names that + * are "special," i.e., that have some property beyond just being + * substitutions. At the RuleBasedBreakIterator level, we have one + * special substitution name, "". Subclasses can override this + * function to add more. Any special processing that has to go on beyond + * that which is done by the normal substitution-processing code is done + * here. + */ + protected void handleSpecialSubstitution(String replace, String replaceWith, + int startPos, String description) { + // if we get a definition for a substitution called "ignore", it defines + // the ignore characters for the iterator. Check to make sure the expression + // is a [] expression, and if it is, parse it and store the characters off + // to the side. + if (replace.equals("")) { + if (replaceWith.charAt(0) == '(') { + error("Ignore group can't be enclosed in (", startPos, description); + } + ignoreChars = CharSet.parseString(replaceWith); + } + } + + /** + * This function builds the character category table. On entry, + * tempRuleList is a vector of break rules that has had variable names substituted. + * On exit, the charCategoryTable data member has been initialized to hold the + * character category table, and tempRuleList's rules have been munged to contain + * character category numbers everywhere a literal character or a [] expression + * originally occurred. + */ + @SuppressWarnings("fallthrough") + protected void buildCharCategories(Vector tempRuleList) { + int bracketLevel = 0; + int p = 0; + int lineNum = 0; + + // build hash table of every literal character or [] expression in the rule list + // and use CharSet.parseString() to derive a CharSet object representing the + // characters each refers to + expressions = new Hashtable<>(); + while (lineNum < tempRuleList.size()) { + String line = tempRuleList.elementAt(lineNum); + p = 0; + while (p < line.length()) { + int c = line.codePointAt(p); + switch (c) { + // skip over all syntax characters except [ + case '{': case '}': case '(': case ')': case '*': case '.': + case '/': case '|': case ';': case '?': case '!': + break; + + // for [, find the matching ] (taking nested [] pairs into account) + // and add the whole expression to the expression list + case '[': + int q = p + 1; + ++bracketLevel; + while (q < line.length() && bracketLevel != 0) { + c = line.codePointAt(q); + switch (c) { + case '\\': + q++; + break; + case '[': + ++bracketLevel; + break; + case ']': + --bracketLevel; + break; + } + q = q + Character.charCount(c); + } + if (expressions.get(line.substring(p, q)) == null) { + expressions.put(line.substring(p, q), CharSet.parseString(line.substring(p, q))); + } + p = q - 1; + break; + + // for \ sequences, just move to the next character and treat + // it as a single character + case '\\': + ++p; + c = line.codePointAt(p); + // DON'T break; fall through into "default" clause + + // for an isolated single character, add it to the expression list + default: + expressions.put(line.substring(p, p + 1), CharSet.parseString(line.substring(p, p + 1))); + break; + } + p += Character.charCount(line.codePointAt(p)); + } + ++lineNum; + } + // dump CharSet's internal expression cache + CharSet.releaseExpressionCache(); + + // create the temporary category table (which is a vector of CharSet objects) + categories = new Vector<>(); + if (ignoreChars != null) { + categories.addElement(ignoreChars); + } + else { + categories.addElement(new CharSet()); + } + ignoreChars = null; + + // this is a hook to allow subclasses to add categories on their own + mungeExpressionList(expressions); + + // Derive the character categories. Go through the existing character categories + // looking for overlap. Any time there's overlap, we create a new character + // category for the characters that overlapped and remove them from their original + // category. At the end, any characters that are left in the expression haven't + // been mentioned in any category, so another new category is created for them. + // For example, if the first expression is [abc], then a, b, and c will be placed + // into a single character category. If the next expression is [bcd], we will first + // remove b and c from their existing category (leaving a behind), create a new + // category for b and c, and then create another new category for d (which hadn't + // been mentioned in the previous expression). + // At no time should a character ever occur in more than one character category. + + // for each expression in the expressions list, do... + for (Enumeration iter = expressions.elements(); iter.hasMoreElements(); ) { + // initialize the working char set to the chars in the current expression + CharSet e = (CharSet)iter.nextElement(); + + // for each category in the category list, do... + for (int j = categories.size() - 1; !e.empty() && j > 0; j--) { + + // if there's overlap between the current working set of chars + // and the current category... + CharSet that = categories.elementAt(j); + if (!that.intersection(e).empty()) { + + // add a new category for the characters that were in the + // current category but not in the working char set + CharSet temp = that.difference(e); + if (!temp.empty()) { + categories.addElement(temp); + } + + // remove those characters from the working char set and replace + // the current category with the characters that it did + // have in common with the current working char set + temp = e.intersection(that); + e = e.difference(that); + if (!temp.equals(that)) { + categories.setElementAt(temp, j); + } + } + } + + // if there are still characters left in the working char set, + // add a new category containing them + if (!e.empty()) { + categories.addElement(e); + } + } + + // we have the ignore characters stored in position 0. Make an extra pass through + // the character category list and remove anything from the ignore list that shows + // up in some other category + CharSet allChars = new CharSet(); + for (int i = 1; i < categories.size(); i++) { + allChars = allChars.union(categories.elementAt(i)); + } + CharSet ignoreChars = categories.elementAt(0); + ignoreChars = ignoreChars.difference(allChars); + categories.setElementAt(ignoreChars, 0); + + // now that we've derived the character categories, go back through the expression + // list and replace each CharSet object with a String that represents the + // character categories that expression refers to. The String is encoded: each + // character is a character category number (plus 0x100 to avoid confusing them + // with syntax characters in the rule grammar) + + for (Enumeration iter = expressions.keys(); iter.hasMoreElements(); ) { + String key = iter.nextElement(); + CharSet cs = (CharSet)expressions.get(key); + StringBuffer cats = new StringBuffer(); + + // for each category... + for (int j = 0; j < categories.size(); j++) { + + // if the current expression contains characters in that category... + CharSet temp = cs.intersection(categories.elementAt(j)); + if (!temp.empty()) { + + // then add the encoded category number to the String for this + // expression + cats.append((char)(0x100 + j)); + if (temp.equals(cs)) { + break; + } + } + } + + // once we've finished building the encoded String for this expression, + // replace the CharSet object with it + expressions.put(key, cats.toString()); + } + + // and finally, we turn the temporary category table into a permanent category + // table, which is a CompactByteArray. (we skip category 0, which by definition + // refers to all characters not mentioned specifically in the rules) + charCategoryTable = new CompactByteArray((byte)0); + supplementaryCharCategoryTable = new SupplementaryCharacterData((byte)0); + + // for each category... + for (int i = 0; i < categories.size(); i++) { + CharSet chars = categories.elementAt(i); + + // go through the character ranges in the category one by one... + Enumeration enum_ = chars.getChars(); + while (enum_.hasMoreElements()) { + int[] range = enum_.nextElement(); + + // and set the corresponding elements in the CompactArray accordingly + if (i != 0) { + if (range[0] < Character.MIN_SUPPLEMENTARY_CODE_POINT) { + if (range[1] < Character.MIN_SUPPLEMENTARY_CODE_POINT) { + charCategoryTable.setElementAt((char)range[0], (char)range[1], (byte)i); + } else { + charCategoryTable.setElementAt((char)range[0], (char)0xFFFF, (byte)i); + supplementaryCharCategoryTable.appendElement(Character.MIN_SUPPLEMENTARY_CODE_POINT, range[1], (byte)i); + } + } else { + supplementaryCharCategoryTable.appendElement(range[0], range[1], (byte)i); + } + } + + // (category 0 is special-- it's the hiding place for the ignore + // characters, whose real category number in the CompactArray is + // -1 [this is because category 0 contains all characters not + // specifically mentioned anywhere in the rules] ) + else { + if (range[0] < Character.MIN_SUPPLEMENTARY_CODE_POINT) { + if (range[1] < Character.MIN_SUPPLEMENTARY_CODE_POINT) { + charCategoryTable.setElementAt((char)range[0], (char)range[1], IGNORE); + } else { + charCategoryTable.setElementAt((char)range[0], (char)0xFFFF, IGNORE); + supplementaryCharCategoryTable.appendElement(Character.MIN_SUPPLEMENTARY_CODE_POINT, range[1], IGNORE); + } + } else { + supplementaryCharCategoryTable.appendElement(range[0], range[1], IGNORE); + } + } + } + } + + // once we've populated the CompactArray, compact it + charCategoryTable.compact(); + + // And, complete the category table for supplementary characters + supplementaryCharCategoryTable.complete(); + + // initialize numCategories + numCategories = categories.size(); + } + + protected void mungeExpressionList(Hashtable expressions) { + // empty in the parent class. This function provides a hook for subclasses + // to mess with the character category table. + } + + /** + * This is the function that builds the forward state table. Most of the real + * work is done in parseRule(), which is called once for each rule in the + * description. + */ + private void buildStateTable(Vector tempRuleList) { + // initialize our temporary state table, and fill it with two states: + // state 0 is a dummy state that allows state 1 to be the starting state + // and 0 to represent "stop". State 1 is added here to seed things + // before we start parsing + tempStateTable = new Vector<>(); + tempStateTable.addElement(new short[numCategories + 1]); + tempStateTable.addElement(new short[numCategories + 1]); + + // call parseRule() for every rule in the rule list (except those which + // start with !, which are actually backwards-iteration rules) + for (int i = 0; i < tempRuleList.size(); i++) { + String rule = tempRuleList.elementAt(i); + if (rule.charAt(0) != '!') { + parseRule(rule, true); + } + } + + // finally, use finishBuildingStateTable() to minimize the number of + // states in the table and perform some other cleanup work + finishBuildingStateTable(true); + } + + /** + * This is where most of the work really happens. This routine parses a single + * rule in the rule description, adding and modifying states in the state + * table according to the new expression. The state table is kept deterministic + * throughout the whole operation, although some ugly postprocessing is needed + * to handle the *? token. + */ + private void parseRule(String rule, boolean forward) { + // algorithm notes: + // - The basic idea here is to read successive character-category groups + // from the input string. For each group, you create a state and point + // the appropriate entries in the previous state to it. This produces a + // straight line from the start state to the end state. The {}, *, and (|) + // idioms produce branches in this straight line. These branches (states + // that can transition to more than one other state) are called "decision + // points." A list of decision points is kept. This contains a list of + // all states that can transition to the next state to be created. For a + // straight line progression, the only thing in the decision-point list is + // the current state. But if there's a branch, the decision-point list + // will contain all of the beginning points of the branch when the next + // state to be created represents the end point of the branch. A stack is + // used to save decision point lists in the presence of nested parentheses + // and the like. For example, when a { is encountered, the current decision + // point list is saved on the stack and restored when the corresponding } + // is encountered. This way, after the } is read, the decision point list + // will contain both the state right before the } _and_ the state before + // the whole {} expression. Both of these states can transition to the next + // state after the {} expression. + // - one complication arises when we have to stamp a transition value into + // an array cell that already contains one. The updateStateTable() and + // mergeStates() functions handle this case. Their basic approach is to + // create a new state that combines the two states that conflict and point + // at it when necessary. This happens recursively, so if the merged states + // also conflict, they're resolved in the same way, and so on. There are + // a number of tests aimed at preventing infinite recursion. + // - another complication arises with repeating characters. It's somewhat + // ambiguous whether the user wants a greedy or non-greedy match in these cases. + // (e.g., whether "[a-z]*abc" means the SHORTEST sequence of letters ending in + // "abc" or the LONGEST sequence of letters ending in "abc". We've adopted + // the *? to mean "shortest" and * by itself to mean "longest". (You get the + // same result with both if there's no overlap between the repeating character + // group and the group immediately following it.) Handling the *? token is + // rather complicated and involves keeping track of whether a state needs to + // be merged (as described above) or merely overwritten when you update one of + // its cells, and copying the contents of a state that loops with a *? token + // into some of the states that follow it after the rest of the table-building + // process is complete ("backfilling"). + // implementation notes: + // - This function assumes syntax checking has been performed on the input string + // prior to its being passed in here. It assumes that parentheses are + // balanced, all literal characters are enclosed in [] and turned into category + // numbers, that there are no illegal characters or character sequences, and so + // on. Violation of these invariants will lead to undefined behavior. + // - It'd probably be better to use linked lists rather than Vector and Stack + // to maintain the decision point list and stack. I went for simplicity in + // this initial implementation. If performance is critical enough, we can go + // back and fix this later. + // -There are a number of important limitations on the *? token. It does not work + // right when followed by a repeating character sequence (e.g., ".*?(abc)*") + // (although it does work right when followed by a single repeating character). + // It will not always work right when nested in parentheses or braces (although + // sometimes it will). It also will not work right if the group of repeating + // characters and the group of characters that follows overlap partially + // (e.g., "[a-g]*?[e-j]"). None of these capabilites was deemed necessary for + // describing breaking rules we know about, so we left them out for + // expeditiousness. + // - Rules such as "[a-z]*?abc;" will be treated the same as "[a-z]*?aa*bc;"-- + // that is, if the string ends in "aaaabc", the break will go before the first + // "a" rather than the last one. Both of these are limitations in the design + // of RuleBasedBreakIterator and not limitations of the rule parser. + + int p = 0; + int currentState = 1; // don't use state number 0; 0 means "stop" + int lastState = currentState; + String pendingChars = ""; + + decisionPointStack = new Stack<>(); + decisionPointList = new Vector<>(); + loopingStates = new Vector<>(); + statesToBackfill = new Vector<>(); + + short[] state; + boolean sawEarlyBreak = false; + + // if we're adding rules to the backward state table, mark the initial state + // as a looping state + if (!forward) { + loopingStates.addElement(Integer.valueOf(1)); + } + + // put the current state on the decision point list before we start + decisionPointList.addElement(Integer.valueOf(currentState)); // we want currentState to + // be 1 here... + currentState = tempStateTable.size() - 1; // but after that, we want it to be + // 1 less than the state number of the next state + while (p < rule.length()) { + int c = rule.codePointAt(p); + clearLoopingStates = false; + + // this section handles literal characters, escaped characters (which are + // effectively literal characters too), the . token, and [] expressions + if (c == '[' + || c == '\\' + || Character.isLetter(c) + || Character.isDigit(c) + || c < ' ' + || c == '.' + || c >= '\u007f') { + + // if we're not on a period, isolate the expression and look up + // the corresponding category list + if (c != '.') { + int q = p; + + // if we're on a backslash, the expression is the character + // after the backslash + if (c == '\\') { + q = p + 2; + ++p; + } + + // if we're on an opening bracket, scan to the closing bracket + // to isolate the expression + else if (c == '[') { + int bracketLevel = 1; + + q += Character.charCount(rule.codePointAt(q)); + while (bracketLevel > 0) { + c = rule.codePointAt(q); + if (c == '[') { + ++bracketLevel; + } + else if (c == ']') { + --bracketLevel; + } + else if (c == '\\') { + c = rule.codePointAt(++q); + } + q += Character.charCount(c); + } + } + + // otherwise, the expression is just the character itself + else { + q = p + Character.charCount(c); + } + + // look up the category list for the expression and store it + // in pendingChars + pendingChars = (String)expressions.get(rule.substring(p, q)); + + // advance the current position past the expression + p = q - Character.charCount(rule.codePointBefore(q)); + } + + // if the character we're on is a period, we end up down here + else { + int rowNum = decisionPointList.lastElement().intValue(); + state = tempStateTable.elementAt(rowNum); + + // if the period is followed by an asterisk, then just set the current + // state to loop back on itself + if (p + 1 < rule.length() && rule.charAt(p + 1) == '*' && state[0] != 0) { + decisionPointList.addElement(Integer.valueOf(state[0])); + pendingChars = ""; + ++p; + } + + // otherwise, fabricate a category list ("pendingChars") with + // every category in it + else { + StringBuffer temp = new StringBuffer(); + for (int i = 0; i < numCategories; i++) + temp.append((char)(i + 0x100)); + pendingChars = temp.toString(); + } + } + + // we'll end up in here for all expressions except for .*, which is + // special-cased above + if (pendingChars.length() != 0) { + + // if the expression is followed by an asterisk, then push a copy + // of the current desicion point list onto the stack (this is + // the same thing we do on an opening brace) + if (p + 1 < rule.length() && rule.charAt(p + 1) == '*') { + @SuppressWarnings("unchecked") + Vector clone = (Vector)decisionPointList.clone(); + decisionPointStack.push(clone); + } + + // create a new state, add it to the list of states to backfill + // if we have looping states to worry about, set its "don't make + // me an accepting state" flag if we've seen a slash, and add + // it to the end of the state table + int newState = tempStateTable.size(); + if (loopingStates.size() != 0) { + statesToBackfill.addElement(Integer.valueOf(newState)); + } + state = new short[numCategories + 1]; + if (sawEarlyBreak) { + state[numCategories] = DONT_LOOP_FLAG; + } + tempStateTable.addElement(state); + + // update everybody in the decision point list to point to + // the new state (this also performs all the reconciliation + // needed to make the table deterministic), then clear the + // decision point list + updateStateTable(decisionPointList, pendingChars, (short)newState); + decisionPointList.removeAllElements(); + + // add all states created since the last literal character we've + // seen to the decision point list + lastState = currentState; + do { + ++currentState; + decisionPointList.addElement(Integer.valueOf(currentState)); + } while (currentState + 1 < tempStateTable.size()); + } + } + + // a { marks the beginning of an optional run of characters. Push a + // copy of the current decision point list onto the stack. This saves + // it, preventing it from being affected by whatever's inside the parentheses. + // This decision point list is restored when a } is encountered. + else if (c == '{') { + @SuppressWarnings("unchecked") + Vector clone = (Vector)decisionPointList.clone(); + decisionPointStack.push(clone); + } + + // a } marks the end of an optional run of characters. Pop the last decision + // point list off the stack and merge it with the current decision point list. + // a * denotes a repeating character or group (* after () is handled separately + // below). In addition to restoring the decision point list, modify the + // current state to point to itself on the appropriate character categories. + else if (c == '}' || c == '*') { + // when there's a *, update the current state to loop back on itself + // on the character categories that caused us to enter this state + if (c == '*') { + for (int i = lastState + 1; i < tempStateTable.size(); i++) { + Vector temp = new Vector<>(); + temp.addElement(Integer.valueOf(i)); + updateStateTable(temp, pendingChars, (short)(lastState + 1)); + } + } + + // pop the top element off the decision point stack and merge + // it with the current decision point list (this causes the divergent + // paths through the state table to come together again on the next + // new state) + Vector temp = decisionPointStack.pop(); + for (int i = 0; i < decisionPointList.size(); i++) + temp.addElement(decisionPointList.elementAt(i)); + decisionPointList = temp; + } + + // a ? after a * modifies the behavior of * in cases where there is overlap + // between the set of characters that repeat and the characters which follow. + // Without the ?, all states following the repeating state, up to a state which + // is reached by a character that doesn't overlap, will loop back into the + // repeating state. With the ?, the mark states following the *? DON'T loop + // back into the repeating state. Thus, "[a-z]*xyz" will match the longest + // sequence of letters that ends in "xyz," while "[a-z]*? will match the + // _shortest_ sequence of letters that ends in "xyz". + // We use extra bookkeeping to achieve this effect, since everything else works + // according to the "longest possible match" principle. The basic principle + // is that transitions out of a looping state are written in over the looping + // value instead of being reconciled, and that we copy the contents of the + // looping state into empty cells of all non-terminal states that follow the + // looping state. + else if (c == '?') { + setLoopingStates(decisionPointList, decisionPointList); + } + + // a ( marks the beginning of a sequence of characters. Parentheses can either + // contain several alternative character sequences (i.e., "(ab|cd|ef)"), or + // they can contain a sequence of characters that can repeat (i.e., "(abc)*"). Thus, + // A () group can have multiple entry and exit points. To keep track of this, + // we reserve TWO spots on the decision-point stack. The top of the stack is + // the list of exit points, which becomes the current decision point list when + // the ) is reached. The next entry down is the decision point list at the + // beginning of the (), which becomes the current decision point list at every + // entry point. + // In addition to keeping track of the exit points and the active decision + // points before the ( (i.e., the places from which the () can be entered), + // we need to keep track of the entry points in case the expression loops + // (i.e., is followed by *). We do that by creating a dummy state in the + // state table and adding it to the decision point list (BEFORE it's duplicated + // on the stack). Nobody points to this state, so it'll get optimized out + // at the end. It exists only to hold the entry points in case the () + // expression loops. + else if (c == '(') { + + // add a new state to the state table to hold the entry points into + // the () expression + tempStateTable.addElement(new short[numCategories + 1]); + + // we have to adjust lastState and currentState to account for the + // new dummy state + lastState = currentState; + ++currentState; + + // add the current state to the decision point list (add it at the + // BEGINNING so we can find it later) + decisionPointList.insertElementAt(Integer.valueOf(currentState), 0); + + // finally, push a copy of the current decision point list onto the + // stack (this keeps track of the active decision point list before + // the () expression), followed by an empty decision point list + // (this will hold the exit points) + @SuppressWarnings("unchecked") + Vector clone = (Vector)decisionPointList.clone(); + decisionPointStack.push(clone); + decisionPointStack.push(new Vector()); + } + + // a | separates alternative character sequences in a () expression. When + // a | is encountered, we add the current decision point list to the exit-point + // list, and restore the decision point list to its state prior to the (. + else if (c == '|') { + + // pick out the top two decision point lists on the stack + Vector oneDown = decisionPointStack.pop(); + Vector twoDown = decisionPointStack.peek(); + decisionPointStack.push(oneDown); + + // append the current decision point list to the list below it + // on the stack (the list of exit points), and restore the + // current decision point list to its state before the () expression + for (int i = 0; i < decisionPointList.size(); i++) + oneDown.addElement(decisionPointList.elementAt(i)); + @SuppressWarnings("unchecked") + Vector clone = (Vector)twoDown.clone(); + decisionPointList = clone; + } + + // a ) marks the end of a sequence of characters. We do one of two things + // depending on whether the sequence repeats (i.e., whether the ) is followed + // by *): If the sequence doesn't repeat, then the exit-point list is merged + // with the current decision point list and the decision point list from before + // the () is thrown away. If the sequence does repeat, then we fish out the + // state we were in before the ( and copy all of its forward transitions + // (i.e., every transition added by the () expression) into every state in the + // exit-point list and the current decision point list. The current decision + // point list is then merged with both the exit-point list AND the saved version + // of the decision point list from before the (). Then we throw out the *. + else if (c == ')') { + + // pull the exit point list off the stack, merge it with the current + // decision point list, and make the merged version the current + // decision point list + Vector exitPoints = decisionPointStack.pop(); + for (int i = 0; i < decisionPointList.size(); i++) + exitPoints.addElement(decisionPointList.elementAt(i)); + decisionPointList = exitPoints; + + // if the ) isn't followed by a *, then all we have to do is throw + // away the other list on the decision point stack, and we're done + if (p + 1 >= rule.length() || rule.charAt(p + 1) != '*') { + decisionPointStack.pop(); + } + + // but if the sequence repeats, we have a lot more work to do... + else { + + // now exitPoints and decisionPointList have to point to equivalent + // vectors, but not the SAME vector + @SuppressWarnings("unchecked") + Vector clone = (Vector)decisionPointList.clone(); + exitPoints = clone; + + // pop the original decision point list off the stack + Vector temp = decisionPointStack.pop(); + + // we squirreled away the row number of our entry point list + // at the beginning of the original decision point list. Fish + // that state number out and retrieve the entry point list + int tempStateNum = temp.firstElement().intValue(); + short[] tempState = tempStateTable.elementAt(tempStateNum); + + // merge the original decision point list with the current + // decision point list + for (int i = 0; i < decisionPointList.size(); i++) + temp.addElement(decisionPointList.elementAt(i)); + decisionPointList = temp; + + // finally, copy every forward reference from the entry point + // list into every state in the new decision point list + for (int i = 0; i < tempState.length; i++) { + if (tempState[i] > tempStateNum) { + updateStateTable(exitPoints, + Character.valueOf((char)(i + 0x100)).toString(), + tempState[i]); + } + } + + // update lastState and currentState, and throw away the * + lastState = currentState; + currentState = tempStateTable.size() - 1; + ++p; + } + } + + // a / marks the position where the break is to go if the character sequence + // matches this rule. We update the flag word of every state on the decision + // point list to mark them as ending states, and take note of the fact that + // we've seen the slash + else if (c == '/') { + sawEarlyBreak = true; + for (int i = 0; i < decisionPointList.size(); i++) { + state = tempStateTable.elementAt(decisionPointList. + elementAt(i).intValue()); + state[numCategories] |= LOOKAHEAD_STATE_FLAG; + } + } + + // if we get here without executing any of the above clauses, we have a + // syntax error. However, for now we just ignore the offending character + // and move on + + // clearLoopingStates is a signal back from updateStateTable() that we've + // transitioned to a state that won't loop back to the current looping + // state. (In other words, we've gotten to a point where we can no longer + // go back into a *? we saw earlier.) Clear out the list of looping states + // and backfill any states that need to be backfilled. + if (clearLoopingStates) { + setLoopingStates(null, decisionPointList); + } + + // advance to the next character, now that we've processed the current + // character + p += Character.charCount(c); + } + + // this takes care of backfilling any states that still need to be backfilled + setLoopingStates(null, decisionPointList); + + // when we reach the end of the string, we do a postprocessing step to mark the + // end states. The decision point list contains every state that can transition + // to the end state-- that is, every state that is the last state in a sequence + // that matches the rule. All of these states are considered "mark states" + // or "accepting states"-- that is, states that cause the position returned from + // next() to be updated. A mark state represents a possible break position. + // This allows us to look ahead and remember how far the rule matched + // before following the new branch (see next() for more information). + // The temporary state table has an extra "flag column" at the end where this + // information is stored. We mark the end states by setting a flag in their + // flag column. + // Now if we saw the / in the rule, then everything after it is lookahead + // material and the break really goes where the slash is. In this case, + // we mark these states as BOTH accepting states and lookahead states. This + // signals that these states cause the break position to be updated to the + // position of the slash rather than the current break position. + for (int i = 0; i < decisionPointList.size(); i++) { + int rowNum = decisionPointList.elementAt(i).intValue(); + state = tempStateTable.elementAt(rowNum); + state[numCategories] |= END_STATE_FLAG; + if (sawEarlyBreak) { + state[numCategories] |= LOOKAHEAD_STATE_FLAG; + } + } + } + + + /** + * Update entries in the state table, and merge states when necessary to keep + * the table deterministic. + * @param rows The list of rows that need updating (the decision point list) + * @param pendingChars A character category list, encoded in a String. This is the + * list of the columns that need updating. + * @param newValue Update the cells specfied above to contain this value + */ + private void updateStateTable(Vector rows, + String pendingChars, + short newValue) { + // create a dummy state that has the specified row number (newValue) in + // the cells that need to be updated (those specified by pendingChars) + // and 0 in the other cells + short[] newValues = new short[numCategories + 1]; + for (int i = 0; i < pendingChars.length(); i++) + newValues[(int)(pendingChars.charAt(i)) - 0x100] = newValue; + + // go through the list of rows to update, and update them by calling + // mergeStates() to merge them the the dummy state we created + for (int i = 0; i < rows.size(); i++) { + mergeStates(rows.elementAt(i).intValue(), newValues, rows); + } + } + + /** + * The real work of making the state table deterministic happens here. This function + * merges a state in the state table (specified by rowNum) with a state that is + * passed in (newValues). The basic process is to copy the nonzero cells in newStates + * into the state in the state table (we'll call that oldValues). If there's a + * collision (i.e., if the same cell has a nonzero value in both states, and it's + * not the SAME value), then we have to reconcile the collision. We do this by + * creating a new state, adding it to the end of the state table, and using this + * function recursively to merge the original two states into a single, combined + * state. This process may happen recursively (i.e., each successive level may + * involve collisions). To prevent infinite recursion, we keep a log of merge + * operations. Any time we're merging two states we've merged before, we can just + * supply the row number for the result of that merge operation rather than creating + * a new state just like it. + * @param rowNum The row number in the state table of the state to be updated + * @param newValues The state to merge it with. + * @param rowsBeingUpdated A copy of the list of rows passed to updateStateTable() + * (itself a copy of the decision point list from parseRule()). Newly-created + * states get added to the decision point list if their "parents" were on it. + */ + private void mergeStates(int rowNum, + short[] newValues, + Vector rowsBeingUpdated) { + short[] oldValues = tempStateTable.elementAt(rowNum); + boolean isLoopingState = loopingStates.contains(Integer.valueOf(rowNum)); + + // for each of the cells in the rows we're reconciling, do... + for (int i = 0; i < oldValues.length; i++) { + + // if they contain the same value, we don't have to do anything + if (oldValues[i] == newValues[i]) { + continue; + } + + // if oldValues is a looping state and the state the current cell points to + // is too, then we can just stomp over the current value of that cell (and + // set the clear-looping-states flag if necessary) + else if (isLoopingState && loopingStates.contains(Integer.valueOf(oldValues[i]))) { + if (newValues[i] != 0) { + if (oldValues[i] == 0) { + clearLoopingStates = true; + } + oldValues[i] = newValues[i]; + } + } + + // if the current cell in oldValues is 0, copy in the corresponding value + // from newValues + else if (oldValues[i] == 0) { + oldValues[i] = newValues[i]; + } + + // the last column of each row is the flag column. Take care to merge the + // flag words correctly + else if (i == numCategories) { + oldValues[i] = (short)((newValues[i] & ALL_FLAGS) | oldValues[i]); + } + + // if both newValues and oldValues have a nonzero value in the current + // cell, and it isn't the same value both places... + else if (oldValues[i] != 0 && newValues[i] != 0) { + + // look up this pair of cell values in the merge list. If it's + // found, update the cell in oldValues to point to the merged state + int combinedRowNum = searchMergeList(oldValues[i], newValues[i]); + if (combinedRowNum != 0) { + oldValues[i] = (short)combinedRowNum; + } + + // otherwise, we have to reconcile them... + else { + // copy our row numbers into variables to make things easier + int oldRowNum = oldValues[i]; + int newRowNum = newValues[i]; + combinedRowNum = tempStateTable.size(); + + // add this pair of row numbers to the merge list (create it first + // if we haven't created the merge list yet) + if (mergeList == null) { + mergeList = new Vector<>(); + } + mergeList.addElement(new int[] { oldRowNum, newRowNum, combinedRowNum }); + + // create a new row to represent the merged state, and copy the + // contents of oldRow into it, then add it to the end of the + // state table and update the original row (oldValues) to point + // to the new, merged, state + short[] newRow = new short[numCategories + 1]; + short[] oldRow = tempStateTable.elementAt(oldRowNum); + System.arraycopy(oldRow, 0, newRow, 0, numCategories + 1); + tempStateTable.addElement(newRow); + oldValues[i] = (short)combinedRowNum; + + // if the decision point list contains either of the parent rows, + // update it to include the new row as well + if ((decisionPointList.contains(Integer.valueOf(oldRowNum)) + || decisionPointList.contains(Integer.valueOf(newRowNum))) + && !decisionPointList.contains(Integer.valueOf(combinedRowNum)) + ) { + decisionPointList.addElement(Integer.valueOf(combinedRowNum)); + } + + // do the same thing with the list of rows being updated + if ((rowsBeingUpdated.contains(Integer.valueOf(oldRowNum)) + || rowsBeingUpdated.contains(Integer.valueOf(newRowNum))) + && !rowsBeingUpdated.contains(Integer.valueOf(combinedRowNum)) + ) { + decisionPointList.addElement(Integer.valueOf(combinedRowNum)); + } + // now (groan) do the same thing for all the entries on the + // decision point stack + for (int k = 0; k < decisionPointStack.size(); k++) { + Vector dpl = decisionPointStack.elementAt(k); + if ((dpl.contains(Integer.valueOf(oldRowNum)) + || dpl.contains(Integer.valueOf(newRowNum))) + && !dpl.contains(Integer.valueOf(combinedRowNum)) + ) { + dpl.addElement(Integer.valueOf(combinedRowNum)); + } + } + + // FINALLY (puff puff puff), call mergeStates() recursively to copy + // the row referred to by newValues into the new row and resolve any + // conflicts that come up at that level + mergeStates(combinedRowNum, tempStateTable.elementAt( + newValues[i]), rowsBeingUpdated); + } + } + } + return; + } + + /** + * The merge list is a list of pairs of rows that have been merged somewhere in + * the process of building this state table, along with the row number of the + * row containing the merged state. This function looks up a pair of row numbers + * and returns the row number of the row they combine into. (It returns 0 if + * this pair of rows isn't in the merge list.) + */ + private int searchMergeList(int a, int b) { + // if there is no merge list, there obviously isn't anything in it + if (mergeList == null) { + return 0; + } + + // otherwise, for each element in the merge list... + else { + int[] entry; + for (int i = 0; i < mergeList.size(); i++) { + entry = mergeList.elementAt(i); + + // we have a hit if the two row numbers match the two row numbers + // in the beginning of the entry (the two that combine), in either + // order + if ((entry[0] == a && entry[1] == b) || (entry[0] == b && entry[1] == a)) { + return entry[2]; + } + + // we also have a hit if one of the two row numbers matches the marged + // row number and the other one matches one of the original row numbers + if ((entry[2] == a && (entry[0] == b || entry[1] == b))) { + return entry[2]; + } + if ((entry[2] == b && (entry[0] == a || entry[1] == a))) { + return entry[2]; + } + } + return 0; + } + } + + /** + * This function is used to update the list of current loooping states (i.e., + * states that are controlled by a *? construct). It backfills values from + * the looping states into unpopulated cells of the states that are currently + * marked for backfilling, and then updates the list of looping states to be + * the new list + * @param newLoopingStates The list of new looping states + * @param endStates The list of states to treat as end states (states that + * can exit the loop). + */ + private void setLoopingStates(Vector newLoopingStates, + Vector endStates) { + + // if the current list of looping states isn't empty, we have to backfill + // values from the looping states into the states that are waiting to be + // backfilled + if (!loopingStates.isEmpty()) { + int loopingState = loopingStates.lastElement().intValue(); + int rowNum; + + // don't backfill into an end state OR any state reachable from an end state + // (since the search for reachable states is recursive, it's split out into + // a separate function, eliminateBackfillStates(), below) + for (int i = 0; i < endStates.size(); i++) { + eliminateBackfillStates(endStates.elementAt(i).intValue()); + } + + // we DON'T actually backfill the states that need to be backfilled here. + // Instead, we MARK them for backfilling. The reason for this is that if + // there are multiple rules in the state-table description, the looping + // states may have some of their values changed by a succeeding rule, and + // this wouldn't be reflected in the backfilled states. We mark a state + // for backfilling by putting the row number of the state to copy from + // into the flag cell at the end of the row + for (int i = 0; i < statesToBackfill.size(); i++) { + rowNum = statesToBackfill.elementAt(i).intValue(); + short[] state = tempStateTable.elementAt(rowNum); + state[numCategories] = + (short)((state[numCategories] & ALL_FLAGS) | loopingState); + } + statesToBackfill.removeAllElements(); + loopingStates.removeAllElements(); + } + + if (newLoopingStates != null) { + @SuppressWarnings("unchecked") + Vector clone = (Vector)newLoopingStates.clone(); + loopingStates = clone; + } + } + + /** + * This removes "ending states" and states reachable from them from the + * list of states to backfill. + * @param The row number of the state to remove from the backfill list + */ + private void eliminateBackfillStates(int baseState) { + + // don't do anything unless this state is actually in the backfill list... + if (statesToBackfill.contains(Integer.valueOf(baseState))) { + + // if it is, take it out + statesToBackfill.removeElement(Integer.valueOf(baseState)); + + // then go through and recursively call this function for every + // state that the base state points to + short[] state = tempStateTable.elementAt(baseState); + for (int i = 0; i < numCategories; i++) { + if (state[i] != 0) { + eliminateBackfillStates(state[i]); + } + } + } + } + + /** + * This function completes the backfilling process by actually doing the + * backfilling on the states that are marked for it + */ + private void backfillLoopingStates() { + short[] state; + short[] loopingState = null; + int loopingStateRowNum = 0; + int fromState; + + // for each state in the state table... + for (int i = 0; i < tempStateTable.size(); i++) { + state = tempStateTable.elementAt(i); + + // check the state's flag word to see if it's marked for backfilling + // (it's marked for backfilling if any bits other than the two high-order + // bits are set-- if they are, then the flag word, minus the two high bits, + // is the row number to copy from) + fromState = state[numCategories] & ~ALL_FLAGS; + if (fromState > 0) { + + // load up the state to copy from (if we haven't already) + if (fromState != loopingStateRowNum) { + loopingStateRowNum = fromState; + loopingState = tempStateTable.elementAt(loopingStateRowNum); + } + + // clear out the backfill part of the flag word + state[numCategories] &= ALL_FLAGS; + + // then fill all zero cells in the current state with values + // from the corresponding cells of the fromState + for (int j = 0; j < state.length; j++) { + if (state[j] == 0) { + state[j] = loopingState[j]; + } + else if (state[j] == DONT_LOOP_FLAG) { + state[j] = 0; + } + } + } + } + } + + /** + * This function completes the state-table-building process by doing several + * postprocessing steps and copying everything into its final resting place + * in the iterator itself + * @param forward True if we're working on the forward state table + */ + private void finishBuildingStateTable(boolean forward) { + // start by backfilling the looping states + backfillLoopingStates(); + + int[] rowNumMap = new int[tempStateTable.size()]; + Stack rowsToFollow = new Stack<>(); + rowsToFollow.push(Integer.valueOf(1)); + rowNumMap[1] = 1; + + // determine which states are no longer reachable from the start state + // (the reachable states will have their row numbers in the row number + // map, and the nonreachable states will have zero in the row number map) + while (rowsToFollow.size() != 0) { + int rowNum = rowsToFollow.pop().intValue(); + short[] row = tempStateTable.elementAt(rowNum); + + for (int i = 0; i < numCategories; i++) { + if (row[i] != 0) { + if (rowNumMap[row[i]] == 0) { + rowNumMap[row[i]] = row[i]; + rowsToFollow.push(Integer.valueOf(row[i])); + } + } + } + } + + boolean madeChange; + int newRowNum; + + // algorithm for minimizing the number of states in the table adapted from + // Aho & Ullman, "Principles of Compiler Design" + // The basic idea here is to organize the states into classes. When we're done, + // all states in the same class can be considered identical and all but one eliminated. + + // initially assign states to classes based on the number of populated cells they + // contain (the class number is the number of populated cells) + int[] stateClasses = new int[tempStateTable.size()]; + int nextClass = numCategories + 1; + short[] state1, state2; + for (int i = 1; i < stateClasses.length; i++) { + if (rowNumMap[i] == 0) { + continue; + } + state1 = tempStateTable.elementAt(i); + for (int j = 0; j < numCategories; j++) { + if (state1[j] != 0) { + ++stateClasses[i]; + } + } + if (stateClasses[i] == 0) { + stateClasses[i] = nextClass; + } + } + ++nextClass; + + // then, for each class, elect the first member of that class as that class's + // "representative". For each member of the class, compare it to the "representative." + // If there's a column position where the state being tested transitions to a + // state in a DIFFERENT class from the class where the "representative" transitions, + // then move the state into a new class. Repeat this process until no new classes + // are created. + int currentClass; + int lastClass; + boolean split; + + do { + currentClass = 1; + lastClass = nextClass; + while (currentClass < nextClass) { + split = false; + state1 = state2 = null; + for (int i = 0; i < stateClasses.length; i++) { + if (stateClasses[i] == currentClass) { + if (state1 == null) { + state1 = tempStateTable.elementAt(i); + } + else { + state2 = tempStateTable.elementAt(i); + for (int j = 0; j < state2.length; j++) { + if ((j == numCategories && state1[j] != state2[j] && forward) + || (j != numCategories && stateClasses[state1[j]] + != stateClasses[state2[j]])) { + stateClasses[i] = nextClass; + split = true; + break; + } + } + } + } + } + if (split) { + ++nextClass; + } + ++currentClass; + } + } while (lastClass != nextClass); + + // at this point, all of the states in a class except the first one (the + //"representative") can be eliminated, so update the row-number map accordingly + int[] representatives = new int[nextClass]; + for (int i = 1; i < stateClasses.length; i++) + if (representatives[stateClasses[i]] == 0) { + representatives[stateClasses[i]] = i; + } + else { + rowNumMap[i] = representatives[stateClasses[i]]; + } + + // renumber all remaining rows... + // first drop all that are either unreferenced or not a class representative + for (int i = 1; i < rowNumMap.length; i++) { + if (rowNumMap[i] != i) { + tempStateTable.setElementAt(null, i); + } + } + + // then calculate everybody's new row number and update the row + // number map appropriately (the first pass updates the row numbers + // of all the class representatives [the rows we're keeping], and the + // second pass updates the cross references for all the rows that + // are being deleted) + newRowNum = 1; + for (int i = 1; i < rowNumMap.length; i++) { + if (tempStateTable.elementAt(i) != null) { + rowNumMap[i] = newRowNum++; + } + } + for (int i = 1; i < rowNumMap.length; i++) { + if (tempStateTable.elementAt(i) == null) { + rowNumMap[i] = rowNumMap[rowNumMap[i]]; + } + } + + // allocate the permanent state table, and copy the remaining rows into it + // (adjusting all the cell values, of course) + + // this section does that for the forward state table + if (forward) { + endStates = new boolean[newRowNum]; + lookaheadStates = new boolean[newRowNum]; + stateTable = new short[newRowNum * numCategories]; + int p = 0; + int p2 = 0; + for (int i = 0; i < tempStateTable.size(); i++) { + short[] row = tempStateTable.elementAt(i); + if (row == null) { + continue; + } + for (int j = 0; j < numCategories; j++) { + stateTable[p] = (short)(rowNumMap[row[j]]); + ++p; + } + endStates[p2] = ((row[numCategories] & END_STATE_FLAG) != 0); + lookaheadStates[p2] = ((row[numCategories] & LOOKAHEAD_STATE_FLAG) != 0); + ++p2; + } + } + + // and this section does it for the backward state table + else { + backwardsStateTable = new short[newRowNum * numCategories]; + int p = 0; + for (int i = 0; i < tempStateTable.size(); i++) { + short[] row = tempStateTable.elementAt(i); + if (row == null) { + continue; + } + for (int j = 0; j < numCategories; j++) { + backwardsStateTable[p] = (short)(rowNumMap[row[j]]); + ++p; + } + } + } + } + + /** + * This function builds the backward state table from the forward state + * table and any additional rules (identified by the ! on the front) + * supplied in the description + */ + private void buildBackwardsStateTable(Vector tempRuleList) { + + // create the temporary state table and seed it with two rows (row 0 + // isn't used for anything, and we have to create row 1 (the initial + // state) before we can do anything else + tempStateTable = new Vector<>(); + tempStateTable.addElement(new short[numCategories + 1]); + tempStateTable.addElement(new short[numCategories + 1]); + + // although the backwards state table is built automatically from the forward + // state table, there are some situations (the default sentence-break rules, + // for example) where this doesn't yield enough stop states, causing a dramatic + // drop in performance. To help with these cases, the user may supply + // supplemental rules that are added to the backward state table. These have + // the same syntax as the normal break rules, but begin with '!' to distinguish + // them from normal break rules + for (int i = 0; i < tempRuleList.size(); i++) { + String rule = tempRuleList.elementAt(i); + if (rule.charAt(0) == '!') { + parseRule(rule.substring(1), false); + } + } + backfillLoopingStates(); + + // Backwards iteration is qualitatively different from forwards iteration. + // This is because backwards iteration has to be made to operate from no context + // at all-- the user should be able to ask BreakIterator for the break position + // immediately on either side of some arbitrary offset in the text. The + // forward iteration table doesn't let us do that-- it assumes complete + // information on the context, which means starting from the beginning of the + // document. + // The way we do backward and random-access iteration is to back up from the + // current (or user-specified) position until we see something we're sure is + // a break position (it may not be the last break position immediately + // preceding our starting point, however). Then we roll forward from there to + // locate the actual break position we're after. + // This means that the backwards state table doesn't have to identify every + // break position, allowing the building algorithm to be much simpler. Here, + // we use a "pairs" approach, scanning the forward-iteration state table for + // pairs of character categories we ALWAYS break between, and building a state + // table from that information. No context is required-- all this state table + // looks at is a pair of adjacent characters. + + // It's possible that the user has supplied supplementary rules (see above). + // This has to be done first to keep parseRule() and friends from becoming + // EVEN MORE complicated. The automatically-generated states are appended + // onto the end of the state table, and then the two sets of rules are + // stitched together at the end. Take note of the row number of the + // first row of the auromatically-generated part. + int backTableOffset = tempStateTable.size(); + if (backTableOffset > 2) { + ++backTableOffset; + } + + // the automatically-generated part of the table models a two-dimensional + // array where the two dimensions represent the two characters we're currently + // looking at. To model this as a state table, we actually need one additional + // row to represent the initial state. It gets populated with the row numbers + // of the other rows (in order). + for (int i = 0; i < numCategories + 1; i++) + tempStateTable.addElement(new short[numCategories + 1]); + + short[] state = tempStateTable.elementAt(backTableOffset - 1); + for (int i = 0; i < numCategories; i++) + state[i] = (short)(i + backTableOffset); + + // scavenge the forward state table for pairs of character categories + // that always have a break between them. The algorithm is as follows: + // Look down each column in the state table. For each nonzero cell in + // that column, look up the row it points to. For each nonzero cell in + // that row, populate a cell in the backwards state table: the row number + // of that cell is the number of the column we were scanning (plus the + // offset that locates this sub-table), and the column number of that cell + // is the column number of the nonzero cell we just found. This cell is + // populated with its own column number (adjusted according to the actual + // location of the sub-table). This process will produce a state table + // whose behavior is the same as looking up successive pairs of characters + // in an array of Booleans to determine whether there is a break. + int numRows = stateTable.length / numCategories; + for (int column = 0; column < numCategories; column++) { + for (int row = 0; row < numRows; row++) { + int nextRow = lookupState(row, column); + if (nextRow != 0) { + for (int nextColumn = 0; nextColumn < numCategories; nextColumn++) { + int cellValue = lookupState(nextRow, nextColumn); + if (cellValue != 0) { + state = tempStateTable.elementAt(nextColumn + + backTableOffset); + state[column] = (short)(column + backTableOffset); + } + } + } + } + } + + // if the user specified some backward-iteration rules with the ! token, + // we have to merge the resulting state table with the auto-generated one + // above. First copy the populated cells from row 1 over the populated + // cells in the auto-generated table. Then copy values from row 1 of the + // auto-generated table into all of the the unpopulated cells of the + // rule-based table. + if (backTableOffset > 1) { + + // for every row in the auto-generated sub-table, if a cell is + // populated that is also populated in row 1 of the rule-based + // sub-table, copy the value from row 1 over the value in the + // auto-generated sub-table + state = tempStateTable.elementAt(1); + for (int i = backTableOffset - 1; i < tempStateTable.size(); i++) { + short[] state2 = tempStateTable.elementAt(i); + for (int j = 0; j < numCategories; j++) { + if (state[j] != 0 && state2[j] != 0) { + state2[j] = state[j]; + } + } + } + + // now, for every row in the rule-based sub-table that is not + // an end state, fill in all unpopulated cells with the values + // of the corresponding cells in the first row of the auto- + // generated sub-table. + state = tempStateTable.elementAt(backTableOffset - 1); + for (int i = 1; i < backTableOffset - 1; i++) { + short[] state2 = tempStateTable.elementAt(i); + if ((state2[numCategories] & END_STATE_FLAG) == 0) { + for (int j = 0; j < numCategories; j++) { + if (state2[j] == 0) { + state2[j] = state[j]; + } + } + } + } + } + + // finally, clean everything up and copy it into the actual BreakIterator + // by calling finishBuildingStateTable() + finishBuildingStateTable(false); + } + + /** + * Given a current state and a character category, looks up the + * next state to transition to in the state table. + */ + protected int lookupState(int state, int category) { + return stateTable[state * numCategories + category]; + } + + /** + * Throws an IllegalArgumentException representing a syntax error in the rule + * description. The exception's message contains some debugging information. + * @param message A message describing the problem + * @param position The position in the description where the problem was + * discovered + * @param context The string containing the error + */ + protected void error(String message, int position, String context) { + throw new IllegalArgumentException("Parse error at position (" + position + "): " + message + "\n" + + context.substring(0, position) + " -here- " + context.substring(position)); + } + + void makeFile(String filename) { + writeTables(filename); + } + + /** + * Magic number for the BreakIterator data file format. + */ + private static final byte[] LABEL = { + (byte)'B', (byte)'I', (byte)'d', (byte)'a', (byte)'t', (byte)'a', + (byte)'\0' + }; + + /** + * Version number of the dictionary that was read in. + */ + private static final byte[] supportedVersion = { (byte)1 }; + + /** + * Header size in byte count + */ + private static final int HEADER_LENGTH = 36; + + /** + * Array length of indices for BMP characters + */ + private static final int BMP_INDICES_LENGTH = 512; + + /** + * Read datafile. The datafile's format is as follows: + *
+     *   BreakIteratorData {
+     *       u1           magic[7];
+     *       u1           version;
+     *       u4           totalDataSize;
+     *       header_info  header;
+     *       body         value;
+     *   }
+     * 
+ * totalDataSize is the summation of the size of + * header_info and body in byte count. + *

+ * In header, each field except for checksum implies the + * length of each field. Since BMPdataLength is a fixed-length + * data(512 entries), its length isn't included in header. + * checksum is a CRC32 value of all in body. + *

+     *   header_info {
+     *       u4           stateTableLength;
+     *       u4           backwardsStateTableLength;
+     *       u4           endStatesLength;
+     *       u4           lookaheadStatesLength;
+     *       u4           BMPdataLength;
+     *       u4           nonBMPdataLength;
+     *       u4           additionalDataLength;
+     *       u8           checksum;
+     *   }
+     * 
+ *

+ * + * Finally, BMPindices and BMPdata are set to + * charCategoryTable. nonBMPdata is set to + * supplementaryCharCategoryTable. + *

+     *   body {
+     *       u2           stateTable[stateTableLength];
+     *       u2           backwardsStateTable[backwardsStateTableLength];
+     *       u1           endStates[endStatesLength];
+     *       u1           lookaheadStates[lookaheadStatesLength];
+     *       u2           BMPindices[512];
+     *       u1           BMPdata[BMPdataLength];
+     *       u4           nonBMPdata[numNonBMPdataLength];
+     *       u1           additionalData[additionalDataLength];
+     *   }
+     * 
+ */ + protected void writeTables(String datafile) { + final String filename; + final String outputDir; + String tmpbuf = GenerateBreakIteratorData.getOutputDirectory(); + + if (tmpbuf.equals("")) { + filename = datafile; + outputDir = ""; + } else { + char sep = File.separatorChar; + if (sep == '/') { + outputDir = tmpbuf; + } else if (sep == '\\') { + outputDir = tmpbuf.replaceAll("/", "\\\\"); + } else { + outputDir = tmpbuf.replaceAll("/", String.valueOf(sep)); + } + + filename = outputDir + sep + datafile; + } + + try { + if (!outputDir.equals("")) { + new File(outputDir).mkdirs(); + } + BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(filename)); + + byte[] BMPdata = charCategoryTable.getStringArray(); + short[] BMPindices = charCategoryTable.getIndexArray(); + int[] nonBMPdata = supplementaryCharCategoryTable.getArray(); + + if (BMPdata.length <= 0) { + throw new InternalError("Wrong BMP data length(" + BMPdata.length + ")"); + } + if (BMPindices.length != BMP_INDICES_LENGTH) { + throw new InternalError("Wrong BMP indices length(" + BMPindices.length + ")"); + } + if (nonBMPdata.length <= 0) { + throw new InternalError("Wrong non-BMP data length(" + nonBMPdata.length + ")"); + } + + int len; + + /* Compute checksum */ + CRC32 crc32 = new CRC32(); + len = stateTable.length; + for (int i = 0; i < len; i++) { + crc32.update(stateTable[i]); + } + len = backwardsStateTable.length; + for (int i = 0; i < len; i++) { + crc32.update(backwardsStateTable[i]); + } + crc32.update(toByteArray(endStates)); + crc32.update(toByteArray(lookaheadStates)); + for (int i = 0; i < BMP_INDICES_LENGTH; i++) { + crc32.update(BMPindices[i]); + } + crc32.update(BMPdata); + len = nonBMPdata.length; + for (int i = 0; i < len; i++) { + crc32.update(nonBMPdata[i]); + } + if (additionalData != null) { + len = additionalData.length; + for (int i = 0; i < len; i++) { + crc32.update(additionalData[i]); + } + } + + /* First, write magic, version, and totalDataSize. */ + len = HEADER_LENGTH + + (stateTable.length + backwardsStateTable.length) * 2 + + endStates.length + lookaheadStates.length + 1024 + + BMPdata.length + nonBMPdata.length * 4 + + ((additionalData == null) ? 0 : additionalData.length); + out.write(LABEL); + out.write(supportedVersion); + out.write(toByteArray(len)); + + /* Write header_info. */ + out.write(toByteArray(stateTable.length)); + out.write(toByteArray(backwardsStateTable.length)); + out.write(toByteArray(endStates.length)); + out.write(toByteArray(lookaheadStates.length)); + out.write(toByteArray(BMPdata.length)); + out.write(toByteArray(nonBMPdata.length)); + if (additionalData == null) { + out.write(toByteArray(0)); + } else { + out.write(toByteArray(additionalData.length)); + } + out.write(toByteArray(crc32.getValue())); + + /* Write stateTable[numCategories * numRows] */ + len = stateTable.length; + for (int i = 0; i < len; i++) { + out.write(toByteArray(stateTable[i])); + } + + /* Write backwardsStateTable[numCategories * numRows] */ + len = backwardsStateTable.length; + for (int i = 0; i < len; i++) { + out.write(toByteArray(backwardsStateTable[i])); + } + + /* Write endStates[numRows] */ + out.write(toByteArray(endStates)); + + /* Write lookaheadStates[numRows] */ + out.write(toByteArray(lookaheadStates)); + + for (int i = 0; i < BMP_INDICES_LENGTH; i++) { + out.write(toByteArray(BMPindices[i])); + } + BMPindices = null; + out.write(BMPdata); + BMPdata = null; + + /* Write a category table for non-BMP characters. */ + len = nonBMPdata.length; + for (int i = 0; i < len; i++) { + out.write(toByteArray(nonBMPdata[i])); + } + nonBMPdata = null; + + /* Write additional data */ + if (additionalData != null) { + out.write(additionalData); + } + + out.close(); + } + catch (Exception e) { + throw new InternalError(e.toString()); + } + } + + byte[] toByteArray(short val) { + byte[] buf = new byte[2]; + buf[0] = (byte)((val>>>8) & 0xFF); + buf[1] = (byte)(val & 0xFF); + return buf; + } + + byte[] toByteArray(int val) { + byte[] buf = new byte[4]; + buf[0] = (byte)((val>>>24) & 0xFF); + buf[1] = (byte)((val>>>16) & 0xFF); + buf[2] = (byte)((val>>>8) & 0xFF); + buf[3] = (byte)(val & 0xFF); + return buf; + } + + byte[] toByteArray(long val) { + byte[] buf = new byte[8]; + buf[0] = (byte)((val>>>56) & 0xff); + buf[1] = (byte)((val>>>48) & 0xff); + buf[2] = (byte)((val>>>40) & 0xff); + buf[3] = (byte)((val>>>32) & 0xff); + buf[4] = (byte)((val>>>24) & 0xff); + buf[5] = (byte)((val>>>16) & 0xff); + buf[6] = (byte)((val>>>8) & 0xff); + buf[7] = (byte)(val & 0xff); + return buf; + } + + byte[] toByteArray(boolean[] data) { + byte[] buf = new byte[data.length]; + for (int i = 0; i < data.length; i++) { + buf[i] = data[i] ? (byte)1 : (byte)0; + } + return buf; + } + + void setAdditionalData(byte[] data) { + additionalData = data; + } +} --- old/make/jdk/src/classes/build/tools/generatebreakiteratordata/SupplementaryCharacterData.java 2020-03-23 19:56:42.343962660 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,184 +0,0 @@ -/* - * Copyright (c) 2003, 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 build.tools.generatebreakiteratordata; - -import java.util.Arrays; - -final class SupplementaryCharacterData { - - /** - * Default value - */ - private static final byte DEFAULT_VALUE = 0; - private byte defaultValue; - - /** - * A array which has a unicode code point(0x010000-0x10FFFF) as the upper - * 3 bytes and a value as the remaining one byte in each data. - */ - private int[] dataTable; - - /* - * Counter to keep the number of data in tempTable - */ - private int dataCount; - - /* - * Temporary data table used until dataTable is generated. - */ - private long[] tempTable; - - /* - * Initila tempTable size - */ - private static final int INITIAL_TABLE_SIZE = 150; - - /* - * The number of entries to be appended when tempTable becomes full - */ - private static final int ADDITIONAL_TABLE_SIZE = 10; - - /* - * Upper limit, used as a sentinel - */ - private static final int UPPER_LIMIT = Character.MAX_CODE_POINT + 1; - - /* - * Mask for supplementary code points(0x010000-0x10FFFF) - */ - private static final int CODEPOINT_MASK = 0x1FFFFF; - - - public SupplementaryCharacterData(byte value) { - defaultValue = value; - dataCount = 0; - } - - /** - * Appends the given data to tempTable - */ - public void appendElement(int start, int end, byte value) { - if (tempTable == null) { - tempTable = new long[INITIAL_TABLE_SIZE]; - } - - if (dataCount == tempTable.length) { - long[] tempTempTable = new long[dataCount + ADDITIONAL_TABLE_SIZE]; - System.arraycopy(tempTable, 0, tempTempTable, 0, dataCount); - tempTable = tempTempTable; - } - tempTable[dataCount++] = ((((long)start<<24) + end)<<8) + value; - } - - /** - * Returns the data table - */ - public int[] getArray() { - return dataTable; - } - - /** - * Creates dataTable - */ - public void complete() { - dataTable = generateTable(); - } - - /** - * Generates a table from the given data - */ - private int[] generateTable() { - /* If tempTable is empty, put two data */ - if (dataCount == 0) { - int[] tmpArray = new int[2]; - tmpArray[0] = composeEntry(0, DEFAULT_VALUE); - tmpArray[1] = composeEntry(UPPER_LIMIT, DEFAULT_VALUE); - tempTable = null; - return tmpArray; - } - - Arrays.sort(tempTable, 0, dataCount); - - int[] newTempTable = new int[dataCount*2 + 3]; - - int old_index = 0; - int new_index = 0; - int loop_count = dataCount - 1; - long data = tempTable[old_index]; - int start = (int)(data>>32) & CODEPOINT_MASK; - int end = (int)(data>>8) & CODEPOINT_MASK; - - /* - * Add an entry if the first start code point in tempTable is not - * the minimum supplementary code point. - */ - if (start != Character.MIN_SUPPLEMENTARY_CODE_POINT) { - newTempTable[new_index++] = composeEntry(Character.MIN_SUPPLEMENTARY_CODE_POINT, defaultValue); - } - - newTempTable[new_index++] = composeEntry(start, (int)data); - for (int i = 0; i < loop_count; i++) { - data = tempTable[++old_index]; - int nextStart = (int)(data>>32) & CODEPOINT_MASK; - - /* - * If the previous end code point is not equal to the previous start - * code point and is not consecutive with the next start code point, - * insert a filler entry before an entry for the next start code - * point. - */ - if (end != start && end != nextStart-1) { - newTempTable[new_index++] = composeEntry(end + 1, defaultValue); - } - newTempTable[new_index++] = composeEntry(nextStart, (int)data); - start = nextStart; - end = (int)(data>>8) & CODEPOINT_MASK; - } - newTempTable[new_index++] = composeEntry(++end, defaultValue); - - /* Add an entry for a sentinel if necessary. */ - if (end < UPPER_LIMIT) { - newTempTable[new_index++] = composeEntry(UPPER_LIMIT, defaultValue); - } - - /* Copy data to dataTable. */ - dataTable = new int[new_index]; - System.arraycopy(newTempTable, 0, dataTable, 0, new_index); - - tempTable = null; - - return dataTable; - } - - /** - * Composes an entry with the given supplementary code point - * (0x010000-0x10FFFF) for the upper 3 bytes and the given value for the - * remaining one byte. - */ - private int composeEntry(int codePoint, int value) { - return (codePoint<<8) | (value&0xFF); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.base/share/tools/org/openjdk/buildtools/generatebreakiteratordata/SupplementaryCharacterData.java 2020-03-23 19:56:41.951962662 +0100 @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2003, 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 org.openjdk.buildtools.generatebreakiteratordata; + +import java.util.Arrays; + +final class SupplementaryCharacterData { + + /** + * Default value + */ + private static final byte DEFAULT_VALUE = 0; + private byte defaultValue; + + /** + * A array which has a unicode code point(0x010000-0x10FFFF) as the upper + * 3 bytes and a value as the remaining one byte in each data. + */ + private int[] dataTable; + + /* + * Counter to keep the number of data in tempTable + */ + private int dataCount; + + /* + * Temporary data table used until dataTable is generated. + */ + private long[] tempTable; + + /* + * Initila tempTable size + */ + private static final int INITIAL_TABLE_SIZE = 150; + + /* + * The number of entries to be appended when tempTable becomes full + */ + private static final int ADDITIONAL_TABLE_SIZE = 10; + + /* + * Upper limit, used as a sentinel + */ + private static final int UPPER_LIMIT = Character.MAX_CODE_POINT + 1; + + /* + * Mask for supplementary code points(0x010000-0x10FFFF) + */ + private static final int CODEPOINT_MASK = 0x1FFFFF; + + + public SupplementaryCharacterData(byte value) { + defaultValue = value; + dataCount = 0; + } + + /** + * Appends the given data to tempTable + */ + public void appendElement(int start, int end, byte value) { + if (tempTable == null) { + tempTable = new long[INITIAL_TABLE_SIZE]; + } + + if (dataCount == tempTable.length) { + long[] tempTempTable = new long[dataCount + ADDITIONAL_TABLE_SIZE]; + System.arraycopy(tempTable, 0, tempTempTable, 0, dataCount); + tempTable = tempTempTable; + } + tempTable[dataCount++] = ((((long)start<<24) + end)<<8) + value; + } + + /** + * Returns the data table + */ + public int[] getArray() { + return dataTable; + } + + /** + * Creates dataTable + */ + public void complete() { + dataTable = generateTable(); + } + + /** + * Generates a table from the given data + */ + private int[] generateTable() { + /* If tempTable is empty, put two data */ + if (dataCount == 0) { + int[] tmpArray = new int[2]; + tmpArray[0] = composeEntry(0, DEFAULT_VALUE); + tmpArray[1] = composeEntry(UPPER_LIMIT, DEFAULT_VALUE); + tempTable = null; + return tmpArray; + } + + Arrays.sort(tempTable, 0, dataCount); + + int[] newTempTable = new int[dataCount*2 + 3]; + + int old_index = 0; + int new_index = 0; + int loop_count = dataCount - 1; + long data = tempTable[old_index]; + int start = (int)(data>>32) & CODEPOINT_MASK; + int end = (int)(data>>8) & CODEPOINT_MASK; + + /* + * Add an entry if the first start code point in tempTable is not + * the minimum supplementary code point. + */ + if (start != Character.MIN_SUPPLEMENTARY_CODE_POINT) { + newTempTable[new_index++] = composeEntry(Character.MIN_SUPPLEMENTARY_CODE_POINT, defaultValue); + } + + newTempTable[new_index++] = composeEntry(start, (int)data); + for (int i = 0; i < loop_count; i++) { + data = tempTable[++old_index]; + int nextStart = (int)(data>>32) & CODEPOINT_MASK; + + /* + * If the previous end code point is not equal to the previous start + * code point and is not consecutive with the next start code point, + * insert a filler entry before an entry for the next start code + * point. + */ + if (end != start && end != nextStart-1) { + newTempTable[new_index++] = composeEntry(end + 1, defaultValue); + } + newTempTable[new_index++] = composeEntry(nextStart, (int)data); + start = nextStart; + end = (int)(data>>8) & CODEPOINT_MASK; + } + newTempTable[new_index++] = composeEntry(++end, defaultValue); + + /* Add an entry for a sentinel if necessary. */ + if (end < UPPER_LIMIT) { + newTempTable[new_index++] = composeEntry(UPPER_LIMIT, defaultValue); + } + + /* Copy data to dataTable. */ + dataTable = new int[new_index]; + System.arraycopy(newTempTable, 0, dataTable, 0, new_index); + + tempTable = null; + + return dataTable; + } + + /** + * Composes an entry with the given supplementary code point + * (0x010000-0x10FFFF) for the upper 3 bytes and the given value for the + * remaining one byte. + */ + private int composeEntry(int codePoint, int value) { + return (codePoint<<8) | (value&0xFF); + } +} --- old/make/jdk/src/classes/build/tools/generatecacerts/GenerateCacerts.java 2020-03-23 19:56:43.227962653 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2019, 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.generatecacerts; - -import java.io.DataOutputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.security.DigestOutputStream; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - -/** - * Generate cacerts - * args[0]: Full path string to the directory that contains CA certs - * args[1]: Full path string to the generated cacerts - */ -public class GenerateCacerts { - public static void main(String[] args) throws Exception { - try (FileOutputStream fos = new FileOutputStream(args[1])) { - store(args[0], fos, "changeit".toCharArray()); - } - } - - // The following code are copied from JavaKeyStore.java. - - private static final int MAGIC = 0xfeedfeed; - private static final int VERSION_2 = 0x02; - - // This method is a simplified version of JavaKeyStore::engineStore. - // A new "dir" argument is added. All cert names in "dir" is collected into - // a sorted array. Each cert is stored with a creation date set to its - // notBefore value. Thus the output is determined as long as the certs - // are the same. - public static void store(String dir, OutputStream stream, char[] password) - throws IOException, NoSuchAlgorithmException, CertificateException - { - byte[] encoded; // the certificate encoding - CertificateFactory cf = CertificateFactory.getInstance("X509"); - - MessageDigest md = getPreKeyedHash(password); - DataOutputStream dos - = new DataOutputStream(new DigestOutputStream(stream, md)); - - dos.writeInt(MAGIC); - // always write the latest version - dos.writeInt(VERSION_2); - - // All file names in dir sorted. - // README is excluded. Name starting with "." excluded. - List entries = Files.list(Path.of(dir)) - .map(p -> p.getFileName().toString()) - .filter(s -> !s.equals("README") && !s.startsWith(".")) - .collect(Collectors.toList()); - - entries.sort(String::compareTo); - - dos.writeInt(entries.size()); - - for (String entry : entries) { - - String alias = entry + " [jdk]"; - X509Certificate cert; - try (InputStream fis = Files.newInputStream(Path.of(dir, entry))) { - cert = (X509Certificate) cf.generateCertificate(fis); - } - - dos.writeInt(2); - - // Write the alias - dos.writeUTF(alias); - - // Write the (entry creation) date, which is notBefore of the cert - dos.writeLong(cert.getNotBefore().getTime()); - - // Write the trusted certificate - encoded = cert.getEncoded(); - dos.writeUTF(cert.getType()); - dos.writeInt(encoded.length); - dos.write(encoded); - } - - /* - * Write the keyed hash which is used to detect tampering with - * the keystore (such as deleting or modifying key or - * certificate entries). - */ - byte[] digest = md.digest(); - - dos.write(digest); - dos.flush(); - } - - private static MessageDigest getPreKeyedHash(char[] password) - throws NoSuchAlgorithmException, UnsupportedEncodingException - { - - MessageDigest md = MessageDigest.getInstance("SHA"); - byte[] passwdBytes = convertToBytes(password); - md.update(passwdBytes); - Arrays.fill(passwdBytes, (byte) 0x00); - md.update("Mighty Aphrodite".getBytes("UTF8")); - return md; - } - - private static byte[] convertToBytes(char[] password) { - int i, j; - byte[] passwdBytes = new byte[password.length * 2]; - for (i=0, j=0; i> 8); - passwdBytes[j++] = (byte)password[i]; - } - return passwdBytes; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.base/share/tools/org/openjdk/buildtools/generatecacerts/GenerateCacerts.java 2020-03-23 19:56:42.799962656 +0100 @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatecacerts; + +import java.io.DataOutputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.DigestOutputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Generate cacerts + * args[0]: Full path string to the directory that contains CA certs + * args[1]: Full path string to the generated cacerts + */ +public class GenerateCacerts { + public static void main(String[] args) throws Exception { + try (FileOutputStream fos = new FileOutputStream(args[1])) { + store(args[0], fos, "changeit".toCharArray()); + } + } + + // The following code are copied from JavaKeyStore.java. + + private static final int MAGIC = 0xfeedfeed; + private static final int VERSION_2 = 0x02; + + // This method is a simplified version of JavaKeyStore::engineStore. + // A new "dir" argument is added. All cert names in "dir" is collected into + // a sorted array. Each cert is stored with a creation date set to its + // notBefore value. Thus the output is determined as long as the certs + // are the same. + public static void store(String dir, OutputStream stream, char[] password) + throws IOException, NoSuchAlgorithmException, CertificateException + { + byte[] encoded; // the certificate encoding + CertificateFactory cf = CertificateFactory.getInstance("X509"); + + MessageDigest md = getPreKeyedHash(password); + DataOutputStream dos + = new DataOutputStream(new DigestOutputStream(stream, md)); + + dos.writeInt(MAGIC); + // always write the latest version + dos.writeInt(VERSION_2); + + // All file names in dir sorted. + // README is excluded. Name starting with "." excluded. + List entries = Files.list(Path.of(dir)) + .map(p -> p.getFileName().toString()) + .filter(s -> !s.equals("README") && !s.startsWith(".")) + .collect(Collectors.toList()); + + entries.sort(String::compareTo); + + dos.writeInt(entries.size()); + + for (String entry : entries) { + + String alias = entry + " [jdk]"; + X509Certificate cert; + try (InputStream fis = Files.newInputStream(Path.of(dir, entry))) { + cert = (X509Certificate) cf.generateCertificate(fis); + } + + dos.writeInt(2); + + // Write the alias + dos.writeUTF(alias); + + // Write the (entry creation) date, which is notBefore of the cert + dos.writeLong(cert.getNotBefore().getTime()); + + // Write the trusted certificate + encoded = cert.getEncoded(); + dos.writeUTF(cert.getType()); + dos.writeInt(encoded.length); + dos.write(encoded); + } + + /* + * Write the keyed hash which is used to detect tampering with + * the keystore (such as deleting or modifying key or + * certificate entries). + */ + byte[] digest = md.digest(); + + dos.write(digest); + dos.flush(); + } + + private static MessageDigest getPreKeyedHash(char[] password) + throws NoSuchAlgorithmException, UnsupportedEncodingException + { + + MessageDigest md = MessageDigest.getInstance("SHA"); + byte[] passwdBytes = convertToBytes(password); + md.update(passwdBytes); + Arrays.fill(passwdBytes, (byte) 0x00); + md.update("Mighty Aphrodite".getBytes("UTF8")); + return md; + } + + private static byte[] convertToBytes(char[] password) { + int i, j; + byte[] passwdBytes = new byte[password.length * 2]; + for (i=0, j=0; i> 8); + passwdBytes[j++] = (byte)password[i]; + } + return passwdBytes; + } +} --- old/make/jdk/src/classes/build/tools/generatecharacter/CharacterName.java 2020-03-23 19:56:44.087962647 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2010, 2020, 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.generatecharacter; - -import java.io.*; -import java.nio.*; -import java.util.*; -import java.util.zip.*; - -public class CharacterName { - - public static void main(String[] args) { - FileReader reader = null; - try { - if (args.length != 2) { - System.err.println("Usage: java CharacterName UnicodeData.txt uniName.dat"); - System.exit(1); - } - reader = new FileReader(args[0]); - BufferedReader bfr = new BufferedReader(reader); - String line = null; - - StringBuilder namePool = new StringBuilder(); - byte[] cpPoolBytes = new byte[0x100000]; - boolean[] cpBlocks = new boolean[(Character.MAX_CODE_POINT + 1) >> 8]; - int bkNum = 0; - ByteBuffer cpBB = ByteBuffer.wrap(cpPoolBytes); - int lastCp = 0; - int cpNum = 0; - - while ((line = bfr.readLine()) != null) { - if (line.startsWith("#")) - continue; - UnicodeSpec spec = UnicodeSpec.parse(line); - if (spec != null) { - int cp = spec.getCodePoint(); - String name = spec.getName(); - if (name.equals("") && spec.getOldName() != null) { - if (cp == 0x7) // BELL -> BEL; u+1f514 <-> BELL - name = "BEL"; - else if (spec.getOldName().length() != 0) - name = spec.getOldName(); - /* - 3 "figment" characters from NameAliases.txt - Several documented labels for C1 control code points which - were never actually approved in any standard...but were - implemented in Perl regex. - 0080;PADDING CHARACTER;figment - 0081;HIGH OCTET PRESET;figment - 0099;SINGLE GRAPHIC CHARACTER INTRODUCER;figment - */ - else if (cp == 0x80) - name = "PADDING CHARACTER"; - else if (cp == 0x81) - name = "HIGH OCTET PRESET"; - else if (cp == 0x99) - name = "SINGLE GRAPHIC CHARACTER INTRODUCER"; - else - continue; - } else if (name.startsWith("<")) { - /* - 3400 - 4db5 - 4e00 - 9fc3 - ac00 - d7a3 - d800 - db7f - db80 - dbff - dc00 - dfff - e000 - f8ff - 20000 - 2a6d6 - f0000 - ffffd - */ - continue; - } - cpNum++; - if (!cpBlocks[cp >> 8]) { - cpBlocks[cp >> 8] = true; - bkNum++; - } - if (cp == lastCp + 1) { - cpBB.put((byte)name.length()); - } else { - cpBB.put((byte)0); // segment start flag - cpBB.putInt((name.length() << 24) | (cp & 0xffffff)); - } - namePool.append(name); - lastCp = cp; - } - } - - byte[] namePoolBytes = namePool.toString().getBytes("ASCII"); - int cpLen = cpBB.position(); - int total = cpLen + namePoolBytes.length; - DataOutputStream dos = new DataOutputStream( - new DeflaterOutputStream( - new FileOutputStream(args[1]))); - dos.writeInt(total); // total - dos.writeInt(bkNum); // bkNum; - dos.writeInt(cpNum); // cpNum - dos.writeInt(cpLen); // nameOff - dos.write(cpPoolBytes, 0, cpLen); - dos.write(namePoolBytes); - dos.close(); - - } catch (Throwable e) { - System.out.println("Unexpected exception:"); - e.printStackTrace(); - } finally { - if (reader != null) { - try { - reader.close(); - } catch (Throwable ee) { ee.printStackTrace(); } - } - } - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.base/share/tools/org/openjdk/buildtools/generatecharacter/CharacterName.java 2020-03-23 19:56:43.683962650 +0100 @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatecharacter; + +import java.io.*; +import java.nio.*; +import java.util.*; +import java.util.zip.*; + +public class CharacterName { + + public static void main(String[] args) { + FileReader reader = null; + try { + if (args.length != 2) { + System.err.println("Usage: java CharacterName UnicodeData.txt uniName.dat"); + System.exit(1); + } + reader = new FileReader(args[0]); + BufferedReader bfr = new BufferedReader(reader); + String line = null; + + StringBuilder namePool = new StringBuilder(); + byte[] cpPoolBytes = new byte[0x100000]; + boolean[] cpBlocks = new boolean[(Character.MAX_CODE_POINT + 1) >> 8]; + int bkNum = 0; + ByteBuffer cpBB = ByteBuffer.wrap(cpPoolBytes); + int lastCp = 0; + int cpNum = 0; + + while ((line = bfr.readLine()) != null) { + if (line.startsWith("#")) + continue; + UnicodeSpec spec = UnicodeSpec.parse(line); + if (spec != null) { + int cp = spec.getCodePoint(); + String name = spec.getName(); + if (name.equals("") && spec.getOldName() != null) { + if (cp == 0x7) // BELL -> BEL; u+1f514 <-> BELL + name = "BEL"; + else if (spec.getOldName().length() != 0) + name = spec.getOldName(); + /* + 3 "figment" characters from NameAliases.txt + Several documented labels for C1 control code points which + were never actually approved in any standard...but were + implemented in Perl regex. + 0080;PADDING CHARACTER;figment + 0081;HIGH OCTET PRESET;figment + 0099;SINGLE GRAPHIC CHARACTER INTRODUCER;figment + */ + else if (cp == 0x80) + name = "PADDING CHARACTER"; + else if (cp == 0x81) + name = "HIGH OCTET PRESET"; + else if (cp == 0x99) + name = "SINGLE GRAPHIC CHARACTER INTRODUCER"; + else + continue; + } else if (name.startsWith("<")) { + /* + 3400 + 4db5 + 4e00 + 9fc3 + ac00 + d7a3 + d800 + db7f + db80 + dbff + dc00 + dfff + e000 + f8ff + 20000 + 2a6d6 + f0000 + ffffd + */ + continue; + } + cpNum++; + if (!cpBlocks[cp >> 8]) { + cpBlocks[cp >> 8] = true; + bkNum++; + } + if (cp == lastCp + 1) { + cpBB.put((byte)name.length()); + } else { + cpBB.put((byte)0); // segment start flag + cpBB.putInt((name.length() << 24) | (cp & 0xffffff)); + } + namePool.append(name); + lastCp = cp; + } + } + + byte[] namePoolBytes = namePool.toString().getBytes("ASCII"); + int cpLen = cpBB.position(); + int total = cpLen + namePoolBytes.length; + DataOutputStream dos = new DataOutputStream( + new DeflaterOutputStream( + new FileOutputStream(args[1]))); + dos.writeInt(total); // total + dos.writeInt(bkNum); // bkNum; + dos.writeInt(cpNum); // cpNum + dos.writeInt(cpLen); // nameOff + dos.write(cpPoolBytes, 0, cpLen); + dos.write(namePoolBytes); + dos.close(); + + } catch (Throwable e) { + System.out.println("Unexpected exception:"); + e.printStackTrace(); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (Throwable ee) { ee.printStackTrace(); } + } + } + } +} --- old/make/jdk/src/classes/build/tools/generatecharacter/CharacterScript.java 2020-03-23 19:56:44.903962641 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,241 +0,0 @@ -/* - * Copyright (c) 2010, 2020, 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.generatecharacter; - -import java.util.regex.*; -import java.util.*; -import java.io.*; - -public class CharacterScript { - - // generate the code needed for j.l.C.UnicodeScript - static void fortest(String fmt, Object... o) { - //System.out.printf(fmt, o); - } - - static void print(String fmt, Object... o) { - System.out.printf(fmt, o); - } - - static void debug(String fmt, Object... o) { - //System.out.printf(fmt, o); - } - - public static void main(String args[]){ - try { - if (args.length != 1) { - System.out.println("java CharacterScript script.txt out"); - System.exit(1); - } - - int i, j; - BufferedReader sbfr = new BufferedReader(new FileReader(args[0])); - HashMap scriptMap = new HashMap(); - String line = null; - - Matcher m = Pattern.compile("(\\p{XDigit}+)(?:\\.{2}(\\p{XDigit}+))?\\s+;\\s+(\\w+)\\s+#.*").matcher(""); - - int prevS = -1; - int prevE = -1; - String prevN = null; - int[][] scripts = new int[1024][3]; - int scriptSize = 0; - - while ((line = sbfr.readLine()) != null) { - if (line.length() <= 1 || line.charAt(0) == '#') { - continue; - } - m.reset(line); - if (m.matches()) { - int start = Integer.parseInt(m.group(1), 16); - int end = (m.group(2)==null)?start - :Integer.parseInt(m.group(2), 16); - String name = m.group(3); - if (name.equals(prevN) && start == prevE + 1) { - prevE = end; - } else { - if (prevS != -1) { - if (scriptMap.get(prevN) == null) { - scriptMap.put(prevN, scriptMap.size()); - } - scripts[scriptSize][0] = prevS; - scripts[scriptSize][1] = prevE; - scripts[scriptSize][2] = scriptMap.get(prevN); - scriptSize++; - } - debug("%x-%x\t%s%n", prevS, prevE, prevN); - prevS = start; prevE = end; prevN = name; - } - } else { - debug("Warning: Unrecognized line <%s>%n", line); - } - } - - //last one. - if (scriptMap.get(prevN) == null) { - scriptMap.put(prevN, scriptMap.size()); - } - scripts[scriptSize][0] = prevS; - scripts[scriptSize][1] = prevE; - scripts[scriptSize][2] = scriptMap.get(prevN); - scriptSize++; - - debug("%x-%x\t%s%n", prevS, prevE, prevN); - debug("-----------------%n"); - debug("Total scripts=%s%n", scriptMap.size()); - debug("-----------------%n%n"); - - String[] names = new String[scriptMap.size()]; - for (String name: scriptMap.keySet()) { - names[scriptMap.get(name).intValue()] = name; - } - - for (j = 0; j < scriptSize; j++) { - for (int cp = scripts[j][0]; cp <= scripts[j][1]; cp++) { - String name = names[scripts[j][2]].toUpperCase(Locale.ENGLISH);; - if (cp > 0xffff) - System.out.printf("%05X %s%n", cp, name); - else - System.out.printf("%05X %s%n", cp, name); - } - } - - Arrays.sort(scripts, 0, scriptSize, - new Comparator() { - public int compare(int[] a1, int[] a2) { - return a1[0] - a2[0]; - } - public boolean compare(Object obj) { - return obj == this; - } - }); - - - - // Consolidation: there are lots of "reserved" code points - // embedded in those otherwise "sequential" blocks. - // To make the lookup table smaller, we combine those - // separated segments with the assumption that the lookup - // implementation checks - // Character.getType() != Character.UNASSIGNED - // first (return UNKNOWN for unassigned) - - ArrayList list = new ArrayList<>(); - list.add(scripts[0]); - - int[] last = scripts[0]; - for (i = 1; i < scriptSize; i++) { - if (scripts[i][0] != (last[1] + 1)) { - - boolean isNotUnassigned = false; - for (int cp = last[1] + 1; cp < scripts[i][0]; cp++) { - if (Character.getType(cp) != Character.UNASSIGNED) { - isNotUnassigned = true; - debug("Warning: [%x] is ASSIGNED but in NON script%n", cp); - break; - } - } - if (isNotUnassigned) { - // surrogates only? - int[] a = new int[3]; - a[0] = last[1] + 1; - a[1] = scripts[i][0] - 1; - a[2] = -1; // unknown - list.add(a); - } else { - if (last[2] == scripts[i][2]) { - //combine - last[1] = scripts[i][1]; - continue; - } else { - // expand last - last[1] = scripts[i][0] - 1; - } - } - } - list.add(scripts[i]); - last = scripts[i]; - } - - for (i = 0; i < list.size(); i++) { - int[] a = list.get(i); - String name = "UNKNOWN"; - if (a[2] != -1) - name = names[a[2]].toUpperCase(Locale.US); - debug("0x%05x, 0x%05x %s%n", a[0], a[1], name); - } - debug("--->total=%d%n", list.size()); - - - //////////////////OUTPUT////////////////////////////////// - print("public class Scripts {%n%n"); - print(" public static enum UnicodeScript {%n"); - for (i = 0; i < names.length; i++) { - print(" /**%n * Unicode script \"%s\".%n */%n", names[i]); - print(" %s,%n%n", names[i].toUpperCase(Locale.US)); - } - print(" /**%n * Unicode script \"Unknown\".%n */%n UNKNOWN;%n%n"); - - - // lookup table - print(" private static final int[] scriptStarts = {%n"); - for (int[] a : list) { - String name = "UNKNOWN"; - if (a[2] != -1) - name = names[a[2]].toUpperCase(Locale.US); - if (a[0] < 0x10000) - print(" 0x%04X, // %04X..%04X; %s%n", - a[0], a[0], a[1], name); - else - print(" 0x%05X, // %05X..%05X; %s%n", - a[0], a[0], a[1], name); - } - last = list.get(list.size() -1); - if (last[1] != Character.MAX_CODE_POINT) - print(" 0x%05X // %05X..%06X; %s%n", - last[1] + 1, last[1] + 1, Character.MAX_CODE_POINT, - "UNKNOWN"); - print("%n };%n%n"); - - print(" private static final UnicodeScript[] scripts = {%n"); - for (int[] a : list) { - String name = "UNKNOWN"; - if (a[2] != -1) - name = names[a[2]].toUpperCase(Locale.US); - print(" %s,%n", name); - } - - if (last[1] != Character.MAX_CODE_POINT) - print(" UNKNOWN%n"); - print(" };%n"); - print(" }%n"); - print("}%n"); - - } catch (Exception e) { - e.printStackTrace(); - } - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.base/share/tools/org/openjdk/buildtools/generatecharacter/CharacterScript.java 2020-03-23 19:56:44.503962644 +0100 @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatecharacter; + +import java.util.regex.*; +import java.util.*; +import java.io.*; + +public class CharacterScript { + + // generate the code needed for j.l.C.UnicodeScript + static void fortest(String fmt, Object... o) { + //System.out.printf(fmt, o); + } + + static void print(String fmt, Object... o) { + System.out.printf(fmt, o); + } + + static void debug(String fmt, Object... o) { + //System.out.printf(fmt, o); + } + + public static void main(String args[]){ + try { + if (args.length != 1) { + System.out.println("java CharacterScript script.txt out"); + System.exit(1); + } + + int i, j; + BufferedReader sbfr = new BufferedReader(new FileReader(args[0])); + HashMap scriptMap = new HashMap(); + String line = null; + + Matcher m = Pattern.compile("(\\p{XDigit}+)(?:\\.{2}(\\p{XDigit}+))?\\s+;\\s+(\\w+)\\s+#.*").matcher(""); + + int prevS = -1; + int prevE = -1; + String prevN = null; + int[][] scripts = new int[1024][3]; + int scriptSize = 0; + + while ((line = sbfr.readLine()) != null) { + if (line.length() <= 1 || line.charAt(0) == '#') { + continue; + } + m.reset(line); + if (m.matches()) { + int start = Integer.parseInt(m.group(1), 16); + int end = (m.group(2)==null)?start + :Integer.parseInt(m.group(2), 16); + String name = m.group(3); + if (name.equals(prevN) && start == prevE + 1) { + prevE = end; + } else { + if (prevS != -1) { + if (scriptMap.get(prevN) == null) { + scriptMap.put(prevN, scriptMap.size()); + } + scripts[scriptSize][0] = prevS; + scripts[scriptSize][1] = prevE; + scripts[scriptSize][2] = scriptMap.get(prevN); + scriptSize++; + } + debug("%x-%x\t%s%n", prevS, prevE, prevN); + prevS = start; prevE = end; prevN = name; + } + } else { + debug("Warning: Unrecognized line <%s>%n", line); + } + } + + //last one. + if (scriptMap.get(prevN) == null) { + scriptMap.put(prevN, scriptMap.size()); + } + scripts[scriptSize][0] = prevS; + scripts[scriptSize][1] = prevE; + scripts[scriptSize][2] = scriptMap.get(prevN); + scriptSize++; + + debug("%x-%x\t%s%n", prevS, prevE, prevN); + debug("-----------------%n"); + debug("Total scripts=%s%n", scriptMap.size()); + debug("-----------------%n%n"); + + String[] names = new String[scriptMap.size()]; + for (String name: scriptMap.keySet()) { + names[scriptMap.get(name).intValue()] = name; + } + + for (j = 0; j < scriptSize; j++) { + for (int cp = scripts[j][0]; cp <= scripts[j][1]; cp++) { + String name = names[scripts[j][2]].toUpperCase(Locale.ENGLISH);; + if (cp > 0xffff) + System.out.printf("%05X %s%n", cp, name); + else + System.out.printf("%05X %s%n", cp, name); + } + } + + Arrays.sort(scripts, 0, scriptSize, + new Comparator() { + public int compare(int[] a1, int[] a2) { + return a1[0] - a2[0]; + } + public boolean compare(Object obj) { + return obj == this; + } + }); + + + + // Consolidation: there are lots of "reserved" code points + // embedded in those otherwise "sequential" blocks. + // To make the lookup table smaller, we combine those + // separated segments with the assumption that the lookup + // implementation checks + // Character.getType() != Character.UNASSIGNED + // first (return UNKNOWN for unassigned) + + ArrayList list = new ArrayList<>(); + list.add(scripts[0]); + + int[] last = scripts[0]; + for (i = 1; i < scriptSize; i++) { + if (scripts[i][0] != (last[1] + 1)) { + + boolean isNotUnassigned = false; + for (int cp = last[1] + 1; cp < scripts[i][0]; cp++) { + if (Character.getType(cp) != Character.UNASSIGNED) { + isNotUnassigned = true; + debug("Warning: [%x] is ASSIGNED but in NON script%n", cp); + break; + } + } + if (isNotUnassigned) { + // surrogates only? + int[] a = new int[3]; + a[0] = last[1] + 1; + a[1] = scripts[i][0] - 1; + a[2] = -1; // unknown + list.add(a); + } else { + if (last[2] == scripts[i][2]) { + //combine + last[1] = scripts[i][1]; + continue; + } else { + // expand last + last[1] = scripts[i][0] - 1; + } + } + } + list.add(scripts[i]); + last = scripts[i]; + } + + for (i = 0; i < list.size(); i++) { + int[] a = list.get(i); + String name = "UNKNOWN"; + if (a[2] != -1) + name = names[a[2]].toUpperCase(Locale.US); + debug("0x%05x, 0x%05x %s%n", a[0], a[1], name); + } + debug("--->total=%d%n", list.size()); + + + //////////////////OUTPUT////////////////////////////////// + print("public class Scripts {%n%n"); + print(" public static enum UnicodeScript {%n"); + for (i = 0; i < names.length; i++) { + print(" /**%n * Unicode script \"%s\".%n */%n", names[i]); + print(" %s,%n%n", names[i].toUpperCase(Locale.US)); + } + print(" /**%n * Unicode script \"Unknown\".%n */%n UNKNOWN;%n%n"); + + + // lookup table + print(" private static final int[] scriptStarts = {%n"); + for (int[] a : list) { + String name = "UNKNOWN"; + if (a[2] != -1) + name = names[a[2]].toUpperCase(Locale.US); + if (a[0] < 0x10000) + print(" 0x%04X, // %04X..%04X; %s%n", + a[0], a[0], a[1], name); + else + print(" 0x%05X, // %05X..%05X; %s%n", + a[0], a[0], a[1], name); + } + last = list.get(list.size() -1); + if (last[1] != Character.MAX_CODE_POINT) + print(" 0x%05X // %05X..%06X; %s%n", + last[1] + 1, last[1] + 1, Character.MAX_CODE_POINT, + "UNKNOWN"); + print("%n };%n%n"); + + print(" private static final UnicodeScript[] scripts = {%n"); + for (int[] a : list) { + String name = "UNKNOWN"; + if (a[2] != -1) + name = names[a[2]].toUpperCase(Locale.US); + print(" %s,%n", name); + } + + if (last[1] != Character.MAX_CODE_POINT) + print(" UNKNOWN%n"); + print(" };%n"); + print(" }%n"); + print("}%n"); + + } catch (Exception e) { + e.printStackTrace(); + } + } +} --- old/make/jdk/src/classes/build/tools/generatecharacter/GenerateCharacter.java 2020-03-23 19:56:45.715962635 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,2016 +0,0 @@ -/* - * Copyright (c) 2002, 2019, 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.generatecharacter; - -import java.io.IOException; -import java.io.FileNotFoundException; -import java.io.BufferedReader; -import java.io.FileReader; -import java.io.PrintWriter; -import java.io.BufferedWriter; -import java.io.FileWriter; -import java.io.File; -import java.util.List; - -import build.tools.generatecharacter.CharacterName; - -/** - * This program generates the source code for the class java.lang.Character. - * It also generates native C code that can perform the same operations. - * It requires two external input data files: - *
    - *
  • Unicode specification file - *
  • Character class template file - *
- * The Unicode specification file is available from the Unicode consortium. - * It has character specification lines that look like this: - * - * 0041;LATIN CAPITAL LETTER A;Lu;0;L;;;;;N;;;;0061; - * - * The Character class template file is filled in with additional - * information to produce the file Character.java, which can then be - * compiled by a Java compiler. The template file contains certain - * markers consisting of an alphabetic name string preceded by "$$". - * Such markers are replaced with generated program text. As a special - * case, the marker "Lookup(xxx)" is recognized, where "xxx" consists of - * alphabetic characters constituting a variable name. The character "_" - * is considered alphabetic for these purposes. - * - * @author Guy Steele - * @author Alan Liu - * @author John O'Conner - */ - -public class GenerateCharacter { - - final static boolean DEBUG = false; - - final static String commandMarker = "$$"; - static String ROOT = ""; - static String DefaultUnicodeSpecFileName = ROOT + "UnicodeData.txt"; - static String DefaultSpecialCasingFileName = ROOT + "SpecialCasing.txt"; - static String DefaultPropListFileName = ROOT + "PropList.txt"; - static String DefaultDerivedPropsFileName = ROOT + "DerivedCoreProperties.txt"; - static String DefaultJavaTemplateFileName = ROOT + "Character.java.template"; - static String DefaultJavaOutputFileName = ROOT + "Character.java"; - static String DefaultCTemplateFileName = ROOT + "Character.c.template"; - static String DefaultCOutputFileName = ROOT + "Character.c"; - - static int plane = 0; - - /* The overall idea is that, in the generated Character class source code, - most character property data is stored in a special multi-level table whose - structure is defined by a sequence of nonnegative integers [k1, k2, ..., kn]. - The integers must sum to 16 (the number of bits in a character). - The first table is indexed by the k1 high-order bits of the character code. - The result is concatenated to the next k2 bits of the character code to index - the second table, and so on. Eventually the kn low-order bits of the character - code are concatenated and used to index one of two tables A and B; A contains - 32-bit integer entries and B contains 16-bit short entries. The 48 bits that - can be thus obtained encode the properties for the character. - - The default specification is [9, 4, 3, 0]. This particular table format was - designed by conducting an exhaustive search of table formats to minimize the - space consumed by the tables: the first and third tables need have only byte - values (the second table must have short values). Another good choice is - [10, 6, 0], which produces a larger table but allows particularly fast table - lookup code. - - In each case, where the word "concatenated" is used, this may imply - first a << and then a | operation, or perhaps just a | operation if - the values in the table can be preshifted (generally possible if the table - entries are short rather than byte). - */ - - /* The character properties are currently encoded into A (32 bits)and B (16 bits) - two parts. - - A: the low 32 bits are defined in the following manner: - - 1 bit Mirrored property. - 4 bits Bidirectional category (see below) (unused if -nobidi switch specified) - 9 bits A signed offset used for converting case . - 1 bit If 1, adding the signed offset converts the character to lowercase. - 1 bit If 1, subtracting the signed offset converts the character to uppercase. - Note: for a titlecase character, both of the preceding bits will be 1 - and the signed offset will be 1. - 1 bit If 1, this character has a titlecase equivalent (possibly itself); - in this case, the two bits before this bit can be used to decide - whether this character is in fact uppercase, lowercase, or titlecase. - 3 bits This field provides a quick way to lex identifiers. - The eight possible values for this field are as follows: - 0 May not be part of an identifier - 1 Ignorable control; may continue a Unicode identifier or Java identifier - 2 May continue a Java identifier but not a Unicode identifier (unused) - 3 May continue a Unicode identifier or Java identifier - 4 Is a Java whitespace character - 5 May start or continue a Java identifier; - may continue but not start a Unicode identifier - (this value is used for connector punctuation such as _) - 6 May start or continue a Java identifier; - may not occur in a Unicode identifier - (this value is used for currency symbols such as $) - 7 May start or continue a Unicode identifier or Java identifier - Thus: - 5, 6, 7 may start a Java identifier - 1, 2, 3, 5, 6, 7 may continue a Java identifier - 7 may start a Unicode identifier - 1, 3, 5, 7 may continue a Unicode identifier - 1 is ignorable within an identifier - 4 is Java whitespace - 2 bits This field indicates whether the character has a numeric property. - The four possible values for this field are as follows: - 0 This character has no numeric property. - 1 Adding the digit offset to the character code and then - masking with 0x1F will produce the desired numeric value. - 2 This character has a "strange" numeric value. - 3 A Java supradecimal digit: adding the digit offset to the - character code, then masking with 0x1F, then adding 10 - will produce the desired numeric value. - 5 bits The digit offset (see description of previous field) - 5 bits Character type (see below) - - B: the high 16 bits are defined as: - 1 bit Other_Lowercase property - 1 bit Other_Uppercase property - 1 bit Other_Alphabetic property - 1 bit Other_Math property - 1 bit Ideographic property - 1 bit Noncharacter codepoint property - 1 bit ID_Start property - 1 bit ID_Continue property - */ - - - // bit masks identify each component of a 32-bit property field described - // above. - // shift* indicates how many shifts right must happen to get the - // indicated property value in the lowest bits of the 32-bit space. - private static final int - shiftType = 0, maskType = 0x001F, - shiftDigitOffset = 5, maskDigitOffset = 0x03E0, - shiftNumericType = 10, maskNumericType = 0x0C00, - shiftIdentifierInfo = 12, maskIdentifierInfo = 0x7000, - maskUnicodePart = 0x1000, - shiftCaseInfo = 15, maskCaseInfo = 0x38000, - maskLowerCase = 0x20000, - maskUpperCase = 0x10000, - maskTitleCase = 0x08000, - shiftCaseOffset = 18, maskCaseOffset = 0x07FC0000, - shiftCaseOffsetSign = 5, - // used only when calculating and - // storing digit offsets from char values - maskDigit = 0x001F, - // case offset are 9 bits - maskCase = 0x01FF, - shiftBidi = 27, maskBidi = 0x78000000, - shiftMirrored = 31, //maskMirrored = 0x80000000, - shiftPlane = 16, maskPlane = 0xFF0000; - - // maskMirrored needs to be long, if up 16-bit - private static final long maskMirrored = 0x80000000L; - - // bit masks identify the 16-bit property field described above, in B - // table - private static final long - maskOtherLowercase = 0x100000000L, - maskOtherUppercase = 0x200000000L, - maskOtherAlphabetic = 0x400000000L, - maskOtherMath = 0x800000000L, - maskIdeographic = 0x1000000000L, - maskNoncharacterCP = 0x2000000000L, - maskIDStart = 0x4000000000L, - maskIDContinue = 0x8000000000L; - - // Can compare masked values with these to determine - // numeric or lexical types. - public static int - valueNotNumeric = 0x0000, - valueDigit = 0x0400, - valueStrangeNumeric = 0x0800, - valueJavaSupradecimal = 0x0C00, - valueIgnorable = 0x1000, - valueJavaOnlyPart = 0x2000, - valueJavaUnicodePart = 0x3000, - valueJavaWhitespace = 0x4000, - valueJavaStartUnicodePart = 0x5000, - valueJavaOnlyStart = 0x6000, - valueJavaUnicodeStart = 0x7000, - lowJavaStart = 0x5000, - nonzeroJavaPart = 0x3000, - valueUnicodeStart = 0x7000; - - // these values are used when only identifier properties are generated - // for use in verifier code. Shortens the property down to a single byte. - private static final int - bitJavaStart = 0x02, - bitJavaPart = 0x01, - maskIsJavaIdentifierPart = bitJavaPart, - maskIsJavaIdentifierStart = bitJavaStart; - - static int maxOffset = maskCase/2 ; - static int minOffset = -maxOffset; - - /* The following routines provide simple, concise formatting of long integer values. - The number in the name of the method indicates the desired number of characters - to be produced. If the number of digits required to represent the integer value - is less than that number, then the output is padded on the left with zeros - (for hex) or with spaces (for decimal). If the number of digits required to - represent the integer value is greater than the desired number, then all the digits - that are required are actually produced. - */ - - static String hex(long n) { return Long.toHexString(n).toUpperCase(); } - - static String hex2(long n) { - String q = Long.toHexString(n & 0xFF).toUpperCase(); - return "00".substring(Math.min(2, q.length())) + q; - } - - static String hex4(long n) { - String q = Long.toHexString(n & 0xFFFF).toUpperCase(); - return "0000".substring(Math.min(4, q.length())) + q; - } - - static String hex8(long n) { - String q = Long.toHexString(n & 0xFFFFFFFFL).toUpperCase(); - return "00000000".substring(Math.min(8, q.length())) + q; - } - - static String hex16(long n) { - String q = Long.toHexString(n).toUpperCase(); - return "0000000000000000".substring(Math.min(16, q.length())) + q; - } - - static String dec3(long n) { - String q = Long.toString(n); - return " ".substring(Math.min(3, q.length())) + q; - } - - static String dec5(long n) { - String q = Long.toString(n); - return " ".substring(Math.min(5, q.length())) + q; - } - - /* This routine is called when some failure occurs. */ - - static void FAIL(String s) { - System.out.println("** " + s); - } - - /** - * Given the data from the Unicode specification file, this routine builds a map. - * - * The specification file is assumed to contain its data in sorted order by - * character code; as a result, the array passed as an argument to this method - * has its components in the same sorted order, with one entry for each defined - * Unicode character or character range. (A range is indicated by two consecutive - * entries, such that the name of the first entry begins with "<" and ends with - * "First>" and the second entry begins with "<" and ends with "Last>".) This is - * therefore a sparse representation of the character property data. - * - * The resulting map is dense representation of the character data. It contains - * 2^16 = 65536 entries, each of which is a long integer. (Right now only 32 bits - * of this long value are used, but type long is used rather than int to facilitate - * future extensions of this source code generator that might require more than - * 32 bits to encode relevant character properties.) Entry k holds the encoded - * properties for character k. - * - * Method buildMap manages the transformation from the sparse representation to - * the dense representation. It calls method buildOne to handle the encoding - * of character property data from a single UnicodeSpec object into 32 bits. - * For undefined characters, method buildOne is not called and the map entry for - * that character is set to UnicodeSpec.UNASSIGNED. - * - * @param data character property data from the Unicode specification file - * @return an array of length 65536 with one entry for every possible char value - * - * @see GenerateCharacter#buildOne - */ - - static long[] buildMap(UnicodeSpec[] data, SpecialCaseMap[] specialMaps, PropList propList) - { - long[] result; - if (bLatin1 == true) { - result = new long[256]; - } else { - result = new long[1<<16]; - } - int k=0; - int codePoint = plane<<16; - UnicodeSpec nonCharSpec = new UnicodeSpec(); - for (int j = 0; j < data.length && k < result.length; j++) { - if (data[j].codePoint == codePoint) { - result[k] = buildOne(codePoint, data[j], specialMaps); - ++k; - ++codePoint; - } - else if(data[j].codePoint > codePoint) { - if (data[j].name.endsWith("Last>")) { - // build map data for all chars except last in range - while (codePoint < data[j].codePoint && k < result.length) { - result[k] = buildOne(codePoint, data[j], specialMaps); - ++k; - ++codePoint; - } - } - else { - // we have a few unassigned chars before data[j].codePoint - while (codePoint < data[j].codePoint && k < result.length) { - result[k] = buildOne(codePoint, nonCharSpec, specialMaps); - ++k; - ++codePoint; - } - } - k = data[j].codePoint & 0xFFFF; - codePoint = data[j].codePoint; - result[k] = buildOne(codePoint, data[j], specialMaps); - ++k; - ++codePoint; - } - else { - System.out.println("An error has occured during spec mapping."); - System.exit(0); - } - } - // if there are still unprocessed chars, process them - // as unassigned/undefined. - codePoint = (plane<<16) | k; - while (k < result.length) { - result[k] = buildOne(codePoint, nonCharSpec, specialMaps); - ++k; - ++codePoint; - } - // now add all extra supported properties from PropList, to the - // upper 16-bit - addExProp(result, propList, "Other_Lowercase", maskOtherLowercase); - addExProp(result, propList, "Other_Uppercase", maskOtherUppercase); - addExProp(result, propList, "Other_Alphabetic", maskOtherAlphabetic); - addExProp(result, propList, "Ideographic", maskIdeographic); - //addExProp(result, propList, "Other_Math", maskOtherMath); - //addExProp(result, propList, "Noncharacter_CodePoint", maskNoncharacterCP); - addExProp(result, propList, "ID_Start", maskIDStart); - addExProp(result, propList, "ID_Continue", maskIDContinue); - - return result; - } - - // The maximum and minimum offsets found while scanning the database - static int maxOffsetSeen = 0; - static int minOffsetSeen = 0; - - /** - * Some Unicode separator characters are not considered Java whitespace. - * @param c character to test - * @return true if c in an invalid Java whitespace character, false otherwise. - */ - static boolean isInvalidJavaWhiteSpace(int c) { - int[] exceptions = {0x00A0, 0x2007, 0x202F, 0xFEFF}; - boolean retValue = false; - for(int x=0;x= 0x0041) && (c <= 0x005A)) { - val = c - 0x0041; - resultA |= valueJavaSupradecimal; - // c is a-z - } else if ((c >= 0x0061) && (c <= 0x007A)) { - val = c - 0x0061; - resultA |= valueJavaSupradecimal; - // c is a full-width A-Z - } else if ((c >= 0xFF21) && (c <= 0xFF3A)) { - val = c - 0xFF21; - resultA |= valueJavaSupradecimal; - // c is a full-width a-z - } else if ((c >= 0xFF41) && (c <= 0xFF5A)) { - val = c - 0xFF41; - resultA |= valueJavaSupradecimal; - } else if (us.isDecimalValue()) { - val = us.decimalValue; - resultA |= valueDigit; - } else if (us.isDigitValue()) { - val = us.digitValue; - resultA |= valueDigit; - } else { - if (us.numericValue.length() == 0) { - break NUMERIC; // no numeric value at all - } else { - try { - val = Integer.parseInt(us.numericValue); - if (val >= 32 || val < 0) break STRANGE; - if (c == 0x215F) break STRANGE; - } catch(NumberFormatException e) { - break STRANGE; - } - resultA |= valueDigit; - } - } - if (val >= 32 || val < 0) break STRANGE; - resultA |= ((val - c & maskDigit) << shiftDigitOffset); - break NUMERIC; - } // end STRANGE - resultA |= valueStrangeNumeric; - } // end NUMERIC - - // record case mapping - int offset = 0; - // might have a 1:M mapping - int specialMap = SpecialCaseMap.find(c, specialCaseMaps); - boolean bHasUpper = (us.hasUpperMap()) || (specialMap != -1); - if (bHasUpper) { - resultA |= maskUpperCase; - } - if (specialMap != -1) { - // has mapping, but cannot record the - // proper offset; can only flag it and provide special case - // code in Character.java - offset = -1; - } - else if (us.hasUpperMap()) { - offset = c - us.upperMap; - } - - if (us.hasLowerMap()) { - resultA |= maskLowerCase; - if (offset == 0) - offset = us.lowerMap - c; - else if (offset != (us.lowerMap - c)) { - if (DEBUG) { - FAIL("Character " + hex(c) + - " has incompatible lowercase and uppercase mappings"); - } - } - } - if ((us.hasTitleMap() && us.titleMap != us.upperMap) || - (bHasUpper && us.hasLowerMap())) { - resultA |= maskTitleCase; - } - if (bHasUpper && !us.hasLowerMap() && !us.hasTitleMap() && verbose) { - System.out.println("Warning: Character " + hex4(c) + " has upper but " + - "no title case; Java won't know this"); - } - if (offset < minOffsetSeen) minOffsetSeen = offset; - if (offset > maxOffsetSeen) maxOffsetSeen = offset; - if (offset > maxOffset || offset < minOffset) { - if (DEBUG) { - FAIL("Case offset " + offset + " for character " + hex4(c) + " must be handled as a special case"); - } - offset = maskCase; - } - resultA |= ((offset & maskCase) << shiftCaseOffset); - - // record lexical info about this character - if (us.generalCategory == UnicodeSpec.LOWERCASE_LETTER - || us.generalCategory == UnicodeSpec.UPPERCASE_LETTER - || us.generalCategory == UnicodeSpec.TITLECASE_LETTER - || us.generalCategory == UnicodeSpec.MODIFIER_LETTER - || us.generalCategory == UnicodeSpec.OTHER_LETTER - || us.generalCategory == UnicodeSpec.LETTER_NUMBER) { - resultA |= valueJavaUnicodeStart; - } - else if (us.generalCategory == UnicodeSpec.COMBINING_SPACING_MARK - || us.generalCategory == UnicodeSpec.NON_SPACING_MARK - || us.generalCategory == UnicodeSpec.DECIMAL_DIGIT_NUMBER) { - resultA |= valueJavaUnicodePart; - } - else if (us.generalCategory == UnicodeSpec.CONNECTOR_PUNCTUATION) { - resultA |= valueJavaStartUnicodePart; - } - else if (us.generalCategory == UnicodeSpec.CURRENCY_SYMBOL) { - resultA |= valueJavaOnlyStart; - } - else if (((c >= 0x0000) && (c <= 0x0008)) - || ((c >= 0x000E) && (c <= 0x001B)) - || ((c >= 0x007F) && (c <= 0x009F)) - || us.generalCategory == UnicodeSpec.FORMAT) { - resultA |= valueIgnorable; - } - else if (us.generalCategory == UnicodeSpec.SPACE_SEPARATOR - || us.generalCategory == UnicodeSpec.LINE_SEPARATOR - || us.generalCategory == UnicodeSpec.PARAGRAPH_SEPARATOR) { - if (!isInvalidJavaWhiteSpace(c)) resultA |= valueJavaWhitespace; - } - else if (((c >= 0x0009) && (c <= 0x000D)) - || ((c >= 0x001C) && (c <= 0x001F))) { - resultA |= valueJavaWhitespace; - } - - // record bidi category - if (!nobidi) { - int tmpBidi = - (us.bidiCategory > UnicodeSpec.DIRECTIONALITY_OTHER_NEUTRALS || - us.bidiCategory == -1) ? maskBidi : (us.bidiCategory << shiftBidi); - resultA |= tmpBidi; - } - - // record mirrored property - if (!nomirror) { - resultA |= us.mirrored ? maskMirrored : 0; - } - - if (identifiers) { - long replacement = 0; - if ((resultA & maskIdentifierInfo) >= lowJavaStart) { - replacement |= bitJavaStart; - } - if ( ((resultA & nonzeroJavaPart) != 0) - && ((resultA & maskIdentifierInfo) != valueIgnorable)) { - replacement |= bitJavaPart; - } - resultA = replacement; - } - return resultA; - } - - static void addExProp(long[] map, PropList propList, String prop, long mask) { - List cps = propList.codepoints(prop); - if (cps != null) { - for (Integer cp : cps) { - if (cp < map.length) - map[cp] |= mask; - } - } - } - - /** - * This is the heart of the table compression strategy. The inputs are a map - * and a number of bits (size). The map is simply an array of long integer values; - * the number of bits indicates how index values for that map are to be split. - * The length of the given map must be a multiple of (1 << size). The result is - * a new map z and a compressed table t such that for every valid index value k - * for the original map, t[(z[k>>size]<> size) << size) != n) { - FAIL("Length " + n + " is not a multiple of " + (1 << size)); - } - int m = 1 << size; - // We know the final length of the new map up front. - long[] newmap = new long[n >> size]; - // The buffer is used temporarily to hold data for the compressed table - // because we don't know its final length yet. - long[] buffer = new long[n]; - int ptr = 0; -OUTER: for (int i = 0; i < n; i += m) { - // For every block of size m in the original map... - MIDDLE: for (int j = 0; j < ptr; j += m) { - // Find out whether there is already a block just like it in the buffer. - for (int k = 0; k < m; k++) { - if (buffer[j+k] != map[i+k]) - continue MIDDLE; - } - // There is a block just like it at position j, so just - // put its index into the new map (thereby sharing it). - newmap[i >> size] = (j >> size); - continue OUTER; - } // end MIDDLE - // There is no block just like it already, so add it to - // the buffer and put its index into the new map. - for (int k = 0; k < m; k++) { - buffer[ptr+k] = map[i+k]; - } - newmap[i >> size] = (ptr >> size); - ptr += m; - } // end OUTER - // Now we know how long the compressed table should be, - // so create a new array and copy data from the temporary buffer. - long[] newdata = new long[ptr]; - for (int j = 0; j < ptr; j++) { - newdata[j] = buffer[j]; - } - // Return the new map and the new data table. - long[][] result = { newmap, newdata }; - return result; - } - - /** - * Once the compressed tables have been computed, this method reads in a - * template file for the source code to be generated and writes out the final - * source code by acting as a sort of specialized macro processor. - * - * The first output line is a comment saying that the file was automatically - * generated; it includes a timestamp. All other output is generated by - * reading a line from the template file, performing macro replacements, - * and then writing the resulting line or lines of code to the output file. - * - * This method handles the I/O, the timestamp comment, and the locating of - * macro calls within each input line. The method replaceCommand is called - * to generate replacement text for each macro call. - * - * Macro calls to be replaced are indicated in the template file by - * occurrences of the commandMarker "$$". The rest of the call may consist - * of Java letters (including the underscore "_") and also of balanced - * parentheses. - * - * @param theTemplateFileName - * the file name for the template input file - * @param theOutputFileName - * the file name for the source code output file - * - * @see GenerateCharacter#replaceCommand - */ - - static void generateCharacterClass(String theTemplateFileName, - String theOutputFileName) - throws FileNotFoundException, IOException { - BufferedReader in = new BufferedReader(new FileReader(theTemplateFileName)); - PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(theOutputFileName))); - out.println(commentStart + - " This file was generated AUTOMATICALLY from a template file " + - new java.util.Date() + commentEnd); - int marklen = commandMarker.length(); - LOOP: while(true) { - try { - String line = in.readLine(); - if (line == null) break LOOP; - int pos = 0; - int depth = 0; - while ((pos = line.indexOf(commandMarker, pos)) >= 0) { - int newpos = pos + marklen; - char ch = 'x'; - SCAN: while (newpos < line.length() && - (Character.isJavaIdentifierStart(ch = line.charAt(newpos)) - || ch == '(' || (ch == ')' && depth > 0))) { - ++newpos; - if (ch == '(') { - ++depth; - } - else if (ch == ')') { - --depth; - if (depth == 0) - break SCAN; - } - } - String replacement = replaceCommand(line.substring(pos + marklen, newpos)); - line = line.substring(0, pos) + replacement + line.substring(newpos); - pos += replacement.length(); - } - out.println(line); - } - catch (IOException e) { - break LOOP; - } - } - in.close(); - out.close(); - } - - /** - * The replaceCommand method takes a command (a macro call without the - * leading marker "$$") and computes replacement text for it. - * - * Most of the commands are simply names of integer constants that are defined - * in the source code of this GenerateCharacter class. The replacement text is - * simply the value of the constant as an appropriately formatted integer literal. - * - * Two cases are more complicated, however. The command "Tables" causes the - * final map and compressed tables to be emitted, with elaborate comments - * describing their contents. (This is actually handled by method genTables.) - * The command "Lookup(xxx)", where "xxx" is the name of a variable, generates - * an expression that will return the character property data for the character - * whose code is the value of the variable "xxx". (this is handled by method - * "genAccess".) - * - * @param x a command from the template file to be replaced - * @return the replacement text, as a String - * - * @see GenerateCharacter#genTables - * @see GenerateCharacter#genAccess - * @see GenerateCharacter#generateCharacterClass - */ - - static String replaceCommand(String x) { - if (x.equals("Tables")) return genTables(); - if (x.equals("Initializers")) return genInitializers(); - if (x.length() >= 9 && x.substring(0, 7).equals("Lookup(") && - x.substring(x.length()-1).equals(")") ) - return genAccess("A", x.substring(7, x.length()-1), (identifiers ? 2 : 32)); - if (x.length() >= 11 && x.substring(0, 9).equals("LookupEx(") && - x.substring(x.length()-1).equals(")") ) - return genAccess("B", x.substring(9, x.length()-1), 16); - if (x.equals("shiftType")) return Long.toString(shiftType); - if (x.equals("shiftIdentifierInfo")) return Long.toString(shiftIdentifierInfo); - if (x.equals("maskIdentifierInfo")) return "0x" + hex8(maskIdentifierInfo); - if (x.equals("maskUnicodePart")) return "0x" + hex8(maskUnicodePart); - if (x.equals("shiftCaseOffset")) return Long.toString(shiftCaseOffset); - if (x.equals("shiftCaseInfo")) return Long.toString(shiftCaseInfo); - if (x.equals("shiftCaseOffsetSign")) return Long.toString(shiftCaseOffsetSign); - if (x.equals("maskCase")) return "0x" + hex8(maskCase); - if (x.equals("maskCaseOffset")) return "0x" + hex8(maskCaseOffset); - if (x.equals("maskLowerCase")) return "0x" + hex8(maskLowerCase); - if (x.equals("maskUpperCase")) return "0x" + hex8(maskUpperCase); - if (x.equals("maskTitleCase")) return "0x" + hex8(maskTitleCase); - if (x.equals("maskOtherLowercase")) return "0x" + hex4(maskOtherLowercase >> 32); - if (x.equals("maskOtherUppercase")) return "0x" + hex4(maskOtherUppercase >> 32); - if (x.equals("maskOtherAlphabetic")) return "0x" + hex4(maskOtherAlphabetic >> 32); - if (x.equals("maskIdeographic")) return "0x" + hex4(maskIdeographic >> 32); - if (x.equals("maskIDStart")) return "0x" + hex4(maskIDStart >> 32); - if (x.equals("maskIDContinue")) return "0x" + hex4(maskIDContinue >> 32); - if (x.equals("valueIgnorable")) return "0x" + hex8(valueIgnorable); - if (x.equals("valueJavaUnicodeStart")) return "0x" + hex8(valueJavaUnicodeStart); - if (x.equals("valueJavaOnlyStart")) return "0x" + hex8(valueJavaOnlyStart); - if (x.equals("valueJavaUnicodePart")) return "0x" + hex8(valueJavaUnicodePart); - if (x.equals("valueJavaOnlyPart")) return "0x" + hex8(valueJavaOnlyPart); - if (x.equals("valueJavaWhitespace")) return "0x" + hex8(valueJavaWhitespace); - if (x.equals("lowJavaStart")) return "0x" + hex8(lowJavaStart); - if (x.equals("nonzeroJavaPart")) return "0x" + hex8(nonzeroJavaPart); - if (x.equals("bitJavaStart")) return "0x" + hex8(bitJavaStart); - if (x.equals("bitJavaPart")) return Long.toString(bitJavaPart); - if (x.equals("valueUnicodeStart")) return "0x" + hex8(valueUnicodeStart); - if (x.equals("maskIsJavaIdentifierStart")) return "0x" + hex(maskIsJavaIdentifierStart); - if (x.equals("maskIsJavaIdentifierPart")) return "0x" + hex(maskIsJavaIdentifierPart); - if (x.equals("shiftDigitOffset")) return Long.toString(shiftDigitOffset); - if (x.equals("maskDigitOffset")) return "0x" + hex(maskDigitOffset); - if (x.equals("maskDigit")) return "0x" + hex(maskDigit); - if (x.equals("shiftNumericType")) return Long.toString(shiftNumericType); - if (x.equals("maskNumericType")) return "0x" + hex(maskNumericType); - if (x.equals("valueNotNumeric")) return "0x" + hex8(valueNotNumeric); - if (x.equals("valueDigit")) return "0x" + hex8(valueDigit); - if (x.equals("valueStrangeNumeric")) return "0x" + hex8(valueStrangeNumeric); - if (x.equals("valueJavaSupradecimal")) return "0x" + hex8(valueJavaSupradecimal); - if (x.equals("valueDigit")) return "0x" + hex8(valueDigit); - if (x.equals("valueStrangeNumeric")) return "0x" + hex8(valueStrangeNumeric); - if (x.equals("maskType")) return "0x" + hex(maskType); - if (x.equals("shiftBidi")) return Long.toString(shiftBidi); - if (x.equals("maskBidi")) return "0x" + hex(maskBidi); - if (x.equals("maskMirrored")) return "0x" + hex8(maskMirrored); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.UNASSIGNED][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.UNASSIGNED); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.UPPERCASE_LETTER][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.UPPERCASE_LETTER); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.LOWERCASE_LETTER][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.LOWERCASE_LETTER); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.TITLECASE_LETTER][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.TITLECASE_LETTER); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.MODIFIER_LETTER][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.MODIFIER_LETTER); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.OTHER_LETTER][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.OTHER_LETTER); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.NON_SPACING_MARK][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.NON_SPACING_MARK); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.ENCLOSING_MARK][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.ENCLOSING_MARK); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.COMBINING_SPACING_MARK][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.COMBINING_SPACING_MARK); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.DECIMAL_DIGIT_NUMBER][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.DECIMAL_DIGIT_NUMBER); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.OTHER_NUMBER][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.OTHER_NUMBER); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.SPACE_SEPARATOR][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.SPACE_SEPARATOR); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.LINE_SEPARATOR][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.LINE_SEPARATOR); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.PARAGRAPH_SEPARATOR][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.PARAGRAPH_SEPARATOR); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.CONTROL][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.CONTROL); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.FORMAT][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.FORMAT); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.PRIVATE_USE][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.PRIVATE_USE); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.SURROGATE][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.SURROGATE); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.DASH_PUNCTUATION][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.DASH_PUNCTUATION); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.START_PUNCTUATION][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.START_PUNCTUATION); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.END_PUNCTUATION][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.END_PUNCTUATION); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.INITIAL_QUOTE_PUNCTUATION][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.INITIAL_QUOTE_PUNCTUATION); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.FINAL_QUOTE_PUNCTUATION][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.FINAL_QUOTE_PUNCTUATION); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.CONNECTOR_PUNCTUATION][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.CONNECTOR_PUNCTUATION); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.OTHER_PUNCTUATION][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.OTHER_PUNCTUATION); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.LETTER_NUMBER][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.LETTER_NUMBER); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.MATH_SYMBOL][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.MATH_SYMBOL); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.CURRENCY_SYMBOL][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.CURRENCY_SYMBOL); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.MODIFIER_SYMBOL][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.MODIFIER_SYMBOL); - if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.OTHER_SYMBOL][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.OTHER_SYMBOL); - if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_LEFT_TO_RIGHT][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.DIRECTIONALITY_LEFT_TO_RIGHT); - if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING); - if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE); - if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_RIGHT_TO_LEFT][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.DIRECTIONALITY_RIGHT_TO_LEFT); - if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC); - if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING); - if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE); - if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_POP_DIRECTIONAL_FORMAT][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.DIRECTIONALITY_POP_DIRECTIONAL_FORMAT); - if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_EUROPEAN_NUMBER][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.DIRECTIONALITY_EUROPEAN_NUMBER); - if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR); - if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR); - if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_ARABIC_NUMBER][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.DIRECTIONALITY_ARABIC_NUMBER); - if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_COMMON_NUMBER_SEPARATOR][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.DIRECTIONALITY_COMMON_NUMBER_SEPARATOR); - if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_NONSPACING_MARK][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.DIRECTIONALITY_NONSPACING_MARK); - if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_BOUNDARY_NEUTRAL][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.DIRECTIONALITY_BOUNDARY_NEUTRAL); - if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_PARAGRAPH_SEPARATOR][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.DIRECTIONALITY_PARAGRAPH_SEPARATOR); - if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_SEGMENT_SEPARATOR][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.DIRECTIONALITY_SEGMENT_SEPARATOR); - if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_WHITESPACE][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.DIRECTIONALITY_WHITESPACE); - if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_OTHER_NEUTRALS][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.DIRECTIONALITY_OTHER_NEUTRALS); - if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE); - if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE); - if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_FIRST_STRONG_ISOLATE][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.DIRECTIONALITY_FIRST_STRONG_ISOLATE); - if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE][UnicodeSpec.LONG])) - return Integer.toString(UnicodeSpec.DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE); - FAIL("Unknown text substitution marker " + commandMarker + x); - return commandMarker + x; - } - - /** - * The genTables method generates source code for all the lookup tables - * needed to represent the various Unicode character properties. - * It simply calls the method genTable once for each table to be generated - * and then generates a summary comment. - * - * @return the replacement text for the "Tables" command, as a String - * - * @see GenerateCharacter#genTable - * @see GenerateCharacter#replaceCommand - */ - static String genTables() { - int n = sizes.length; - StringBuffer result = new StringBuffer(); - // liu : Add a comment showing the source of this table - result.append(commentStart + " The following tables and code generated using:" + - commentEnd + "\n "); - result.append(commentStart + ' ' + commandLineDescription + commentEnd + "\n "); - - if (plane == 0 && bLatin1 == false) { - genCaseMapTableDeclaration(result); - genCaseMapTable(initializers, specialCaseMaps); - } - int totalBytes = 0; - for (int k = 0; k < n - 1; k++) { - genTable(result, tableNames[k], tables[k], 0, bytes[k]<<3, sizes[k], preshifted[k], - sizes[k+1], false, false, k==0); - int s = bytes[k]; - if (s == 1 && useCharForByte) { - s = 2; - } - totalBytes += tables[k].length * s; - } - genTable(result, "A", tables[n - 1], 0, (identifiers ? 2 : 32), - sizes[n - 1], false, 0, true, !(identifiers), false); - - // If we ever need more than 32 bits to represent the character properties, - // then a table "B" may be needed as well. - genTable(result, "B", tables[n - 1], 32, 16, sizes[n - 1], false, 0, true, true, false); - - totalBytes += ((((tables[n - 1].length * (identifiers ? 2 : 32)) + 31) >> 5) << 2); - result.append(commentStart); - result.append(" In all, the character property tables require "); - result.append(totalBytes).append(" bytes.").append(commentEnd); - if (verbose) { - System.out.println("The character property tables require " - + totalBytes + " bytes."); - } - return result.toString(); - } - - /** - * The genInitializers method generates the body of the - * ensureInitted() method, which enables lazy initialization of - * the case map table and other tables. - */ - static String genInitializers() { - return initializers.toString(); - } - - /** - * Return the total number of bytes needed by all tables. This is a stripped- - * down copy of genTables(). - */ - static int getTotalBytes() { - int n = sizes.length; - int totalBytes = 0; - for (int k = 0; k < n - 1; k++) { - totalBytes += tables[k].length * bytes[k]; - } - totalBytes += ((((tables[n - 1].length * (identifiers ? 2 : 32)) - + 31) >> 5) << 2); - return totalBytes; - } - - static void appendEscapedStringFragment(StringBuffer result, - char[] line, - int length, - boolean lastFragment) { - result.append(" \""); - for (int k=0; k>= $$bits;\n"+ - " }\n"+ - " }\n"+ - " assert (j == $$size);\n"+ - " }\n"; - - static String SAME_SIZE_INITIALIZER = - " { // THIS CODE WAS AUTOMATICALLY CREATED BY GenerateCharacter:\n"+ - " assert ($$name_DATA.length() == $$size);\n"+ - // " $$name = new $$type[$$size];\n"+ - " for (int i=0; i<$$size; ++i)\n"+ - " $$name[i] = ($$type)$$name_DATA.charAt(i);\n"+ - " }\n"; - - static String BIG_INITIALIZER = - " { // THIS CODE WAS AUTOMATICALLY CREATED BY GenerateCharacter:\n"+ - // " $$name = new $$type[$$size];\n"+ - " int len = $$name_DATA.length();\n"+ - " int j=0;\n"+ - " int charsInEntry=0;\n"+ - " $$type entry=0;\n"+ - " for (int i=0; i 0) ? SMALL_INITIALIZER : BIG_INITIALIZER); - if (entriesPerChar == -2) { - template = INT32_INITIALIZER; - } - int marklen = commandMarker.length(); - int pos = 0; - while ((pos = template.indexOf(commandMarker, pos)) >= 0) { - int newpos = pos + marklen; - char ch = 'x'; - while (newpos < template.length() && - Character.isJavaIdentifierStart(ch = template.charAt(newpos)) && - ch != '_') // Don't allow this in token names - ++newpos; - String token = template.substring(pos+marklen, newpos); - String replacement = "ERROR"; - - if (token.equals("name")) replacement = name; - else if (token.equals("type")) replacement = type; - else if (token.equals("bits")) replacement = ""+bits; - else if (token.equals("size")) replacement = ""+size; - else if (token.equals("entriesPerChar")) replacement = ""+entriesPerChar; - else if (token.equals("charsPerEntry")) replacement = ""+(-entriesPerChar); - else FAIL("Unrecognized token: " + token); - - template = template.substring(0, pos) + replacement + template.substring(newpos); - pos += replacement.length(); - } - initializers.append(template); - } - - /** - * The genTable method generates source code for one lookup table. - * Most of the complexity stems from handling various options as to - * the type of the array components, the precise representation of the - * values, the format in which to render each value, the number of values - * to emit on each line of source code, and the kinds of useful comments - * to be generated. - * - * @param result a StringBuffer, to which the generated source code - * text is to be appended - * @param name the name of the table - * @param table the table data (an array of long values) - * @param extract a distance, in bits, by which each entry of the table - * is to be right-shifted before it is processed - * @param bits the number of bits (not bytes) to be used to represent - * each table entry - * @param size the table data is divided up into blocks of size (1<> 5) << 2; - if (bits == 8 && useCharForByte) { - sizeOfTable *= 2; - } - result.append(sizeOfTable); - result.append(" bytes.").append(commentEnd).append("\n\n"); - if (Csyntax) - result.append(" static "); - else - result.append(" static final "); - result.append(atype); - result.append(" ").append(name).append("["); - if (Csyntax) - result.append(table.length >> (bits == 1 ? 5 : bits == 2 ? 4 : bits == 4 ? 3 : 0)); - if (tableAsString) { - if (noConversion) { - result.append("] = (\n"); - } else { - result.append("] = new ").append(atype).append("["+table.length+"];\n "); - result.append("static final String ").append(name).append("_DATA =\n"); - } - int CHARS_PER_LINE = 8; - StringBuffer theString = new StringBuffer(); - int entriesInCharSoFar = 0; - char ch = '\u0000'; - int charsPerEntry = -entriesPerChar; - for (int j=0; j> extract; - long entry; - if ("A".equals(name)) - entry = (table[j] & 0xffffffffL) >> extract; - else - entry = (table[j] >> extract); - if (shiftEntries) entry <<= shift; - if (entry >= (1L << bits)) { - FAIL("Entry too big"); - } - if (entriesPerChar > 0) { - // Pack multiple entries into a character - ch = (char)(((int)ch >> bits) | (entry << (entriesPerChar-1)*bits)); - ++entriesInCharSoFar; - if (entriesInCharSoFar == entriesPerChar) { - // Character is full - theString.append(ch); - entriesInCharSoFar = 0; - ch = '\u0000'; - } - } - else { - // Use multiple characters per entry - for (int k=0; k> ((charsPerEntry-1)*16)); - entry <<= 16; - theString.append(ch); - } - } - } - if (entriesInCharSoFar > 0) { - while (entriesInCharSoFar < entriesPerChar) { - ch = (char)((int)ch >> bits); - ++entriesInCharSoFar; - } - theString.append(ch); - entriesInCharSoFar = 0; - } - result.append(Utility.formatForSource(theString.toString(), " ")); - if (noConversion) { - result.append(").toCharArray()"); - } - result.append(";\n\n "); - - if (!noConversion) { - addInitializer(name, atype, entriesPerChar, bits, table.length); - } - } - else { - result.append("] = {"); - boolean castEntries = shiftEntries && (bits < 32); - int printPerLine = hexFormat ? (bits == 1 ? 32*4 : - bits == 2 ? 16*4 : - bits == 4 ? 8*4 : - bits == 8 ? 8 : - bits == 16 ? 8 : - bits == 32 ? 4 : 2) : - (bits == 8 ? 8 : - bits == 16 ? 8 : 4); - int printMask = properties ? 0 : - Math.min(1 << size, - printPerLine >> (castEntries ? (Csyntax ? 2 : 1) : 0)) - 1; - int commentShift = ((1 << size) == table.length) ? 0 : size; - int commentMask = ((1 << size) == table.length) ? printMask : (1 << size) - 1; - long val = 0; - for (int j = 0; j < table.length; j++) { - if ((j & printMask) == 0) { - while (result.charAt(result.length() - 1) == ' ') - result.setLength(result.length() - 1); - result.append("\n "); - } - PRINT: { - if (castEntries) - result.append("(").append(atype).append(")("); - long entry = table[j] >> extract; - int packMask = ((1 << (bits == 1 ? 5 : bits == 2 ? 4 : bits == 4 ? 3 : 2)) - 1); - int k = j & packMask; - if (bits >= 8) - val = entry; - else if (k == 0) { - val = entry; - break PRINT; - } - else { - val |= (entry << (k*bits)); - if (k != packMask) - break PRINT; - } - if (val > maxPosEntry && !Csyntax) { // liu - // For values that are out of range, convert them to in-range negative values. - // Actually, output the '-' and convert them to the negative of the corresponding - // in-range negative values. E.g., convert 130 == -126 (in 8 bits) -> 126. - result.append('-'); - val = maxPosEntry + maxPosEntry + 2 - val; - } - if (hexFormat) { - result.append("0x"); - if (bits == 8) - result.append(hex2((byte)val)); - else if (bits == 16) - result.append(hex4((short)val)); - else if (bits == 32 || bits < 8) - result.append(hex8((int)val)); - else { - result.append(hex16(val)); - if (!Csyntax) - result.append("L"); - } - } - else { - if (bits == 8) - result.append(dec3(val)); - else if (bits == 64) { - result.append(dec5(val)); - if (!Csyntax) - result.append("L"); - } - else - result.append(dec5(val)); - } - if (shiftEntries) - result.append("<<").append(shift); - if (castEntries) result.append(")"); - if (j < (table.length - 1)) - result.append(", "); - else - result.append(" "); - if ((j & printMask) == printMask) { - result.append(" ").append(commentStart).append(" "); - if (hexComment) - result.append("0x").append(hex4((j & ~commentMask) << (16 - size))); - else - result.append(dec3((j & ~commentMask) >> commentShift)); - if (properties) propertiesComments(result, val); - result.append(commentEnd); - } - } // end PRINT - } - result.append("\n };\n\n "); - } - } - - static void genCaseMapTableDeclaration(StringBuffer result) { - String myTab = " "; - result.append(myTab + "static final char[][][] charMap;\n"); - } - - static void genCaseMapTable(StringBuffer result, SpecialCaseMap[] specialCaseMaps){ - String myTab = " "; - int ch; - char[] map; - result.append(myTab + "charMap = new char[][][] {\n"); - for (int x = 0; x < specialCaseMaps.length; x++) { - ch = specialCaseMaps[x].getCharSource(); - map = specialCaseMaps[x].getUpperCaseMap(); - result.append(myTab + myTab); - result.append("{ "); - result.append("{\'\\u"+hex4(ch)+"\'}, {"); - for (int y = 0; y < map.length; y++) { - result.append("\'\\u"+hex4(map[y])+"\', "); - } - result.append("} },\n"); - } - result.append(myTab + "};\n"); - - } - - /** - * The propertiesComments method generates comments describing encoded - * character properties. - * - * @param result a StringBuffer, to which the generated source code - * text is to be appended - * @param val encoded character properties - * - * @see GenerateCharacter#genTable - */ - - static void propertiesComments(StringBuffer result, long val) { - result.append(" "); - switch ((int)(val & maskType)) { - case UnicodeSpec.CONTROL: - result.append("Cc"); - break; - case UnicodeSpec.FORMAT: - result.append("Cf"); - break; - case UnicodeSpec.PRIVATE_USE: - result.append("Co"); - break; - case UnicodeSpec.SURROGATE: - result.append("Cs"); - break; - case UnicodeSpec.LOWERCASE_LETTER: - result.append("Ll"); - break; - case UnicodeSpec.MODIFIER_LETTER: - result.append("Lm"); - break; - case UnicodeSpec.OTHER_LETTER: - result.append("Lo"); - break; - case UnicodeSpec.TITLECASE_LETTER: - result.append("Lt"); - break; - case UnicodeSpec.UPPERCASE_LETTER: - result.append("Lu"); - break; - case UnicodeSpec.COMBINING_SPACING_MARK: - result.append("Mc"); - break; - case UnicodeSpec.ENCLOSING_MARK: - result.append("Me"); - break; - case UnicodeSpec.NON_SPACING_MARK: - result.append("Mn"); - break; - case UnicodeSpec.DECIMAL_DIGIT_NUMBER: - result.append("Nd"); - break; - case UnicodeSpec.LETTER_NUMBER: - result.append("Nl"); - break; - case UnicodeSpec.OTHER_NUMBER: - result.append("No"); - break; - case UnicodeSpec.CONNECTOR_PUNCTUATION: - result.append("Pc"); - break; - case UnicodeSpec.DASH_PUNCTUATION: - result.append("Pd"); - break; - case UnicodeSpec.END_PUNCTUATION: - result.append("Pe"); - break; - case UnicodeSpec.OTHER_PUNCTUATION: - result.append("Po"); - break; - case UnicodeSpec.START_PUNCTUATION: - result.append("Ps"); - break; - case UnicodeSpec.CURRENCY_SYMBOL: - result.append("Sc"); - break; - case UnicodeSpec.MODIFIER_SYMBOL: - result.append("Sk"); - break; - case UnicodeSpec.MATH_SYMBOL: - result.append("Sm"); - break; - case UnicodeSpec.OTHER_SYMBOL: - result.append("So"); - break; - case UnicodeSpec.LINE_SEPARATOR: - result.append("Zl"); break; - case UnicodeSpec.PARAGRAPH_SEPARATOR: - result.append("Zp"); - break; - case UnicodeSpec.SPACE_SEPARATOR: - result.append("Zs"); - break; - case UnicodeSpec.UNASSIGNED: - result.append("unassigned"); - break; - } - - switch ((int)((val & maskBidi) >> shiftBidi)) { - case UnicodeSpec.DIRECTIONALITY_LEFT_TO_RIGHT: - result.append(", L"); - break; - case UnicodeSpec.DIRECTIONALITY_RIGHT_TO_LEFT: - result.append(", R"); - break; - case UnicodeSpec.DIRECTIONALITY_EUROPEAN_NUMBER: - result.append(", EN"); - break; - case UnicodeSpec.DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR: - result.append(", ES"); - break; - case UnicodeSpec.DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR: - result.append(", ET"); - break; - case UnicodeSpec.DIRECTIONALITY_ARABIC_NUMBER: - result.append(", AN"); - break; - case UnicodeSpec.DIRECTIONALITY_COMMON_NUMBER_SEPARATOR: - result.append(", CS"); - break; - case UnicodeSpec.DIRECTIONALITY_PARAGRAPH_SEPARATOR: - result.append(", B"); - break; - case UnicodeSpec.DIRECTIONALITY_SEGMENT_SEPARATOR: - result.append(", S"); - break; - case UnicodeSpec.DIRECTIONALITY_WHITESPACE: - result.append(", WS"); - break; - case UnicodeSpec.DIRECTIONALITY_OTHER_NEUTRALS: - result.append(", ON"); - break; - } - if ((val & maskUpperCase) != 0) { - result.append(", hasUpper (subtract "); - result.append((val & maskCaseOffset) >> shiftCaseOffset).append(")"); - } - if ((val & maskLowerCase) != 0) { - result.append(", hasLower (add "); - result.append((val & maskCaseOffset) >> shiftCaseOffset).append(")"); - } - if ((val & maskTitleCase) != 0) { - result.append(", hasTitle"); - } - if ((val & maskIdentifierInfo) == valueIgnorable) { - result.append(", ignorable"); - } - if ((val & maskIdentifierInfo) == valueJavaUnicodePart) { - result.append(", identifier part"); - } - if ((val & maskIdentifierInfo) == valueJavaStartUnicodePart) { - result.append(", underscore"); - } - if ((val & maskIdentifierInfo) == valueJavaWhitespace) { - result.append(", whitespace"); - } - if ((val & maskIdentifierInfo) == valueJavaOnlyStart) { - result.append(", currency"); - } - if ((val & maskIdentifierInfo) == valueJavaUnicodeStart) { - result.append(", identifier start"); - } - if ((val & maskNumericType) == valueDigit) { - result.append(", decimal "); - result.append((val & maskDigitOffset) >> shiftDigitOffset); - } - if ((val & maskNumericType) == valueStrangeNumeric) { - result.append(", strange"); - } - if ((val & maskNumericType) == valueJavaSupradecimal) { - result.append(", supradecimal "); - result.append((val & maskDigitOffset) >> shiftDigitOffset); - } - } - - static String[] tableNames = { "X", "Y", "Z", "P", "Q", "R", "S", "T", "U", "V", "W" }; - - static String tableName(int j) { return tableNames[j]; } - - /** - * The genAccess method generates source code for one table access expression. - * - * Most of the complexity stems from handling various options as to - * table representation, such as whether it contains values so large that - * they are represented as negative values and whether the table values are - * preshifted. This method also avoids such "ugly" expressions as shifting - * by distance zero, masking when no masking is necessary, and so on. - * For clarity, it generates expressions that do not rely on operator - * precedence, but otherwise it avoids generating redundant parentheses. - * - * A generated expression might look like A[Y[(X[ch>>6]<<6)|(ch&0x3F)]] - * or A[Z[Y[(X[ch>>7]<<4)|((ch>>3)&0xF)]|(ch&0x7)]], for example. - * - * @param tbl the name of the final table to be accessed - * @param var the variable name that appeared in parentheses in the - * "Lookup" command - * @param bits the number of bits (not bytes) to be used to represent - * the final table entry - * @return the replacement text for the "Lookup(xxx)" command, as a String - * - * @see GenerateCharacter#replaceCommand - */ - - static String genAccess(String tbl, String var, int bits) { - String access = null; - int bitoffset = bits == 1 ? 5 : bits == 2 ? 4 : bits == 4 ? 3 : 0; - for (int k = 0; k < sizes.length; k++) { - int offset = ((k < sizes.length - 1) ? 0 : bitoffset); - int shift = shifts[k] + offset; - String shifted = (shift == 0) ? var : "(" + var + ">>" + shift + ")"; - int mask = (1 << (sizes[k] - offset)) - 1; - String masked = (k == 0) ? shifted : - "(" + shifted + "&0x" + hex(mask) + ")"; - String index = (k == 0) ? masked : - (mask == 0) ? access : "(" + access + "|" + masked + ")"; - String indexNoParens = (index.charAt(0) != '(') ? index : - index.substring(1, index.length() - 1); - String tblname = (k == sizes.length - 1) ? tbl : tableName(k); - String fetched = tblname + "[" + indexNoParens + "]"; - String zeroextended = (zeroextend[k] == 0) ? fetched : - "(" + fetched + "&0x" + hex(zeroextend[k]) + ")"; - int adjustment = preshifted[k] ? 0 : - sizes[k+1] - ((k == sizes.length - 2) ? bitoffset : 0); - String adjusted = (preshifted[k] || adjustment == 0) ? zeroextended : - "(" + zeroextended + "<<" + adjustment + ")"; - String bitshift = (bits == 1) ? "(" + var + "&0x1F)" : - (bits == 2) ? "((" + var + "&0xF)<<1)" : - (bits == 4) ? "((" + var + "&7)<<2)" : null; - String extracted = ((k < sizes.length - 1) || (bits >= 8)) ? adjusted : - "((" + adjusted + ">>" + bitshift + ")&" + - (bits == 4 ? "0xF" : "" + ((1 << bits) - 1)) + ")"; - access = extracted; - } - return access; - } - - /* The command line arguments are decoded and used to set the following - global variables. - */ - - static boolean verbose = false; - static boolean nobidi = false; - static boolean nomirror = false; - static boolean identifiers = false; - static boolean Csyntax = false; - static String TemplateFileName = null; - static String OutputFileName = null; - static String UnicodeSpecFileName = null; // liu - static String SpecialCasingFileName = null; - static String PropListFileName = null; - static String DerivedPropsFileName = null; - static boolean useCharForByte = false; - static int[] sizes; - static int bins = 0; // liu; if > 0, then perform search - static boolean tableAsString = false; - static boolean bLatin1 = false; - - static String commandLineDescription; - - /* Other global variables, equal in length to the "sizes" array. */ - - static int[] shifts; - static int[] zeroextend; - static int[] bytes; - static boolean[] preshifted; - static long[][] tables; - - - /* Other global variables */ - static String commentStart; - static String commentEnd; - - static StringBuffer initializers = new StringBuffer(); - - /* special casing rules for 1:M toUpperCase mappings */ - static SpecialCaseMap[] specialCaseMaps; - - /** - * Process the command line arguments. - * - * The allowed flags in command line are: - *
- *
-verbose
Emit comments to standard output describing - * what's going on during the processing. - *
-nobidi
Do not include bidi categories in the - * encoded character properties. - *
-nomirror
Do no include mirror property in the encoded - * character properties. - *
-identifiers
Generate tables for scanning identifiers only. - *
-c
Output code in C syntax instead of Java syntax. - *
-o filename
Specify output file name. - *
-template filename
Specify template input file name. - *
-spec filename
Specify Unicode spec file name. - *
-specialcasing filename
Specify Unicode special casing file name. - *
-search bins
Try different partitions into the specified - * number of bins. E.g., for 2 bins, try - * 16 0, 15 1,..., 0 16. - *
-string
Create table as string. Only valid with Java - * syntax. - *
-latin1
Create a latin 1 only property table. - *
- * In addition, decimal literals may appear as command line arguments; - * each one represents the number of bits of the character to be broken - * off at each lookup step. If present, they must add up to 16 (the number - * of bits in a char value). For smaller tables, the last value should - * be 0; values other than the last one may not be zero. If no such - * numeric values are provided, default values are used. - * - * @param args the command line arguments, as an array of String - * - * @see GenerateCharacter#main - */ - - static void processArgs(String[] args) { - StringBuffer desc = new StringBuffer("java GenerateCharacter"); - for (int j=0; j 10) - FAIL("Bin count must be >= 1 and <= 10"); - } - } - else if (args[j].equals("-template")) { - if (j == args.length - 1) - FAIL("File name missing after -template"); - else - TemplateFileName = args[++j]; - } - else if (args[j].equals("-spec")) { // liu - if (j == args.length - 1) { - FAIL("File name missing after -spec"); - } - else { - UnicodeSpecFileName = args[++j]; - } - } - else if (args[j].equals("-specialcasing")) { - if (j == args.length -1) { - FAIL("File name missing after -specialcasing"); - } - else { - SpecialCasingFileName = args[++j]; - } - } - else if (args[j].equals("-proplist")) { - if (j == args.length -1) { - FAIL("File name missing after -proplist"); - } - else { - PropListFileName = args[++j]; - } - } - else if (args[j].equals("-derivedprops")) { - if (j == args.length -1) { - FAIL("File name missing after -derivedprops"); - } - else { - DerivedPropsFileName = args[++j]; - } - } - else if (args[j].equals("-plane")) { - if (j == args.length -1) { - FAIL("Plane number missing after -plane"); - } - else { - plane = Integer.parseInt(args[++j]); - } - if (plane > 0) { - bLatin1 = false; - } - } - else if ("-usecharforbyte".equals(args[j])) { - useCharForByte = true; - } - else if (args[j].equals("-latin1")) { - bLatin1 = true; - plane = 0; - } - else { - try { - int val = Integer.parseInt(args[j]); - if (val < 0 || val > 32) FAIL("Incorrect bit field width: " + args[j]); - if (sizes == null) - sizes = new int[1]; - else { - int[] newsizes = new int[sizes.length + 1]; - System.arraycopy(sizes, 0, newsizes, 0, sizes.length); - sizes = newsizes; - } - sizes[sizes.length - 1] = val; - } - catch(NumberFormatException e) { - FAIL("Unknown switch: " + args[j]); - } - } - } - if (Csyntax && tableAsString) { - FAIL("Can't specify table as string with C syntax"); - } - if (sizes == null) { - desc.append(" ["); - if (identifiers) { - int[] newsizes = { 8, 4, 4 }; // Good default values - desc.append("8 4 4]"); - sizes = newsizes; - } - else { - int[] newsizes = { 10, 5, 1 }; // Guy's old defaults for 2.0.14: { 9, 4, 3, 0 } - desc.append("10 5 1]"); - sizes = newsizes; - } - } - if (UnicodeSpecFileName == null) { // liu - UnicodeSpecFileName = DefaultUnicodeSpecFileName; - desc.append(" [-spec " + UnicodeSpecFileName + ']'); - } - if (SpecialCasingFileName == null) { - SpecialCasingFileName = DefaultSpecialCasingFileName; - desc.append(" [-specialcasing " + SpecialCasingFileName + ']'); - } - if (PropListFileName == null) { - PropListFileName = DefaultPropListFileName; - desc.append(" [-proplist " + PropListFileName + ']'); - } - if (DerivedPropsFileName == null) { - DerivedPropsFileName = DefaultDerivedPropsFileName; - desc.append(" [-derivedprops " + DerivedPropsFileName + ']'); - } - if (TemplateFileName == null) { - TemplateFileName = (Csyntax ? DefaultCTemplateFileName - : DefaultJavaTemplateFileName); - desc.append(" [-template " + TemplateFileName + ']'); - } - if (OutputFileName == null) { - OutputFileName = (Csyntax ? DefaultCOutputFileName - : DefaultJavaOutputFileName); - desc.append(" [-o " + OutputFileName + ']'); - } - commentStart = (Csyntax ? "/*" : "//"); - commentEnd = (Csyntax ? " */" : ""); - commandLineDescription = desc.toString(); - } - - private static void searchBins(long[] map, int binsOccupied) throws Exception { - int bitsFree = 16; - for (int i=0; i= 0; k--) { - shifts[k] = sum; - sum += sizes[k]; - } - if ((1 << sum) < map.length || (1 << (sum - 1)) >= map.length) { - FAIL("Bit field widths total to " + sum + - ": wrong total for map of size " + map.length); - } - // need a table for each set of lookup bits in char - tables = new long[sizes.length][]; - // the last table is the map - tables[sizes.length - 1] = map; - for (int j = sizes.length - 1; j > 0; j--) { - if (verbose && bins==0) - System.err.println("Building map " + (j+1) + " of bit width " + sizes[j]); - long[][] temp = buildTable(tables[j], sizes[j]); - tables[j-1] = temp[0]; - tables[j] = temp[1]; - } - preshifted = new boolean[sizes.length]; - zeroextend = new int[sizes.length]; - bytes = new int[sizes.length]; - for (int j = 0; j < sizes.length - 1; j++) { - int len = tables[j+1].length; - int size = sizes[j+1]; - if (len > 0x100 && (len >> size) <= 0x100) { - len >>= size; - preshifted[j] = false; - } - else if (len > 0x10000 && (len >> size) <= 0x10000) { - len >>= size; - preshifted[j] = false; - } - else preshifted[j] = true; - if (Csyntax) - zeroextend[j] = 0; - else if (len > 0x7F && len <= 0xFF) { - if (!useCharForByte) { - zeroextend[j] = 0xFF; - } - } else if (len > 0x7FFF && len <= 0xFFFF) - zeroextend[j] = 0xFFFF; - else zeroextend[j] = 0; - if (len <= 0x100) bytes[j] = 1; - else if (len <= 0x10000) bytes[j] = 2; - else bytes[j] = 4; - } - preshifted[sizes.length - 1] = true; - zeroextend[sizes.length - 1] = 0; - bytes[sizes.length - 1] = 0; - if (bins > 0) { - int totalBytes = getTotalBytes(); - String access = genAccess("A", "ch", (identifiers ? 2 : 32)); - int accessComplexity = 0; - for (int j=0; j<".indexOf(ch) >= 0) ++accessComplexity; - if (ch == '<' || ch == '>') ++j; - } - System.out.print("("); - for (int j=0; j - *
  • Process the command line arguments. One result of this process - * is a list of sizes (measured in bits and summing to 16). - *
  • Get the Unicode character property data from the specification file. - *
  • From that, build a map that has, for each character code, its - * relevant properties encoded as a long integer value. - *
  • Repeatedly compress the map, producing a compressed table and a - * new map. This is done once for each size value in the list. - * When this is done, we have a set of tables. - *
  • Make some decisions about table representation; record these - * decisions in arrays named preshifted, zeroextend, and bytes. - *
  • Generate the source code for the class Character by performing - * macro processing on a template file. - * - * - * @param args the command line arguments, as an array of String - * - * @see GenerateCharacter#processArgs - * @see UnicodeSpec@readSpecFile - * @see GenerateCharacter#buildMap - * @see GenerateCharacter#buildTable - * @see GenerateCharacter#generateCharacterClass - */ - - public static void main(String[] args) { - processArgs(args); - try { - - UnicodeSpec[] data = UnicodeSpec.readSpecFile(new File(UnicodeSpecFileName), plane); - specialCaseMaps = SpecialCaseMap.readSpecFile(new File(SpecialCasingFileName), plane); - PropList propList = PropList.readSpecFile(new File(PropListFileName), plane); - propList.putAll(PropList.readSpecFile(new File(DerivedPropsFileName), plane)); - - if (verbose) { - System.out.println(data.length + " items read from Unicode spec file " + UnicodeSpecFileName); // liu - } - long[] map = buildMap(data, specialCaseMaps, propList); - if (verbose) { - System.err.println("Completed building of initial map"); - } - - if (bins == 0) { - generateForSizes(map); - } - else { - while (bins > 0) { - sizes = new int[bins]; - searchBins(map, 0); - --bins; - } - } - if (verbose && false) { - System.out.println("Offset range seen: -" + hex8(-minOffsetSeen) + "..+" + - hex8(maxOffsetSeen)); - System.out.println(" allowed: -" + hex8(-minOffset) + "..+" + - hex8(maxOffset)); - } - } - catch (FileNotFoundException e) { FAIL(e.toString()); } - catch (IOException e) { FAIL(e.toString()); } - catch (Throwable e) { - System.out.println("Unexpected exception:"); - e.printStackTrace(); - FAIL("Unexpected exception!"); - } - if (verbose) { System.out.println("Done!");} - } - -} // end class --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.base/share/tools/org/openjdk/buildtools/generatecharacter/GenerateCharacter.java 2020-03-23 19:56:45.319962638 +0100 @@ -0,0 +1,2016 @@ +/* + * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatecharacter; + +import java.io.IOException; +import java.io.FileNotFoundException; +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.PrintWriter; +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.File; +import java.util.List; + +import org.openjdk.buildtools.generatecharacter.CharacterName; + +/** + * This program generates the source code for the class java.lang.Character. + * It also generates native C code that can perform the same operations. + * It requires two external input data files: + *
      + *
    • Unicode specification file + *
    • Character class template file + *
    + * The Unicode specification file is available from the Unicode consortium. + * It has character specification lines that look like this: + * + * 0041;LATIN CAPITAL LETTER A;Lu;0;L;;;;;N;;;;0061; + * + * The Character class template file is filled in with additional + * information to produce the file Character.java, which can then be + * compiled by a Java compiler. The template file contains certain + * markers consisting of an alphabetic name string preceded by "$$". + * Such markers are replaced with generated program text. As a special + * case, the marker "Lookup(xxx)" is recognized, where "xxx" consists of + * alphabetic characters constituting a variable name. The character "_" + * is considered alphabetic for these purposes. + * + * @author Guy Steele + * @author Alan Liu + * @author John O'Conner + */ + +public class GenerateCharacter { + + final static boolean DEBUG = false; + + final static String commandMarker = "$$"; + static String ROOT = ""; + static String DefaultUnicodeSpecFileName = ROOT + "UnicodeData.txt"; + static String DefaultSpecialCasingFileName = ROOT + "SpecialCasing.txt"; + static String DefaultPropListFileName = ROOT + "PropList.txt"; + static String DefaultDerivedPropsFileName = ROOT + "DerivedCoreProperties.txt"; + static String DefaultJavaTemplateFileName = ROOT + "Character.java.template"; + static String DefaultJavaOutputFileName = ROOT + "Character.java"; + static String DefaultCTemplateFileName = ROOT + "Character.c.template"; + static String DefaultCOutputFileName = ROOT + "Character.c"; + + static int plane = 0; + + /* The overall idea is that, in the generated Character class source code, + most character property data is stored in a special multi-level table whose + structure is defined by a sequence of nonnegative integers [k1, k2, ..., kn]. + The integers must sum to 16 (the number of bits in a character). + The first table is indexed by the k1 high-order bits of the character code. + The result is concatenated to the next k2 bits of the character code to index + the second table, and so on. Eventually the kn low-order bits of the character + code are concatenated and used to index one of two tables A and B; A contains + 32-bit integer entries and B contains 16-bit short entries. The 48 bits that + can be thus obtained encode the properties for the character. + + The default specification is [9, 4, 3, 0]. This particular table format was + designed by conducting an exhaustive search of table formats to minimize the + space consumed by the tables: the first and third tables need have only byte + values (the second table must have short values). Another good choice is + [10, 6, 0], which produces a larger table but allows particularly fast table + lookup code. + + In each case, where the word "concatenated" is used, this may imply + first a << and then a | operation, or perhaps just a | operation if + the values in the table can be preshifted (generally possible if the table + entries are short rather than byte). + */ + + /* The character properties are currently encoded into A (32 bits)and B (16 bits) + two parts. + + A: the low 32 bits are defined in the following manner: + + 1 bit Mirrored property. + 4 bits Bidirectional category (see below) (unused if -nobidi switch specified) + 9 bits A signed offset used for converting case . + 1 bit If 1, adding the signed offset converts the character to lowercase. + 1 bit If 1, subtracting the signed offset converts the character to uppercase. + Note: for a titlecase character, both of the preceding bits will be 1 + and the signed offset will be 1. + 1 bit If 1, this character has a titlecase equivalent (possibly itself); + in this case, the two bits before this bit can be used to decide + whether this character is in fact uppercase, lowercase, or titlecase. + 3 bits This field provides a quick way to lex identifiers. + The eight possible values for this field are as follows: + 0 May not be part of an identifier + 1 Ignorable control; may continue a Unicode identifier or Java identifier + 2 May continue a Java identifier but not a Unicode identifier (unused) + 3 May continue a Unicode identifier or Java identifier + 4 Is a Java whitespace character + 5 May start or continue a Java identifier; + may continue but not start a Unicode identifier + (this value is used for connector punctuation such as _) + 6 May start or continue a Java identifier; + may not occur in a Unicode identifier + (this value is used for currency symbols such as $) + 7 May start or continue a Unicode identifier or Java identifier + Thus: + 5, 6, 7 may start a Java identifier + 1, 2, 3, 5, 6, 7 may continue a Java identifier + 7 may start a Unicode identifier + 1, 3, 5, 7 may continue a Unicode identifier + 1 is ignorable within an identifier + 4 is Java whitespace + 2 bits This field indicates whether the character has a numeric property. + The four possible values for this field are as follows: + 0 This character has no numeric property. + 1 Adding the digit offset to the character code and then + masking with 0x1F will produce the desired numeric value. + 2 This character has a "strange" numeric value. + 3 A Java supradecimal digit: adding the digit offset to the + character code, then masking with 0x1F, then adding 10 + will produce the desired numeric value. + 5 bits The digit offset (see description of previous field) + 5 bits Character type (see below) + + B: the high 16 bits are defined as: + 1 bit Other_Lowercase property + 1 bit Other_Uppercase property + 1 bit Other_Alphabetic property + 1 bit Other_Math property + 1 bit Ideographic property + 1 bit Noncharacter codepoint property + 1 bit ID_Start property + 1 bit ID_Continue property + */ + + + // bit masks identify each component of a 32-bit property field described + // above. + // shift* indicates how many shifts right must happen to get the + // indicated property value in the lowest bits of the 32-bit space. + private static final int + shiftType = 0, maskType = 0x001F, + shiftDigitOffset = 5, maskDigitOffset = 0x03E0, + shiftNumericType = 10, maskNumericType = 0x0C00, + shiftIdentifierInfo = 12, maskIdentifierInfo = 0x7000, + maskUnicodePart = 0x1000, + shiftCaseInfo = 15, maskCaseInfo = 0x38000, + maskLowerCase = 0x20000, + maskUpperCase = 0x10000, + maskTitleCase = 0x08000, + shiftCaseOffset = 18, maskCaseOffset = 0x07FC0000, + shiftCaseOffsetSign = 5, + // used only when calculating and + // storing digit offsets from char values + maskDigit = 0x001F, + // case offset are 9 bits + maskCase = 0x01FF, + shiftBidi = 27, maskBidi = 0x78000000, + shiftMirrored = 31, //maskMirrored = 0x80000000, + shiftPlane = 16, maskPlane = 0xFF0000; + + // maskMirrored needs to be long, if up 16-bit + private static final long maskMirrored = 0x80000000L; + + // bit masks identify the 16-bit property field described above, in B + // table + private static final long + maskOtherLowercase = 0x100000000L, + maskOtherUppercase = 0x200000000L, + maskOtherAlphabetic = 0x400000000L, + maskOtherMath = 0x800000000L, + maskIdeographic = 0x1000000000L, + maskNoncharacterCP = 0x2000000000L, + maskIDStart = 0x4000000000L, + maskIDContinue = 0x8000000000L; + + // Can compare masked values with these to determine + // numeric or lexical types. + public static int + valueNotNumeric = 0x0000, + valueDigit = 0x0400, + valueStrangeNumeric = 0x0800, + valueJavaSupradecimal = 0x0C00, + valueIgnorable = 0x1000, + valueJavaOnlyPart = 0x2000, + valueJavaUnicodePart = 0x3000, + valueJavaWhitespace = 0x4000, + valueJavaStartUnicodePart = 0x5000, + valueJavaOnlyStart = 0x6000, + valueJavaUnicodeStart = 0x7000, + lowJavaStart = 0x5000, + nonzeroJavaPart = 0x3000, + valueUnicodeStart = 0x7000; + + // these values are used when only identifier properties are generated + // for use in verifier code. Shortens the property down to a single byte. + private static final int + bitJavaStart = 0x02, + bitJavaPart = 0x01, + maskIsJavaIdentifierPart = bitJavaPart, + maskIsJavaIdentifierStart = bitJavaStart; + + static int maxOffset = maskCase/2 ; + static int minOffset = -maxOffset; + + /* The following routines provide simple, concise formatting of long integer values. + The number in the name of the method indicates the desired number of characters + to be produced. If the number of digits required to represent the integer value + is less than that number, then the output is padded on the left with zeros + (for hex) or with spaces (for decimal). If the number of digits required to + represent the integer value is greater than the desired number, then all the digits + that are required are actually produced. + */ + + static String hex(long n) { return Long.toHexString(n).toUpperCase(); } + + static String hex2(long n) { + String q = Long.toHexString(n & 0xFF).toUpperCase(); + return "00".substring(Math.min(2, q.length())) + q; + } + + static String hex4(long n) { + String q = Long.toHexString(n & 0xFFFF).toUpperCase(); + return "0000".substring(Math.min(4, q.length())) + q; + } + + static String hex8(long n) { + String q = Long.toHexString(n & 0xFFFFFFFFL).toUpperCase(); + return "00000000".substring(Math.min(8, q.length())) + q; + } + + static String hex16(long n) { + String q = Long.toHexString(n).toUpperCase(); + return "0000000000000000".substring(Math.min(16, q.length())) + q; + } + + static String dec3(long n) { + String q = Long.toString(n); + return " ".substring(Math.min(3, q.length())) + q; + } + + static String dec5(long n) { + String q = Long.toString(n); + return " ".substring(Math.min(5, q.length())) + q; + } + + /* This routine is called when some failure occurs. */ + + static void FAIL(String s) { + System.out.println("** " + s); + } + + /** + * Given the data from the Unicode specification file, this routine builds a map. + * + * The specification file is assumed to contain its data in sorted order by + * character code; as a result, the array passed as an argument to this method + * has its components in the same sorted order, with one entry for each defined + * Unicode character or character range. (A range is indicated by two consecutive + * entries, such that the name of the first entry begins with "<" and ends with + * "First>" and the second entry begins with "<" and ends with "Last>".) This is + * therefore a sparse representation of the character property data. + * + * The resulting map is dense representation of the character data. It contains + * 2^16 = 65536 entries, each of which is a long integer. (Right now only 32 bits + * of this long value are used, but type long is used rather than int to facilitate + * future extensions of this source code generator that might require more than + * 32 bits to encode relevant character properties.) Entry k holds the encoded + * properties for character k. + * + * Method buildMap manages the transformation from the sparse representation to + * the dense representation. It calls method buildOne to handle the encoding + * of character property data from a single UnicodeSpec object into 32 bits. + * For undefined characters, method buildOne is not called and the map entry for + * that character is set to UnicodeSpec.UNASSIGNED. + * + * @param data character property data from the Unicode specification file + * @return an array of length 65536 with one entry for every possible char value + * + * @see GenerateCharacter#buildOne + */ + + static long[] buildMap(UnicodeSpec[] data, SpecialCaseMap[] specialMaps, PropList propList) + { + long[] result; + if (bLatin1 == true) { + result = new long[256]; + } else { + result = new long[1<<16]; + } + int k=0; + int codePoint = plane<<16; + UnicodeSpec nonCharSpec = new UnicodeSpec(); + for (int j = 0; j < data.length && k < result.length; j++) { + if (data[j].codePoint == codePoint) { + result[k] = buildOne(codePoint, data[j], specialMaps); + ++k; + ++codePoint; + } + else if(data[j].codePoint > codePoint) { + if (data[j].name.endsWith("Last>")) { + // build map data for all chars except last in range + while (codePoint < data[j].codePoint && k < result.length) { + result[k] = buildOne(codePoint, data[j], specialMaps); + ++k; + ++codePoint; + } + } + else { + // we have a few unassigned chars before data[j].codePoint + while (codePoint < data[j].codePoint && k < result.length) { + result[k] = buildOne(codePoint, nonCharSpec, specialMaps); + ++k; + ++codePoint; + } + } + k = data[j].codePoint & 0xFFFF; + codePoint = data[j].codePoint; + result[k] = buildOne(codePoint, data[j], specialMaps); + ++k; + ++codePoint; + } + else { + System.out.println("An error has occured during spec mapping."); + System.exit(0); + } + } + // if there are still unprocessed chars, process them + // as unassigned/undefined. + codePoint = (plane<<16) | k; + while (k < result.length) { + result[k] = buildOne(codePoint, nonCharSpec, specialMaps); + ++k; + ++codePoint; + } + // now add all extra supported properties from PropList, to the + // upper 16-bit + addExProp(result, propList, "Other_Lowercase", maskOtherLowercase); + addExProp(result, propList, "Other_Uppercase", maskOtherUppercase); + addExProp(result, propList, "Other_Alphabetic", maskOtherAlphabetic); + addExProp(result, propList, "Ideographic", maskIdeographic); + //addExProp(result, propList, "Other_Math", maskOtherMath); + //addExProp(result, propList, "Noncharacter_CodePoint", maskNoncharacterCP); + addExProp(result, propList, "ID_Start", maskIDStart); + addExProp(result, propList, "ID_Continue", maskIDContinue); + + return result; + } + + // The maximum and minimum offsets found while scanning the database + static int maxOffsetSeen = 0; + static int minOffsetSeen = 0; + + /** + * Some Unicode separator characters are not considered Java whitespace. + * @param c character to test + * @return true if c in an invalid Java whitespace character, false otherwise. + */ + static boolean isInvalidJavaWhiteSpace(int c) { + int[] exceptions = {0x00A0, 0x2007, 0x202F, 0xFEFF}; + boolean retValue = false; + for(int x=0;x= 0x0041) && (c <= 0x005A)) { + val = c - 0x0041; + resultA |= valueJavaSupradecimal; + // c is a-z + } else if ((c >= 0x0061) && (c <= 0x007A)) { + val = c - 0x0061; + resultA |= valueJavaSupradecimal; + // c is a full-width A-Z + } else if ((c >= 0xFF21) && (c <= 0xFF3A)) { + val = c - 0xFF21; + resultA |= valueJavaSupradecimal; + // c is a full-width a-z + } else if ((c >= 0xFF41) && (c <= 0xFF5A)) { + val = c - 0xFF41; + resultA |= valueJavaSupradecimal; + } else if (us.isDecimalValue()) { + val = us.decimalValue; + resultA |= valueDigit; + } else if (us.isDigitValue()) { + val = us.digitValue; + resultA |= valueDigit; + } else { + if (us.numericValue.length() == 0) { + break NUMERIC; // no numeric value at all + } else { + try { + val = Integer.parseInt(us.numericValue); + if (val >= 32 || val < 0) break STRANGE; + if (c == 0x215F) break STRANGE; + } catch(NumberFormatException e) { + break STRANGE; + } + resultA |= valueDigit; + } + } + if (val >= 32 || val < 0) break STRANGE; + resultA |= ((val - c & maskDigit) << shiftDigitOffset); + break NUMERIC; + } // end STRANGE + resultA |= valueStrangeNumeric; + } // end NUMERIC + + // record case mapping + int offset = 0; + // might have a 1:M mapping + int specialMap = SpecialCaseMap.find(c, specialCaseMaps); + boolean bHasUpper = (us.hasUpperMap()) || (specialMap != -1); + if (bHasUpper) { + resultA |= maskUpperCase; + } + if (specialMap != -1) { + // has mapping, but cannot record the + // proper offset; can only flag it and provide special case + // code in Character.java + offset = -1; + } + else if (us.hasUpperMap()) { + offset = c - us.upperMap; + } + + if (us.hasLowerMap()) { + resultA |= maskLowerCase; + if (offset == 0) + offset = us.lowerMap - c; + else if (offset != (us.lowerMap - c)) { + if (DEBUG) { + FAIL("Character " + hex(c) + + " has incompatible lowercase and uppercase mappings"); + } + } + } + if ((us.hasTitleMap() && us.titleMap != us.upperMap) || + (bHasUpper && us.hasLowerMap())) { + resultA |= maskTitleCase; + } + if (bHasUpper && !us.hasLowerMap() && !us.hasTitleMap() && verbose) { + System.out.println("Warning: Character " + hex4(c) + " has upper but " + + "no title case; Java won't know this"); + } + if (offset < minOffsetSeen) minOffsetSeen = offset; + if (offset > maxOffsetSeen) maxOffsetSeen = offset; + if (offset > maxOffset || offset < minOffset) { + if (DEBUG) { + FAIL("Case offset " + offset + " for character " + hex4(c) + " must be handled as a special case"); + } + offset = maskCase; + } + resultA |= ((offset & maskCase) << shiftCaseOffset); + + // record lexical info about this character + if (us.generalCategory == UnicodeSpec.LOWERCASE_LETTER + || us.generalCategory == UnicodeSpec.UPPERCASE_LETTER + || us.generalCategory == UnicodeSpec.TITLECASE_LETTER + || us.generalCategory == UnicodeSpec.MODIFIER_LETTER + || us.generalCategory == UnicodeSpec.OTHER_LETTER + || us.generalCategory == UnicodeSpec.LETTER_NUMBER) { + resultA |= valueJavaUnicodeStart; + } + else if (us.generalCategory == UnicodeSpec.COMBINING_SPACING_MARK + || us.generalCategory == UnicodeSpec.NON_SPACING_MARK + || us.generalCategory == UnicodeSpec.DECIMAL_DIGIT_NUMBER) { + resultA |= valueJavaUnicodePart; + } + else if (us.generalCategory == UnicodeSpec.CONNECTOR_PUNCTUATION) { + resultA |= valueJavaStartUnicodePart; + } + else if (us.generalCategory == UnicodeSpec.CURRENCY_SYMBOL) { + resultA |= valueJavaOnlyStart; + } + else if (((c >= 0x0000) && (c <= 0x0008)) + || ((c >= 0x000E) && (c <= 0x001B)) + || ((c >= 0x007F) && (c <= 0x009F)) + || us.generalCategory == UnicodeSpec.FORMAT) { + resultA |= valueIgnorable; + } + else if (us.generalCategory == UnicodeSpec.SPACE_SEPARATOR + || us.generalCategory == UnicodeSpec.LINE_SEPARATOR + || us.generalCategory == UnicodeSpec.PARAGRAPH_SEPARATOR) { + if (!isInvalidJavaWhiteSpace(c)) resultA |= valueJavaWhitespace; + } + else if (((c >= 0x0009) && (c <= 0x000D)) + || ((c >= 0x001C) && (c <= 0x001F))) { + resultA |= valueJavaWhitespace; + } + + // record bidi category + if (!nobidi) { + int tmpBidi = + (us.bidiCategory > UnicodeSpec.DIRECTIONALITY_OTHER_NEUTRALS || + us.bidiCategory == -1) ? maskBidi : (us.bidiCategory << shiftBidi); + resultA |= tmpBidi; + } + + // record mirrored property + if (!nomirror) { + resultA |= us.mirrored ? maskMirrored : 0; + } + + if (identifiers) { + long replacement = 0; + if ((resultA & maskIdentifierInfo) >= lowJavaStart) { + replacement |= bitJavaStart; + } + if ( ((resultA & nonzeroJavaPart) != 0) + && ((resultA & maskIdentifierInfo) != valueIgnorable)) { + replacement |= bitJavaPart; + } + resultA = replacement; + } + return resultA; + } + + static void addExProp(long[] map, PropList propList, String prop, long mask) { + List cps = propList.codepoints(prop); + if (cps != null) { + for (Integer cp : cps) { + if (cp < map.length) + map[cp] |= mask; + } + } + } + + /** + * This is the heart of the table compression strategy. The inputs are a map + * and a number of bits (size). The map is simply an array of long integer values; + * the number of bits indicates how index values for that map are to be split. + * The length of the given map must be a multiple of (1 << size). The result is + * a new map z and a compressed table t such that for every valid index value k + * for the original map, t[(z[k>>size]<> size) << size) != n) { + FAIL("Length " + n + " is not a multiple of " + (1 << size)); + } + int m = 1 << size; + // We know the final length of the new map up front. + long[] newmap = new long[n >> size]; + // The buffer is used temporarily to hold data for the compressed table + // because we don't know its final length yet. + long[] buffer = new long[n]; + int ptr = 0; +OUTER: for (int i = 0; i < n; i += m) { + // For every block of size m in the original map... + MIDDLE: for (int j = 0; j < ptr; j += m) { + // Find out whether there is already a block just like it in the buffer. + for (int k = 0; k < m; k++) { + if (buffer[j+k] != map[i+k]) + continue MIDDLE; + } + // There is a block just like it at position j, so just + // put its index into the new map (thereby sharing it). + newmap[i >> size] = (j >> size); + continue OUTER; + } // end MIDDLE + // There is no block just like it already, so add it to + // the buffer and put its index into the new map. + for (int k = 0; k < m; k++) { + buffer[ptr+k] = map[i+k]; + } + newmap[i >> size] = (ptr >> size); + ptr += m; + } // end OUTER + // Now we know how long the compressed table should be, + // so create a new array and copy data from the temporary buffer. + long[] newdata = new long[ptr]; + for (int j = 0; j < ptr; j++) { + newdata[j] = buffer[j]; + } + // Return the new map and the new data table. + long[][] result = { newmap, newdata }; + return result; + } + + /** + * Once the compressed tables have been computed, this method reads in a + * template file for the source code to be generated and writes out the final + * source code by acting as a sort of specialized macro processor. + * + * The first output line is a comment saying that the file was automatically + * generated; it includes a timestamp. All other output is generated by + * reading a line from the template file, performing macro replacements, + * and then writing the resulting line or lines of code to the output file. + * + * This method handles the I/O, the timestamp comment, and the locating of + * macro calls within each input line. The method replaceCommand is called + * to generate replacement text for each macro call. + * + * Macro calls to be replaced are indicated in the template file by + * occurrences of the commandMarker "$$". The rest of the call may consist + * of Java letters (including the underscore "_") and also of balanced + * parentheses. + * + * @param theTemplateFileName + * the file name for the template input file + * @param theOutputFileName + * the file name for the source code output file + * + * @see GenerateCharacter#replaceCommand + */ + + static void generateCharacterClass(String theTemplateFileName, + String theOutputFileName) + throws FileNotFoundException, IOException { + BufferedReader in = new BufferedReader(new FileReader(theTemplateFileName)); + PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(theOutputFileName))); + out.println(commentStart + + " This file was generated AUTOMATICALLY from a template file " + + new java.util.Date() + commentEnd); + int marklen = commandMarker.length(); + LOOP: while(true) { + try { + String line = in.readLine(); + if (line == null) break LOOP; + int pos = 0; + int depth = 0; + while ((pos = line.indexOf(commandMarker, pos)) >= 0) { + int newpos = pos + marklen; + char ch = 'x'; + SCAN: while (newpos < line.length() && + (Character.isJavaIdentifierStart(ch = line.charAt(newpos)) + || ch == '(' || (ch == ')' && depth > 0))) { + ++newpos; + if (ch == '(') { + ++depth; + } + else if (ch == ')') { + --depth; + if (depth == 0) + break SCAN; + } + } + String replacement = replaceCommand(line.substring(pos + marklen, newpos)); + line = line.substring(0, pos) + replacement + line.substring(newpos); + pos += replacement.length(); + } + out.println(line); + } + catch (IOException e) { + break LOOP; + } + } + in.close(); + out.close(); + } + + /** + * The replaceCommand method takes a command (a macro call without the + * leading marker "$$") and computes replacement text for it. + * + * Most of the commands are simply names of integer constants that are defined + * in the source code of this GenerateCharacter class. The replacement text is + * simply the value of the constant as an appropriately formatted integer literal. + * + * Two cases are more complicated, however. The command "Tables" causes the + * final map and compressed tables to be emitted, with elaborate comments + * describing their contents. (This is actually handled by method genTables.) + * The command "Lookup(xxx)", where "xxx" is the name of a variable, generates + * an expression that will return the character property data for the character + * whose code is the value of the variable "xxx". (this is handled by method + * "genAccess".) + * + * @param x a command from the template file to be replaced + * @return the replacement text, as a String + * + * @see GenerateCharacter#genTables + * @see GenerateCharacter#genAccess + * @see GenerateCharacter#generateCharacterClass + */ + + static String replaceCommand(String x) { + if (x.equals("Tables")) return genTables(); + if (x.equals("Initializers")) return genInitializers(); + if (x.length() >= 9 && x.substring(0, 7).equals("Lookup(") && + x.substring(x.length()-1).equals(")") ) + return genAccess("A", x.substring(7, x.length()-1), (identifiers ? 2 : 32)); + if (x.length() >= 11 && x.substring(0, 9).equals("LookupEx(") && + x.substring(x.length()-1).equals(")") ) + return genAccess("B", x.substring(9, x.length()-1), 16); + if (x.equals("shiftType")) return Long.toString(shiftType); + if (x.equals("shiftIdentifierInfo")) return Long.toString(shiftIdentifierInfo); + if (x.equals("maskIdentifierInfo")) return "0x" + hex8(maskIdentifierInfo); + if (x.equals("maskUnicodePart")) return "0x" + hex8(maskUnicodePart); + if (x.equals("shiftCaseOffset")) return Long.toString(shiftCaseOffset); + if (x.equals("shiftCaseInfo")) return Long.toString(shiftCaseInfo); + if (x.equals("shiftCaseOffsetSign")) return Long.toString(shiftCaseOffsetSign); + if (x.equals("maskCase")) return "0x" + hex8(maskCase); + if (x.equals("maskCaseOffset")) return "0x" + hex8(maskCaseOffset); + if (x.equals("maskLowerCase")) return "0x" + hex8(maskLowerCase); + if (x.equals("maskUpperCase")) return "0x" + hex8(maskUpperCase); + if (x.equals("maskTitleCase")) return "0x" + hex8(maskTitleCase); + if (x.equals("maskOtherLowercase")) return "0x" + hex4(maskOtherLowercase >> 32); + if (x.equals("maskOtherUppercase")) return "0x" + hex4(maskOtherUppercase >> 32); + if (x.equals("maskOtherAlphabetic")) return "0x" + hex4(maskOtherAlphabetic >> 32); + if (x.equals("maskIdeographic")) return "0x" + hex4(maskIdeographic >> 32); + if (x.equals("maskIDStart")) return "0x" + hex4(maskIDStart >> 32); + if (x.equals("maskIDContinue")) return "0x" + hex4(maskIDContinue >> 32); + if (x.equals("valueIgnorable")) return "0x" + hex8(valueIgnorable); + if (x.equals("valueJavaUnicodeStart")) return "0x" + hex8(valueJavaUnicodeStart); + if (x.equals("valueJavaOnlyStart")) return "0x" + hex8(valueJavaOnlyStart); + if (x.equals("valueJavaUnicodePart")) return "0x" + hex8(valueJavaUnicodePart); + if (x.equals("valueJavaOnlyPart")) return "0x" + hex8(valueJavaOnlyPart); + if (x.equals("valueJavaWhitespace")) return "0x" + hex8(valueJavaWhitespace); + if (x.equals("lowJavaStart")) return "0x" + hex8(lowJavaStart); + if (x.equals("nonzeroJavaPart")) return "0x" + hex8(nonzeroJavaPart); + if (x.equals("bitJavaStart")) return "0x" + hex8(bitJavaStart); + if (x.equals("bitJavaPart")) return Long.toString(bitJavaPart); + if (x.equals("valueUnicodeStart")) return "0x" + hex8(valueUnicodeStart); + if (x.equals("maskIsJavaIdentifierStart")) return "0x" + hex(maskIsJavaIdentifierStart); + if (x.equals("maskIsJavaIdentifierPart")) return "0x" + hex(maskIsJavaIdentifierPart); + if (x.equals("shiftDigitOffset")) return Long.toString(shiftDigitOffset); + if (x.equals("maskDigitOffset")) return "0x" + hex(maskDigitOffset); + if (x.equals("maskDigit")) return "0x" + hex(maskDigit); + if (x.equals("shiftNumericType")) return Long.toString(shiftNumericType); + if (x.equals("maskNumericType")) return "0x" + hex(maskNumericType); + if (x.equals("valueNotNumeric")) return "0x" + hex8(valueNotNumeric); + if (x.equals("valueDigit")) return "0x" + hex8(valueDigit); + if (x.equals("valueStrangeNumeric")) return "0x" + hex8(valueStrangeNumeric); + if (x.equals("valueJavaSupradecimal")) return "0x" + hex8(valueJavaSupradecimal); + if (x.equals("valueDigit")) return "0x" + hex8(valueDigit); + if (x.equals("valueStrangeNumeric")) return "0x" + hex8(valueStrangeNumeric); + if (x.equals("maskType")) return "0x" + hex(maskType); + if (x.equals("shiftBidi")) return Long.toString(shiftBidi); + if (x.equals("maskBidi")) return "0x" + hex(maskBidi); + if (x.equals("maskMirrored")) return "0x" + hex8(maskMirrored); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.UNASSIGNED][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.UNASSIGNED); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.UPPERCASE_LETTER][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.UPPERCASE_LETTER); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.LOWERCASE_LETTER][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.LOWERCASE_LETTER); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.TITLECASE_LETTER][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.TITLECASE_LETTER); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.MODIFIER_LETTER][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.MODIFIER_LETTER); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.OTHER_LETTER][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.OTHER_LETTER); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.NON_SPACING_MARK][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.NON_SPACING_MARK); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.ENCLOSING_MARK][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.ENCLOSING_MARK); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.COMBINING_SPACING_MARK][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.COMBINING_SPACING_MARK); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.DECIMAL_DIGIT_NUMBER][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DECIMAL_DIGIT_NUMBER); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.OTHER_NUMBER][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.OTHER_NUMBER); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.SPACE_SEPARATOR][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.SPACE_SEPARATOR); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.LINE_SEPARATOR][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.LINE_SEPARATOR); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.PARAGRAPH_SEPARATOR][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.PARAGRAPH_SEPARATOR); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.CONTROL][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.CONTROL); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.FORMAT][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.FORMAT); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.PRIVATE_USE][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.PRIVATE_USE); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.SURROGATE][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.SURROGATE); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.DASH_PUNCTUATION][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DASH_PUNCTUATION); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.START_PUNCTUATION][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.START_PUNCTUATION); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.END_PUNCTUATION][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.END_PUNCTUATION); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.INITIAL_QUOTE_PUNCTUATION][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.INITIAL_QUOTE_PUNCTUATION); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.FINAL_QUOTE_PUNCTUATION][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.FINAL_QUOTE_PUNCTUATION); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.CONNECTOR_PUNCTUATION][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.CONNECTOR_PUNCTUATION); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.OTHER_PUNCTUATION][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.OTHER_PUNCTUATION); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.LETTER_NUMBER][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.LETTER_NUMBER); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.MATH_SYMBOL][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.MATH_SYMBOL); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.CURRENCY_SYMBOL][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.CURRENCY_SYMBOL); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.MODIFIER_SYMBOL][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.MODIFIER_SYMBOL); + if (x.equals(UnicodeSpec.generalCategoryList[UnicodeSpec.OTHER_SYMBOL][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.OTHER_SYMBOL); + if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_LEFT_TO_RIGHT][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DIRECTIONALITY_LEFT_TO_RIGHT); + if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING); + if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE); + if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_RIGHT_TO_LEFT][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DIRECTIONALITY_RIGHT_TO_LEFT); + if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC); + if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING); + if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE); + if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_POP_DIRECTIONAL_FORMAT][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DIRECTIONALITY_POP_DIRECTIONAL_FORMAT); + if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_EUROPEAN_NUMBER][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DIRECTIONALITY_EUROPEAN_NUMBER); + if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR); + if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR); + if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_ARABIC_NUMBER][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DIRECTIONALITY_ARABIC_NUMBER); + if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_COMMON_NUMBER_SEPARATOR][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DIRECTIONALITY_COMMON_NUMBER_SEPARATOR); + if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_NONSPACING_MARK][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DIRECTIONALITY_NONSPACING_MARK); + if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_BOUNDARY_NEUTRAL][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DIRECTIONALITY_BOUNDARY_NEUTRAL); + if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_PARAGRAPH_SEPARATOR][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DIRECTIONALITY_PARAGRAPH_SEPARATOR); + if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_SEGMENT_SEPARATOR][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DIRECTIONALITY_SEGMENT_SEPARATOR); + if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_WHITESPACE][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DIRECTIONALITY_WHITESPACE); + if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_OTHER_NEUTRALS][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DIRECTIONALITY_OTHER_NEUTRALS); + if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE); + if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE); + if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_FIRST_STRONG_ISOLATE][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DIRECTIONALITY_FIRST_STRONG_ISOLATE); + if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE); + FAIL("Unknown text substitution marker " + commandMarker + x); + return commandMarker + x; + } + + /** + * The genTables method generates source code for all the lookup tables + * needed to represent the various Unicode character properties. + * It simply calls the method genTable once for each table to be generated + * and then generates a summary comment. + * + * @return the replacement text for the "Tables" command, as a String + * + * @see GenerateCharacter#genTable + * @see GenerateCharacter#replaceCommand + */ + static String genTables() { + int n = sizes.length; + StringBuffer result = new StringBuffer(); + // liu : Add a comment showing the source of this table + result.append(commentStart + " The following tables and code generated using:" + + commentEnd + "\n "); + result.append(commentStart + ' ' + commandLineDescription + commentEnd + "\n "); + + if (plane == 0 && bLatin1 == false) { + genCaseMapTableDeclaration(result); + genCaseMapTable(initializers, specialCaseMaps); + } + int totalBytes = 0; + for (int k = 0; k < n - 1; k++) { + genTable(result, tableNames[k], tables[k], 0, bytes[k]<<3, sizes[k], preshifted[k], + sizes[k+1], false, false, k==0); + int s = bytes[k]; + if (s == 1 && useCharForByte) { + s = 2; + } + totalBytes += tables[k].length * s; + } + genTable(result, "A", tables[n - 1], 0, (identifiers ? 2 : 32), + sizes[n - 1], false, 0, true, !(identifiers), false); + + // If we ever need more than 32 bits to represent the character properties, + // then a table "B" may be needed as well. + genTable(result, "B", tables[n - 1], 32, 16, sizes[n - 1], false, 0, true, true, false); + + totalBytes += ((((tables[n - 1].length * (identifiers ? 2 : 32)) + 31) >> 5) << 2); + result.append(commentStart); + result.append(" In all, the character property tables require "); + result.append(totalBytes).append(" bytes.").append(commentEnd); + if (verbose) { + System.out.println("The character property tables require " + + totalBytes + " bytes."); + } + return result.toString(); + } + + /** + * The genInitializers method generates the body of the + * ensureInitted() method, which enables lazy initialization of + * the case map table and other tables. + */ + static String genInitializers() { + return initializers.toString(); + } + + /** + * Return the total number of bytes needed by all tables. This is a stripped- + * down copy of genTables(). + */ + static int getTotalBytes() { + int n = sizes.length; + int totalBytes = 0; + for (int k = 0; k < n - 1; k++) { + totalBytes += tables[k].length * bytes[k]; + } + totalBytes += ((((tables[n - 1].length * (identifiers ? 2 : 32)) + + 31) >> 5) << 2); + return totalBytes; + } + + static void appendEscapedStringFragment(StringBuffer result, + char[] line, + int length, + boolean lastFragment) { + result.append(" \""); + for (int k=0; k>= $$bits;\n"+ + " }\n"+ + " }\n"+ + " assert (j == $$size);\n"+ + " }\n"; + + static String SAME_SIZE_INITIALIZER = + " { // THIS CODE WAS AUTOMATICALLY CREATED BY GenerateCharacter:\n"+ + " assert ($$name_DATA.length() == $$size);\n"+ + // " $$name = new $$type[$$size];\n"+ + " for (int i=0; i<$$size; ++i)\n"+ + " $$name[i] = ($$type)$$name_DATA.charAt(i);\n"+ + " }\n"; + + static String BIG_INITIALIZER = + " { // THIS CODE WAS AUTOMATICALLY CREATED BY GenerateCharacter:\n"+ + // " $$name = new $$type[$$size];\n"+ + " int len = $$name_DATA.length();\n"+ + " int j=0;\n"+ + " int charsInEntry=0;\n"+ + " $$type entry=0;\n"+ + " for (int i=0; i 0) ? SMALL_INITIALIZER : BIG_INITIALIZER); + if (entriesPerChar == -2) { + template = INT32_INITIALIZER; + } + int marklen = commandMarker.length(); + int pos = 0; + while ((pos = template.indexOf(commandMarker, pos)) >= 0) { + int newpos = pos + marklen; + char ch = 'x'; + while (newpos < template.length() && + Character.isJavaIdentifierStart(ch = template.charAt(newpos)) && + ch != '_') // Don't allow this in token names + ++newpos; + String token = template.substring(pos+marklen, newpos); + String replacement = "ERROR"; + + if (token.equals("name")) replacement = name; + else if (token.equals("type")) replacement = type; + else if (token.equals("bits")) replacement = ""+bits; + else if (token.equals("size")) replacement = ""+size; + else if (token.equals("entriesPerChar")) replacement = ""+entriesPerChar; + else if (token.equals("charsPerEntry")) replacement = ""+(-entriesPerChar); + else FAIL("Unrecognized token: " + token); + + template = template.substring(0, pos) + replacement + template.substring(newpos); + pos += replacement.length(); + } + initializers.append(template); + } + + /** + * The genTable method generates source code for one lookup table. + * Most of the complexity stems from handling various options as to + * the type of the array components, the precise representation of the + * values, the format in which to render each value, the number of values + * to emit on each line of source code, and the kinds of useful comments + * to be generated. + * + * @param result a StringBuffer, to which the generated source code + * text is to be appended + * @param name the name of the table + * @param table the table data (an array of long values) + * @param extract a distance, in bits, by which each entry of the table + * is to be right-shifted before it is processed + * @param bits the number of bits (not bytes) to be used to represent + * each table entry + * @param size the table data is divided up into blocks of size (1<> 5) << 2; + if (bits == 8 && useCharForByte) { + sizeOfTable *= 2; + } + result.append(sizeOfTable); + result.append(" bytes.").append(commentEnd).append("\n\n"); + if (Csyntax) + result.append(" static "); + else + result.append(" static final "); + result.append(atype); + result.append(" ").append(name).append("["); + if (Csyntax) + result.append(table.length >> (bits == 1 ? 5 : bits == 2 ? 4 : bits == 4 ? 3 : 0)); + if (tableAsString) { + if (noConversion) { + result.append("] = (\n"); + } else { + result.append("] = new ").append(atype).append("["+table.length+"];\n "); + result.append("static final String ").append(name).append("_DATA =\n"); + } + int CHARS_PER_LINE = 8; + StringBuffer theString = new StringBuffer(); + int entriesInCharSoFar = 0; + char ch = '\u0000'; + int charsPerEntry = -entriesPerChar; + for (int j=0; j> extract; + long entry; + if ("A".equals(name)) + entry = (table[j] & 0xffffffffL) >> extract; + else + entry = (table[j] >> extract); + if (shiftEntries) entry <<= shift; + if (entry >= (1L << bits)) { + FAIL("Entry too big"); + } + if (entriesPerChar > 0) { + // Pack multiple entries into a character + ch = (char)(((int)ch >> bits) | (entry << (entriesPerChar-1)*bits)); + ++entriesInCharSoFar; + if (entriesInCharSoFar == entriesPerChar) { + // Character is full + theString.append(ch); + entriesInCharSoFar = 0; + ch = '\u0000'; + } + } + else { + // Use multiple characters per entry + for (int k=0; k> ((charsPerEntry-1)*16)); + entry <<= 16; + theString.append(ch); + } + } + } + if (entriesInCharSoFar > 0) { + while (entriesInCharSoFar < entriesPerChar) { + ch = (char)((int)ch >> bits); + ++entriesInCharSoFar; + } + theString.append(ch); + entriesInCharSoFar = 0; + } + result.append(Utility.formatForSource(theString.toString(), " ")); + if (noConversion) { + result.append(").toCharArray()"); + } + result.append(";\n\n "); + + if (!noConversion) { + addInitializer(name, atype, entriesPerChar, bits, table.length); + } + } + else { + result.append("] = {"); + boolean castEntries = shiftEntries && (bits < 32); + int printPerLine = hexFormat ? (bits == 1 ? 32*4 : + bits == 2 ? 16*4 : + bits == 4 ? 8*4 : + bits == 8 ? 8 : + bits == 16 ? 8 : + bits == 32 ? 4 : 2) : + (bits == 8 ? 8 : + bits == 16 ? 8 : 4); + int printMask = properties ? 0 : + Math.min(1 << size, + printPerLine >> (castEntries ? (Csyntax ? 2 : 1) : 0)) - 1; + int commentShift = ((1 << size) == table.length) ? 0 : size; + int commentMask = ((1 << size) == table.length) ? printMask : (1 << size) - 1; + long val = 0; + for (int j = 0; j < table.length; j++) { + if ((j & printMask) == 0) { + while (result.charAt(result.length() - 1) == ' ') + result.setLength(result.length() - 1); + result.append("\n "); + } + PRINT: { + if (castEntries) + result.append("(").append(atype).append(")("); + long entry = table[j] >> extract; + int packMask = ((1 << (bits == 1 ? 5 : bits == 2 ? 4 : bits == 4 ? 3 : 2)) - 1); + int k = j & packMask; + if (bits >= 8) + val = entry; + else if (k == 0) { + val = entry; + break PRINT; + } + else { + val |= (entry << (k*bits)); + if (k != packMask) + break PRINT; + } + if (val > maxPosEntry && !Csyntax) { // liu + // For values that are out of range, convert them to in-range negative values. + // Actually, output the '-' and convert them to the negative of the corresponding + // in-range negative values. E.g., convert 130 == -126 (in 8 bits) -> 126. + result.append('-'); + val = maxPosEntry + maxPosEntry + 2 - val; + } + if (hexFormat) { + result.append("0x"); + if (bits == 8) + result.append(hex2((byte)val)); + else if (bits == 16) + result.append(hex4((short)val)); + else if (bits == 32 || bits < 8) + result.append(hex8((int)val)); + else { + result.append(hex16(val)); + if (!Csyntax) + result.append("L"); + } + } + else { + if (bits == 8) + result.append(dec3(val)); + else if (bits == 64) { + result.append(dec5(val)); + if (!Csyntax) + result.append("L"); + } + else + result.append(dec5(val)); + } + if (shiftEntries) + result.append("<<").append(shift); + if (castEntries) result.append(")"); + if (j < (table.length - 1)) + result.append(", "); + else + result.append(" "); + if ((j & printMask) == printMask) { + result.append(" ").append(commentStart).append(" "); + if (hexComment) + result.append("0x").append(hex4((j & ~commentMask) << (16 - size))); + else + result.append(dec3((j & ~commentMask) >> commentShift)); + if (properties) propertiesComments(result, val); + result.append(commentEnd); + } + } // end PRINT + } + result.append("\n };\n\n "); + } + } + + static void genCaseMapTableDeclaration(StringBuffer result) { + String myTab = " "; + result.append(myTab + "static final char[][][] charMap;\n"); + } + + static void genCaseMapTable(StringBuffer result, SpecialCaseMap[] specialCaseMaps){ + String myTab = " "; + int ch; + char[] map; + result.append(myTab + "charMap = new char[][][] {\n"); + for (int x = 0; x < specialCaseMaps.length; x++) { + ch = specialCaseMaps[x].getCharSource(); + map = specialCaseMaps[x].getUpperCaseMap(); + result.append(myTab + myTab); + result.append("{ "); + result.append("{\'\\u"+hex4(ch)+"\'}, {"); + for (int y = 0; y < map.length; y++) { + result.append("\'\\u"+hex4(map[y])+"\', "); + } + result.append("} },\n"); + } + result.append(myTab + "};\n"); + + } + + /** + * The propertiesComments method generates comments describing encoded + * character properties. + * + * @param result a StringBuffer, to which the generated source code + * text is to be appended + * @param val encoded character properties + * + * @see GenerateCharacter#genTable + */ + + static void propertiesComments(StringBuffer result, long val) { + result.append(" "); + switch ((int)(val & maskType)) { + case UnicodeSpec.CONTROL: + result.append("Cc"); + break; + case UnicodeSpec.FORMAT: + result.append("Cf"); + break; + case UnicodeSpec.PRIVATE_USE: + result.append("Co"); + break; + case UnicodeSpec.SURROGATE: + result.append("Cs"); + break; + case UnicodeSpec.LOWERCASE_LETTER: + result.append("Ll"); + break; + case UnicodeSpec.MODIFIER_LETTER: + result.append("Lm"); + break; + case UnicodeSpec.OTHER_LETTER: + result.append("Lo"); + break; + case UnicodeSpec.TITLECASE_LETTER: + result.append("Lt"); + break; + case UnicodeSpec.UPPERCASE_LETTER: + result.append("Lu"); + break; + case UnicodeSpec.COMBINING_SPACING_MARK: + result.append("Mc"); + break; + case UnicodeSpec.ENCLOSING_MARK: + result.append("Me"); + break; + case UnicodeSpec.NON_SPACING_MARK: + result.append("Mn"); + break; + case UnicodeSpec.DECIMAL_DIGIT_NUMBER: + result.append("Nd"); + break; + case UnicodeSpec.LETTER_NUMBER: + result.append("Nl"); + break; + case UnicodeSpec.OTHER_NUMBER: + result.append("No"); + break; + case UnicodeSpec.CONNECTOR_PUNCTUATION: + result.append("Pc"); + break; + case UnicodeSpec.DASH_PUNCTUATION: + result.append("Pd"); + break; + case UnicodeSpec.END_PUNCTUATION: + result.append("Pe"); + break; + case UnicodeSpec.OTHER_PUNCTUATION: + result.append("Po"); + break; + case UnicodeSpec.START_PUNCTUATION: + result.append("Ps"); + break; + case UnicodeSpec.CURRENCY_SYMBOL: + result.append("Sc"); + break; + case UnicodeSpec.MODIFIER_SYMBOL: + result.append("Sk"); + break; + case UnicodeSpec.MATH_SYMBOL: + result.append("Sm"); + break; + case UnicodeSpec.OTHER_SYMBOL: + result.append("So"); + break; + case UnicodeSpec.LINE_SEPARATOR: + result.append("Zl"); break; + case UnicodeSpec.PARAGRAPH_SEPARATOR: + result.append("Zp"); + break; + case UnicodeSpec.SPACE_SEPARATOR: + result.append("Zs"); + break; + case UnicodeSpec.UNASSIGNED: + result.append("unassigned"); + break; + } + + switch ((int)((val & maskBidi) >> shiftBidi)) { + case UnicodeSpec.DIRECTIONALITY_LEFT_TO_RIGHT: + result.append(", L"); + break; + case UnicodeSpec.DIRECTIONALITY_RIGHT_TO_LEFT: + result.append(", R"); + break; + case UnicodeSpec.DIRECTIONALITY_EUROPEAN_NUMBER: + result.append(", EN"); + break; + case UnicodeSpec.DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR: + result.append(", ES"); + break; + case UnicodeSpec.DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR: + result.append(", ET"); + break; + case UnicodeSpec.DIRECTIONALITY_ARABIC_NUMBER: + result.append(", AN"); + break; + case UnicodeSpec.DIRECTIONALITY_COMMON_NUMBER_SEPARATOR: + result.append(", CS"); + break; + case UnicodeSpec.DIRECTIONALITY_PARAGRAPH_SEPARATOR: + result.append(", B"); + break; + case UnicodeSpec.DIRECTIONALITY_SEGMENT_SEPARATOR: + result.append(", S"); + break; + case UnicodeSpec.DIRECTIONALITY_WHITESPACE: + result.append(", WS"); + break; + case UnicodeSpec.DIRECTIONALITY_OTHER_NEUTRALS: + result.append(", ON"); + break; + } + if ((val & maskUpperCase) != 0) { + result.append(", hasUpper (subtract "); + result.append((val & maskCaseOffset) >> shiftCaseOffset).append(")"); + } + if ((val & maskLowerCase) != 0) { + result.append(", hasLower (add "); + result.append((val & maskCaseOffset) >> shiftCaseOffset).append(")"); + } + if ((val & maskTitleCase) != 0) { + result.append(", hasTitle"); + } + if ((val & maskIdentifierInfo) == valueIgnorable) { + result.append(", ignorable"); + } + if ((val & maskIdentifierInfo) == valueJavaUnicodePart) { + result.append(", identifier part"); + } + if ((val & maskIdentifierInfo) == valueJavaStartUnicodePart) { + result.append(", underscore"); + } + if ((val & maskIdentifierInfo) == valueJavaWhitespace) { + result.append(", whitespace"); + } + if ((val & maskIdentifierInfo) == valueJavaOnlyStart) { + result.append(", currency"); + } + if ((val & maskIdentifierInfo) == valueJavaUnicodeStart) { + result.append(", identifier start"); + } + if ((val & maskNumericType) == valueDigit) { + result.append(", decimal "); + result.append((val & maskDigitOffset) >> shiftDigitOffset); + } + if ((val & maskNumericType) == valueStrangeNumeric) { + result.append(", strange"); + } + if ((val & maskNumericType) == valueJavaSupradecimal) { + result.append(", supradecimal "); + result.append((val & maskDigitOffset) >> shiftDigitOffset); + } + } + + static String[] tableNames = { "X", "Y", "Z", "P", "Q", "R", "S", "T", "U", "V", "W" }; + + static String tableName(int j) { return tableNames[j]; } + + /** + * The genAccess method generates source code for one table access expression. + * + * Most of the complexity stems from handling various options as to + * table representation, such as whether it contains values so large that + * they are represented as negative values and whether the table values are + * preshifted. This method also avoids such "ugly" expressions as shifting + * by distance zero, masking when no masking is necessary, and so on. + * For clarity, it generates expressions that do not rely on operator + * precedence, but otherwise it avoids generating redundant parentheses. + * + * A generated expression might look like A[Y[(X[ch>>6]<<6)|(ch&0x3F)]] + * or A[Z[Y[(X[ch>>7]<<4)|((ch>>3)&0xF)]|(ch&0x7)]], for example. + * + * @param tbl the name of the final table to be accessed + * @param var the variable name that appeared in parentheses in the + * "Lookup" command + * @param bits the number of bits (not bytes) to be used to represent + * the final table entry + * @return the replacement text for the "Lookup(xxx)" command, as a String + * + * @see GenerateCharacter#replaceCommand + */ + + static String genAccess(String tbl, String var, int bits) { + String access = null; + int bitoffset = bits == 1 ? 5 : bits == 2 ? 4 : bits == 4 ? 3 : 0; + for (int k = 0; k < sizes.length; k++) { + int offset = ((k < sizes.length - 1) ? 0 : bitoffset); + int shift = shifts[k] + offset; + String shifted = (shift == 0) ? var : "(" + var + ">>" + shift + ")"; + int mask = (1 << (sizes[k] - offset)) - 1; + String masked = (k == 0) ? shifted : + "(" + shifted + "&0x" + hex(mask) + ")"; + String index = (k == 0) ? masked : + (mask == 0) ? access : "(" + access + "|" + masked + ")"; + String indexNoParens = (index.charAt(0) != '(') ? index : + index.substring(1, index.length() - 1); + String tblname = (k == sizes.length - 1) ? tbl : tableName(k); + String fetched = tblname + "[" + indexNoParens + "]"; + String zeroextended = (zeroextend[k] == 0) ? fetched : + "(" + fetched + "&0x" + hex(zeroextend[k]) + ")"; + int adjustment = preshifted[k] ? 0 : + sizes[k+1] - ((k == sizes.length - 2) ? bitoffset : 0); + String adjusted = (preshifted[k] || adjustment == 0) ? zeroextended : + "(" + zeroextended + "<<" + adjustment + ")"; + String bitshift = (bits == 1) ? "(" + var + "&0x1F)" : + (bits == 2) ? "((" + var + "&0xF)<<1)" : + (bits == 4) ? "((" + var + "&7)<<2)" : null; + String extracted = ((k < sizes.length - 1) || (bits >= 8)) ? adjusted : + "((" + adjusted + ">>" + bitshift + ")&" + + (bits == 4 ? "0xF" : "" + ((1 << bits) - 1)) + ")"; + access = extracted; + } + return access; + } + + /* The command line arguments are decoded and used to set the following + global variables. + */ + + static boolean verbose = false; + static boolean nobidi = false; + static boolean nomirror = false; + static boolean identifiers = false; + static boolean Csyntax = false; + static String TemplateFileName = null; + static String OutputFileName = null; + static String UnicodeSpecFileName = null; // liu + static String SpecialCasingFileName = null; + static String PropListFileName = null; + static String DerivedPropsFileName = null; + static boolean useCharForByte = false; + static int[] sizes; + static int bins = 0; // liu; if > 0, then perform search + static boolean tableAsString = false; + static boolean bLatin1 = false; + + static String commandLineDescription; + + /* Other global variables, equal in length to the "sizes" array. */ + + static int[] shifts; + static int[] zeroextend; + static int[] bytes; + static boolean[] preshifted; + static long[][] tables; + + + /* Other global variables */ + static String commentStart; + static String commentEnd; + + static StringBuffer initializers = new StringBuffer(); + + /* special casing rules for 1:M toUpperCase mappings */ + static SpecialCaseMap[] specialCaseMaps; + + /** + * Process the command line arguments. + * + * The allowed flags in command line are: + *
    + *
    -verbose
    Emit comments to standard output describing + * what's going on during the processing. + *
    -nobidi
    Do not include bidi categories in the + * encoded character properties. + *
    -nomirror
    Do no include mirror property in the encoded + * character properties. + *
    -identifiers
    Generate tables for scanning identifiers only. + *
    -c
    Output code in C syntax instead of Java syntax. + *
    -o filename
    Specify output file name. + *
    -template filename
    Specify template input file name. + *
    -spec filename
    Specify Unicode spec file name. + *
    -specialcasing filename
    Specify Unicode special casing file name. + *
    -search bins
    Try different partitions into the specified + * number of bins. E.g., for 2 bins, try + * 16 0, 15 1,..., 0 16. + *
    -string
    Create table as string. Only valid with Java + * syntax. + *
    -latin1
    Create a latin 1 only property table. + *
    + * In addition, decimal literals may appear as command line arguments; + * each one represents the number of bits of the character to be broken + * off at each lookup step. If present, they must add up to 16 (the number + * of bits in a char value). For smaller tables, the last value should + * be 0; values other than the last one may not be zero. If no such + * numeric values are provided, default values are used. + * + * @param args the command line arguments, as an array of String + * + * @see GenerateCharacter#main + */ + + static void processArgs(String[] args) { + StringBuffer desc = new StringBuffer("java GenerateCharacter"); + for (int j=0; j 10) + FAIL("Bin count must be >= 1 and <= 10"); + } + } + else if (args[j].equals("-template")) { + if (j == args.length - 1) + FAIL("File name missing after -template"); + else + TemplateFileName = args[++j]; + } + else if (args[j].equals("-spec")) { // liu + if (j == args.length - 1) { + FAIL("File name missing after -spec"); + } + else { + UnicodeSpecFileName = args[++j]; + } + } + else if (args[j].equals("-specialcasing")) { + if (j == args.length -1) { + FAIL("File name missing after -specialcasing"); + } + else { + SpecialCasingFileName = args[++j]; + } + } + else if (args[j].equals("-proplist")) { + if (j == args.length -1) { + FAIL("File name missing after -proplist"); + } + else { + PropListFileName = args[++j]; + } + } + else if (args[j].equals("-derivedprops")) { + if (j == args.length -1) { + FAIL("File name missing after -derivedprops"); + } + else { + DerivedPropsFileName = args[++j]; + } + } + else if (args[j].equals("-plane")) { + if (j == args.length -1) { + FAIL("Plane number missing after -plane"); + } + else { + plane = Integer.parseInt(args[++j]); + } + if (plane > 0) { + bLatin1 = false; + } + } + else if ("-usecharforbyte".equals(args[j])) { + useCharForByte = true; + } + else if (args[j].equals("-latin1")) { + bLatin1 = true; + plane = 0; + } + else { + try { + int val = Integer.parseInt(args[j]); + if (val < 0 || val > 32) FAIL("Incorrect bit field width: " + args[j]); + if (sizes == null) + sizes = new int[1]; + else { + int[] newsizes = new int[sizes.length + 1]; + System.arraycopy(sizes, 0, newsizes, 0, sizes.length); + sizes = newsizes; + } + sizes[sizes.length - 1] = val; + } + catch(NumberFormatException e) { + FAIL("Unknown switch: " + args[j]); + } + } + } + if (Csyntax && tableAsString) { + FAIL("Can't specify table as string with C syntax"); + } + if (sizes == null) { + desc.append(" ["); + if (identifiers) { + int[] newsizes = { 8, 4, 4 }; // Good default values + desc.append("8 4 4]"); + sizes = newsizes; + } + else { + int[] newsizes = { 10, 5, 1 }; // Guy's old defaults for 2.0.14: { 9, 4, 3, 0 } + desc.append("10 5 1]"); + sizes = newsizes; + } + } + if (UnicodeSpecFileName == null) { // liu + UnicodeSpecFileName = DefaultUnicodeSpecFileName; + desc.append(" [-spec " + UnicodeSpecFileName + ']'); + } + if (SpecialCasingFileName == null) { + SpecialCasingFileName = DefaultSpecialCasingFileName; + desc.append(" [-specialcasing " + SpecialCasingFileName + ']'); + } + if (PropListFileName == null) { + PropListFileName = DefaultPropListFileName; + desc.append(" [-proplist " + PropListFileName + ']'); + } + if (DerivedPropsFileName == null) { + DerivedPropsFileName = DefaultDerivedPropsFileName; + desc.append(" [-derivedprops " + DerivedPropsFileName + ']'); + } + if (TemplateFileName == null) { + TemplateFileName = (Csyntax ? DefaultCTemplateFileName + : DefaultJavaTemplateFileName); + desc.append(" [-template " + TemplateFileName + ']'); + } + if (OutputFileName == null) { + OutputFileName = (Csyntax ? DefaultCOutputFileName + : DefaultJavaOutputFileName); + desc.append(" [-o " + OutputFileName + ']'); + } + commentStart = (Csyntax ? "/*" : "//"); + commentEnd = (Csyntax ? " */" : ""); + commandLineDescription = desc.toString(); + } + + private static void searchBins(long[] map, int binsOccupied) throws Exception { + int bitsFree = 16; + for (int i=0; i= 0; k--) { + shifts[k] = sum; + sum += sizes[k]; + } + if ((1 << sum) < map.length || (1 << (sum - 1)) >= map.length) { + FAIL("Bit field widths total to " + sum + + ": wrong total for map of size " + map.length); + } + // need a table for each set of lookup bits in char + tables = new long[sizes.length][]; + // the last table is the map + tables[sizes.length - 1] = map; + for (int j = sizes.length - 1; j > 0; j--) { + if (verbose && bins==0) + System.err.println("Building map " + (j+1) + " of bit width " + sizes[j]); + long[][] temp = buildTable(tables[j], sizes[j]); + tables[j-1] = temp[0]; + tables[j] = temp[1]; + } + preshifted = new boolean[sizes.length]; + zeroextend = new int[sizes.length]; + bytes = new int[sizes.length]; + for (int j = 0; j < sizes.length - 1; j++) { + int len = tables[j+1].length; + int size = sizes[j+1]; + if (len > 0x100 && (len >> size) <= 0x100) { + len >>= size; + preshifted[j] = false; + } + else if (len > 0x10000 && (len >> size) <= 0x10000) { + len >>= size; + preshifted[j] = false; + } + else preshifted[j] = true; + if (Csyntax) + zeroextend[j] = 0; + else if (len > 0x7F && len <= 0xFF) { + if (!useCharForByte) { + zeroextend[j] = 0xFF; + } + } else if (len > 0x7FFF && len <= 0xFFFF) + zeroextend[j] = 0xFFFF; + else zeroextend[j] = 0; + if (len <= 0x100) bytes[j] = 1; + else if (len <= 0x10000) bytes[j] = 2; + else bytes[j] = 4; + } + preshifted[sizes.length - 1] = true; + zeroextend[sizes.length - 1] = 0; + bytes[sizes.length - 1] = 0; + if (bins > 0) { + int totalBytes = getTotalBytes(); + String access = genAccess("A", "ch", (identifiers ? 2 : 32)); + int accessComplexity = 0; + for (int j=0; j<".indexOf(ch) >= 0) ++accessComplexity; + if (ch == '<' || ch == '>') ++j; + } + System.out.print("("); + for (int j=0; j + *
  • Process the command line arguments. One result of this process + * is a list of sizes (measured in bits and summing to 16). + *
  • Get the Unicode character property data from the specification file. + *
  • From that, build a map that has, for each character code, its + * relevant properties encoded as a long integer value. + *
  • Repeatedly compress the map, producing a compressed table and a + * new map. This is done once for each size value in the list. + * When this is done, we have a set of tables. + *
  • Make some decisions about table representation; record these + * decisions in arrays named preshifted, zeroextend, and bytes. + *
  • Generate the source code for the class Character by performing + * macro processing on a template file. + * + * + * @param args the command line arguments, as an array of String + * + * @see GenerateCharacter#processArgs + * @see UnicodeSpec@readSpecFile + * @see GenerateCharacter#buildMap + * @see GenerateCharacter#buildTable + * @see GenerateCharacter#generateCharacterClass + */ + + public static void main(String[] args) { + processArgs(args); + try { + + UnicodeSpec[] data = UnicodeSpec.readSpecFile(new File(UnicodeSpecFileName), plane); + specialCaseMaps = SpecialCaseMap.readSpecFile(new File(SpecialCasingFileName), plane); + PropList propList = PropList.readSpecFile(new File(PropListFileName), plane); + propList.putAll(PropList.readSpecFile(new File(DerivedPropsFileName), plane)); + + if (verbose) { + System.out.println(data.length + " items read from Unicode spec file " + UnicodeSpecFileName); // liu + } + long[] map = buildMap(data, specialCaseMaps, propList); + if (verbose) { + System.err.println("Completed building of initial map"); + } + + if (bins == 0) { + generateForSizes(map); + } + else { + while (bins > 0) { + sizes = new int[bins]; + searchBins(map, 0); + --bins; + } + } + if (verbose && false) { + System.out.println("Offset range seen: -" + hex8(-minOffsetSeen) + "..+" + + hex8(maxOffsetSeen)); + System.out.println(" allowed: -" + hex8(-minOffset) + "..+" + + hex8(maxOffset)); + } + } + catch (FileNotFoundException e) { FAIL(e.toString()); } + catch (IOException e) { FAIL(e.toString()); } + catch (Throwable e) { + System.out.println("Unexpected exception:"); + e.printStackTrace(); + FAIL("Unexpected exception!"); + } + if (verbose) { System.out.println("Done!");} + } + +} // end class --- old/make/jdk/src/classes/build/tools/generatecharacter/PrintCharacterRanges.java 2020-03-23 19:56:46.623962628 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,205 +0,0 @@ -/* - * Copyright (c) 2002, 2020, 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.generatecharacter; - -import java.lang.reflect.*; -import java.util.*; - -/** Recovers and prints ranges for certain java.lang.Character - properties. Useful for generating fast-path Latin-1 code. */ - -public class PrintCharacterRanges { - static class BooleanRange { - private int begin; - private int end; - - BooleanRange(int begin, int end) { - this.begin = begin; - this.end = end; - } - - int begin() { return begin; } - int end() { return end; } - } - - private static List recoverBooleanRanges(String methodName) throws Exception { - List result = new ArrayList<>(); - int currentRangeStart = -1; - Method method = Character.class.getDeclaredMethod(methodName, new Class[] { Character.TYPE }); - if (method == null) { - throw new RuntimeException("No method \"" + methodName + "\"(C) found"); - } - - for (int i = 0; i <= 255; i++) { - boolean methodRes = ((Boolean) method.invoke(null, new Object[] { Character.valueOf((char) i) })).booleanValue(); - if (methodRes) { - if (currentRangeStart < 0) { - currentRangeStart = i; - } - if (i == 255) { - result.add(new BooleanRange(currentRangeStart, i)); - } - } else { - if (currentRangeStart >= 0) { - result.add(new BooleanRange(currentRangeStart, i - 1)); - currentRangeStart = -1; - } - } - } - - return result; - } - - private static String describe(int num) { - StringBuffer s = new StringBuffer(); - s.append(num); - s.append(" ('"); - if (num > 32 && num < 123) { - s.append((char) num); - } else { - s.append("\\u"); - String hex = Long.toHexString(num).toUpperCase(); - for (int i = 0; i < (4 - hex.length()); i++) { - s.append('0'); - } - s.append(hex); - } - s.append("')"); - return s.toString(); - } - - private static void printBooleanRanges(List ranges, String methodName) { - System.out.print(methodName + ":"); - for (Iterator iter = ranges.iterator(); iter.hasNext();) { - BooleanRange range = iter.next(); - System.out.print(" [ " + describe(range.begin()) + ", " + describe(range.end()) + " ]"); - } - System.out.println(""); - } - - private static void recoverAndPrintBooleanRanges(String methodName) throws Exception { - List ranges = recoverBooleanRanges(methodName); - printBooleanRanges(ranges, methodName); - } - - static class ShiftRange { - private int begin; - private int end; - private int offset; - - ShiftRange(int begin, int end, int offset) { - this.begin = begin; - this.end = end; - this.offset = offset; - } - - int begin() { return begin; } - int end() { return end; } - int offset() { return offset; } - } - - private static List recoverShiftRanges(String methodName) throws Exception { - List result = new ArrayList<>(); - int currentRangeStart = -1; - int currentRangeOffset = -1; - Method method = Character.class.getDeclaredMethod(methodName, new Class[] { Character.TYPE }); - if (method == null) { - throw new RuntimeException("No method \"" + methodName + "\"(C) found"); - } - - for (int i = 0; i <= 255; i++) { - char methodRes = ((Character) method.invoke(null, new Object[] { Character.valueOf((char) i) })).charValue(); - if (methodRes != i) { - int offset = methodRes - i; - if (currentRangeStart < 0) { - currentRangeStart = i; - } else if (offset != currentRangeOffset) { - result.add(new ShiftRange(currentRangeStart, i - 1, currentRangeOffset)); - currentRangeStart = i; - } - currentRangeOffset = offset; - if (i == 255) { - result.add(new ShiftRange(currentRangeStart, i, currentRangeOffset)); - } - } else { - if (currentRangeStart >= 0) { - result.add(new ShiftRange(currentRangeStart, i - 1, currentRangeOffset)); - currentRangeStart = -1; - } - } - } - - return result; - } - - private static void printShiftRanges(List ranges, String methodName) { - System.out.print(methodName + ":"); - boolean isFirst = true; - for (Iterator iter = ranges.iterator(); iter.hasNext();) { - ShiftRange range = iter.next(); - if (isFirst) { - isFirst = false; - } else { - System.out.print(", "); - } - System.out.print(" [ " + describe(range.begin()) + ", " + describe(range.end()) + " ] -> [ " + - describe((range.begin() + range.offset())) + ", " + describe((range.end() + range.offset())) + " ] (" + - range.offset() + ")"); - } - System.out.println(""); - } - - private static void recoverAndPrintShiftRanges(String methodName) throws Exception { - List ranges = recoverShiftRanges(methodName); - printShiftRanges(ranges, methodName); - } - - public static void main(String[] args) { - try { - recoverAndPrintBooleanRanges("isDefined"); - recoverAndPrintBooleanRanges("isDigit"); - recoverAndPrintBooleanRanges("isIdentifierIgnorable"); - recoverAndPrintBooleanRanges("isISOControl"); - recoverAndPrintBooleanRanges("isJavaIdentifierPart"); - recoverAndPrintBooleanRanges("isJavaIdentifierStart"); - recoverAndPrintBooleanRanges("isLetter"); - recoverAndPrintBooleanRanges("isLetterOrDigit"); - recoverAndPrintBooleanRanges("isLowerCase"); - recoverAndPrintBooleanRanges("isMirrored"); - recoverAndPrintBooleanRanges("isSpaceChar"); - recoverAndPrintBooleanRanges("isTitleCase"); - recoverAndPrintBooleanRanges("isUnicodeIdentifierPart"); - recoverAndPrintBooleanRanges("isUnicodeIdentifierStart"); - recoverAndPrintBooleanRanges("isUpperCase"); - recoverAndPrintBooleanRanges("isWhitespace"); - - recoverAndPrintShiftRanges("toUpperCase"); - recoverAndPrintShiftRanges("toLowerCase"); - } catch (Exception e) { - e.printStackTrace(); - } - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.base/share/tools/org/openjdk/buildtools/generatecharacter/PrintCharacterRanges.java 2020-03-23 19:56:46.187962631 +0100 @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatecharacter; + +import java.lang.reflect.*; +import java.util.*; + +/** Recovers and prints ranges for certain java.lang.Character + properties. Useful for generating fast-path Latin-1 code. */ + +public class PrintCharacterRanges { + static class BooleanRange { + private int begin; + private int end; + + BooleanRange(int begin, int end) { + this.begin = begin; + this.end = end; + } + + int begin() { return begin; } + int end() { return end; } + } + + private static List recoverBooleanRanges(String methodName) throws Exception { + List result = new ArrayList<>(); + int currentRangeStart = -1; + Method method = Character.class.getDeclaredMethod(methodName, new Class[] { Character.TYPE }); + if (method == null) { + throw new RuntimeException("No method \"" + methodName + "\"(C) found"); + } + + for (int i = 0; i <= 255; i++) { + boolean methodRes = ((Boolean) method.invoke(null, new Object[] { Character.valueOf((char) i) })).booleanValue(); + if (methodRes) { + if (currentRangeStart < 0) { + currentRangeStart = i; + } + if (i == 255) { + result.add(new BooleanRange(currentRangeStart, i)); + } + } else { + if (currentRangeStart >= 0) { + result.add(new BooleanRange(currentRangeStart, i - 1)); + currentRangeStart = -1; + } + } + } + + return result; + } + + private static String describe(int num) { + StringBuffer s = new StringBuffer(); + s.append(num); + s.append(" ('"); + if (num > 32 && num < 123) { + s.append((char) num); + } else { + s.append("\\u"); + String hex = Long.toHexString(num).toUpperCase(); + for (int i = 0; i < (4 - hex.length()); i++) { + s.append('0'); + } + s.append(hex); + } + s.append("')"); + return s.toString(); + } + + private static void printBooleanRanges(List ranges, String methodName) { + System.out.print(methodName + ":"); + for (Iterator iter = ranges.iterator(); iter.hasNext();) { + BooleanRange range = iter.next(); + System.out.print(" [ " + describe(range.begin()) + ", " + describe(range.end()) + " ]"); + } + System.out.println(""); + } + + private static void recoverAndPrintBooleanRanges(String methodName) throws Exception { + List ranges = recoverBooleanRanges(methodName); + printBooleanRanges(ranges, methodName); + } + + static class ShiftRange { + private int begin; + private int end; + private int offset; + + ShiftRange(int begin, int end, int offset) { + this.begin = begin; + this.end = end; + this.offset = offset; + } + + int begin() { return begin; } + int end() { return end; } + int offset() { return offset; } + } + + private static List recoverShiftRanges(String methodName) throws Exception { + List result = new ArrayList<>(); + int currentRangeStart = -1; + int currentRangeOffset = -1; + Method method = Character.class.getDeclaredMethod(methodName, new Class[] { Character.TYPE }); + if (method == null) { + throw new RuntimeException("No method \"" + methodName + "\"(C) found"); + } + + for (int i = 0; i <= 255; i++) { + char methodRes = ((Character) method.invoke(null, new Object[] { Character.valueOf((char) i) })).charValue(); + if (methodRes != i) { + int offset = methodRes - i; + if (currentRangeStart < 0) { + currentRangeStart = i; + } else if (offset != currentRangeOffset) { + result.add(new ShiftRange(currentRangeStart, i - 1, currentRangeOffset)); + currentRangeStart = i; + } + currentRangeOffset = offset; + if (i == 255) { + result.add(new ShiftRange(currentRangeStart, i, currentRangeOffset)); + } + } else { + if (currentRangeStart >= 0) { + result.add(new ShiftRange(currentRangeStart, i - 1, currentRangeOffset)); + currentRangeStart = -1; + } + } + } + + return result; + } + + private static void printShiftRanges(List ranges, String methodName) { + System.out.print(methodName + ":"); + boolean isFirst = true; + for (Iterator iter = ranges.iterator(); iter.hasNext();) { + ShiftRange range = iter.next(); + if (isFirst) { + isFirst = false; + } else { + System.out.print(", "); + } + System.out.print(" [ " + describe(range.begin()) + ", " + describe(range.end()) + " ] -> [ " + + describe((range.begin() + range.offset())) + ", " + describe((range.end() + range.offset())) + " ] (" + + range.offset() + ")"); + } + System.out.println(""); + } + + private static void recoverAndPrintShiftRanges(String methodName) throws Exception { + List ranges = recoverShiftRanges(methodName); + printShiftRanges(ranges, methodName); + } + + public static void main(String[] args) { + try { + recoverAndPrintBooleanRanges("isDefined"); + recoverAndPrintBooleanRanges("isDigit"); + recoverAndPrintBooleanRanges("isIdentifierIgnorable"); + recoverAndPrintBooleanRanges("isISOControl"); + recoverAndPrintBooleanRanges("isJavaIdentifierPart"); + recoverAndPrintBooleanRanges("isJavaIdentifierStart"); + recoverAndPrintBooleanRanges("isLetter"); + recoverAndPrintBooleanRanges("isLetterOrDigit"); + recoverAndPrintBooleanRanges("isLowerCase"); + recoverAndPrintBooleanRanges("isMirrored"); + recoverAndPrintBooleanRanges("isSpaceChar"); + recoverAndPrintBooleanRanges("isTitleCase"); + recoverAndPrintBooleanRanges("isUnicodeIdentifierPart"); + recoverAndPrintBooleanRanges("isUnicodeIdentifierStart"); + recoverAndPrintBooleanRanges("isUpperCase"); + recoverAndPrintBooleanRanges("isWhitespace"); + + recoverAndPrintShiftRanges("toUpperCase"); + recoverAndPrintShiftRanges("toLowerCase"); + } catch (Exception e) { + e.printStackTrace(); + } + } +} --- old/make/jdk/src/classes/build/tools/generatecharacter/PropList.java 2020-03-23 19:56:47.459962622 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2011, 2019, 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.generatecharacter; - -import java.util.regex.*; -import java.util.*; -import java.io.*; - -/** - * A PropList object contains the lists of code points that have - * the same Unicode property defined in PropList.txt and - * DerivedCoreProperties.txt - * - * @author Xueming Shen - */ -public class PropList { - - public static PropList readSpecFile(File file, int plane) - throws IOException - { - return new PropList(file, plane); - } - - public List codepoints(String name) { - return propMap.get(name); - } - - public Set names() { - return propMap.keySet(); - } - - public void putAll(PropList pl) { - pl.names().stream() - .forEach(name -> propMap.put(name, pl.codepoints(name))); - } - - private Map> propMap = - new LinkedHashMap>(); - - private PropList(File file, int plane) throws IOException { - - int i, j; - BufferedReader sbfr = new BufferedReader(new FileReader(file)); - Matcher m = Pattern.compile("(\\p{XDigit}+)(?:\\.{2}(\\p{XDigit}+))?\\s*;\\s+(\\w+)\\s+#.*").matcher(""); - String line = null; - int lineNo = 0; - while ((line = sbfr.readLine()) != null) { - lineNo++; - if (line.length() <= 1 || line.charAt(0) == '#') { - continue; - } - m.reset(line); - if (m.matches()) { - int start = Integer.parseInt(m.group(1), 16); - if ((start >> 16) != plane) - continue; - int end = (m.group(2)==null)?start - :Integer.parseInt(m.group(2), 16); - String name = m.group(3); - - start &= 0xffff; - end &= 0xffff; - - List list = propMap.get(name); - if (list == null) { - list = new ArrayList(); - propMap.put(name, list); - } - while (start <= end) - list.add(start++); - } else { - System.out.printf("Warning: Unrecognized line %d <%s>%n", lineNo, line); - } - } - sbfr.close(); - - //for (String name: propMap.keySet()) { - // System.out.printf("%s %d%n", name, propMap.get(name).size()); - //} - } - - public static void main(String[] args) throws IOException { - readSpecFile(new File(args[0]), Integer.decode(args[1])); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.base/share/tools/org/openjdk/buildtools/generatecharacter/PropList.java 2020-03-23 19:56:47.035962625 +0100 @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatecharacter; + +import java.util.regex.*; +import java.util.*; +import java.io.*; + +/** + * A PropList object contains the lists of code points that have + * the same Unicode property defined in PropList.txt and + * DerivedCoreProperties.txt + * + * @author Xueming Shen + */ +public class PropList { + + public static PropList readSpecFile(File file, int plane) + throws IOException + { + return new PropList(file, plane); + } + + public List codepoints(String name) { + return propMap.get(name); + } + + public Set names() { + return propMap.keySet(); + } + + public void putAll(PropList pl) { + pl.names().stream() + .forEach(name -> propMap.put(name, pl.codepoints(name))); + } + + private Map> propMap = + new LinkedHashMap>(); + + private PropList(File file, int plane) throws IOException { + + int i, j; + BufferedReader sbfr = new BufferedReader(new FileReader(file)); + Matcher m = Pattern.compile("(\\p{XDigit}+)(?:\\.{2}(\\p{XDigit}+))?\\s*;\\s+(\\w+)\\s+#.*").matcher(""); + String line = null; + int lineNo = 0; + while ((line = sbfr.readLine()) != null) { + lineNo++; + if (line.length() <= 1 || line.charAt(0) == '#') { + continue; + } + m.reset(line); + if (m.matches()) { + int start = Integer.parseInt(m.group(1), 16); + if ((start >> 16) != plane) + continue; + int end = (m.group(2)==null)?start + :Integer.parseInt(m.group(2), 16); + String name = m.group(3); + + start &= 0xffff; + end &= 0xffff; + + List list = propMap.get(name); + if (list == null) { + list = new ArrayList(); + propMap.put(name, list); + } + while (start <= end) + list.add(start++); + } else { + System.out.printf("Warning: Unrecognized line %d <%s>%n", lineNo, line); + } + } + sbfr.close(); + + //for (String name: propMap.keySet()) { + // System.out.printf("%s %d%n", name, propMap.get(name).size()); + //} + } + + public static void main(String[] args) throws IOException { + readSpecFile(new File(args[0]), Integer.decode(args[1])); + } +} --- old/make/jdk/src/classes/build/tools/generatecharacter/SpecialCaseMap.java 2020-03-23 19:56:48.303962616 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,362 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatecharacter; - -import java.io.*; -import java.util.*; -import java.lang.*; - -/** - * SpecialCaseMap has the responsibility of storing the - * 1:M, locale-sensitive, and context sensitive case mappings - * that occur when uppercasing Unicode 4.0 characters. This class can - * read and parse the SpecialCasing.txt file that contains those mappings. - *

    - * A single SpecialCaseMap contains the mapping for one character. - *

    - * @author John O'Conner - */ -public class SpecialCaseMap implements Comparable { - - SpecialCaseMap() { - chSource = 0xFFFF; - } - - - /** - * Read and parse a Unicode special case map file. - * - * @param file a file specifying the Unicode special case mappings - * @return an array of SpecialCaseMap objects, one for each line of the - * special case map data file that could be successfully parsed - */ - - public static SpecialCaseMap[] readSpecFile(File file, int plane) throws FileNotFoundException { - ArrayList caseMaps = new ArrayList<>(150); - int count = 0; - BufferedReader f = new BufferedReader(new FileReader(file)); - String line = null; - loop: - while(true) { - try { - line = f.readLine(); - } - catch (IOException e) { break loop; } - if (line == null) break loop; - SpecialCaseMap item = parse(line.trim()); - if (item != null) { - if(item.getCharSource() >> 16 < plane) continue; - if(item.getCharSource() >> 16 > plane) break; - caseMaps.add(item); - ++count; - } - - } - caseMaps.trimToSize(); - SpecialCaseMap[] result = new SpecialCaseMap[caseMaps.size()]; - caseMaps.toArray(result); - Arrays.sort(result); - return result; - - } - - /** - * Given one line of a Unicode special casing data file as a String, parse the line - * and return a SpecialCaseMap object that contains the case mapping. - * - * @param s a line of the Unicode special case map data file to be parsed - * @return a SpecialCaseMap object, or null if the parsing process failed for some reason - */ - public static SpecialCaseMap parse(String s) { - SpecialCaseMap spec = null; - String[] tokens = new String[REQUIRED_FIELDS]; - if ( s != null && s.length() != 0 && s.charAt(0) != '#') { - try { - int x = 0, tokenStart = 0, tokenEnd = 0; - for (x=0; x 0xFFFF) { - buff.append(getHighSurrogate(ch)); - buff.append(getLowSurrogate(ch)); - } else { - buff.append((char)ch); - } - } - char[] map = new char[buff.length()]; - buff.getChars(0, buff.length(), map, 0); - return map; - } - - static Locale parseLocale(String token) { - return null; - } - - static String[] parseContext(String token) { - return null; - } - - static int find(int ch, SpecialCaseMap[] map) { - if ((map == null) || (map.length == 0)) { - return -1; - } - int top, bottom, current; - bottom = 0; - top = map.length; - current = top/2; - // invariant: top > current >= bottom && ch >= map.chSource - while (top - bottom > 1) { - if (ch >= map[current].getCharSource()) { - bottom = current; - } else { - top = current; - } - current = (top + bottom) / 2; - } - if (ch == map[current].getCharSource()) return current; - else return -1; - } - - /* - * Extracts and returns the high surrogate value from a UTF-32 code point. - * If argument is a BMP character, then it is converted to a char and returned; - * otherwise the high surrogate value is extracted. - * @param codePoint a UTF-32 codePoint with value greater than 0xFFFF. - * @return the high surrogate value that helps create codePoint; else - * the char representation of codePoint if it is a BMP character. - * @since 1.5 - */ - static char getHighSurrogate(int codePoint) { - char high = (char)codePoint; - if (codePoint > 0xFFFF) { - high = (char)((codePoint - 0x10000)/0x0400 + 0xD800); - } - return high; - } - - - /* - * Extracts and returns the low surrogate value from a UTF-32 code point. - * If argument is a BMP character, then it is converted to a char and returned; - * otherwise the high surrogate value is extracted. - * @param codePoint a UTF-32 codePoint with value greater than 0xFFFF. - * @return the low surrogate value that helps create codePoint; else - * the char representation of codePoint if it is a BMP character. - * @since 1.5 - */ - static char getLowSurrogate(int codePoint) { - char low = (char)codePoint; - if(codePoint > 0xFFFF) { - low = (char)((codePoint - 0x10000)%0x0400 + 0xDC00); - } - return low; - } - - static String hex6(int n) { - String str = Integer.toHexString(n & 0xFFFFFF).toUpperCase(); - return "000000".substring(Math.min(6, str.length())) + str; - } - - static String hex6(char[] map){ - StringBuffer buff = new StringBuffer(); - int x=0; - buff.append(hex6(map[x++])); - while(x otherObject.chSource) { - return 1; - } - else return 0; - } - - public boolean equals(Object o1) { - if (this == o1) { - return true; - } - if (o1 == null || !(o1 instanceof SpecialCaseMap)) { - return false; - } - SpecialCaseMap other = (SpecialCaseMap)o1; - boolean bEqual = false; - if (0 == compareTo(other)) { - bEqual = true; - } - return bEqual; - } - - public String toString() { - StringBuffer buff = new StringBuffer(); - buff.append(hex6(getCharSource())); - buff.append("|" + hex6(lowerCaseMap)); - buff.append("|" + hex6(upperCaseMap)); - buff.append("|" + hex6(titleCaseMap)); - buff.append("|" + context); - return buff.toString(); - } - - public int hashCode() { - return chSource; - } - - public static void main(String[] args) { - SpecialCaseMap[] spec = null; - if (args.length == 2 ) { - try { - File file = new File(args[0]); - int plane = Integer.parseInt(args[1]); - spec = SpecialCaseMap.readSpecFile(file, plane); - System.out.println("SpecialCaseMap[" + spec.length + "]:"); - for (int x=0; x + * A single SpecialCaseMap contains the mapping for one character. + *

    + * @author John O'Conner + */ +public class SpecialCaseMap implements Comparable { + + SpecialCaseMap() { + chSource = 0xFFFF; + } + + + /** + * Read and parse a Unicode special case map file. + * + * @param file a file specifying the Unicode special case mappings + * @return an array of SpecialCaseMap objects, one for each line of the + * special case map data file that could be successfully parsed + */ + + public static SpecialCaseMap[] readSpecFile(File file, int plane) throws FileNotFoundException { + ArrayList caseMaps = new ArrayList<>(150); + int count = 0; + BufferedReader f = new BufferedReader(new FileReader(file)); + String line = null; + loop: + while(true) { + try { + line = f.readLine(); + } + catch (IOException e) { break loop; } + if (line == null) break loop; + SpecialCaseMap item = parse(line.trim()); + if (item != null) { + if(item.getCharSource() >> 16 < plane) continue; + if(item.getCharSource() >> 16 > plane) break; + caseMaps.add(item); + ++count; + } + + } + caseMaps.trimToSize(); + SpecialCaseMap[] result = new SpecialCaseMap[caseMaps.size()]; + caseMaps.toArray(result); + Arrays.sort(result); + return result; + + } + + /** + * Given one line of a Unicode special casing data file as a String, parse the line + * and return a SpecialCaseMap object that contains the case mapping. + * + * @param s a line of the Unicode special case map data file to be parsed + * @return a SpecialCaseMap object, or null if the parsing process failed for some reason + */ + public static SpecialCaseMap parse(String s) { + SpecialCaseMap spec = null; + String[] tokens = new String[REQUIRED_FIELDS]; + if ( s != null && s.length() != 0 && s.charAt(0) != '#') { + try { + int x = 0, tokenStart = 0, tokenEnd = 0; + for (x=0; x 0xFFFF) { + buff.append(getHighSurrogate(ch)); + buff.append(getLowSurrogate(ch)); + } else { + buff.append((char)ch); + } + } + char[] map = new char[buff.length()]; + buff.getChars(0, buff.length(), map, 0); + return map; + } + + static Locale parseLocale(String token) { + return null; + } + + static String[] parseContext(String token) { + return null; + } + + static int find(int ch, SpecialCaseMap[] map) { + if ((map == null) || (map.length == 0)) { + return -1; + } + int top, bottom, current; + bottom = 0; + top = map.length; + current = top/2; + // invariant: top > current >= bottom && ch >= map.chSource + while (top - bottom > 1) { + if (ch >= map[current].getCharSource()) { + bottom = current; + } else { + top = current; + } + current = (top + bottom) / 2; + } + if (ch == map[current].getCharSource()) return current; + else return -1; + } + + /* + * Extracts and returns the high surrogate value from a UTF-32 code point. + * If argument is a BMP character, then it is converted to a char and returned; + * otherwise the high surrogate value is extracted. + * @param codePoint a UTF-32 codePoint with value greater than 0xFFFF. + * @return the high surrogate value that helps create codePoint; else + * the char representation of codePoint if it is a BMP character. + * @since 1.5 + */ + static char getHighSurrogate(int codePoint) { + char high = (char)codePoint; + if (codePoint > 0xFFFF) { + high = (char)((codePoint - 0x10000)/0x0400 + 0xD800); + } + return high; + } + + + /* + * Extracts and returns the low surrogate value from a UTF-32 code point. + * If argument is a BMP character, then it is converted to a char and returned; + * otherwise the high surrogate value is extracted. + * @param codePoint a UTF-32 codePoint with value greater than 0xFFFF. + * @return the low surrogate value that helps create codePoint; else + * the char representation of codePoint if it is a BMP character. + * @since 1.5 + */ + static char getLowSurrogate(int codePoint) { + char low = (char)codePoint; + if(codePoint > 0xFFFF) { + low = (char)((codePoint - 0x10000)%0x0400 + 0xDC00); + } + return low; + } + + static String hex6(int n) { + String str = Integer.toHexString(n & 0xFFFFFF).toUpperCase(); + return "000000".substring(Math.min(6, str.length())) + str; + } + + static String hex6(char[] map){ + StringBuffer buff = new StringBuffer(); + int x=0; + buff.append(hex6(map[x++])); + while(x otherObject.chSource) { + return 1; + } + else return 0; + } + + public boolean equals(Object o1) { + if (this == o1) { + return true; + } + if (o1 == null || !(o1 instanceof SpecialCaseMap)) { + return false; + } + SpecialCaseMap other = (SpecialCaseMap)o1; + boolean bEqual = false; + if (0 == compareTo(other)) { + bEqual = true; + } + return bEqual; + } + + public String toString() { + StringBuffer buff = new StringBuffer(); + buff.append(hex6(getCharSource())); + buff.append("|" + hex6(lowerCaseMap)); + buff.append("|" + hex6(upperCaseMap)); + buff.append("|" + hex6(titleCaseMap)); + buff.append("|" + context); + return buff.toString(); + } + + public int hashCode() { + return chSource; + } + + public static void main(String[] args) { + SpecialCaseMap[] spec = null; + if (args.length == 2 ) { + try { + File file = new File(args[0]); + int plane = Integer.parseInt(args[1]); + spec = SpecialCaseMap.readSpecFile(file, plane); + System.out.println("SpecialCaseMap[" + spec.length + "]:"); + for (int x=0; xcodePoint - * argument. Provide default properties. - * @param codePoint a Unicode code point between 0x0000 and 0x10FFFF - */ - public UnicodeSpec(int codePoint) { - this.codePoint = codePoint; - generalCategory = UNASSIGNED; - bidiCategory = DIRECTIONALITY_UNDEFINED; - mirrored = false; - titleMap = MAP_UNDEFINED; - upperMap = MAP_UNDEFINED; - lowerMap = MAP_UNDEFINED; - decimalValue = -1; - digitValue = -1; - numericValue = ""; - oldName = null; - comment = null; - name = null; - } - - /** - * Create a String representation of this UnicodeSpec object. - * The string will contain the code point and all its case mappings - * if available. - */ - public String toString() { - StringBuffer result = new StringBuffer(hex6(codePoint)); - if (getUpperMap() != MAP_UNDEFINED) { - result.append(", upper=").append(hex6(upperMap)); - } - if (getLowerMap() != MAP_UNDEFINED) { - result.append(", lower=").append(hex6(lowerMap)); - } - if (getTitleMap() != MAP_UNDEFINED) { - result.append(", title=").append(hex6(titleMap)); - } - return result.toString(); - } - - static String hex4(int n) { - String q = Integer.toHexString(n & 0xFFFF).toUpperCase(); - return "0000".substring(Math.min(4, q.length())) + q; - } - - static String hex6(int n) { - String str = Integer.toHexString(n & 0xFFFFFF).toUpperCase(); - return "000000".substring(Math.min(6, str.length())) + str; - - } - - - /** - * Given one line of a Unicode data file as a String, parse the line - * and return a UnicodeSpec object that contains the same character information. - * - * @param s a line of the Unicode data file to be parsed - * @return a UnicodeSpec object, or null if the parsing process failed for some reason - */ - public static UnicodeSpec parse(String s) { - UnicodeSpec spec = null; - String[] tokens = null; - - try { - tokens = tokenSeparator.split(s, REQUIRED_FIELDS); - spec = new UnicodeSpec(); - spec.setCodePoint(parseCodePoint(tokens[FIELD_VALUE])); - spec.setName(parseName(tokens[FIELD_NAME])); - spec.setGeneralCategory(parseGeneralCategory(tokens[FIELD_CATEGORY])); - spec.setBidiCategory(parseBidiCategory(tokens[FIELD_BIDI])); - spec.setCombiningClass(parseCombiningClass(tokens[FIELD_CLASS])); - spec.setDecomposition(parseDecomposition(tokens[FIELD_DECOMPOSITION])); - spec.setDecimalValue(parseDecimalValue(tokens[FIELD_DECIMAL])); - spec.setDigitValue(parseDigitValue(tokens[FIELD_DIGIT])); - spec.setNumericValue(parseNumericValue(tokens[FIELD_NUMERIC])); - spec.setMirrored(parseMirrored(tokens[FIELD_MIRRORED])); - spec.setOldName(parseOldName(tokens[FIELD_OLDNAME])); - spec.setComment(parseComment(tokens[FIELD_COMMENT])); - spec.setUpperMap(parseUpperMap(tokens[FIELD_UPPERCASE])); - spec.setLowerMap(parseLowerMap(tokens[FIELD_LOWERCASE])); - spec.setTitleMap(parseTitleMap(tokens[FIELD_TITLECASE])); - } - - catch(Exception e) { - spec = null; - System.out.println("Error parsing spec line."); - } - return spec; - } - - /** - * Parse the codePoint attribute for a Unicode character. If the parse succeeds, - * the codePoint field of this UnicodeSpec object is updated and false is returned. - * - * The codePoint attribute should be a four to six digit hexadecimal integer. - * - * @param s the codePoint attribute extracted from a line of the Unicode data file - * @return code point if successful - * @exception NumberFormatException if unable to parse argument - */ - public static int parseCodePoint(String s) throws NumberFormatException { - return Integer.parseInt(s, 16); - } - - public static String parseName(String s) throws Exception { - if (s==null) throw new Exception("Cannot parse name."); - return s; - } - - public static byte parseGeneralCategory(String s) throws Exception { - byte category = GENERAL_CATEGORY_COUNT; - - for (byte x=0; x= GENERAL_CATEGORY_COUNT) { - throw new Exception("Could not parse general category."); - } - return category; - } - - public static byte parseBidiCategory(String s) throws Exception { - byte category = DIRECTIONALITY_CATEGORY_COUNT; - - for (byte x=0; x= DIRECTIONALITY_CATEGORY_COUNT) { - throw new Exception("Could not parse bidi category."); - } - return category; - } - - - /** - * Parse the combining attribute for a Unicode character. If there is a combining - * attribute and the parse succeeds, then the hasCombining field is set to true, - * the combining field of this UnicodeSpec object is updated, and false is returned. - * If the combining attribute is an empty string, the parse succeeds but the - * hasCombining field is set to false. (and false is returned). - * - * The combining attribute, if any, should be a nonnegative decimal integer. - * - * @param s the combining attribute extracted from a line of the Unicode data file - * @return the combining class value if any, -1 if property not defined - * @exception Exception if can't parse the combining class - */ - - public static int parseCombiningClass(String s) throws Exception { - int combining = -1; - if (s.length()>0) { - combining = Integer.parseInt(s, 10); - } - return combining; - } - - /** - * Parse the decomposition attribute for a Unicode character. If the parse succeeds, - * the decomposition field of this UnicodeSpec object is updated and false is returned. - * - * The decomposition attribute is complicated; for now, it is treated as a string. - * - * @param s the decomposition attribute extracted from a line of the Unicode data file - * @return true if the parse failed; otherwise false - */ - - public static String parseDecomposition(String s) throws Exception { - if (s==null) throw new Exception("Cannot parse decomposition."); - return s; - } - - - /** - * Parse the decimal value attribute for a Unicode character. If there is a decimal value - * attribute and the parse succeeds, then the hasDecimalValue field is set to true, - * the decimalValue field of this UnicodeSpec object is updated, and false is returned. - * If the decimal value attribute is an empty string, the parse succeeds but the - * hasDecimalValue field is set to false. (and false is returned). - * - * The decimal value attribute, if any, should be a nonnegative decimal integer. - * - * @param s the decimal value attribute extracted from a line of the Unicode data file - * @return the decimal value as an int, -1 if no decimal value defined - * @exception NumberFormatException if the parse fails - */ - public static int parseDecimalValue(String s) throws NumberFormatException { - int value = -1; - - if (s.length() > 0) { - value = Integer.parseInt(s, 10); - } - return value; - } - - /** - * Parse the digit value attribute for a Unicode character. If there is a digit value - * attribute and the parse succeeds, then the hasDigitValue field is set to true, - * the digitValue field of this UnicodeSpec object is updated, and false is returned. - * If the digit value attribute is an empty string, the parse succeeds but the - * hasDigitValue field is set to false. (and false is returned). - * - * The digit value attribute, if any, should be a nonnegative decimal integer. - * - * @param s the digit value attribute extracted from a line of the Unicode data file - * @return the digit value as an non-negative int, or -1 if no digit property defined - * @exception NumberFormatException if the parse fails - */ - public static int parseDigitValue(String s) throws NumberFormatException { - int value = -1; - - if (s.length() > 0) { - value = Integer.parseInt(s, 10); - } - return value; - } - - public static String parseNumericValue(String s) throws Exception { - if (s == null) throw new Exception("Cannot parse numeric value."); - return s; - } - - public static String parseComment(String s) throws Exception { - if (s == null) throw new Exception("Cannot parse comment."); - return s; - } - - public static boolean parseMirrored(String s) throws Exception { - boolean mirrored; - if (s.length() == 1) { - if (s.charAt(0) == 'Y') {mirrored = true;} - else if (s.charAt(0) == 'N') {mirrored = false;} - else {throw new Exception("Cannot parse mirrored property.");} - } - else { throw new Exception("Cannot parse mirrored property.");} - return mirrored; - } - - public static String parseOldName(String s) throws Exception { - if (s == null) throw new Exception("Cannot parse old name"); - return s; - } - - /** - * Parse the uppercase mapping attribute for a Unicode character. If there is a uppercase - * mapping attribute and the parse succeeds, then the hasUpperMap field is set to true, - * the upperMap field of this UnicodeSpec object is updated, and false is returned. - * If the uppercase mapping attribute is an empty string, the parse succeeds but the - * hasUpperMap field is set to false. (and false is returned). - * - * The uppercase mapping attribute should be a four to six digit hexadecimal integer. - * - * @param s the uppercase mapping attribute extracted from a line of the Unicode data file - * @return simple uppercase character mapping if defined, MAP_UNDEFINED otherwise - * @exception NumberFormatException if parse fails - */ - public static int parseUpperMap(String s) throws NumberFormatException { - int upperCase = MAP_UNDEFINED; - - int length = s.length(); - if (length >= 4 && length <=6) { - upperCase = Integer.parseInt(s, 16); - } - else if (s.length() != 0) { - throw new NumberFormatException(); - } - return upperCase; - } - - /** - * Parse the lowercase mapping attribute for a Unicode character. If there is a lowercase - * mapping attribute and the parse succeeds, then the hasLowerMap field is set to true, - * the lowerMap field of this UnicodeSpec object is updated, and false is returned. - * If the lowercase mapping attribute is an empty string, the parse succeeds but the - * hasLowerMap field is set to false. (and false is returned). - * - * The lowercase mapping attribute should be a four to six digit hexadecimal integer. - * - * @param s the lowercase mapping attribute extracted from a line of the Unicode data file - * @return simple lowercase character mapping if defined, MAP_UNDEFINED otherwise - * @exception NumberFormatException if parse fails - */ - public static int parseLowerMap(String s) throws NumberFormatException { - int lowerCase = MAP_UNDEFINED; - int length = s.length(); - if (length >= 4 && length <= 6) { - lowerCase = Integer.parseInt(s, 16); - } - else if (s.length() != 0) { - throw new NumberFormatException(); - } - return lowerCase; - } - - /** - * Parse the titlecase mapping attribute for a Unicode character. If there is a titlecase - * mapping attribute and the parse succeeds, then the hasTitleMap field is set to true, - * the titleMap field of this UnicodeSpec object is updated, and false is returned. - * If the titlecase mapping attribute is an empty string, the parse succeeds but the - * hasTitleMap field is set to false. (and false is returned). - * - * The titlecase mapping attribute should be a four to six digit hexadecimal integer. - * - * @param s the titlecase mapping attribute extracted from a line of the Unicode data file - * @return simple title case char mapping if defined, MAP_UNDEFINED otherwise - * @exception NumberFormatException if parse fails - */ - public static int parseTitleMap(String s) throws NumberFormatException { - int titleCase = MAP_UNDEFINED; - int length = s.length(); - if (length >= 4 && length <= 6) { - titleCase = Integer.parseInt(s, 16); - } - else if (s.length() != 0) { - throw new NumberFormatException(); - } - return titleCase; - } - - /** - * Read and parse a Unicode data file. - * - * @param file a file specifying the Unicode data file to be read - * @return an array of UnicodeSpec objects, one for each line of the - * Unicode data file that could be successfully parsed as - * specifying Unicode character attributes - */ - - public static UnicodeSpec[] readSpecFile(File file, int plane) throws FileNotFoundException { - ArrayList list = new ArrayList<>(3000); - UnicodeSpec[] result = null; - int count = 0; - BufferedReader f = new BufferedReader(new FileReader(file)); - String line = null; - loop: - while(true) { - try { - line = f.readLine(); - } - catch (IOException e) { - break loop; - } - if (line == null) break loop; - UnicodeSpec item = parse(line.trim()); - int specPlane = item.getCodePoint() >>> 16; - if (specPlane < plane) continue; - if (specPlane > plane) break; - - if (item != null) { - list.add(item); - } - } - result = new UnicodeSpec[list.size()]; - list.toArray(result); - return result; - } - - void setCodePoint(int value) { - codePoint = value; - } - - /** - * Return the code point in this Unicode specification - * @return the char code point representing by the specification - */ - public int getCodePoint() { - return codePoint; - } - - void setName(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - void setGeneralCategory(byte category) { - generalCategory = category; - } - - public byte getGeneralCategory() { - return generalCategory; - } - - void setBidiCategory(byte category) { - bidiCategory = category; - } - - public byte getBidiCategory() { - return bidiCategory; - } - - void setCombiningClass(int combiningClass) { - this.combiningClass = combiningClass; - } - - public int getCombiningClass() { - return combiningClass; - } - - void setDecomposition(String decomposition) { - this.decomposition = decomposition; - } - - public String getDecomposition() { - return decomposition; - } - - void setDecimalValue(int value) { - decimalValue = value; - } - - public int getDecimalValue() { - return decimalValue; - } - - public boolean isDecimalValue() { - return decimalValue != -1; - } - - void setDigitValue(int value) { - digitValue = value; - } - - public int getDigitValue() { - return digitValue; - } - - public boolean isDigitValue() { - return digitValue != -1; - } - - void setNumericValue(String value) { - numericValue = value; - } - - public String getNumericValue() { - return numericValue; - } - - public boolean isNumericValue() { - return numericValue.length() > 0; - } - - void setMirrored(boolean value) { - mirrored = value; - } - - public boolean isMirrored() { - return mirrored; - } - - void setOldName(String name) { - oldName = name; - } - - public String getOldName() { - return oldName; - } - - void setComment(String comment) { - this.comment = comment; - } - - public String getComment() { - return comment; - } - - void setUpperMap(int ch) { - upperMap = ch; - }; - - public int getUpperMap() { - return upperMap; - } - - public boolean hasUpperMap() { - return upperMap != MAP_UNDEFINED; - } - - void setLowerMap(int ch) { - lowerMap = ch; - } - - public int getLowerMap() { - return lowerMap; - } - - public boolean hasLowerMap() { - return lowerMap != MAP_UNDEFINED; - } - - void setTitleMap(int ch) { - titleMap = ch; - } - - public int getTitleMap() { - return titleMap; - } - - public boolean hasTitleMap() { - return titleMap != MAP_UNDEFINED; - } - - int codePoint; // the characters UTF-32 code value - String name; // the ASCII name - byte generalCategory; // general category, available via Characte.getType() - byte bidiCategory; // available via Character.getBidiType() - int combiningClass; // not used in Character - String decomposition; // not used in Character - int decimalValue; // decimal digit value - int digitValue; // not all digits are decimal - String numericValue; // numeric value if digit or non-digit - boolean mirrored; // - String oldName; - String comment; - int upperMap; - int lowerMap; - int titleMap; - - // this is the number of fields in one line of the UnicodeData.txt file - // each field is separated by a semicolon (a token) - static final int REQUIRED_FIELDS = 15; - - /** - * General category types - * To preserve compatibility, these values cannot be changed - */ - public static final byte - UNASSIGNED = 0, // Cn normative - UPPERCASE_LETTER = 1, // Lu normative - LOWERCASE_LETTER = 2, // Ll normative - TITLECASE_LETTER = 3, // Lt normative - MODIFIER_LETTER = 4, // Lm normative - OTHER_LETTER = 5, // Lo normative - NON_SPACING_MARK = 6, // Mn informative - ENCLOSING_MARK = 7, // Me informative - COMBINING_SPACING_MARK = 8, // Mc normative - DECIMAL_DIGIT_NUMBER = 9, // Nd normative - LETTER_NUMBER = 10, // Nl normative - OTHER_NUMBER = 11, // No normative - SPACE_SEPARATOR = 12, // Zs normative - LINE_SEPARATOR = 13, // Zl normative - PARAGRAPH_SEPARATOR = 14, // Zp normative - CONTROL = 15, // Cc normative - FORMAT = 16, // Cf normative - // 17 is unused for no apparent reason, - // but must preserve forward compatibility - PRIVATE_USE = 18, // Co normative - SURROGATE = 19, // Cs normative - DASH_PUNCTUATION = 20, // Pd informative - START_PUNCTUATION = 21, // Ps informative - END_PUNCTUATION = 22, // Pe informative - CONNECTOR_PUNCTUATION = 23, // Pc informative - OTHER_PUNCTUATION = 24, // Po informative - MATH_SYMBOL = 25, // Sm informative - CURRENCY_SYMBOL = 26, // Sc informative - MODIFIER_SYMBOL = 27, // Sk informative - OTHER_SYMBOL = 28, // So informative - INITIAL_QUOTE_PUNCTUATION = 29, // Pi informative - FINAL_QUOTE_PUNCTUATION = 30, // Pf informative - - // this value is only used in the character generation tool - // it can change to accommodate the addition of new categories. - GENERAL_CATEGORY_COUNT = 31; // sentinel value - - static final byte SHORT = 0, LONG = 1; - // general category type strings - // NOTE: The order of this category array is dependent on the assignment of - // category constants above. We want to access this array using constants above. - // [][SHORT] is the SHORT name, [][LONG] is the LONG name - static final String[][] generalCategoryList = { - {"Cn", "UNASSIGNED"}, - {"Lu", "UPPERCASE_LETTER"}, - {"Ll", "LOWERCASE_LETTER"}, - {"Lt", "TITLECASE_LETTER"}, - {"Lm", "MODIFIER_LETTER"}, - {"Lo", "OTHER_LETTER"}, - {"Mn", "NON_SPACING_MARK"}, - {"Me", "ENCLOSING_MARK"}, - {"Mc", "COMBINING_SPACING_MARK"}, - {"Nd", "DECIMAL_DIGIT_NUMBER"}, - {"Nl", "LETTER_NUMBER"}, - {"No", "OTHER_NUMBER"}, - {"Zs", "SPACE_SEPARATOR"}, - {"Zl", "LINE_SEPARATOR"}, - {"Zp", "PARAGRAPH_SEPARATOR"}, - {"Cc", "CONTROL"}, - {"Cf", "FORMAT"}, - {"xx", "unused"}, - {"Co", "PRIVATE_USE"}, - {"Cs", "SURROGATE"}, - {"Pd", "DASH_PUNCTUATION"}, - {"Ps", "START_PUNCTUATION"}, - {"Pe", "END_PUNCTUATION"}, - {"Pc", "CONNECTOR_PUNCTUATION"}, - {"Po", "OTHER_PUNCTUATION"}, - {"Sm", "MATH_SYMBOL"}, - {"Sc", "CURRENCY_SYMBOL"}, - {"Sk", "MODIFIER_SYMBOL"}, - {"So", "OTHER_SYMBOL"}, - {"Pi", "INITIAL_QUOTE_PUNCTUATION"}, - {"Pf", "FINAL_QUOTE_PUNCTUATION"} - }; - - /** - * Bidirectional categories - */ - public static final byte - DIRECTIONALITY_UNDEFINED = -1, - - // Strong category - DIRECTIONALITY_LEFT_TO_RIGHT = 0, // L - DIRECTIONALITY_RIGHT_TO_LEFT = 1, // R - DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC = 2, // AL - // Weak category - DIRECTIONALITY_EUROPEAN_NUMBER = 3, // EN - DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR = 4, // ES - DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR = 5, // ET - DIRECTIONALITY_ARABIC_NUMBER = 6, // AN - DIRECTIONALITY_COMMON_NUMBER_SEPARATOR = 7, // CS - DIRECTIONALITY_NONSPACING_MARK = 8, // NSM - DIRECTIONALITY_BOUNDARY_NEUTRAL = 9, // BN - // Neutral category - DIRECTIONALITY_PARAGRAPH_SEPARATOR = 10, // B - DIRECTIONALITY_SEGMENT_SEPARATOR = 11, // S - DIRECTIONALITY_WHITESPACE = 12, // WS - DIRECTIONALITY_OTHER_NEUTRALS = 13, // ON - // Explicit Formatting category - DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING = 14, // LRE - DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE = 15, // LRO - DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING = 16, // RLE - DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE = 17, // RLO - DIRECTIONALITY_POP_DIRECTIONAL_FORMAT = 18, // PDF - DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE = 19, // LRI - DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE = 20, // RLI - DIRECTIONALITY_FIRST_STRONG_ISOLATE = 21, // FSI - DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE = 22, // PDI - - DIRECTIONALITY_CATEGORY_COUNT = 23; // sentinel value - - // If changes are made to the above bidi category assignments, this - // list of bidi category names must be changed to keep their order in synch. - // Access this list using the bidi category constants above. - static final String[][] bidiCategoryList = { - {"L", "DIRECTIONALITY_LEFT_TO_RIGHT"}, - {"R", "DIRECTIONALITY_RIGHT_TO_LEFT"}, - {"AL", "DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC"}, - {"EN", "DIRECTIONALITY_EUROPEAN_NUMBER"}, - {"ES", "DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR"}, - {"ET", "DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR"}, - {"AN", "DIRECTIONALITY_ARABIC_NUMBER"}, - {"CS", "DIRECTIONALITY_COMMON_NUMBER_SEPARATOR"}, - {"NSM", "DIRECTIONALITY_NONSPACING_MARK"}, - {"BN", "DIRECTIONALITY_BOUNDARY_NEUTRAL"}, - {"B", "DIRECTIONALITY_PARAGRAPH_SEPARATOR"}, - {"S", "DIRECTIONALITY_SEGMENT_SEPARATOR"}, - {"WS", "DIRECTIONALITY_WHITESPACE"}, - {"ON", "DIRECTIONALITY_OTHER_NEUTRALS"}, - {"LRE", "DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING"}, - {"LRO", "DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE"}, - {"RLE", "DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING"}, - {"RLO", "DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE"}, - {"PDF", "DIRECTIONALITY_POP_DIRECTIONAL_FORMAT"}, - {"LRI", "DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE"}, - {"RLI", "DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE"}, - {"FSI", "DIRECTIONALITY_FIRST_STRONG_ISOLATE"}, - {"PDI", "DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE"}, - }; - - // Unicode specification lines have fields in this order. - static final byte - FIELD_VALUE = 0, - FIELD_NAME = 1, - FIELD_CATEGORY = 2, - FIELD_CLASS = 3, - FIELD_BIDI = 4, - FIELD_DECOMPOSITION = 5, - FIELD_DECIMAL = 6, - FIELD_DIGIT = 7, - FIELD_NUMERIC = 8, - FIELD_MIRRORED = 9, - FIELD_OLDNAME = 10, - FIELD_COMMENT = 11, - FIELD_UPPERCASE = 12, - FIELD_LOWERCASE = 13, - FIELD_TITLECASE = 14; - - static final Pattern tokenSeparator = Pattern.compile(";"); - - public static void main(String[] args) { - UnicodeSpec[] spec = null; - if (args.length == 2 ) { - try { - File file = new File(args[0]); - int plane = Integer.parseInt(args[1]); - spec = UnicodeSpec.readSpecFile(file, plane); - System.out.println("UnicodeSpec[" + spec.length + "]:"); - for (int x=0; xcodePoint + * argument. Provide default properties. + * @param codePoint a Unicode code point between 0x0000 and 0x10FFFF + */ + public UnicodeSpec(int codePoint) { + this.codePoint = codePoint; + generalCategory = UNASSIGNED; + bidiCategory = DIRECTIONALITY_UNDEFINED; + mirrored = false; + titleMap = MAP_UNDEFINED; + upperMap = MAP_UNDEFINED; + lowerMap = MAP_UNDEFINED; + decimalValue = -1; + digitValue = -1; + numericValue = ""; + oldName = null; + comment = null; + name = null; + } + + /** + * Create a String representation of this UnicodeSpec object. + * The string will contain the code point and all its case mappings + * if available. + */ + public String toString() { + StringBuffer result = new StringBuffer(hex6(codePoint)); + if (getUpperMap() != MAP_UNDEFINED) { + result.append(", upper=").append(hex6(upperMap)); + } + if (getLowerMap() != MAP_UNDEFINED) { + result.append(", lower=").append(hex6(lowerMap)); + } + if (getTitleMap() != MAP_UNDEFINED) { + result.append(", title=").append(hex6(titleMap)); + } + return result.toString(); + } + + static String hex4(int n) { + String q = Integer.toHexString(n & 0xFFFF).toUpperCase(); + return "0000".substring(Math.min(4, q.length())) + q; + } + + static String hex6(int n) { + String str = Integer.toHexString(n & 0xFFFFFF).toUpperCase(); + return "000000".substring(Math.min(6, str.length())) + str; + + } + + + /** + * Given one line of a Unicode data file as a String, parse the line + * and return a UnicodeSpec object that contains the same character information. + * + * @param s a line of the Unicode data file to be parsed + * @return a UnicodeSpec object, or null if the parsing process failed for some reason + */ + public static UnicodeSpec parse(String s) { + UnicodeSpec spec = null; + String[] tokens = null; + + try { + tokens = tokenSeparator.split(s, REQUIRED_FIELDS); + spec = new UnicodeSpec(); + spec.setCodePoint(parseCodePoint(tokens[FIELD_VALUE])); + spec.setName(parseName(tokens[FIELD_NAME])); + spec.setGeneralCategory(parseGeneralCategory(tokens[FIELD_CATEGORY])); + spec.setBidiCategory(parseBidiCategory(tokens[FIELD_BIDI])); + spec.setCombiningClass(parseCombiningClass(tokens[FIELD_CLASS])); + spec.setDecomposition(parseDecomposition(tokens[FIELD_DECOMPOSITION])); + spec.setDecimalValue(parseDecimalValue(tokens[FIELD_DECIMAL])); + spec.setDigitValue(parseDigitValue(tokens[FIELD_DIGIT])); + spec.setNumericValue(parseNumericValue(tokens[FIELD_NUMERIC])); + spec.setMirrored(parseMirrored(tokens[FIELD_MIRRORED])); + spec.setOldName(parseOldName(tokens[FIELD_OLDNAME])); + spec.setComment(parseComment(tokens[FIELD_COMMENT])); + spec.setUpperMap(parseUpperMap(tokens[FIELD_UPPERCASE])); + spec.setLowerMap(parseLowerMap(tokens[FIELD_LOWERCASE])); + spec.setTitleMap(parseTitleMap(tokens[FIELD_TITLECASE])); + } + + catch(Exception e) { + spec = null; + System.out.println("Error parsing spec line."); + } + return spec; + } + + /** + * Parse the codePoint attribute for a Unicode character. If the parse succeeds, + * the codePoint field of this UnicodeSpec object is updated and false is returned. + * + * The codePoint attribute should be a four to six digit hexadecimal integer. + * + * @param s the codePoint attribute extracted from a line of the Unicode data file + * @return code point if successful + * @exception NumberFormatException if unable to parse argument + */ + public static int parseCodePoint(String s) throws NumberFormatException { + return Integer.parseInt(s, 16); + } + + public static String parseName(String s) throws Exception { + if (s==null) throw new Exception("Cannot parse name."); + return s; + } + + public static byte parseGeneralCategory(String s) throws Exception { + byte category = GENERAL_CATEGORY_COUNT; + + for (byte x=0; x= GENERAL_CATEGORY_COUNT) { + throw new Exception("Could not parse general category."); + } + return category; + } + + public static byte parseBidiCategory(String s) throws Exception { + byte category = DIRECTIONALITY_CATEGORY_COUNT; + + for (byte x=0; x= DIRECTIONALITY_CATEGORY_COUNT) { + throw new Exception("Could not parse bidi category."); + } + return category; + } + + + /** + * Parse the combining attribute for a Unicode character. If there is a combining + * attribute and the parse succeeds, then the hasCombining field is set to true, + * the combining field of this UnicodeSpec object is updated, and false is returned. + * If the combining attribute is an empty string, the parse succeeds but the + * hasCombining field is set to false. (and false is returned). + * + * The combining attribute, if any, should be a nonnegative decimal integer. + * + * @param s the combining attribute extracted from a line of the Unicode data file + * @return the combining class value if any, -1 if property not defined + * @exception Exception if can't parse the combining class + */ + + public static int parseCombiningClass(String s) throws Exception { + int combining = -1; + if (s.length()>0) { + combining = Integer.parseInt(s, 10); + } + return combining; + } + + /** + * Parse the decomposition attribute for a Unicode character. If the parse succeeds, + * the decomposition field of this UnicodeSpec object is updated and false is returned. + * + * The decomposition attribute is complicated; for now, it is treated as a string. + * + * @param s the decomposition attribute extracted from a line of the Unicode data file + * @return true if the parse failed; otherwise false + */ + + public static String parseDecomposition(String s) throws Exception { + if (s==null) throw new Exception("Cannot parse decomposition."); + return s; + } + + + /** + * Parse the decimal value attribute for a Unicode character. If there is a decimal value + * attribute and the parse succeeds, then the hasDecimalValue field is set to true, + * the decimalValue field of this UnicodeSpec object is updated, and false is returned. + * If the decimal value attribute is an empty string, the parse succeeds but the + * hasDecimalValue field is set to false. (and false is returned). + * + * The decimal value attribute, if any, should be a nonnegative decimal integer. + * + * @param s the decimal value attribute extracted from a line of the Unicode data file + * @return the decimal value as an int, -1 if no decimal value defined + * @exception NumberFormatException if the parse fails + */ + public static int parseDecimalValue(String s) throws NumberFormatException { + int value = -1; + + if (s.length() > 0) { + value = Integer.parseInt(s, 10); + } + return value; + } + + /** + * Parse the digit value attribute for a Unicode character. If there is a digit value + * attribute and the parse succeeds, then the hasDigitValue field is set to true, + * the digitValue field of this UnicodeSpec object is updated, and false is returned. + * If the digit value attribute is an empty string, the parse succeeds but the + * hasDigitValue field is set to false. (and false is returned). + * + * The digit value attribute, if any, should be a nonnegative decimal integer. + * + * @param s the digit value attribute extracted from a line of the Unicode data file + * @return the digit value as an non-negative int, or -1 if no digit property defined + * @exception NumberFormatException if the parse fails + */ + public static int parseDigitValue(String s) throws NumberFormatException { + int value = -1; + + if (s.length() > 0) { + value = Integer.parseInt(s, 10); + } + return value; + } + + public static String parseNumericValue(String s) throws Exception { + if (s == null) throw new Exception("Cannot parse numeric value."); + return s; + } + + public static String parseComment(String s) throws Exception { + if (s == null) throw new Exception("Cannot parse comment."); + return s; + } + + public static boolean parseMirrored(String s) throws Exception { + boolean mirrored; + if (s.length() == 1) { + if (s.charAt(0) == 'Y') {mirrored = true;} + else if (s.charAt(0) == 'N') {mirrored = false;} + else {throw new Exception("Cannot parse mirrored property.");} + } + else { throw new Exception("Cannot parse mirrored property.");} + return mirrored; + } + + public static String parseOldName(String s) throws Exception { + if (s == null) throw new Exception("Cannot parse old name"); + return s; + } + + /** + * Parse the uppercase mapping attribute for a Unicode character. If there is a uppercase + * mapping attribute and the parse succeeds, then the hasUpperMap field is set to true, + * the upperMap field of this UnicodeSpec object is updated, and false is returned. + * If the uppercase mapping attribute is an empty string, the parse succeeds but the + * hasUpperMap field is set to false. (and false is returned). + * + * The uppercase mapping attribute should be a four to six digit hexadecimal integer. + * + * @param s the uppercase mapping attribute extracted from a line of the Unicode data file + * @return simple uppercase character mapping if defined, MAP_UNDEFINED otherwise + * @exception NumberFormatException if parse fails + */ + public static int parseUpperMap(String s) throws NumberFormatException { + int upperCase = MAP_UNDEFINED; + + int length = s.length(); + if (length >= 4 && length <=6) { + upperCase = Integer.parseInt(s, 16); + } + else if (s.length() != 0) { + throw new NumberFormatException(); + } + return upperCase; + } + + /** + * Parse the lowercase mapping attribute for a Unicode character. If there is a lowercase + * mapping attribute and the parse succeeds, then the hasLowerMap field is set to true, + * the lowerMap field of this UnicodeSpec object is updated, and false is returned. + * If the lowercase mapping attribute is an empty string, the parse succeeds but the + * hasLowerMap field is set to false. (and false is returned). + * + * The lowercase mapping attribute should be a four to six digit hexadecimal integer. + * + * @param s the lowercase mapping attribute extracted from a line of the Unicode data file + * @return simple lowercase character mapping if defined, MAP_UNDEFINED otherwise + * @exception NumberFormatException if parse fails + */ + public static int parseLowerMap(String s) throws NumberFormatException { + int lowerCase = MAP_UNDEFINED; + int length = s.length(); + if (length >= 4 && length <= 6) { + lowerCase = Integer.parseInt(s, 16); + } + else if (s.length() != 0) { + throw new NumberFormatException(); + } + return lowerCase; + } + + /** + * Parse the titlecase mapping attribute for a Unicode character. If there is a titlecase + * mapping attribute and the parse succeeds, then the hasTitleMap field is set to true, + * the titleMap field of this UnicodeSpec object is updated, and false is returned. + * If the titlecase mapping attribute is an empty string, the parse succeeds but the + * hasTitleMap field is set to false. (and false is returned). + * + * The titlecase mapping attribute should be a four to six digit hexadecimal integer. + * + * @param s the titlecase mapping attribute extracted from a line of the Unicode data file + * @return simple title case char mapping if defined, MAP_UNDEFINED otherwise + * @exception NumberFormatException if parse fails + */ + public static int parseTitleMap(String s) throws NumberFormatException { + int titleCase = MAP_UNDEFINED; + int length = s.length(); + if (length >= 4 && length <= 6) { + titleCase = Integer.parseInt(s, 16); + } + else if (s.length() != 0) { + throw new NumberFormatException(); + } + return titleCase; + } + + /** + * Read and parse a Unicode data file. + * + * @param file a file specifying the Unicode data file to be read + * @return an array of UnicodeSpec objects, one for each line of the + * Unicode data file that could be successfully parsed as + * specifying Unicode character attributes + */ + + public static UnicodeSpec[] readSpecFile(File file, int plane) throws FileNotFoundException { + ArrayList list = new ArrayList<>(3000); + UnicodeSpec[] result = null; + int count = 0; + BufferedReader f = new BufferedReader(new FileReader(file)); + String line = null; + loop: + while(true) { + try { + line = f.readLine(); + } + catch (IOException e) { + break loop; + } + if (line == null) break loop; + UnicodeSpec item = parse(line.trim()); + int specPlane = item.getCodePoint() >>> 16; + if (specPlane < plane) continue; + if (specPlane > plane) break; + + if (item != null) { + list.add(item); + } + } + result = new UnicodeSpec[list.size()]; + list.toArray(result); + return result; + } + + void setCodePoint(int value) { + codePoint = value; + } + + /** + * Return the code point in this Unicode specification + * @return the char code point representing by the specification + */ + public int getCodePoint() { + return codePoint; + } + + void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + void setGeneralCategory(byte category) { + generalCategory = category; + } + + public byte getGeneralCategory() { + return generalCategory; + } + + void setBidiCategory(byte category) { + bidiCategory = category; + } + + public byte getBidiCategory() { + return bidiCategory; + } + + void setCombiningClass(int combiningClass) { + this.combiningClass = combiningClass; + } + + public int getCombiningClass() { + return combiningClass; + } + + void setDecomposition(String decomposition) { + this.decomposition = decomposition; + } + + public String getDecomposition() { + return decomposition; + } + + void setDecimalValue(int value) { + decimalValue = value; + } + + public int getDecimalValue() { + return decimalValue; + } + + public boolean isDecimalValue() { + return decimalValue != -1; + } + + void setDigitValue(int value) { + digitValue = value; + } + + public int getDigitValue() { + return digitValue; + } + + public boolean isDigitValue() { + return digitValue != -1; + } + + void setNumericValue(String value) { + numericValue = value; + } + + public String getNumericValue() { + return numericValue; + } + + public boolean isNumericValue() { + return numericValue.length() > 0; + } + + void setMirrored(boolean value) { + mirrored = value; + } + + public boolean isMirrored() { + return mirrored; + } + + void setOldName(String name) { + oldName = name; + } + + public String getOldName() { + return oldName; + } + + void setComment(String comment) { + this.comment = comment; + } + + public String getComment() { + return comment; + } + + void setUpperMap(int ch) { + upperMap = ch; + }; + + public int getUpperMap() { + return upperMap; + } + + public boolean hasUpperMap() { + return upperMap != MAP_UNDEFINED; + } + + void setLowerMap(int ch) { + lowerMap = ch; + } + + public int getLowerMap() { + return lowerMap; + } + + public boolean hasLowerMap() { + return lowerMap != MAP_UNDEFINED; + } + + void setTitleMap(int ch) { + titleMap = ch; + } + + public int getTitleMap() { + return titleMap; + } + + public boolean hasTitleMap() { + return titleMap != MAP_UNDEFINED; + } + + int codePoint; // the characters UTF-32 code value + String name; // the ASCII name + byte generalCategory; // general category, available via Characte.getType() + byte bidiCategory; // available via Character.getBidiType() + int combiningClass; // not used in Character + String decomposition; // not used in Character + int decimalValue; // decimal digit value + int digitValue; // not all digits are decimal + String numericValue; // numeric value if digit or non-digit + boolean mirrored; // + String oldName; + String comment; + int upperMap; + int lowerMap; + int titleMap; + + // this is the number of fields in one line of the UnicodeData.txt file + // each field is separated by a semicolon (a token) + static final int REQUIRED_FIELDS = 15; + + /** + * General category types + * To preserve compatibility, these values cannot be changed + */ + public static final byte + UNASSIGNED = 0, // Cn normative + UPPERCASE_LETTER = 1, // Lu normative + LOWERCASE_LETTER = 2, // Ll normative + TITLECASE_LETTER = 3, // Lt normative + MODIFIER_LETTER = 4, // Lm normative + OTHER_LETTER = 5, // Lo normative + NON_SPACING_MARK = 6, // Mn informative + ENCLOSING_MARK = 7, // Me informative + COMBINING_SPACING_MARK = 8, // Mc normative + DECIMAL_DIGIT_NUMBER = 9, // Nd normative + LETTER_NUMBER = 10, // Nl normative + OTHER_NUMBER = 11, // No normative + SPACE_SEPARATOR = 12, // Zs normative + LINE_SEPARATOR = 13, // Zl normative + PARAGRAPH_SEPARATOR = 14, // Zp normative + CONTROL = 15, // Cc normative + FORMAT = 16, // Cf normative + // 17 is unused for no apparent reason, + // but must preserve forward compatibility + PRIVATE_USE = 18, // Co normative + SURROGATE = 19, // Cs normative + DASH_PUNCTUATION = 20, // Pd informative + START_PUNCTUATION = 21, // Ps informative + END_PUNCTUATION = 22, // Pe informative + CONNECTOR_PUNCTUATION = 23, // Pc informative + OTHER_PUNCTUATION = 24, // Po informative + MATH_SYMBOL = 25, // Sm informative + CURRENCY_SYMBOL = 26, // Sc informative + MODIFIER_SYMBOL = 27, // Sk informative + OTHER_SYMBOL = 28, // So informative + INITIAL_QUOTE_PUNCTUATION = 29, // Pi informative + FINAL_QUOTE_PUNCTUATION = 30, // Pf informative + + // this value is only used in the character generation tool + // it can change to accommodate the addition of new categories. + GENERAL_CATEGORY_COUNT = 31; // sentinel value + + static final byte SHORT = 0, LONG = 1; + // general category type strings + // NOTE: The order of this category array is dependent on the assignment of + // category constants above. We want to access this array using constants above. + // [][SHORT] is the SHORT name, [][LONG] is the LONG name + static final String[][] generalCategoryList = { + {"Cn", "UNASSIGNED"}, + {"Lu", "UPPERCASE_LETTER"}, + {"Ll", "LOWERCASE_LETTER"}, + {"Lt", "TITLECASE_LETTER"}, + {"Lm", "MODIFIER_LETTER"}, + {"Lo", "OTHER_LETTER"}, + {"Mn", "NON_SPACING_MARK"}, + {"Me", "ENCLOSING_MARK"}, + {"Mc", "COMBINING_SPACING_MARK"}, + {"Nd", "DECIMAL_DIGIT_NUMBER"}, + {"Nl", "LETTER_NUMBER"}, + {"No", "OTHER_NUMBER"}, + {"Zs", "SPACE_SEPARATOR"}, + {"Zl", "LINE_SEPARATOR"}, + {"Zp", "PARAGRAPH_SEPARATOR"}, + {"Cc", "CONTROL"}, + {"Cf", "FORMAT"}, + {"xx", "unused"}, + {"Co", "PRIVATE_USE"}, + {"Cs", "SURROGATE"}, + {"Pd", "DASH_PUNCTUATION"}, + {"Ps", "START_PUNCTUATION"}, + {"Pe", "END_PUNCTUATION"}, + {"Pc", "CONNECTOR_PUNCTUATION"}, + {"Po", "OTHER_PUNCTUATION"}, + {"Sm", "MATH_SYMBOL"}, + {"Sc", "CURRENCY_SYMBOL"}, + {"Sk", "MODIFIER_SYMBOL"}, + {"So", "OTHER_SYMBOL"}, + {"Pi", "INITIAL_QUOTE_PUNCTUATION"}, + {"Pf", "FINAL_QUOTE_PUNCTUATION"} + }; + + /** + * Bidirectional categories + */ + public static final byte + DIRECTIONALITY_UNDEFINED = -1, + + // Strong category + DIRECTIONALITY_LEFT_TO_RIGHT = 0, // L + DIRECTIONALITY_RIGHT_TO_LEFT = 1, // R + DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC = 2, // AL + // Weak category + DIRECTIONALITY_EUROPEAN_NUMBER = 3, // EN + DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR = 4, // ES + DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR = 5, // ET + DIRECTIONALITY_ARABIC_NUMBER = 6, // AN + DIRECTIONALITY_COMMON_NUMBER_SEPARATOR = 7, // CS + DIRECTIONALITY_NONSPACING_MARK = 8, // NSM + DIRECTIONALITY_BOUNDARY_NEUTRAL = 9, // BN + // Neutral category + DIRECTIONALITY_PARAGRAPH_SEPARATOR = 10, // B + DIRECTIONALITY_SEGMENT_SEPARATOR = 11, // S + DIRECTIONALITY_WHITESPACE = 12, // WS + DIRECTIONALITY_OTHER_NEUTRALS = 13, // ON + // Explicit Formatting category + DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING = 14, // LRE + DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE = 15, // LRO + DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING = 16, // RLE + DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE = 17, // RLO + DIRECTIONALITY_POP_DIRECTIONAL_FORMAT = 18, // PDF + DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE = 19, // LRI + DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE = 20, // RLI + DIRECTIONALITY_FIRST_STRONG_ISOLATE = 21, // FSI + DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE = 22, // PDI + + DIRECTIONALITY_CATEGORY_COUNT = 23; // sentinel value + + // If changes are made to the above bidi category assignments, this + // list of bidi category names must be changed to keep their order in synch. + // Access this list using the bidi category constants above. + static final String[][] bidiCategoryList = { + {"L", "DIRECTIONALITY_LEFT_TO_RIGHT"}, + {"R", "DIRECTIONALITY_RIGHT_TO_LEFT"}, + {"AL", "DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC"}, + {"EN", "DIRECTIONALITY_EUROPEAN_NUMBER"}, + {"ES", "DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR"}, + {"ET", "DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR"}, + {"AN", "DIRECTIONALITY_ARABIC_NUMBER"}, + {"CS", "DIRECTIONALITY_COMMON_NUMBER_SEPARATOR"}, + {"NSM", "DIRECTIONALITY_NONSPACING_MARK"}, + {"BN", "DIRECTIONALITY_BOUNDARY_NEUTRAL"}, + {"B", "DIRECTIONALITY_PARAGRAPH_SEPARATOR"}, + {"S", "DIRECTIONALITY_SEGMENT_SEPARATOR"}, + {"WS", "DIRECTIONALITY_WHITESPACE"}, + {"ON", "DIRECTIONALITY_OTHER_NEUTRALS"}, + {"LRE", "DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING"}, + {"LRO", "DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE"}, + {"RLE", "DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING"}, + {"RLO", "DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE"}, + {"PDF", "DIRECTIONALITY_POP_DIRECTIONAL_FORMAT"}, + {"LRI", "DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE"}, + {"RLI", "DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE"}, + {"FSI", "DIRECTIONALITY_FIRST_STRONG_ISOLATE"}, + {"PDI", "DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE"}, + }; + + // Unicode specification lines have fields in this order. + static final byte + FIELD_VALUE = 0, + FIELD_NAME = 1, + FIELD_CATEGORY = 2, + FIELD_CLASS = 3, + FIELD_BIDI = 4, + FIELD_DECOMPOSITION = 5, + FIELD_DECIMAL = 6, + FIELD_DIGIT = 7, + FIELD_NUMERIC = 8, + FIELD_MIRRORED = 9, + FIELD_OLDNAME = 10, + FIELD_COMMENT = 11, + FIELD_UPPERCASE = 12, + FIELD_LOWERCASE = 13, + FIELD_TITLECASE = 14; + + static final Pattern tokenSeparator = Pattern.compile(";"); + + public static void main(String[] args) { + UnicodeSpec[] spec = null; + if (args.length == 2 ) { + try { + File file = new File(args[0]); + int plane = Integer.parseInt(args[1]); + spec = UnicodeSpec.readSpecFile(file, plane); + System.out.println("UnicodeSpec[" + spec.length + "]:"); + for (int x=0; x>8):(byte)c; - } - - static short peekShort(String s, int index) { - return (short)s.charAt(index); - } - - static int peekInt(String s, int index) { - index *= 2; - return (((int)s.charAt(index)) << 16) | s.charAt(index+1); - } - - static void poke(String s, int index, byte value) { - int mask = 0xFF00; - int ivalue = value; - if ((index&1)==0) { - ivalue <<= 8; - mask = 0x00FF; - } - index /= 2; - if (index == s.length()) { - s = s + (char)ivalue; - } - else if (index == 0) { - s = (char)(ivalue|(s.charAt(0)&mask)) + s.substring(1); - } - else { - s = s.substring(0, index) + (char)(ivalue|(s.charAt(index)&mask)) - + s.substring(index+1); - } - } - - static void poke(String s, int index, short value) { - if (index == s.length()) { - s = s + (char)value; - } - else if (index == 0) { - s = (char)value + s.substring(1); - } - else { - s = s.substring(0, index) + (char)value + s.substring(index+1); - } - } - - static void poke(String s, int index, int value) { - index *= 2; - char hi = (char)(value >> 16); - if (index == s.length()) { - s = s + hi + (char)value; - } - else if (index == 0) { - s = hi + (char)value + s.substring(2); - } - else { - s = s.substring(0, index) + hi + (char)value + s.substring(index+2); - } - } - - /** - * The ESCAPE character is used during run-length encoding. It signals - * a run of identical chars. - */ - static final char ESCAPE = '\uA5A5'; - - /** - * The ESCAPE_BYTE character is used during run-length encoding. It signals - * a run of identical bytes. - */ - static final byte ESCAPE_BYTE = (byte)0xA5; - - /** - * Construct a string representing a short array. Use run-length encoding. - * A character represents itself, unless it is the ESCAPE character. Then - * the following notations are possible: - * ESCAPE ESCAPE ESCAPE literal - * ESCAPE n c n instances of character c - * Since an encoded run occupies 3 characters, we only encode runs of 4 or - * more characters. Thus we have n > 0 and n != ESCAPE and n <= 0xFFFF. - * If we encounter a run where n == ESCAPE, we represent this as: - * c ESCAPE n-1 c - * The ESCAPE value is chosen so as not to collide with commonly - * seen values. - */ - static final String arrayToRLEString(short[] a) { - StringBuffer buffer = new StringBuffer(); - // for (int i=0; i> 16)); - buffer.append((char) a.length); - short runValue = a[0]; - int runLength = 1; - for (int i=1; i 0 and n != ESCAPE_BYTE and n <= 0xFF. - * If we encounter a run where n == ESCAPE_BYTE, we represent this as: - * b ESCAPE_BYTE n-1 b - * The ESCAPE_BYTE value is chosen so as not to collide with commonly - * seen values. - */ - static final String arrayToRLEString(byte[] a) { - StringBuffer buffer = new StringBuffer(); - buffer.append((char) (a.length >> 16)); - buffer.append((char) a.length); - byte runValue = a[0]; - int runLength = 1; - byte[] state = new byte[2]; - for (int i=1; i 0 && <= 0xFFFF. - */ - private static final void encodeRun(StringBuffer buffer, short value, int length) { - if (length < 4) { - for (int j=0; j 0 && <= 0xFF. - */ - private static final void encodeRun(StringBuffer buffer, byte value, int length, - byte[] state) { - if (length < 4) { - for (int j=0; j> 8); - nextChar = false; - } - else { - b = (byte) (c & 0xFF); - nextChar = true; - } - - // This part of the loop is a tiny state machine which handles - // the parsing of the run-length encoding. This would be simpler - // if we could look ahead, but we can't, so we use 'node' to - // move between three nodes in the state machine. - switch (node) { - case 0: - // Normal idle node - if (b == ESCAPE_BYTE) { - node = 1; - } - else { - array[ai++] = b; - } - break; - case 1: - // We have seen one ESCAPE_BYTE; we expect either a second - // one, or a run length and value. - if (b == ESCAPE_BYTE) { - array[ai++] = ESCAPE_BYTE; - node = 0; - } - else { - runLength = b; - // Interpret signed byte as unsigned - if (runLength < 0) runLength += 0x100; - node = 2; - } - break; - case 2: - // We have seen an ESCAPE_BYTE and length byte. We interpret - // the next byte as the value to be repeated. - for (int j=0; j 0) buffer.append("+\n"); - int limit = buffer.length() + 78; // Leave 2 for trailing <"+> - buffer.append(indent + '"'); - while (i= '\u0020' && c <= '\u007E') { - // Printable ASCII ranges from ' ' to '~' - buffer.append(c); - } - else - */ - if (c <= '\377') { - // Represent control characters - // using octal notation; otherwise the string we form - // won't compile, since Unicode escape sequences are - // processed before tokenization. - buffer.append('\\'); - buffer.append(HEX_DIGIT[(c & 0700) >> 6]); // HEX_DIGIT works for octal - buffer.append(HEX_DIGIT[(c & 0070) >> 3]); - buffer.append(HEX_DIGIT[(c & 0007)]); - } - else { - // Handle the rest with Unicode - buffer.append("\\u"); - buffer.append(HEX_DIGIT[(c & 0xF000) >> 12]); - buffer.append(HEX_DIGIT[(c & 0x0F00) >> 8]); - buffer.append(HEX_DIGIT[(c & 0x00F0) >> 4]); - buffer.append(HEX_DIGIT[(c & 0x000F)]); - } - } - buffer.append('"'); - } - return buffer.toString(); - } - - static final char[] HEX_DIGIT = {'0','1','2','3','4','5','6','7', - '8','9','A','B','C','D','E','F'}; -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.base/share/tools/org/openjdk/buildtools/generatecharacter/Utility.java 2020-03-23 19:56:49.563962606 +0100 @@ -0,0 +1,407 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatecharacter; + +import java.text.*; +import java.util.*; + +public class Utility { + static byte peekByte(String s, int index) { + char c = s.charAt(index/2); + return ((index&1)==0)?(byte)(c>>8):(byte)c; + } + + static short peekShort(String s, int index) { + return (short)s.charAt(index); + } + + static int peekInt(String s, int index) { + index *= 2; + return (((int)s.charAt(index)) << 16) | s.charAt(index+1); + } + + static void poke(String s, int index, byte value) { + int mask = 0xFF00; + int ivalue = value; + if ((index&1)==0) { + ivalue <<= 8; + mask = 0x00FF; + } + index /= 2; + if (index == s.length()) { + s = s + (char)ivalue; + } + else if (index == 0) { + s = (char)(ivalue|(s.charAt(0)&mask)) + s.substring(1); + } + else { + s = s.substring(0, index) + (char)(ivalue|(s.charAt(index)&mask)) + + s.substring(index+1); + } + } + + static void poke(String s, int index, short value) { + if (index == s.length()) { + s = s + (char)value; + } + else if (index == 0) { + s = (char)value + s.substring(1); + } + else { + s = s.substring(0, index) + (char)value + s.substring(index+1); + } + } + + static void poke(String s, int index, int value) { + index *= 2; + char hi = (char)(value >> 16); + if (index == s.length()) { + s = s + hi + (char)value; + } + else if (index == 0) { + s = hi + (char)value + s.substring(2); + } + else { + s = s.substring(0, index) + hi + (char)value + s.substring(index+2); + } + } + + /** + * The ESCAPE character is used during run-length encoding. It signals + * a run of identical chars. + */ + static final char ESCAPE = '\uA5A5'; + + /** + * The ESCAPE_BYTE character is used during run-length encoding. It signals + * a run of identical bytes. + */ + static final byte ESCAPE_BYTE = (byte)0xA5; + + /** + * Construct a string representing a short array. Use run-length encoding. + * A character represents itself, unless it is the ESCAPE character. Then + * the following notations are possible: + * ESCAPE ESCAPE ESCAPE literal + * ESCAPE n c n instances of character c + * Since an encoded run occupies 3 characters, we only encode runs of 4 or + * more characters. Thus we have n > 0 and n != ESCAPE and n <= 0xFFFF. + * If we encounter a run where n == ESCAPE, we represent this as: + * c ESCAPE n-1 c + * The ESCAPE value is chosen so as not to collide with commonly + * seen values. + */ + static final String arrayToRLEString(short[] a) { + StringBuffer buffer = new StringBuffer(); + // for (int i=0; i> 16)); + buffer.append((char) a.length); + short runValue = a[0]; + int runLength = 1; + for (int i=1; i 0 and n != ESCAPE_BYTE and n <= 0xFF. + * If we encounter a run where n == ESCAPE_BYTE, we represent this as: + * b ESCAPE_BYTE n-1 b + * The ESCAPE_BYTE value is chosen so as not to collide with commonly + * seen values. + */ + static final String arrayToRLEString(byte[] a) { + StringBuffer buffer = new StringBuffer(); + buffer.append((char) (a.length >> 16)); + buffer.append((char) a.length); + byte runValue = a[0]; + int runLength = 1; + byte[] state = new byte[2]; + for (int i=1; i 0 && <= 0xFFFF. + */ + private static final void encodeRun(StringBuffer buffer, short value, int length) { + if (length < 4) { + for (int j=0; j 0 && <= 0xFF. + */ + private static final void encodeRun(StringBuffer buffer, byte value, int length, + byte[] state) { + if (length < 4) { + for (int j=0; j> 8); + nextChar = false; + } + else { + b = (byte) (c & 0xFF); + nextChar = true; + } + + // This part of the loop is a tiny state machine which handles + // the parsing of the run-length encoding. This would be simpler + // if we could look ahead, but we can't, so we use 'node' to + // move between three nodes in the state machine. + switch (node) { + case 0: + // Normal idle node + if (b == ESCAPE_BYTE) { + node = 1; + } + else { + array[ai++] = b; + } + break; + case 1: + // We have seen one ESCAPE_BYTE; we expect either a second + // one, or a run length and value. + if (b == ESCAPE_BYTE) { + array[ai++] = ESCAPE_BYTE; + node = 0; + } + else { + runLength = b; + // Interpret signed byte as unsigned + if (runLength < 0) runLength += 0x100; + node = 2; + } + break; + case 2: + // We have seen an ESCAPE_BYTE and length byte. We interpret + // the next byte as the value to be repeated. + for (int j=0; j 0) buffer.append("+\n"); + int limit = buffer.length() + 78; // Leave 2 for trailing <"+> + buffer.append(indent + '"'); + while (i= '\u0020' && c <= '\u007E') { + // Printable ASCII ranges from ' ' to '~' + buffer.append(c); + } + else + */ + if (c <= '\377') { + // Represent control characters + // using octal notation; otherwise the string we form + // won't compile, since Unicode escape sequences are + // processed before tokenization. + buffer.append('\\'); + buffer.append(HEX_DIGIT[(c & 0700) >> 6]); // HEX_DIGIT works for octal + buffer.append(HEX_DIGIT[(c & 0070) >> 3]); + buffer.append(HEX_DIGIT[(c & 0007)]); + } + else { + // Handle the rest with Unicode + buffer.append("\\u"); + buffer.append(HEX_DIGIT[(c & 0xF000) >> 12]); + buffer.append(HEX_DIGIT[(c & 0x0F00) >> 8]); + buffer.append(HEX_DIGIT[(c & 0x00F0) >> 4]); + buffer.append(HEX_DIGIT[(c & 0x000F)]); + } + } + buffer.append('"'); + } + return buffer.toString(); + } + + static final char[] HEX_DIGIT = {'0','1','2','3','4','5','6','7', + '8','9','A','B','C','D','E','F'}; +} --- old/make/jdk/src/classes/build/tools/generatecurrencydata/GenerateCurrencyData.java 2020-03-23 19:56:50.803962597 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,414 +0,0 @@ -/* - * Copyright (c) 2001, 2020, 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.generatecurrencydata; - -import java.io.IOException; -import java.io.FileNotFoundException; -import java.io.DataOutputStream; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.HashMap; -import java.util.Locale; -import java.util.Objects; -import java.util.Properties; -import java.util.TimeZone; - -/** - * Reads currency data in properties format from the file specified in the - * command line and generates a binary data file as specified in the command line. - * - * Output of this tool is a binary file that contains the data in - * the following order: - * - * - magic number (int): always 0x43757244 ('CurD') - * - formatVersion (int) - * - dataVersion (int) - * - mainTable (int[26*26]) - * - specialCaseCount (int) - * - specialCaseCutOverTimes (long[specialCaseCount]) - * - specialCaseOldCurrencies (String[specialCaseCount]) - * - specialCaseNewCurrencies (String[specialCaseCount]) - * - specialCaseOldCurrenciesDefaultFractionDigits (int[specialCaseCount]) - * - specialCaseNewCurrenciesDefaultFractionDigits (int[specialCaseCount]) - * - specialCaseOldCurrenciesNumericCode (int[specialCaseCount]) - * - specialCaseNewCurrenciesNumericCode (int[specialCaseCount]) - * - otherCurrenciesCount (int) - * - otherCurrencies (String) - * - otherCurrenciesDefaultFractionDigits (int[otherCurrenciesCount]) - * - otherCurrenciesNumericCode (int[otherCurrenciesCount]) - * - * See CurrencyData.properties for the input format description and - * Currency.java for the format descriptions of the generated tables. - */ -public class GenerateCurrencyData { - - private static DataOutputStream out; - - // input data: currency data obtained from properties on input stream - private static Properties currencyData; - private static String formatVersion; - private static String dataVersion; - private static String validCurrencyCodes; - - // handy constants - must match definitions in java.util.Currency - // magic number - private static final int MAGIC_NUMBER = 0x43757244; - // number of characters from A to Z - private static final int A_TO_Z = ('Z' - 'A') + 1; - // entry for invalid country codes - private static final int INVALID_COUNTRY_ENTRY = 0x0000007F; - // entry for countries without currency - private static final int COUNTRY_WITHOUT_CURRENCY_ENTRY = 0x00000200; - // mask for simple case country entries - private static final int SIMPLE_CASE_COUNTRY_MASK = 0x00000000; - // mask for simple case country entry final character - private static final int SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK = 0x0000001F; - // mask for simple case country entry default currency digits - private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK = 0x000001E0; - // shift count for simple case country entry default currency digits - private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT = 5; - // maximum number for simple case country entry default currency digits - private static final int SIMPLE_CASE_COUNTRY_MAX_DEFAULT_DIGITS = 9; - // mask for special case country entries - private static final int SPECIAL_CASE_COUNTRY_MASK = 0x00000200; - // mask for special case country index - private static final int SPECIAL_CASE_COUNTRY_INDEX_MASK = 0x0000001F; - // delta from entry index component in main table to index into special case tables - private static final int SPECIAL_CASE_COUNTRY_INDEX_DELTA = 1; - // mask for distinguishing simple and special case countries - private static final int COUNTRY_TYPE_MASK = SIMPLE_CASE_COUNTRY_MASK | SPECIAL_CASE_COUNTRY_MASK; - // mask for the numeric code of the currency - private static final int NUMERIC_CODE_MASK = 0x000FFC00; - // shift count for the numeric code of the currency - private static final int NUMERIC_CODE_SHIFT = 10; - - // generated data - private static int[] mainTable = new int[A_TO_Z * A_TO_Z]; - - private static final int maxSpecialCases = 30; - private static int specialCaseCount = 0; - private static long[] specialCaseCutOverTimes = new long[maxSpecialCases]; - private static String[] specialCaseOldCurrencies = new String[maxSpecialCases]; - private static String[] specialCaseNewCurrencies = new String[maxSpecialCases]; - private static int[] specialCaseOldCurrenciesDefaultFractionDigits = new int[maxSpecialCases]; - private static int[] specialCaseNewCurrenciesDefaultFractionDigits = new int[maxSpecialCases]; - private static int[] specialCaseOldCurrenciesNumericCode = new int[maxSpecialCases]; - private static int[] specialCaseNewCurrenciesNumericCode = new int[maxSpecialCases]; - - private static final int maxOtherCurrencies = 128; - private static int otherCurrenciesCount = 0; - private static String[] otherCurrencies = new String[maxOtherCurrencies]; - private static int[] otherCurrenciesDefaultFractionDigits = new int[maxOtherCurrencies]; - private static int[] otherCurrenciesNumericCode= new int[maxOtherCurrencies]; - - // date format for parsing cut-over times - private static SimpleDateFormat format; - - // Minor Units - private static String[] currenciesWithDefinedMinorUnitDecimals = - new String[SIMPLE_CASE_COUNTRY_MAX_DEFAULT_DIGITS + 1]; - private static String currenciesWithMinorUnitsUndefined; - - public static void main(String[] args) { - InputStream in = System.in; - // Look for "-o outputfilename" option - for (int n = 0; n < args.length; ++n) { - if (args[n].equals("-o")) { - ++n; - if (n >= args.length) { - System.err.println("Error: Invalid argument format"); - System.exit(1); - } - try { - out = new DataOutputStream(new FileOutputStream(args[n])); - } catch ( FileNotFoundException e ) { - System.err.println("Error: " + e.getMessage()); - e.printStackTrace(System.err); - System.exit(1); - } - } else if (args[n].equals("-i")) { - ++n; - if (n >= args.length) { - System.err.println("Error: Invalid argument format"); - System.exit(1); - } - try { - in = new FileInputStream(args[n]); - } catch ( FileNotFoundException e ) { - System.err.println("Error: " + e.getMessage()); - e.printStackTrace(System.err); - System.exit(1); - } - } else { - System.err.println("Error: Invalid argument " + args[n]); - System.exit(1); - } - } - - if (out == null) { - System.err.println("Error: Invalid argument format"); - System.exit(1); - } - - format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.US); - format.setTimeZone(TimeZone.getTimeZone("GMT")); - format.setLenient(false); - - try { - readInput(in); - buildMainAndSpecialCaseTables(); - buildOtherTables(); - writeOutput(); - out.flush(); - out.close(); - } catch (Exception e) { - System.err.println("Error: " + e.getMessage()); - e.printStackTrace(System.err); - System.exit(1); - } - } - - private static void readInput(InputStream in) throws IOException { - currencyData = new Properties(); - currencyData.load(in); - - // initialize other lookup strings - formatVersion = (String) currencyData.get("formatVersion"); - dataVersion = (String) currencyData.get("dataVersion"); - validCurrencyCodes = (String) currencyData.get("all"); - for (int i = 0; i <= SIMPLE_CASE_COUNTRY_MAX_DEFAULT_DIGITS; i++) { - currenciesWithDefinedMinorUnitDecimals[i] - = (String) currencyData.get("minor"+i); - } - currenciesWithMinorUnitsUndefined = (String) currencyData.get("minorUndefined"); - if (formatVersion == null || - dataVersion == null || - validCurrencyCodes == null || - currenciesWithMinorUnitsUndefined == null) { - throw new NullPointerException("not all required data is defined in input"); - } - } - - private static void buildMainAndSpecialCaseTables() throws Exception { - for (int first = 0; first < A_TO_Z; first++) { - for (int second = 0; second < A_TO_Z; second++) { - char firstChar = (char) ('A' + first); - char secondChar = (char) ('A' + second); - String countryCode = (new StringBuffer()).append(firstChar).append(secondChar).toString(); - String currencyInfo = (String) currencyData.get(countryCode); - int tableEntry = 0; - if (currencyInfo == null) { - // no entry -> must be invalid ISO 3166 country code - tableEntry = INVALID_COUNTRY_ENTRY; - } else { - int length = currencyInfo.length(); - if (length == 0) { - // special case: country without currency - tableEntry = COUNTRY_WITHOUT_CURRENCY_ENTRY; - } else if (length == 3) { - // valid currency - if (currencyInfo.charAt(0) == firstChar && currencyInfo.charAt(1) == secondChar) { - checkCurrencyCode(currencyInfo); - int digits = getDefaultFractionDigits(currencyInfo); - if (digits < 0 || digits > SIMPLE_CASE_COUNTRY_MAX_DEFAULT_DIGITS) { - throw new RuntimeException("fraction digits out of range for " + currencyInfo); - } - int numericCode= getNumericCode(currencyInfo); - if (numericCode < 0 || numericCode >= 1000 ) { - throw new RuntimeException("numeric code out of range for " + currencyInfo); - } - tableEntry = SIMPLE_CASE_COUNTRY_MASK - | (currencyInfo.charAt(2) - 'A') - | (digits << SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT) - | (numericCode << NUMERIC_CODE_SHIFT); - } else { - tableEntry = SPECIAL_CASE_COUNTRY_MASK | (makeSpecialCaseEntry(currencyInfo) + SPECIAL_CASE_COUNTRY_INDEX_DELTA); - } - } else { - tableEntry = SPECIAL_CASE_COUNTRY_MASK | (makeSpecialCaseEntry(currencyInfo) + SPECIAL_CASE_COUNTRY_INDEX_DELTA); - } - } - mainTable[first * A_TO_Z + second] = tableEntry; - } - } - } - - private static int getDefaultFractionDigits(String currencyCode) { - for (int i = 0; i <= SIMPLE_CASE_COUNTRY_MAX_DEFAULT_DIGITS; i++) { - if (Objects.nonNull(currenciesWithDefinedMinorUnitDecimals[i]) && - currenciesWithDefinedMinorUnitDecimals[i].indexOf(currencyCode) != -1) { - return i; - } - } - - if (currenciesWithMinorUnitsUndefined.indexOf(currencyCode) != -1) { - return -1; - } else { - return 2; - } - } - - private static int getNumericCode(String currencyCode) { - int index = validCurrencyCodes.indexOf(currencyCode); - String numericCode = validCurrencyCodes.substring(index + 3, index + 6); - return Integer.parseInt(numericCode); - } - - static HashMap specialCaseMap = new HashMap<>(); - - private static int makeSpecialCaseEntry(String currencyInfo) throws Exception { - Integer oldEntry = specialCaseMap.get(currencyInfo); - if (oldEntry != null) { - return oldEntry.intValue(); - } - if (specialCaseCount == maxSpecialCases) { - throw new RuntimeException("too many special cases"); - } - if (currencyInfo.length() == 3) { - checkCurrencyCode(currencyInfo); - specialCaseCutOverTimes[specialCaseCount] = Long.MAX_VALUE; - specialCaseOldCurrencies[specialCaseCount] = currencyInfo; - specialCaseOldCurrenciesDefaultFractionDigits[specialCaseCount] = getDefaultFractionDigits(currencyInfo); - specialCaseOldCurrenciesNumericCode[specialCaseCount] = getNumericCode(currencyInfo); - specialCaseNewCurrencies[specialCaseCount] = null; - specialCaseNewCurrenciesDefaultFractionDigits[specialCaseCount] = 0; - specialCaseNewCurrenciesNumericCode[specialCaseCount] = 0; - } else { - int length = currencyInfo.length(); - if (currencyInfo.charAt(3) != ';' || - currencyInfo.charAt(length - 4) != ';') { - throw new RuntimeException("invalid currency info: " + currencyInfo); - } - String oldCurrency = currencyInfo.substring(0, 3); - String newCurrency = currencyInfo.substring(length - 3, length); - checkCurrencyCode(oldCurrency); - checkCurrencyCode(newCurrency); - String timeString = currencyInfo.substring(4, length - 4); - long time = format.parse(timeString).getTime(); - if (Math.abs(time - System.currentTimeMillis()) > ((long) 10) * 365 * 24 * 60 * 60 * 1000) { - throw new RuntimeException("time is more than 10 years from present: " + time); - } - specialCaseCutOverTimes[specialCaseCount] = time; - specialCaseOldCurrencies[specialCaseCount] = oldCurrency; - specialCaseOldCurrenciesDefaultFractionDigits[specialCaseCount] = getDefaultFractionDigits(oldCurrency); - specialCaseOldCurrenciesNumericCode[specialCaseCount] = getNumericCode(oldCurrency); - specialCaseNewCurrencies[specialCaseCount] = newCurrency; - specialCaseNewCurrenciesDefaultFractionDigits[specialCaseCount] = getDefaultFractionDigits(newCurrency); - specialCaseNewCurrenciesNumericCode[specialCaseCount] = getNumericCode(newCurrency); - } - specialCaseMap.put(currencyInfo, Integer.valueOf(specialCaseCount)); - return specialCaseCount++; - } - - private static void buildOtherTables() { - if (validCurrencyCodes.length() % 7 != 6) { - throw new RuntimeException("\"all\" entry has incorrect size"); - } - for (int i = 0; i < (validCurrencyCodes.length() + 1) / 7; i++) { - if (i > 0 && validCurrencyCodes.charAt(i * 7 - 1) != '-') { - throw new RuntimeException("incorrect separator in \"all\" entry"); - } - String currencyCode = validCurrencyCodes.substring(i * 7, i * 7 + 3); - int numericCode = Integer.parseInt( - validCurrencyCodes.substring(i * 7 + 3, i * 7 + 6)); - checkCurrencyCode(currencyCode); - int tableEntry = mainTable[(currencyCode.charAt(0) - 'A') * A_TO_Z + (currencyCode.charAt(1) - 'A')]; - if (tableEntry == INVALID_COUNTRY_ENTRY || - (tableEntry & SPECIAL_CASE_COUNTRY_MASK) != 0 || - (tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) != (currencyCode.charAt(2) - 'A')) { - if (otherCurrenciesCount == maxOtherCurrencies) { - throw new RuntimeException("too many other currencies"); - } - otherCurrencies[otherCurrenciesCount] = currencyCode; - otherCurrenciesDefaultFractionDigits[otherCurrenciesCount] = getDefaultFractionDigits(currencyCode); - otherCurrenciesNumericCode[otherCurrenciesCount] = getNumericCode(currencyCode); - otherCurrenciesCount++; - } - } - } - - private static void checkCurrencyCode(String currencyCode) { - if (currencyCode.length() != 3) { - throw new RuntimeException("illegal length for currency code: " + currencyCode); - } - for (int i = 0; i < 3; i++) { - char aChar = currencyCode.charAt(i); - if ((aChar < 'A' || aChar > 'Z') && !currencyCode.equals("XB5")) { - throw new RuntimeException("currency code contains illegal character: " + currencyCode); - } - } - if (validCurrencyCodes.indexOf(currencyCode) == -1) { - throw new RuntimeException("currency code not listed as valid: " + currencyCode); - } - } - - private static void writeOutput() throws IOException { - out.writeInt(MAGIC_NUMBER); - out.writeInt(Integer.parseInt(formatVersion)); - out.writeInt(Integer.parseInt(dataVersion)); - writeIntArray(mainTable, mainTable.length); - out.writeInt(specialCaseCount); - writeSpecialCaseEntries(); - out.writeInt(otherCurrenciesCount); - writeOtherCurrencies(); - } - - private static void writeIntArray(int[] ia, int count) throws IOException { - for (int i = 0; i < count; i++) { - out.writeInt(ia[i]); - } - } - - private static void writeSpecialCaseEntries() throws IOException { - for (int index = 0; index < specialCaseCount; index++) { - out.writeLong(specialCaseCutOverTimes[index]); - String str = (specialCaseOldCurrencies[index] != null) - ? specialCaseOldCurrencies[index] : ""; - out.writeUTF(str); - str = (specialCaseNewCurrencies[index] != null) - ? specialCaseNewCurrencies[index] : ""; - out.writeUTF(str); - out.writeInt(specialCaseOldCurrenciesDefaultFractionDigits[index]); - out.writeInt(specialCaseNewCurrenciesDefaultFractionDigits[index]); - out.writeInt(specialCaseOldCurrenciesNumericCode[index]); - out.writeInt(specialCaseNewCurrenciesNumericCode[index]); - } - } - - private static void writeOtherCurrencies() throws IOException { - for (int index = 0; index < otherCurrenciesCount; index++) { - String str = (otherCurrencies[index] != null) - ? otherCurrencies[index] : ""; - out.writeUTF(str); - out.writeInt(otherCurrenciesDefaultFractionDigits[index]); - out.writeInt(otherCurrenciesNumericCode[index]); - } - } - -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.base/share/tools/org/openjdk/buildtools/generatecurrencydata/GenerateCurrencyData.java 2020-03-23 19:56:50.375962600 +0100 @@ -0,0 +1,414 @@ +/* + * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatecurrencydata; + +import java.io.IOException; +import java.io.FileNotFoundException; +import java.io.DataOutputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Locale; +import java.util.Objects; +import java.util.Properties; +import java.util.TimeZone; + +/** + * Reads currency data in properties format from the file specified in the + * command line and generates a binary data file as specified in the command line. + * + * Output of this tool is a binary file that contains the data in + * the following order: + * + * - magic number (int): always 0x43757244 ('CurD') + * - formatVersion (int) + * - dataVersion (int) + * - mainTable (int[26*26]) + * - specialCaseCount (int) + * - specialCaseCutOverTimes (long[specialCaseCount]) + * - specialCaseOldCurrencies (String[specialCaseCount]) + * - specialCaseNewCurrencies (String[specialCaseCount]) + * - specialCaseOldCurrenciesDefaultFractionDigits (int[specialCaseCount]) + * - specialCaseNewCurrenciesDefaultFractionDigits (int[specialCaseCount]) + * - specialCaseOldCurrenciesNumericCode (int[specialCaseCount]) + * - specialCaseNewCurrenciesNumericCode (int[specialCaseCount]) + * - otherCurrenciesCount (int) + * - otherCurrencies (String) + * - otherCurrenciesDefaultFractionDigits (int[otherCurrenciesCount]) + * - otherCurrenciesNumericCode (int[otherCurrenciesCount]) + * + * See CurrencyData.properties for the input format description and + * Currency.java for the format descriptions of the generated tables. + */ +public class GenerateCurrencyData { + + private static DataOutputStream out; + + // input data: currency data obtained from properties on input stream + private static Properties currencyData; + private static String formatVersion; + private static String dataVersion; + private static String validCurrencyCodes; + + // handy constants - must match definitions in java.util.Currency + // magic number + private static final int MAGIC_NUMBER = 0x43757244; + // number of characters from A to Z + private static final int A_TO_Z = ('Z' - 'A') + 1; + // entry for invalid country codes + private static final int INVALID_COUNTRY_ENTRY = 0x0000007F; + // entry for countries without currency + private static final int COUNTRY_WITHOUT_CURRENCY_ENTRY = 0x00000200; + // mask for simple case country entries + private static final int SIMPLE_CASE_COUNTRY_MASK = 0x00000000; + // mask for simple case country entry final character + private static final int SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK = 0x0000001F; + // mask for simple case country entry default currency digits + private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK = 0x000001E0; + // shift count for simple case country entry default currency digits + private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT = 5; + // maximum number for simple case country entry default currency digits + private static final int SIMPLE_CASE_COUNTRY_MAX_DEFAULT_DIGITS = 9; + // mask for special case country entries + private static final int SPECIAL_CASE_COUNTRY_MASK = 0x00000200; + // mask for special case country index + private static final int SPECIAL_CASE_COUNTRY_INDEX_MASK = 0x0000001F; + // delta from entry index component in main table to index into special case tables + private static final int SPECIAL_CASE_COUNTRY_INDEX_DELTA = 1; + // mask for distinguishing simple and special case countries + private static final int COUNTRY_TYPE_MASK = SIMPLE_CASE_COUNTRY_MASK | SPECIAL_CASE_COUNTRY_MASK; + // mask for the numeric code of the currency + private static final int NUMERIC_CODE_MASK = 0x000FFC00; + // shift count for the numeric code of the currency + private static final int NUMERIC_CODE_SHIFT = 10; + + // generated data + private static int[] mainTable = new int[A_TO_Z * A_TO_Z]; + + private static final int maxSpecialCases = 30; + private static int specialCaseCount = 0; + private static long[] specialCaseCutOverTimes = new long[maxSpecialCases]; + private static String[] specialCaseOldCurrencies = new String[maxSpecialCases]; + private static String[] specialCaseNewCurrencies = new String[maxSpecialCases]; + private static int[] specialCaseOldCurrenciesDefaultFractionDigits = new int[maxSpecialCases]; + private static int[] specialCaseNewCurrenciesDefaultFractionDigits = new int[maxSpecialCases]; + private static int[] specialCaseOldCurrenciesNumericCode = new int[maxSpecialCases]; + private static int[] specialCaseNewCurrenciesNumericCode = new int[maxSpecialCases]; + + private static final int maxOtherCurrencies = 128; + private static int otherCurrenciesCount = 0; + private static String[] otherCurrencies = new String[maxOtherCurrencies]; + private static int[] otherCurrenciesDefaultFractionDigits = new int[maxOtherCurrencies]; + private static int[] otherCurrenciesNumericCode= new int[maxOtherCurrencies]; + + // date format for parsing cut-over times + private static SimpleDateFormat format; + + // Minor Units + private static String[] currenciesWithDefinedMinorUnitDecimals = + new String[SIMPLE_CASE_COUNTRY_MAX_DEFAULT_DIGITS + 1]; + private static String currenciesWithMinorUnitsUndefined; + + public static void main(String[] args) { + InputStream in = System.in; + // Look for "-o outputfilename" option + for (int n = 0; n < args.length; ++n) { + if (args[n].equals("-o")) { + ++n; + if (n >= args.length) { + System.err.println("Error: Invalid argument format"); + System.exit(1); + } + try { + out = new DataOutputStream(new FileOutputStream(args[n])); + } catch ( FileNotFoundException e ) { + System.err.println("Error: " + e.getMessage()); + e.printStackTrace(System.err); + System.exit(1); + } + } else if (args[n].equals("-i")) { + ++n; + if (n >= args.length) { + System.err.println("Error: Invalid argument format"); + System.exit(1); + } + try { + in = new FileInputStream(args[n]); + } catch ( FileNotFoundException e ) { + System.err.println("Error: " + e.getMessage()); + e.printStackTrace(System.err); + System.exit(1); + } + } else { + System.err.println("Error: Invalid argument " + args[n]); + System.exit(1); + } + } + + if (out == null) { + System.err.println("Error: Invalid argument format"); + System.exit(1); + } + + format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.US); + format.setTimeZone(TimeZone.getTimeZone("GMT")); + format.setLenient(false); + + try { + readInput(in); + buildMainAndSpecialCaseTables(); + buildOtherTables(); + writeOutput(); + out.flush(); + out.close(); + } catch (Exception e) { + System.err.println("Error: " + e.getMessage()); + e.printStackTrace(System.err); + System.exit(1); + } + } + + private static void readInput(InputStream in) throws IOException { + currencyData = new Properties(); + currencyData.load(in); + + // initialize other lookup strings + formatVersion = (String) currencyData.get("formatVersion"); + dataVersion = (String) currencyData.get("dataVersion"); + validCurrencyCodes = (String) currencyData.get("all"); + for (int i = 0; i <= SIMPLE_CASE_COUNTRY_MAX_DEFAULT_DIGITS; i++) { + currenciesWithDefinedMinorUnitDecimals[i] + = (String) currencyData.get("minor"+i); + } + currenciesWithMinorUnitsUndefined = (String) currencyData.get("minorUndefined"); + if (formatVersion == null || + dataVersion == null || + validCurrencyCodes == null || + currenciesWithMinorUnitsUndefined == null) { + throw new NullPointerException("not all required data is defined in input"); + } + } + + private static void buildMainAndSpecialCaseTables() throws Exception { + for (int first = 0; first < A_TO_Z; first++) { + for (int second = 0; second < A_TO_Z; second++) { + char firstChar = (char) ('A' + first); + char secondChar = (char) ('A' + second); + String countryCode = (new StringBuffer()).append(firstChar).append(secondChar).toString(); + String currencyInfo = (String) currencyData.get(countryCode); + int tableEntry = 0; + if (currencyInfo == null) { + // no entry -> must be invalid ISO 3166 country code + tableEntry = INVALID_COUNTRY_ENTRY; + } else { + int length = currencyInfo.length(); + if (length == 0) { + // special case: country without currency + tableEntry = COUNTRY_WITHOUT_CURRENCY_ENTRY; + } else if (length == 3) { + // valid currency + if (currencyInfo.charAt(0) == firstChar && currencyInfo.charAt(1) == secondChar) { + checkCurrencyCode(currencyInfo); + int digits = getDefaultFractionDigits(currencyInfo); + if (digits < 0 || digits > SIMPLE_CASE_COUNTRY_MAX_DEFAULT_DIGITS) { + throw new RuntimeException("fraction digits out of range for " + currencyInfo); + } + int numericCode= getNumericCode(currencyInfo); + if (numericCode < 0 || numericCode >= 1000 ) { + throw new RuntimeException("numeric code out of range for " + currencyInfo); + } + tableEntry = SIMPLE_CASE_COUNTRY_MASK + | (currencyInfo.charAt(2) - 'A') + | (digits << SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT) + | (numericCode << NUMERIC_CODE_SHIFT); + } else { + tableEntry = SPECIAL_CASE_COUNTRY_MASK | (makeSpecialCaseEntry(currencyInfo) + SPECIAL_CASE_COUNTRY_INDEX_DELTA); + } + } else { + tableEntry = SPECIAL_CASE_COUNTRY_MASK | (makeSpecialCaseEntry(currencyInfo) + SPECIAL_CASE_COUNTRY_INDEX_DELTA); + } + } + mainTable[first * A_TO_Z + second] = tableEntry; + } + } + } + + private static int getDefaultFractionDigits(String currencyCode) { + for (int i = 0; i <= SIMPLE_CASE_COUNTRY_MAX_DEFAULT_DIGITS; i++) { + if (Objects.nonNull(currenciesWithDefinedMinorUnitDecimals[i]) && + currenciesWithDefinedMinorUnitDecimals[i].indexOf(currencyCode) != -1) { + return i; + } + } + + if (currenciesWithMinorUnitsUndefined.indexOf(currencyCode) != -1) { + return -1; + } else { + return 2; + } + } + + private static int getNumericCode(String currencyCode) { + int index = validCurrencyCodes.indexOf(currencyCode); + String numericCode = validCurrencyCodes.substring(index + 3, index + 6); + return Integer.parseInt(numericCode); + } + + static HashMap specialCaseMap = new HashMap<>(); + + private static int makeSpecialCaseEntry(String currencyInfo) throws Exception { + Integer oldEntry = specialCaseMap.get(currencyInfo); + if (oldEntry != null) { + return oldEntry.intValue(); + } + if (specialCaseCount == maxSpecialCases) { + throw new RuntimeException("too many special cases"); + } + if (currencyInfo.length() == 3) { + checkCurrencyCode(currencyInfo); + specialCaseCutOverTimes[specialCaseCount] = Long.MAX_VALUE; + specialCaseOldCurrencies[specialCaseCount] = currencyInfo; + specialCaseOldCurrenciesDefaultFractionDigits[specialCaseCount] = getDefaultFractionDigits(currencyInfo); + specialCaseOldCurrenciesNumericCode[specialCaseCount] = getNumericCode(currencyInfo); + specialCaseNewCurrencies[specialCaseCount] = null; + specialCaseNewCurrenciesDefaultFractionDigits[specialCaseCount] = 0; + specialCaseNewCurrenciesNumericCode[specialCaseCount] = 0; + } else { + int length = currencyInfo.length(); + if (currencyInfo.charAt(3) != ';' || + currencyInfo.charAt(length - 4) != ';') { + throw new RuntimeException("invalid currency info: " + currencyInfo); + } + String oldCurrency = currencyInfo.substring(0, 3); + String newCurrency = currencyInfo.substring(length - 3, length); + checkCurrencyCode(oldCurrency); + checkCurrencyCode(newCurrency); + String timeString = currencyInfo.substring(4, length - 4); + long time = format.parse(timeString).getTime(); + if (Math.abs(time - System.currentTimeMillis()) > ((long) 10) * 365 * 24 * 60 * 60 * 1000) { + throw new RuntimeException("time is more than 10 years from present: " + time); + } + specialCaseCutOverTimes[specialCaseCount] = time; + specialCaseOldCurrencies[specialCaseCount] = oldCurrency; + specialCaseOldCurrenciesDefaultFractionDigits[specialCaseCount] = getDefaultFractionDigits(oldCurrency); + specialCaseOldCurrenciesNumericCode[specialCaseCount] = getNumericCode(oldCurrency); + specialCaseNewCurrencies[specialCaseCount] = newCurrency; + specialCaseNewCurrenciesDefaultFractionDigits[specialCaseCount] = getDefaultFractionDigits(newCurrency); + specialCaseNewCurrenciesNumericCode[specialCaseCount] = getNumericCode(newCurrency); + } + specialCaseMap.put(currencyInfo, Integer.valueOf(specialCaseCount)); + return specialCaseCount++; + } + + private static void buildOtherTables() { + if (validCurrencyCodes.length() % 7 != 6) { + throw new RuntimeException("\"all\" entry has incorrect size"); + } + for (int i = 0; i < (validCurrencyCodes.length() + 1) / 7; i++) { + if (i > 0 && validCurrencyCodes.charAt(i * 7 - 1) != '-') { + throw new RuntimeException("incorrect separator in \"all\" entry"); + } + String currencyCode = validCurrencyCodes.substring(i * 7, i * 7 + 3); + int numericCode = Integer.parseInt( + validCurrencyCodes.substring(i * 7 + 3, i * 7 + 6)); + checkCurrencyCode(currencyCode); + int tableEntry = mainTable[(currencyCode.charAt(0) - 'A') * A_TO_Z + (currencyCode.charAt(1) - 'A')]; + if (tableEntry == INVALID_COUNTRY_ENTRY || + (tableEntry & SPECIAL_CASE_COUNTRY_MASK) != 0 || + (tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) != (currencyCode.charAt(2) - 'A')) { + if (otherCurrenciesCount == maxOtherCurrencies) { + throw new RuntimeException("too many other currencies"); + } + otherCurrencies[otherCurrenciesCount] = currencyCode; + otherCurrenciesDefaultFractionDigits[otherCurrenciesCount] = getDefaultFractionDigits(currencyCode); + otherCurrenciesNumericCode[otherCurrenciesCount] = getNumericCode(currencyCode); + otherCurrenciesCount++; + } + } + } + + private static void checkCurrencyCode(String currencyCode) { + if (currencyCode.length() != 3) { + throw new RuntimeException("illegal length for currency code: " + currencyCode); + } + for (int i = 0; i < 3; i++) { + char aChar = currencyCode.charAt(i); + if ((aChar < 'A' || aChar > 'Z') && !currencyCode.equals("XB5")) { + throw new RuntimeException("currency code contains illegal character: " + currencyCode); + } + } + if (validCurrencyCodes.indexOf(currencyCode) == -1) { + throw new RuntimeException("currency code not listed as valid: " + currencyCode); + } + } + + private static void writeOutput() throws IOException { + out.writeInt(MAGIC_NUMBER); + out.writeInt(Integer.parseInt(formatVersion)); + out.writeInt(Integer.parseInt(dataVersion)); + writeIntArray(mainTable, mainTable.length); + out.writeInt(specialCaseCount); + writeSpecialCaseEntries(); + out.writeInt(otherCurrenciesCount); + writeOtherCurrencies(); + } + + private static void writeIntArray(int[] ia, int count) throws IOException { + for (int i = 0; i < count; i++) { + out.writeInt(ia[i]); + } + } + + private static void writeSpecialCaseEntries() throws IOException { + for (int index = 0; index < specialCaseCount; index++) { + out.writeLong(specialCaseCutOverTimes[index]); + String str = (specialCaseOldCurrencies[index] != null) + ? specialCaseOldCurrencies[index] : ""; + out.writeUTF(str); + str = (specialCaseNewCurrencies[index] != null) + ? specialCaseNewCurrencies[index] : ""; + out.writeUTF(str); + out.writeInt(specialCaseOldCurrenciesDefaultFractionDigits[index]); + out.writeInt(specialCaseNewCurrenciesDefaultFractionDigits[index]); + out.writeInt(specialCaseOldCurrenciesNumericCode[index]); + out.writeInt(specialCaseNewCurrenciesNumericCode[index]); + } + } + + private static void writeOtherCurrencies() throws IOException { + for (int index = 0; index < otherCurrenciesCount; index++) { + String str = (otherCurrencies[index] != null) + ? otherCurrencies[index] : ""; + out.writeUTF(str); + out.writeInt(otherCurrenciesDefaultFractionDigits[index]); + out.writeInt(otherCurrenciesNumericCode[index]); + } + } + +} --- old/make/jdk/src/classes/build/tools/generateemojidata/GenerateEmojiData.java 2020-03-23 19:56:51.591962591 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,155 +0,0 @@ -/* - * Copyright (c) 2019, 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.generateemojidata; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.nio.file.StandardOpenOption; -import java.util.ArrayList; -import java.util.List; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * Generate EmojiData.java - * args[0]: Full path string to the template file - * args[1]: Full path string to the directory that contains "emoji-data.txt" - * args[2]: Full path string to the generated .java file - */ -public class GenerateEmojiData { - public static void main(String[] args) { - try { - final Range[] last = new Range[1]; // last extended pictographic range - last[0] = new Range(0, 0); - - List extPictRanges = Files.lines(Paths.get(args[1], "emoji-data.txt")) - .filter(Predicate.not(l -> l.startsWith("#") || l.isBlank())) - .filter(l -> l.contains("; Extended_Pictograph")) - .map(l -> new Range(l.replaceFirst(" .*", ""))) - .sorted() - .collect(ArrayList::new, - (list, r) -> { - // collapsing consecutive pictographic ranges - int lastIndex = list.size() - 1; - if (lastIndex >= 0) { - Range lastRange = list.get(lastIndex); - if (lastRange.last + 1 == r.start) { - list.set(lastIndex, new Range(lastRange.start, r.last)); - return; - } - } - list.add(r); - }, - ArrayList::addAll); - - - // make the code point conditions - // only very few codepoints below 0x2000 are "emojis", so separate them - // out to generate a fast-path check that can be efficiently inlined - String lowExtPictCodePoints = extPictRanges.stream() - .takeWhile(r -> r.last < 0x2000) - .map(r -> rangeToString(r)) - .collect(Collectors.joining(" ||\n", "", ";\n")); - - String highExtPictCodePoints = extPictRanges.stream() - .dropWhile(r -> r.last < 0x2000) - .map(r -> rangeToString(r)) - .collect(Collectors.joining(" ||\n", "", ";\n")); - - // Generate EmojiData.java file - Files.write(Paths.get(args[2]), - Files.lines(Paths.get(args[0])) - .flatMap(l -> { - if (l.equals("%%%EXTPICT_LOW%%%")) { - return Stream.of(lowExtPictCodePoints); - } else if (l.equals("%%%EXTPICT_HIGH%%%")) { - return Stream.of(highExtPictCodePoints); - } else { - return Stream.of(l); - } - }) - .collect(Collectors.toList()), - StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); - } catch (IOException e) { - e.printStackTrace(); - } - } - - static String rangeToString(Range r) { - if (r.start == r.last) { - return (" ".repeat(16) + "cp == 0x" + toHexString(r.start)); - } else if (r.start == r.last - 1) { - return " ".repeat(16) + "cp == 0x" + toHexString(r.start) + " ||\n" + - " ".repeat(16) + "cp == 0x" + toHexString(r.last); - } else { - return " ".repeat(15) + "(cp >= 0x" + toHexString(r.start) + - " && cp <= 0x" + toHexString(r.last) + ")"; - } - } - - static int toInt(String hexStr) { - return Integer.parseUnsignedInt(hexStr, 16); - } - - static String toHexString(int cp) { - String ret = Integer.toUnsignedString(cp, 16).toUpperCase(); - if (ret.length() < 4) { - ret = "0".repeat(4 - ret.length()) + ret; - } - return ret; - } - - static class Range implements Comparable { - int start; - int last; - - Range (int start, int last) { - this.start = start; - this.last = last; - } - - Range (String input) { - input = input.replaceFirst("\\s#.*", ""); - start = toInt(input.replaceFirst("[\\s\\.].*", "")); - last = input.contains("..") ? - toInt(input.replaceFirst(".*\\.\\.", "") - .replaceFirst(";.*", "").trim()) - : start; - } - - @Override - public String toString() { - return "Start: " + toHexString(start) + ", Last: " + toHexString(last); - } - - @Override - public int compareTo(Range other) { - return Integer.compare(start, other.start); - } - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.base/share/tools/org/openjdk/buildtools/generateemojidata/GenerateEmojiData.java 2020-03-23 19:56:51.219962594 +0100 @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generateemojidata; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Generate EmojiData.java + * args[0]: Full path string to the template file + * args[1]: Full path string to the directory that contains "emoji-data.txt" + * args[2]: Full path string to the generated .java file + */ +public class GenerateEmojiData { + public static void main(String[] args) { + try { + final Range[] last = new Range[1]; // last extended pictographic range + last[0] = new Range(0, 0); + + List extPictRanges = Files.lines(Paths.get(args[1], "emoji-data.txt")) + .filter(Predicate.not(l -> l.startsWith("#") || l.isBlank())) + .filter(l -> l.contains("; Extended_Pictograph")) + .map(l -> new Range(l.replaceFirst(" .*", ""))) + .sorted() + .collect(ArrayList::new, + (list, r) -> { + // collapsing consecutive pictographic ranges + int lastIndex = list.size() - 1; + if (lastIndex >= 0) { + Range lastRange = list.get(lastIndex); + if (lastRange.last + 1 == r.start) { + list.set(lastIndex, new Range(lastRange.start, r.last)); + return; + } + } + list.add(r); + }, + ArrayList::addAll); + + + // make the code point conditions + // only very few codepoints below 0x2000 are "emojis", so separate them + // out to generate a fast-path check that can be efficiently inlined + String lowExtPictCodePoints = extPictRanges.stream() + .takeWhile(r -> r.last < 0x2000) + .map(r -> rangeToString(r)) + .collect(Collectors.joining(" ||\n", "", ";\n")); + + String highExtPictCodePoints = extPictRanges.stream() + .dropWhile(r -> r.last < 0x2000) + .map(r -> rangeToString(r)) + .collect(Collectors.joining(" ||\n", "", ";\n")); + + // Generate EmojiData.java file + Files.write(Paths.get(args[2]), + Files.lines(Paths.get(args[0])) + .flatMap(l -> { + if (l.equals("%%%EXTPICT_LOW%%%")) { + return Stream.of(lowExtPictCodePoints); + } else if (l.equals("%%%EXTPICT_HIGH%%%")) { + return Stream.of(highExtPictCodePoints); + } else { + return Stream.of(l); + } + }) + .collect(Collectors.toList()), + StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); + } catch (IOException e) { + e.printStackTrace(); + } + } + + static String rangeToString(Range r) { + if (r.start == r.last) { + return (" ".repeat(16) + "cp == 0x" + toHexString(r.start)); + } else if (r.start == r.last - 1) { + return " ".repeat(16) + "cp == 0x" + toHexString(r.start) + " ||\n" + + " ".repeat(16) + "cp == 0x" + toHexString(r.last); + } else { + return " ".repeat(15) + "(cp >= 0x" + toHexString(r.start) + + " && cp <= 0x" + toHexString(r.last) + ")"; + } + } + + static int toInt(String hexStr) { + return Integer.parseUnsignedInt(hexStr, 16); + } + + static String toHexString(int cp) { + String ret = Integer.toUnsignedString(cp, 16).toUpperCase(); + if (ret.length() < 4) { + ret = "0".repeat(4 - ret.length()) + ret; + } + return ret; + } + + static class Range implements Comparable { + int start; + int last; + + Range (int start, int last) { + this.start = start; + this.last = last; + } + + Range (String input) { + input = input.replaceFirst("\\s#.*", ""); + start = toInt(input.replaceFirst("[\\s\\.].*", "")); + last = input.contains("..") ? + toInt(input.replaceFirst(".*\\.\\.", "") + .replaceFirst(";.*", "").trim()) + : start; + } + + @Override + public String toString() { + return "Start: " + toHexString(start) + ", Last: " + toHexString(last); + } + + @Override + public int compareTo(Range other) { + return Integer.compare(start, other.start); + } + } +} --- old/make/jdk/src/classes/build/tools/generatelsrequivmaps/EquivMapsGenerator.java 2020-03-23 19:56:52.467962585 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,286 +0,0 @@ -/* - * Copyright (c) 2012, 2020, 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.generatelsrequivmaps; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.time.ZoneId; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.TreeMap; - -/** - * This tool reads the IANA Language Subtag Registry data file downloaded from - * http://www.iana.org/assignments/language-subtag-registry, which is specified - * in the command line and generates a .java source file as specified in - * command line. The generated .java source file contains equivalent language - * maps. These equivalent language maps are used by LocaleMatcher.java - * for the locale matching mechanism specified in RFC 4647 "Matching of Language - * Tags". - */ -public class EquivMapsGenerator { - - public static void main(String[] args) throws Exception { - if (args.length != 2) { - System.err.println("Usage: java EquivMapsGenerator" - + " language-subtag-registry.txt LocaleEquivalentMaps.java"); - System.exit(1); - } - readLSRfile(args[0]); - generateEquivalentMap(); - generateSourceCode(args[1]); - } - - private static String LSRrevisionDate; - private static Map initialLanguageMap = - new TreeMap<>(); - private static Map initialRegionVariantMap = - new TreeMap<>(); - - private static Map sortedLanguageMap1 = new TreeMap<>(); - private static Map sortedLanguageMap2 = new TreeMap<>(); - private static Map sortedRegionVariantMap = - new TreeMap<>(); - - private static void readLSRfile(String filename) throws Exception { - String type = null; - String tag = null; - String preferred = null; - - for (String line : Files.readAllLines(Paths.get(filename), - Charset.forName("UTF-8"))) { - line = line.toLowerCase(Locale.ROOT); - int index = line.indexOf(' ')+1; - if (line.startsWith("file-date:")) { - LSRrevisionDate = line.substring(index); - } else if (line.startsWith("type:")) { - type = line.substring(index); - } else if (line.startsWith("tag:") || line.startsWith("subtag:")) { - tag = line.substring(index); - } else if (line.startsWith("preferred-value:") - && !type.equals("extlang")) { - preferred = line.substring(index); - processDeprecatedData(type, tag, preferred); - } else if (line.equals("%%")) { - type = null; - tag = null; - } - } - } - - private static void processDeprecatedData(String type, - String tag, - String preferred) { - StringBuilder sb; - if (type.equals("region") || type.equals("variant")) { - if (!initialRegionVariantMap.containsKey(preferred)) { - sb = new StringBuilder("-"); - sb.append(preferred); - sb.append(",-"); - sb.append(tag); - initialRegionVariantMap.put("-"+preferred, sb); - } else { - throw new RuntimeException("New case, need implementation." - + " A region/variant subtag \"" + preferred - + "\" is registered for more than one subtags."); - } - } else { // language, grandfahered, and redundant - if (!initialLanguageMap.containsKey(preferred)) { - sb = new StringBuilder(preferred); - sb.append(','); - sb.append(tag); - initialLanguageMap.put(preferred, sb); - } else { - sb = initialLanguageMap.get(preferred); - sb.append(','); - sb.append(tag); - initialLanguageMap.put(preferred, sb); - } - } - } - - private static void generateEquivalentMap() { - String[] subtags; - for (String preferred : initialLanguageMap.keySet()) { - subtags = initialLanguageMap.get(preferred).toString().split(","); - - if (subtags.length == 2) { - sortedLanguageMap1.put(subtags[0], subtags[1]); - sortedLanguageMap1.put(subtags[1], subtags[0]); - } else if (subtags.length > 2) { - for (int i = 0; i < subtags.length; i++) { - sortedLanguageMap2.put(subtags[i], createLangArray(i, subtags)); - } - } else { - throw new RuntimeException("New case, need implementation." - + " A language subtag \"" + preferred - + "\" is registered for more than two subtags. "); - } - } - - for (String preferred : initialRegionVariantMap.keySet()) { - subtags = - initialRegionVariantMap.get(preferred).toString().split(","); - - sortedRegionVariantMap.put(subtags[0], subtags[1]); - sortedRegionVariantMap.put(subtags[1], subtags[0]); - } - - } - - /* create the array of subtags excluding the subtag at index location */ - private static String[] createLangArray(int index, String[] subtags) { - List list = new ArrayList<>(); - for (int i = 0; i < subtags.length; i++) { - if (i != index) { - list.add(subtags[i]); - } - } - return list.toArray(new String[list.size()]); - } - - private static String generateValuesString(String[] values) { - String outputStr = ""; - for (int i = 0; i < values.length; i++) { - if (i != values.length - 1) { - outputStr = outputStr + "\"" + values[i] + "\", "; - } else { - outputStr = outputStr + "\"" + values[i] + "\""; - } - - } - return outputStr; - } - - private static final String COPYRIGHT = "/*\n" - + " * Copyright (c) 2012, %d, Oracle and/or its affiliates. All rights reserved.\n" - + " * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n" - + " *\n" - + " * This code is free software; you can redistribute it and/or modify it\n" - + " * under the terms of the GNU General Public License version 2 only, as\n" - + " * published by the Free Software Foundation. Oracle designates this\n" - + " * particular file as subject to the \"Classpath\" exception as provided\n" - + " * by Oracle in the LICENSE file that accompanied this code.\n" - + " *\n" - + " * This code is distributed in the hope that it will be useful, but WITHOUT\n" - + " * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n" - + " * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\n" - + " * version 2 for more details (a copy is included in the LICENSE file that\n" - + " * accompanied this code).\n" - + " *\n" - + " * You should have received a copy of the GNU General Public License version\n" - + " * 2 along with this work; if not, write to the Free Software Foundation,\n" - + " * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n" - + " *\n" - + " * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n" - + " * or visit www.oracle.com if you need additional information or have any\n" - + " * questions.\n" - + "*/\n\n"; - - private static final String headerText = - "package sun.util.locale;\n\n" - + "import java.util.HashMap;\n" - + "import java.util.Map;\n\n" - + "final class LocaleEquivalentMaps {\n\n" - + " static final Map singleEquivMap;\n" - + " static final Map multiEquivsMap;\n" - + " static final Map regionVariantEquivMap;\n\n" - + " static {\n" - + " singleEquivMap = new HashMap<>("; - - private static final String footerText = - " }\n\n" - + "}"; - - private static String getOpenJDKCopyright() { - int year = ZonedDateTime.now(ZoneId - .of("America/Los_Angeles")).getYear(); - return String.format(Locale.US, COPYRIGHT, year); - } - - /** - * The input lsr data file is in UTF-8, so theoretically for the characters - * beyond US-ASCII, the generated Java String literals need to be Unicode - * escaped (\\uXXXX) while writing to a file. But as of now, there is not - * the case since we don't use "description", "comment" or alike. - */ - private static void generateSourceCode(String fileName) { - - try (BufferedWriter writer = Files.newBufferedWriter( - Paths.get(fileName))) { - writer.write(getOpenJDKCopyright()); - writer.write(headerText - + (int)(sortedLanguageMap1.size() / 0.75f + 1) + ");\n" - + " multiEquivsMap = new HashMap<>(" - + (int)(sortedLanguageMap2.size() / 0.75f + 1) + ");\n" - + " regionVariantEquivMap = new HashMap<>(" - + (int)(sortedRegionVariantMap.size() / 0.75f + 1) + ");\n\n" - + " // This is an auto-generated file and should not be manually edited.\n" - + " // LSR Revision: " + LSRrevisionDate); - writer.newLine(); - - for (String key : sortedLanguageMap1.keySet()) { - String value = sortedLanguageMap1.get(key); - writer.write(" singleEquivMap.put(\"" - + key + "\", \"" + value + "\");"); - writer.newLine(); - } - - writer.newLine(); - for (String key : sortedLanguageMap2.keySet()) { - String[] values = sortedLanguageMap2.get(key); - - if (values.length >= 2) { - writer.write(" multiEquivsMap.put(\"" - + key + "\", new String[] {" - + generateValuesString(values) + "});"); - writer.newLine(); - } - } - - writer.newLine(); - for (String key : sortedRegionVariantMap.keySet()) { - String value = sortedRegionVariantMap.get(key); - writer.write(" regionVariantEquivMap.put(\"" - + key + "\", \"" + value + "\");"); - writer.newLine(); - } - - writer.write(footerText); - } catch (IOException ex) { - ex.printStackTrace(System.err); - System.exit(1); - } - - } - -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.base/share/tools/org/openjdk/buildtools/generatelsrequivmaps/EquivMapsGenerator.java 2020-03-23 19:56:52.031962588 +0100 @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatelsrequivmaps; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.TreeMap; + +/** + * This tool reads the IANA Language Subtag Registry data file downloaded from + * http://www.iana.org/assignments/language-subtag-registry, which is specified + * in the command line and generates a .java source file as specified in + * command line. The generated .java source file contains equivalent language + * maps. These equivalent language maps are used by LocaleMatcher.java + * for the locale matching mechanism specified in RFC 4647 "Matching of Language + * Tags". + */ +public class EquivMapsGenerator { + + public static void main(String[] args) throws Exception { + if (args.length != 2) { + System.err.println("Usage: java EquivMapsGenerator" + + " language-subtag-registry.txt LocaleEquivalentMaps.java"); + System.exit(1); + } + readLSRfile(args[0]); + generateEquivalentMap(); + generateSourceCode(args[1]); + } + + private static String LSRrevisionDate; + private static Map initialLanguageMap = + new TreeMap<>(); + private static Map initialRegionVariantMap = + new TreeMap<>(); + + private static Map sortedLanguageMap1 = new TreeMap<>(); + private static Map sortedLanguageMap2 = new TreeMap<>(); + private static Map sortedRegionVariantMap = + new TreeMap<>(); + + private static void readLSRfile(String filename) throws Exception { + String type = null; + String tag = null; + String preferred = null; + + for (String line : Files.readAllLines(Paths.get(filename), + Charset.forName("UTF-8"))) { + line = line.toLowerCase(Locale.ROOT); + int index = line.indexOf(' ')+1; + if (line.startsWith("file-date:")) { + LSRrevisionDate = line.substring(index); + } else if (line.startsWith("type:")) { + type = line.substring(index); + } else if (line.startsWith("tag:") || line.startsWith("subtag:")) { + tag = line.substring(index); + } else if (line.startsWith("preferred-value:") + && !type.equals("extlang")) { + preferred = line.substring(index); + processDeprecatedData(type, tag, preferred); + } else if (line.equals("%%")) { + type = null; + tag = null; + } + } + } + + private static void processDeprecatedData(String type, + String tag, + String preferred) { + StringBuilder sb; + if (type.equals("region") || type.equals("variant")) { + if (!initialRegionVariantMap.containsKey(preferred)) { + sb = new StringBuilder("-"); + sb.append(preferred); + sb.append(",-"); + sb.append(tag); + initialRegionVariantMap.put("-"+preferred, sb); + } else { + throw new RuntimeException("New case, need implementation." + + " A region/variant subtag \"" + preferred + + "\" is registered for more than one subtags."); + } + } else { // language, grandfahered, and redundant + if (!initialLanguageMap.containsKey(preferred)) { + sb = new StringBuilder(preferred); + sb.append(','); + sb.append(tag); + initialLanguageMap.put(preferred, sb); + } else { + sb = initialLanguageMap.get(preferred); + sb.append(','); + sb.append(tag); + initialLanguageMap.put(preferred, sb); + } + } + } + + private static void generateEquivalentMap() { + String[] subtags; + for (String preferred : initialLanguageMap.keySet()) { + subtags = initialLanguageMap.get(preferred).toString().split(","); + + if (subtags.length == 2) { + sortedLanguageMap1.put(subtags[0], subtags[1]); + sortedLanguageMap1.put(subtags[1], subtags[0]); + } else if (subtags.length > 2) { + for (int i = 0; i < subtags.length; i++) { + sortedLanguageMap2.put(subtags[i], createLangArray(i, subtags)); + } + } else { + throw new RuntimeException("New case, need implementation." + + " A language subtag \"" + preferred + + "\" is registered for more than two subtags. "); + } + } + + for (String preferred : initialRegionVariantMap.keySet()) { + subtags = + initialRegionVariantMap.get(preferred).toString().split(","); + + sortedRegionVariantMap.put(subtags[0], subtags[1]); + sortedRegionVariantMap.put(subtags[1], subtags[0]); + } + + } + + /* create the array of subtags excluding the subtag at index location */ + private static String[] createLangArray(int index, String[] subtags) { + List list = new ArrayList<>(); + for (int i = 0; i < subtags.length; i++) { + if (i != index) { + list.add(subtags[i]); + } + } + return list.toArray(new String[list.size()]); + } + + private static String generateValuesString(String[] values) { + String outputStr = ""; + for (int i = 0; i < values.length; i++) { + if (i != values.length - 1) { + outputStr = outputStr + "\"" + values[i] + "\", "; + } else { + outputStr = outputStr + "\"" + values[i] + "\""; + } + + } + return outputStr; + } + + private static final String COPYRIGHT = "/*\n" + + " * Copyright (c) 2012, %d, Oracle and/or its affiliates. All rights reserved.\n" + + " * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n" + + " *\n" + + " * This code is free software; you can redistribute it and/or modify it\n" + + " * under the terms of the GNU General Public License version 2 only, as\n" + + " * published by the Free Software Foundation. Oracle designates this\n" + + " * particular file as subject to the \"Classpath\" exception as provided\n" + + " * by Oracle in the LICENSE file that accompanied this code.\n" + + " *\n" + + " * This code is distributed in the hope that it will be useful, but WITHOUT\n" + + " * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n" + + " * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\n" + + " * version 2 for more details (a copy is included in the LICENSE file that\n" + + " * accompanied this code).\n" + + " *\n" + + " * You should have received a copy of the GNU General Public License version\n" + + " * 2 along with this work; if not, write to the Free Software Foundation,\n" + + " * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n" + + " *\n" + + " * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n" + + " * or visit www.oracle.com if you need additional information or have any\n" + + " * questions.\n" + + "*/\n\n"; + + private static final String headerText = + "package sun.util.locale;\n\n" + + "import java.util.HashMap;\n" + + "import java.util.Map;\n\n" + + "final class LocaleEquivalentMaps {\n\n" + + " static final Map singleEquivMap;\n" + + " static final Map multiEquivsMap;\n" + + " static final Map regionVariantEquivMap;\n\n" + + " static {\n" + + " singleEquivMap = new HashMap<>("; + + private static final String footerText = + " }\n\n" + + "}"; + + private static String getOpenJDKCopyright() { + int year = ZonedDateTime.now(ZoneId + .of("America/Los_Angeles")).getYear(); + return String.format(Locale.US, COPYRIGHT, year); + } + + /** + * The input lsr data file is in UTF-8, so theoretically for the characters + * beyond US-ASCII, the generated Java String literals need to be Unicode + * escaped (\\uXXXX) while writing to a file. But as of now, there is not + * the case since we don't use "description", "comment" or alike. + */ + private static void generateSourceCode(String fileName) { + + try (BufferedWriter writer = Files.newBufferedWriter( + Paths.get(fileName))) { + writer.write(getOpenJDKCopyright()); + writer.write(headerText + + (int)(sortedLanguageMap1.size() / 0.75f + 1) + ");\n" + + " multiEquivsMap = new HashMap<>(" + + (int)(sortedLanguageMap2.size() / 0.75f + 1) + ");\n" + + " regionVariantEquivMap = new HashMap<>(" + + (int)(sortedRegionVariantMap.size() / 0.75f + 1) + ");\n\n" + + " // This is an auto-generated file and should not be manually edited.\n" + + " // LSR Revision: " + LSRrevisionDate); + writer.newLine(); + + for (String key : sortedLanguageMap1.keySet()) { + String value = sortedLanguageMap1.get(key); + writer.write(" singleEquivMap.put(\"" + + key + "\", \"" + value + "\");"); + writer.newLine(); + } + + writer.newLine(); + for (String key : sortedLanguageMap2.keySet()) { + String[] values = sortedLanguageMap2.get(key); + + if (values.length >= 2) { + writer.write(" multiEquivsMap.put(\"" + + key + "\", new String[] {" + + generateValuesString(values) + "});"); + writer.newLine(); + } + } + + writer.newLine(); + for (String key : sortedRegionVariantMap.keySet()) { + String value = sortedRegionVariantMap.get(key); + writer.write(" regionVariantEquivMap.put(\"" + + key + "\", \"" + value + "\");"); + writer.newLine(); + } + + writer.write(footerText); + } catch (IOException ex) { + ex.printStackTrace(System.err); + System.exit(1); + } + + } + +} --- old/make/jdk/src/classes/build/tools/intpoly/FieldGen.java 2020-03-23 19:56:53.351962578 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,921 +0,0 @@ -/* - * Copyright (c) 2018, 2019, 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. - */ - - -/* - * This file is used to generated optimized finite field implementations. - */ -package build.tools.intpoly; - -import java.io.*; -import java.math.BigInteger; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.*; - -public class FieldGen { - - static FieldParams Curve25519 = new FieldParams( - "IntegerPolynomial25519", 26, 10, 1, 255, - Arrays.asList( - new Term(0, -19) - ), - Curve25519CrSequence(), simpleSmallCrSequence(10) - ); - - private static List Curve25519CrSequence() { - List result = new ArrayList(); - - // reduce(7,2) - result.add(new Reduce(17)); - result.add(new Reduce(18)); - - // carry(8,2) - result.add(new Carry(8)); - result.add(new Carry(9)); - - // reduce(0,7) - for (int i = 10; i < 17; i++) { - result.add(new Reduce(i)); - } - - // carry(0,9) - result.addAll(fullCarry(10)); - - return result; - } - - static FieldParams Curve448 = new FieldParams( - "IntegerPolynomial448", 28, 16, 1, 448, - Arrays.asList( - new Term(224, -1), - new Term(0, -1) - ), - Curve448CrSequence(), simpleSmallCrSequence(16) - ); - - private static List Curve448CrSequence() { - List result = new ArrayList(); - - // reduce(8, 7) - for (int i = 24; i < 31; i++) { - result.add(new Reduce(i)); - } - // reduce(4, 4) - for (int i = 20; i < 24; i++) { - result.add(new Reduce(i)); - } - - //carry(14, 2) - result.add(new Carry(14)); - result.add(new Carry(15)); - - // reduce(0, 4) - for (int i = 16; i < 20; i++) { - result.add(new Reduce(i)); - } - - // carry(0, 15) - result.addAll(fullCarry(16)); - - return result; - } - - static FieldParams P256 = new FieldParams( - "IntegerPolynomialP256", 26, 10, 2, 256, - Arrays.asList( - new Term(224, -1), - new Term(192, 1), - new Term(96, 1), - new Term(0, -1) - ), - P256CrSequence(), simpleSmallCrSequence(10) - ); - - private static List P256CrSequence() { - List result = new ArrayList(); - result.addAll(fullReduce(10)); - result.addAll(simpleSmallCrSequence(10)); - return result; - } - - static FieldParams P384 = new FieldParams( - "IntegerPolynomialP384", 28, 14, 2, 384, - Arrays.asList( - new Term(128, -1), - new Term(96, -1), - new Term(32, 1), - new Term(0, -1) - ), - P384CrSequence(), simpleSmallCrSequence(14) - ); - - private static List P384CrSequence() { - List result = new ArrayList(); - result.addAll(fullReduce(14)); - result.addAll(simpleSmallCrSequence(14)); - return result; - } - - static FieldParams P521 = new FieldParams( - "IntegerPolynomialP521", 28, 19, 2, 521, - Arrays.asList( - new Term(0, -1) - ), - P521CrSequence(), simpleSmallCrSequence(19) - ); - - private static List P521CrSequence() { - List result = new ArrayList(); - result.addAll(fullReduce(19)); - result.addAll(simpleSmallCrSequence(19)); - return result; - } - - static FieldParams O256 = new FieldParams( - "P256OrderField", 26, 10, 1, 256, - "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", - orderFieldCrSequence(10), orderFieldSmallCrSequence(10) - ); - - static FieldParams O384 = new FieldParams( - "P384OrderField", 28, 14, 1, 384, - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973", - orderFieldCrSequence(14), orderFieldSmallCrSequence(14) - ); - - static FieldParams O521 = new FieldParams( - "P521OrderField", 28, 19, 1, 521, - "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", - o521crSequence(19), orderFieldSmallCrSequence(19) - ); - - private static List o521crSequence(int numLimbs) { - - // split the full reduce in half, with a carry in between - List result = new ArrayList(); - result.addAll(fullCarry(2 * numLimbs)); - for (int i = 2 * numLimbs - 1; i >= numLimbs + numLimbs / 2; i--) { - result.add(new Reduce(i)); - } - // carry - for (int i = numLimbs; i < numLimbs + numLimbs / 2 - 1; i++) { - result.add(new Carry(i)); - } - // rest of reduce - for (int i = numLimbs + numLimbs / 2 - 1; i >= numLimbs; i--) { - result.add(new Reduce(i)); - } - result.addAll(orderFieldSmallCrSequence(numLimbs)); - - return result; - } - - private static List orderFieldCrSequence(int numLimbs) { - List result = new ArrayList(); - result.addAll(fullCarry(2 * numLimbs)); - result.add(new Reduce(2 * numLimbs - 1)); - result.addAll(fullReduce(numLimbs)); - result.addAll(fullCarry(numLimbs + 1)); - result.add(new Reduce(numLimbs)); - result.addAll(fullCarry(numLimbs)); - - return result; - } - - private static List orderFieldSmallCrSequence(int numLimbs) { - List result = new ArrayList(); - result.addAll(fullCarry(numLimbs + 1)); - result.add(new Reduce(numLimbs)); - result.addAll(fullCarry(numLimbs)); - return result; - } - - static final FieldParams[] ALL_FIELDS = { - P256, P384, P521, O256, O384, O521, - }; - - public static class Term { - private final int power; - private final int coefficient; - - public Term(int power, int coefficient) { - this.power = power; - this.coefficient = coefficient; - } - - public int getPower() { - return power; - } - - public int getCoefficient() { - return coefficient; - } - - public BigInteger getValue() { - return BigInteger.valueOf(2).pow(power) - .multiply(BigInteger.valueOf(coefficient)); - } - - public String toString() { - return "2^" + power + " * " + coefficient; - } - } - - static abstract class CarryReduce { - private final int index; - - protected CarryReduce(int index) { - this.index = index; - } - - public int getIndex() { - return index; - } - - public abstract void write(CodeBuffer out, FieldParams params, - String prefix, Iterable remaining); - } - - static class Carry extends CarryReduce { - public Carry(int index) { - super(index); - } - - public void write(CodeBuffer out, FieldParams params, String prefix, - Iterable remaining) { - carry(out, params, prefix, getIndex()); - } - } - - static class Reduce extends CarryReduce { - public Reduce(int index) { - super(index); - } - - public void write(CodeBuffer out, FieldParams params, String prefix, - Iterable remaining) { - reduce(out, params, prefix, getIndex(), remaining); - } - } - - static class FieldParams { - private final String className; - private final int bitsPerLimb; - private final int numLimbs; - private final int maxAdds; - private final int power; - private final Iterable terms; - private final List crSequence; - private final List smallCrSequence; - - public FieldParams(String className, int bitsPerLimb, int numLimbs, - int maxAdds, int power, - Iterable terms, List crSequence, - List smallCrSequence) { - this.className = className; - this.bitsPerLimb = bitsPerLimb; - this.numLimbs = numLimbs; - this.maxAdds = maxAdds; - this.power = power; - this.terms = terms; - this.crSequence = crSequence; - this.smallCrSequence = smallCrSequence; - } - - public FieldParams(String className, int bitsPerLimb, int numLimbs, - int maxAdds, int power, - String term, List crSequence, - List smallCrSequence) { - this.className = className; - this.bitsPerLimb = bitsPerLimb; - this.numLimbs = numLimbs; - this.maxAdds = maxAdds; - this.power = power; - this.crSequence = crSequence; - this.smallCrSequence = smallCrSequence; - - terms = buildTerms(BigInteger.ONE.shiftLeft(power) - .subtract(new BigInteger(term, 16))); - } - - private Iterable buildTerms(BigInteger sub) { - // split a large subtrahend into smaller terms - // that are aligned with limbs - List result = new ArrayList(); - BigInteger mod = BigInteger.valueOf(1 << bitsPerLimb); - int termIndex = 0; - while (!sub.equals(BigInteger.ZERO)) { - int coef = sub.mod(mod).intValue(); - boolean plusOne = false; - if (coef > (1 << (bitsPerLimb - 1))) { - coef = coef - (1 << bitsPerLimb); - plusOne = true; - } - if (coef != 0) { - int pow = termIndex * bitsPerLimb; - result.add(new Term(pow, -coef)); - } - sub = sub.shiftRight(bitsPerLimb); - if (plusOne) { - sub = sub.add(BigInteger.ONE); - } - ++termIndex; - } - return result; - } - - public String getClassName() { - return className; - } - - public int getBitsPerLimb() { - return bitsPerLimb; - } - - public int getNumLimbs() { - return numLimbs; - } - - public int getMaxAdds() { - return maxAdds; - } - - public int getPower() { - return power; - } - - public Iterable getTerms() { - return terms; - } - - public List getCrSequence() { - return crSequence; - } - - public List getSmallCrSequence() { - return smallCrSequence; - } - } - - static Collection fullCarry(int numLimbs) { - List result = new ArrayList(); - for (int i = 0; i < numLimbs - 1; i++) { - result.add(new Carry(i)); - } - return result; - } - - static Collection fullReduce(int numLimbs) { - List result = new ArrayList(); - for (int i = numLimbs - 2; i >= 0; i--) { - result.add(new Reduce(i + numLimbs)); - } - return result; - } - - static List simpleCrSequence(int numLimbs) { - List result = new ArrayList(); - for (int i = 0; i < 4; i++) { - result.addAll(fullCarry(2 * numLimbs - 1)); - result.addAll(fullReduce(numLimbs)); - } - - return result; - } - - static List simpleSmallCrSequence(int numLimbs) { - List result = new ArrayList(); - // carry a few positions at the end - for (int i = numLimbs - 2; i < numLimbs; i++) { - result.add(new Carry(i)); - } - // this carries out a single value that must be reduced back in - result.add(new Reduce(numLimbs)); - // finish with a full carry - result.addAll(fullCarry(numLimbs)); - return result; - } - - private final String packageName; - private final String parentName; - - private final Path headerPath; - private final Path destPath; - - public FieldGen(String packageName, String parentName, - Path headerPath, Path destRoot) throws IOException { - this.packageName = packageName; - this.parentName = parentName; - this.headerPath = headerPath; - this.destPath = destRoot.resolve(packageName.replace(".", "/")); - Files.createDirectories(destPath); - } - - // args: header.txt destpath - public static void main(String[] args) throws Exception { - - FieldGen gen = new FieldGen( - "sun.security.util.math.intpoly", - "IntegerPolynomial", - Path.of(args[0]), - Path.of(args[1])); - for (FieldParams p : ALL_FIELDS) { - System.out.println(p.className); - System.out.println(p.terms); - System.out.println(); - gen.generateFile(p); - } - } - - private void generateFile(FieldParams params) throws IOException { - String text = generate(params); - String fileName = params.getClassName() + ".java"; - PrintWriter out = new PrintWriter(Files.newBufferedWriter( - destPath.resolve(fileName))); - out.println(text); - out.close(); - } - - static class CodeBuffer { - - private int nextTemporary = 0; - private Set temporaries = new HashSet(); - private StringBuffer buffer = new StringBuffer(); - private int indent = 0; - private Class lastCR; - private int lastCrCount = 0; - private int crMethodBreakCount = 0; - private int crNumLimbs = 0; - - public void incrIndent() { - indent++; - } - - public void decrIndent() { - indent--; - } - - public void newTempScope() { - nextTemporary = 0; - temporaries.clear(); - } - - public void appendLine(String s) { - appendIndent(); - buffer.append(s + "\n"); - } - - public void appendLine() { - buffer.append("\n"); - } - - public String toString() { - return buffer.toString(); - } - - public void startCrSequence(int numLimbs) { - this.crNumLimbs = numLimbs; - lastCrCount = 0; - crMethodBreakCount = 0; - lastCR = null; - } - - /* - * Record a carry/reduce of the specified type. This method is used to - * break up large carry/reduce sequences into multiple methods to make - * JIT/optimization easier - */ - public void record(Class type) { - if (type == lastCR) { - lastCrCount++; - } else { - - if (lastCrCount >= 8) { - insertCrMethodBreak(); - } - - lastCR = type; - lastCrCount = 0; - } - } - - private void insertCrMethodBreak() { - - appendLine(); - - // call the new method - appendIndent(); - append("carryReduce" + crMethodBreakCount + "(r"); - for (int i = 0; i < crNumLimbs; i++) { - append(", c" + i); - } - // temporaries are not live between operations, no need to send - append(");\n"); - - decrIndent(); - appendLine("}"); - - // make the method - appendIndent(); - append("void carryReduce" + crMethodBreakCount + "(long[] r"); - for (int i = 0; i < crNumLimbs; i++) { - append(", long c" + i); - } - append(") {\n"); - incrIndent(); - // declare temporaries - for (String temp : temporaries) { - appendLine("long " + temp + ";"); - } - append("\n"); - - crMethodBreakCount++; - } - - public String getTemporary(String type, String value) { - Iterator iter = temporaries.iterator(); - if (iter.hasNext()) { - String result = iter.next(); - iter.remove(); - appendLine(result + " = " + value + ";"); - return result; - } else { - String result = "t" + (nextTemporary++); - appendLine(type + " " + result + " = " + value + ";"); - return result; - } - } - - public void freeTemporary(String temp) { - temporaries.add(temp); - } - - public void appendIndent() { - for (int i = 0; i < indent; i++) { - buffer.append(" "); - } - } - - public void append(String s) { - buffer.append(s); - } - } - - private String generate(FieldParams params) throws IOException { - CodeBuffer result = new CodeBuffer(); - String header = readHeader(); - result.appendLine(header); - - if (packageName != null) { - result.appendLine("package " + packageName + ";"); - result.appendLine(); - } - result.appendLine("import java.math.BigInteger;"); - - result.appendLine("public class " + params.getClassName() - + " extends " + this.parentName + " {"); - result.incrIndent(); - - result.appendLine("private static final int BITS_PER_LIMB = " - + params.getBitsPerLimb() + ";"); - result.appendLine("private static final int NUM_LIMBS = " - + params.getNumLimbs() + ";"); - result.appendLine("private static final int MAX_ADDS = " - + params.getMaxAdds() + ";"); - result.appendLine( - "public static final BigInteger MODULUS = evaluateModulus();"); - result.appendLine("private static final long CARRY_ADD = 1 << " - + (params.getBitsPerLimb() - 1) + ";"); - if (params.getBitsPerLimb() * params.getNumLimbs() != params.getPower()) { - result.appendLine("private static final int LIMB_MASK = -1 " - + ">>> (64 - BITS_PER_LIMB);"); - } - int termIndex = 0; - - result.appendLine("public " + params.getClassName() + "() {"); - result.appendLine(); - result.appendLine(" super(BITS_PER_LIMB, NUM_LIMBS, MAX_ADDS, MODULUS);"); - result.appendLine(); - result.appendLine("}"); - - result.appendLine("private static BigInteger evaluateModulus() {"); - result.incrIndent(); - result.appendLine("BigInteger result = BigInteger.valueOf(2).pow(" - + params.getPower() + ");"); - for (Term t : params.getTerms()) { - boolean subtract = false; - int coefValue = t.getCoefficient(); - if (coefValue < 0) { - coefValue = 0 - coefValue; - subtract = true; - } - String coefExpr = "BigInteger.valueOf(" + coefValue + ")"; - String powExpr = "BigInteger.valueOf(2).pow(" + t.getPower() + ")"; - String termExpr = "ERROR"; - if (t.getPower() == 0) { - termExpr = coefExpr; - } else if (coefValue == 1) { - termExpr = powExpr; - } else { - termExpr = powExpr + ".multiply(" + coefExpr + ")"; - } - if (subtract) { - result.appendLine("result = result.subtract(" + termExpr + ");"); - } else { - result.appendLine("result = result.add(" + termExpr + ");"); - } - } - result.appendLine("return result;"); - result.decrIndent(); - result.appendLine("}"); - - result.appendLine("@Override"); - result.appendLine("protected void finalCarryReduceLast(long[] limbs) {"); - result.incrIndent(); - int extraBits = params.getBitsPerLimb() * params.getNumLimbs() - - params.getPower(); - int highBits = params.getBitsPerLimb() - extraBits; - result.appendLine("long c = limbs[" + (params.getNumLimbs() - 1) - + "] >> " + highBits + ";"); - result.appendLine("limbs[" + (params.getNumLimbs() - 1) + "] -= c << " - + highBits + ";"); - for (Term t : params.getTerms()) { - int reduceBits = params.getPower() + extraBits - t.getPower(); - int negatedCoefficient = -1 * t.getCoefficient(); - modReduceInBits(result, params, true, "limbs", params.getNumLimbs(), - reduceBits, negatedCoefficient, "c"); - } - result.decrIndent(); - result.appendLine("}"); - - // full carry/reduce sequence - result.appendIndent(); - result.append("private void carryReduce(long[] r, "); - for (int i = 0; i < 2 * params.getNumLimbs() - 1; i++) { - result.append("long c" + i); - if (i < 2 * params.getNumLimbs() - 2) { - result.append(", "); - } - } - result.append(") {\n"); - result.newTempScope(); - result.incrIndent(); - result.appendLine("long c" + (2 * params.getNumLimbs() - 1) + " = 0;"); - write(result, params.getCrSequence(), params, "c", - 2 * params.getNumLimbs()); - result.appendLine(); - for (int i = 0; i < params.getNumLimbs(); i++) { - result.appendLine("r[" + i + "] = c" + i + ";"); - } - result.decrIndent(); - result.appendLine("}"); - - // small carry/reduce sequence - result.appendIndent(); - result.append("private void carryReduce(long[] r, "); - for (int i = 0; i < params.getNumLimbs(); i++) { - result.append("long c" + i); - if (i < params.getNumLimbs() - 1) { - result.append(", "); - } - } - result.append(") {\n"); - result.newTempScope(); - result.incrIndent(); - result.appendLine("long c" + params.getNumLimbs() + " = 0;"); - write(result, params.getSmallCrSequence(), params, - "c", params.getNumLimbs() + 1); - result.appendLine(); - for (int i = 0; i < params.getNumLimbs(); i++) { - result.appendLine("r[" + i + "] = c" + i + ";"); - } - result.decrIndent(); - result.appendLine("}"); - - result.appendLine("@Override"); - result.appendLine("protected void mult(long[] a, long[] b, long[] r) {"); - result.incrIndent(); - for (int i = 0; i < 2 * params.getNumLimbs() - 1; i++) { - result.appendIndent(); - result.append("long c" + i + " = "); - int startJ = Math.max(i + 1 - params.getNumLimbs(), 0); - int endJ = Math.min(params.getNumLimbs(), i + 1); - for (int j = startJ; j < endJ; j++) { - int bIndex = i - j; - result.append("(a[" + j + "] * b[" + bIndex + "])"); - if (j < endJ - 1) { - result.append(" + "); - } - } - result.append(";\n"); - } - result.appendLine(); - result.appendIndent(); - result.append("carryReduce(r, "); - for (int i = 0; i < 2 * params.getNumLimbs() - 1; i++) { - result.append("c" + i); - if (i < 2 * params.getNumLimbs() - 2) { - result.append(", "); - } - } - result.append(");\n"); - result.decrIndent(); - result.appendLine("}"); - - result.appendLine("@Override"); - result.appendLine("protected void reduce(long[] a) {"); - result.incrIndent(); - result.appendIndent(); - result.append("carryReduce(a, "); - for (int i = 0; i < params.getNumLimbs(); i++) { - result.append("a[" + i + "]"); - if (i < params.getNumLimbs() - 1) { - result.append(", "); - } - } - result.append(");\n"); - result.decrIndent(); - result.appendLine("}"); - - result.appendLine("@Override"); - result.appendLine("protected void square(long[] a, long[] r) {"); - result.incrIndent(); - for (int i = 0; i < 2 * params.getNumLimbs() - 1; i++) { - result.appendIndent(); - result.append("long c" + i + " = "); - int startJ = Math.max(i + 1 - params.getNumLimbs(), 0); - int endJ = Math.min(params.getNumLimbs(), i + 1); - int jDiff = endJ - startJ; - if (jDiff > 1) { - result.append("2 * ("); - } - for (int j = 0; j < jDiff / 2; j++) { - int aIndex = j + startJ; - int bIndex = i - aIndex; - result.append("(a[" + aIndex + "] * a[" + bIndex + "])"); - if (j < (jDiff / 2) - 1) { - result.append(" + "); - } - } - if (jDiff > 1) { - result.append(")"); - } - if (jDiff % 2 == 1) { - int aIndex = i / 2; - if (jDiff > 1) { - result.append(" + "); - } - result.append("(a[" + aIndex + "] * a[" + aIndex + "])"); - } - result.append(";\n"); - } - result.appendLine(); - result.appendIndent(); - result.append("carryReduce(r, "); - for (int i = 0; i < 2 * params.getNumLimbs() - 1; i++) { - result.append("c" + i); - if (i < 2 * params.getNumLimbs() - 2) { - result.append(", "); - } - } - result.append(");\n"); - result.decrIndent(); - result.appendLine("}"); - - result.decrIndent(); - result.appendLine("}"); // end class - - return result.toString(); - } - - private static void write(CodeBuffer out, List sequence, - FieldParams params, String prefix, int numLimbs) { - - out.startCrSequence(numLimbs); - for (int i = 0; i < sequence.size(); i++) { - CarryReduce cr = sequence.get(i); - Iterator remainingIter = sequence.listIterator(i + 1); - List remaining = new ArrayList(); - remainingIter.forEachRemaining(remaining::add); - cr.write(out, params, prefix, remaining); - } - } - - private static void reduce(CodeBuffer out, FieldParams params, - String prefix, int index, Iterable remaining) { - - out.record(Reduce.class); - - out.appendLine("//reduce from position " + index); - String reduceFrom = indexedExpr(false, prefix, index); - boolean referenced = false; - for (CarryReduce cr : remaining) { - if (cr.index == index) { - referenced = true; - } - } - for (Term t : params.getTerms()) { - int reduceBits = params.getPower() - t.getPower(); - int negatedCoefficient = -1 * t.getCoefficient(); - modReduceInBits(out, params, false, prefix, index, reduceBits, - negatedCoefficient, reduceFrom); - } - if (referenced) { - out.appendLine(reduceFrom + " = 0;"); - } - } - - private static void carry(CodeBuffer out, FieldParams params, - String prefix, int index) { - - out.record(Carry.class); - - out.appendLine("//carry from position " + index); - String carryFrom = prefix + index; - String carryTo = prefix + (index + 1); - String carry = "(" + carryFrom + " + CARRY_ADD) >> " - + params.getBitsPerLimb(); - String temp = out.getTemporary("long", carry); - out.appendLine(carryFrom + " -= (" + temp + " << " - + params.getBitsPerLimb() + ");"); - out.appendLine(carryTo + " += " + temp + ";"); - out.freeTemporary(temp); - } - - private static String indexedExpr( - boolean isArray, String prefix, int index) { - String result = prefix + index; - if (isArray) { - result = prefix + "[" + index + "]"; - } - return result; - } - - private static void modReduceInBits(CodeBuffer result, FieldParams params, - boolean isArray, String prefix, int index, int reduceBits, - int coefficient, String c) { - - String x = coefficient + " * " + c; - String accOp = "+="; - String temp = null; - if (coefficient == 1) { - x = c; - } else if (coefficient == -1) { - x = c; - accOp = "-="; - } else { - temp = result.getTemporary("long", x); - x = temp; - } - - if (reduceBits % params.getBitsPerLimb() == 0) { - int pos = reduceBits / params.getBitsPerLimb(); - result.appendLine(indexedExpr(isArray, prefix, (index - pos)) - + " " + accOp + " " + x + ";"); - } else { - int secondPos = reduceBits / params.getBitsPerLimb(); - int bitOffset = (secondPos + 1) * params.getBitsPerLimb() - - reduceBits; - int rightBitOffset = params.getBitsPerLimb() - bitOffset; - result.appendLine(indexedExpr(isArray, prefix, - (index - (secondPos + 1))) + " " + accOp - + " (" + x + " << " + bitOffset + ") & LIMB_MASK;"); - result.appendLine(indexedExpr(isArray, prefix, - (index - secondPos)) + " " + accOp + " " + x - + " >> " + rightBitOffset + ";"); - } - - if (temp != null) { - result.freeTemporary(temp); - } - } - - private String readHeader() throws IOException { - BufferedReader reader - = Files.newBufferedReader(headerPath); - StringBuffer result = new StringBuffer(); - reader.lines().forEach(s -> result.append(s + "\n")); - return result.toString(); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.base/share/tools/org/openjdk/buildtools/intpoly/FieldGen.java 2020-03-23 19:56:52.911962582 +0100 @@ -0,0 +1,921 @@ +/* + * Copyright (c) 2018, 2019, 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. + */ + + +/* + * This file is used to generated optimized finite field implementations. + */ +package org.openjdk.buildtools.intpoly; + +import java.io.*; +import java.math.BigInteger; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; + +public class FieldGen { + + static FieldParams Curve25519 = new FieldParams( + "IntegerPolynomial25519", 26, 10, 1, 255, + Arrays.asList( + new Term(0, -19) + ), + Curve25519CrSequence(), simpleSmallCrSequence(10) + ); + + private static List Curve25519CrSequence() { + List result = new ArrayList(); + + // reduce(7,2) + result.add(new Reduce(17)); + result.add(new Reduce(18)); + + // carry(8,2) + result.add(new Carry(8)); + result.add(new Carry(9)); + + // reduce(0,7) + for (int i = 10; i < 17; i++) { + result.add(new Reduce(i)); + } + + // carry(0,9) + result.addAll(fullCarry(10)); + + return result; + } + + static FieldParams Curve448 = new FieldParams( + "IntegerPolynomial448", 28, 16, 1, 448, + Arrays.asList( + new Term(224, -1), + new Term(0, -1) + ), + Curve448CrSequence(), simpleSmallCrSequence(16) + ); + + private static List Curve448CrSequence() { + List result = new ArrayList(); + + // reduce(8, 7) + for (int i = 24; i < 31; i++) { + result.add(new Reduce(i)); + } + // reduce(4, 4) + for (int i = 20; i < 24; i++) { + result.add(new Reduce(i)); + } + + //carry(14, 2) + result.add(new Carry(14)); + result.add(new Carry(15)); + + // reduce(0, 4) + for (int i = 16; i < 20; i++) { + result.add(new Reduce(i)); + } + + // carry(0, 15) + result.addAll(fullCarry(16)); + + return result; + } + + static FieldParams P256 = new FieldParams( + "IntegerPolynomialP256", 26, 10, 2, 256, + Arrays.asList( + new Term(224, -1), + new Term(192, 1), + new Term(96, 1), + new Term(0, -1) + ), + P256CrSequence(), simpleSmallCrSequence(10) + ); + + private static List P256CrSequence() { + List result = new ArrayList(); + result.addAll(fullReduce(10)); + result.addAll(simpleSmallCrSequence(10)); + return result; + } + + static FieldParams P384 = new FieldParams( + "IntegerPolynomialP384", 28, 14, 2, 384, + Arrays.asList( + new Term(128, -1), + new Term(96, -1), + new Term(32, 1), + new Term(0, -1) + ), + P384CrSequence(), simpleSmallCrSequence(14) + ); + + private static List P384CrSequence() { + List result = new ArrayList(); + result.addAll(fullReduce(14)); + result.addAll(simpleSmallCrSequence(14)); + return result; + } + + static FieldParams P521 = new FieldParams( + "IntegerPolynomialP521", 28, 19, 2, 521, + Arrays.asList( + new Term(0, -1) + ), + P521CrSequence(), simpleSmallCrSequence(19) + ); + + private static List P521CrSequence() { + List result = new ArrayList(); + result.addAll(fullReduce(19)); + result.addAll(simpleSmallCrSequence(19)); + return result; + } + + static FieldParams O256 = new FieldParams( + "P256OrderField", 26, 10, 1, 256, + "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", + orderFieldCrSequence(10), orderFieldSmallCrSequence(10) + ); + + static FieldParams O384 = new FieldParams( + "P384OrderField", 28, 14, 1, 384, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973", + orderFieldCrSequence(14), orderFieldSmallCrSequence(14) + ); + + static FieldParams O521 = new FieldParams( + "P521OrderField", 28, 19, 1, 521, + "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", + o521crSequence(19), orderFieldSmallCrSequence(19) + ); + + private static List o521crSequence(int numLimbs) { + + // split the full reduce in half, with a carry in between + List result = new ArrayList(); + result.addAll(fullCarry(2 * numLimbs)); + for (int i = 2 * numLimbs - 1; i >= numLimbs + numLimbs / 2; i--) { + result.add(new Reduce(i)); + } + // carry + for (int i = numLimbs; i < numLimbs + numLimbs / 2 - 1; i++) { + result.add(new Carry(i)); + } + // rest of reduce + for (int i = numLimbs + numLimbs / 2 - 1; i >= numLimbs; i--) { + result.add(new Reduce(i)); + } + result.addAll(orderFieldSmallCrSequence(numLimbs)); + + return result; + } + + private static List orderFieldCrSequence(int numLimbs) { + List result = new ArrayList(); + result.addAll(fullCarry(2 * numLimbs)); + result.add(new Reduce(2 * numLimbs - 1)); + result.addAll(fullReduce(numLimbs)); + result.addAll(fullCarry(numLimbs + 1)); + result.add(new Reduce(numLimbs)); + result.addAll(fullCarry(numLimbs)); + + return result; + } + + private static List orderFieldSmallCrSequence(int numLimbs) { + List result = new ArrayList(); + result.addAll(fullCarry(numLimbs + 1)); + result.add(new Reduce(numLimbs)); + result.addAll(fullCarry(numLimbs)); + return result; + } + + static final FieldParams[] ALL_FIELDS = { + P256, P384, P521, O256, O384, O521, + }; + + public static class Term { + private final int power; + private final int coefficient; + + public Term(int power, int coefficient) { + this.power = power; + this.coefficient = coefficient; + } + + public int getPower() { + return power; + } + + public int getCoefficient() { + return coefficient; + } + + public BigInteger getValue() { + return BigInteger.valueOf(2).pow(power) + .multiply(BigInteger.valueOf(coefficient)); + } + + public String toString() { + return "2^" + power + " * " + coefficient; + } + } + + static abstract class CarryReduce { + private final int index; + + protected CarryReduce(int index) { + this.index = index; + } + + public int getIndex() { + return index; + } + + public abstract void write(CodeBuffer out, FieldParams params, + String prefix, Iterable remaining); + } + + static class Carry extends CarryReduce { + public Carry(int index) { + super(index); + } + + public void write(CodeBuffer out, FieldParams params, String prefix, + Iterable remaining) { + carry(out, params, prefix, getIndex()); + } + } + + static class Reduce extends CarryReduce { + public Reduce(int index) { + super(index); + } + + public void write(CodeBuffer out, FieldParams params, String prefix, + Iterable remaining) { + reduce(out, params, prefix, getIndex(), remaining); + } + } + + static class FieldParams { + private final String className; + private final int bitsPerLimb; + private final int numLimbs; + private final int maxAdds; + private final int power; + private final Iterable terms; + private final List crSequence; + private final List smallCrSequence; + + public FieldParams(String className, int bitsPerLimb, int numLimbs, + int maxAdds, int power, + Iterable terms, List crSequence, + List smallCrSequence) { + this.className = className; + this.bitsPerLimb = bitsPerLimb; + this.numLimbs = numLimbs; + this.maxAdds = maxAdds; + this.power = power; + this.terms = terms; + this.crSequence = crSequence; + this.smallCrSequence = smallCrSequence; + } + + public FieldParams(String className, int bitsPerLimb, int numLimbs, + int maxAdds, int power, + String term, List crSequence, + List smallCrSequence) { + this.className = className; + this.bitsPerLimb = bitsPerLimb; + this.numLimbs = numLimbs; + this.maxAdds = maxAdds; + this.power = power; + this.crSequence = crSequence; + this.smallCrSequence = smallCrSequence; + + terms = buildTerms(BigInteger.ONE.shiftLeft(power) + .subtract(new BigInteger(term, 16))); + } + + private Iterable buildTerms(BigInteger sub) { + // split a large subtrahend into smaller terms + // that are aligned with limbs + List result = new ArrayList(); + BigInteger mod = BigInteger.valueOf(1 << bitsPerLimb); + int termIndex = 0; + while (!sub.equals(BigInteger.ZERO)) { + int coef = sub.mod(mod).intValue(); + boolean plusOne = false; + if (coef > (1 << (bitsPerLimb - 1))) { + coef = coef - (1 << bitsPerLimb); + plusOne = true; + } + if (coef != 0) { + int pow = termIndex * bitsPerLimb; + result.add(new Term(pow, -coef)); + } + sub = sub.shiftRight(bitsPerLimb); + if (plusOne) { + sub = sub.add(BigInteger.ONE); + } + ++termIndex; + } + return result; + } + + public String getClassName() { + return className; + } + + public int getBitsPerLimb() { + return bitsPerLimb; + } + + public int getNumLimbs() { + return numLimbs; + } + + public int getMaxAdds() { + return maxAdds; + } + + public int getPower() { + return power; + } + + public Iterable getTerms() { + return terms; + } + + public List getCrSequence() { + return crSequence; + } + + public List getSmallCrSequence() { + return smallCrSequence; + } + } + + static Collection fullCarry(int numLimbs) { + List result = new ArrayList(); + for (int i = 0; i < numLimbs - 1; i++) { + result.add(new Carry(i)); + } + return result; + } + + static Collection fullReduce(int numLimbs) { + List result = new ArrayList(); + for (int i = numLimbs - 2; i >= 0; i--) { + result.add(new Reduce(i + numLimbs)); + } + return result; + } + + static List simpleCrSequence(int numLimbs) { + List result = new ArrayList(); + for (int i = 0; i < 4; i++) { + result.addAll(fullCarry(2 * numLimbs - 1)); + result.addAll(fullReduce(numLimbs)); + } + + return result; + } + + static List simpleSmallCrSequence(int numLimbs) { + List result = new ArrayList(); + // carry a few positions at the end + for (int i = numLimbs - 2; i < numLimbs; i++) { + result.add(new Carry(i)); + } + // this carries out a single value that must be reduced back in + result.add(new Reduce(numLimbs)); + // finish with a full carry + result.addAll(fullCarry(numLimbs)); + return result; + } + + private final String packageName; + private final String parentName; + + private final Path headerPath; + private final Path destPath; + + public FieldGen(String packageName, String parentName, + Path headerPath, Path destRoot) throws IOException { + this.packageName = packageName; + this.parentName = parentName; + this.headerPath = headerPath; + this.destPath = destRoot.resolve(packageName.replace(".", "/")); + Files.createDirectories(destPath); + } + + // args: header.txt destpath + public static void main(String[] args) throws Exception { + + FieldGen gen = new FieldGen( + "sun.security.util.math.intpoly", + "IntegerPolynomial", + Path.of(args[0]), + Path.of(args[1])); + for (FieldParams p : ALL_FIELDS) { + System.out.println(p.className); + System.out.println(p.terms); + System.out.println(); + gen.generateFile(p); + } + } + + private void generateFile(FieldParams params) throws IOException { + String text = generate(params); + String fileName = params.getClassName() + ".java"; + PrintWriter out = new PrintWriter(Files.newBufferedWriter( + destPath.resolve(fileName))); + out.println(text); + out.close(); + } + + static class CodeBuffer { + + private int nextTemporary = 0; + private Set temporaries = new HashSet(); + private StringBuffer buffer = new StringBuffer(); + private int indent = 0; + private Class lastCR; + private int lastCrCount = 0; + private int crMethodBreakCount = 0; + private int crNumLimbs = 0; + + public void incrIndent() { + indent++; + } + + public void decrIndent() { + indent--; + } + + public void newTempScope() { + nextTemporary = 0; + temporaries.clear(); + } + + public void appendLine(String s) { + appendIndent(); + buffer.append(s + "\n"); + } + + public void appendLine() { + buffer.append("\n"); + } + + public String toString() { + return buffer.toString(); + } + + public void startCrSequence(int numLimbs) { + this.crNumLimbs = numLimbs; + lastCrCount = 0; + crMethodBreakCount = 0; + lastCR = null; + } + + /* + * Record a carry/reduce of the specified type. This method is used to + * break up large carry/reduce sequences into multiple methods to make + * JIT/optimization easier + */ + public void record(Class type) { + if (type == lastCR) { + lastCrCount++; + } else { + + if (lastCrCount >= 8) { + insertCrMethodBreak(); + } + + lastCR = type; + lastCrCount = 0; + } + } + + private void insertCrMethodBreak() { + + appendLine(); + + // call the new method + appendIndent(); + append("carryReduce" + crMethodBreakCount + "(r"); + for (int i = 0; i < crNumLimbs; i++) { + append(", c" + i); + } + // temporaries are not live between operations, no need to send + append(");\n"); + + decrIndent(); + appendLine("}"); + + // make the method + appendIndent(); + append("void carryReduce" + crMethodBreakCount + "(long[] r"); + for (int i = 0; i < crNumLimbs; i++) { + append(", long c" + i); + } + append(") {\n"); + incrIndent(); + // declare temporaries + for (String temp : temporaries) { + appendLine("long " + temp + ";"); + } + append("\n"); + + crMethodBreakCount++; + } + + public String getTemporary(String type, String value) { + Iterator iter = temporaries.iterator(); + if (iter.hasNext()) { + String result = iter.next(); + iter.remove(); + appendLine(result + " = " + value + ";"); + return result; + } else { + String result = "t" + (nextTemporary++); + appendLine(type + " " + result + " = " + value + ";"); + return result; + } + } + + public void freeTemporary(String temp) { + temporaries.add(temp); + } + + public void appendIndent() { + for (int i = 0; i < indent; i++) { + buffer.append(" "); + } + } + + public void append(String s) { + buffer.append(s); + } + } + + private String generate(FieldParams params) throws IOException { + CodeBuffer result = new CodeBuffer(); + String header = readHeader(); + result.appendLine(header); + + if (packageName != null) { + result.appendLine("package " + packageName + ";"); + result.appendLine(); + } + result.appendLine("import java.math.BigInteger;"); + + result.appendLine("public class " + params.getClassName() + + " extends " + this.parentName + " {"); + result.incrIndent(); + + result.appendLine("private static final int BITS_PER_LIMB = " + + params.getBitsPerLimb() + ";"); + result.appendLine("private static final int NUM_LIMBS = " + + params.getNumLimbs() + ";"); + result.appendLine("private static final int MAX_ADDS = " + + params.getMaxAdds() + ";"); + result.appendLine( + "public static final BigInteger MODULUS = evaluateModulus();"); + result.appendLine("private static final long CARRY_ADD = 1 << " + + (params.getBitsPerLimb() - 1) + ";"); + if (params.getBitsPerLimb() * params.getNumLimbs() != params.getPower()) { + result.appendLine("private static final int LIMB_MASK = -1 " + + ">>> (64 - BITS_PER_LIMB);"); + } + int termIndex = 0; + + result.appendLine("public " + params.getClassName() + "() {"); + result.appendLine(); + result.appendLine(" super(BITS_PER_LIMB, NUM_LIMBS, MAX_ADDS, MODULUS);"); + result.appendLine(); + result.appendLine("}"); + + result.appendLine("private static BigInteger evaluateModulus() {"); + result.incrIndent(); + result.appendLine("BigInteger result = BigInteger.valueOf(2).pow(" + + params.getPower() + ");"); + for (Term t : params.getTerms()) { + boolean subtract = false; + int coefValue = t.getCoefficient(); + if (coefValue < 0) { + coefValue = 0 - coefValue; + subtract = true; + } + String coefExpr = "BigInteger.valueOf(" + coefValue + ")"; + String powExpr = "BigInteger.valueOf(2).pow(" + t.getPower() + ")"; + String termExpr = "ERROR"; + if (t.getPower() == 0) { + termExpr = coefExpr; + } else if (coefValue == 1) { + termExpr = powExpr; + } else { + termExpr = powExpr + ".multiply(" + coefExpr + ")"; + } + if (subtract) { + result.appendLine("result = result.subtract(" + termExpr + ");"); + } else { + result.appendLine("result = result.add(" + termExpr + ");"); + } + } + result.appendLine("return result;"); + result.decrIndent(); + result.appendLine("}"); + + result.appendLine("@Override"); + result.appendLine("protected void finalCarryReduceLast(long[] limbs) {"); + result.incrIndent(); + int extraBits = params.getBitsPerLimb() * params.getNumLimbs() + - params.getPower(); + int highBits = params.getBitsPerLimb() - extraBits; + result.appendLine("long c = limbs[" + (params.getNumLimbs() - 1) + + "] >> " + highBits + ";"); + result.appendLine("limbs[" + (params.getNumLimbs() - 1) + "] -= c << " + + highBits + ";"); + for (Term t : params.getTerms()) { + int reduceBits = params.getPower() + extraBits - t.getPower(); + int negatedCoefficient = -1 * t.getCoefficient(); + modReduceInBits(result, params, true, "limbs", params.getNumLimbs(), + reduceBits, negatedCoefficient, "c"); + } + result.decrIndent(); + result.appendLine("}"); + + // full carry/reduce sequence + result.appendIndent(); + result.append("private void carryReduce(long[] r, "); + for (int i = 0; i < 2 * params.getNumLimbs() - 1; i++) { + result.append("long c" + i); + if (i < 2 * params.getNumLimbs() - 2) { + result.append(", "); + } + } + result.append(") {\n"); + result.newTempScope(); + result.incrIndent(); + result.appendLine("long c" + (2 * params.getNumLimbs() - 1) + " = 0;"); + write(result, params.getCrSequence(), params, "c", + 2 * params.getNumLimbs()); + result.appendLine(); + for (int i = 0; i < params.getNumLimbs(); i++) { + result.appendLine("r[" + i + "] = c" + i + ";"); + } + result.decrIndent(); + result.appendLine("}"); + + // small carry/reduce sequence + result.appendIndent(); + result.append("private void carryReduce(long[] r, "); + for (int i = 0; i < params.getNumLimbs(); i++) { + result.append("long c" + i); + if (i < params.getNumLimbs() - 1) { + result.append(", "); + } + } + result.append(") {\n"); + result.newTempScope(); + result.incrIndent(); + result.appendLine("long c" + params.getNumLimbs() + " = 0;"); + write(result, params.getSmallCrSequence(), params, + "c", params.getNumLimbs() + 1); + result.appendLine(); + for (int i = 0; i < params.getNumLimbs(); i++) { + result.appendLine("r[" + i + "] = c" + i + ";"); + } + result.decrIndent(); + result.appendLine("}"); + + result.appendLine("@Override"); + result.appendLine("protected void mult(long[] a, long[] b, long[] r) {"); + result.incrIndent(); + for (int i = 0; i < 2 * params.getNumLimbs() - 1; i++) { + result.appendIndent(); + result.append("long c" + i + " = "); + int startJ = Math.max(i + 1 - params.getNumLimbs(), 0); + int endJ = Math.min(params.getNumLimbs(), i + 1); + for (int j = startJ; j < endJ; j++) { + int bIndex = i - j; + result.append("(a[" + j + "] * b[" + bIndex + "])"); + if (j < endJ - 1) { + result.append(" + "); + } + } + result.append(";\n"); + } + result.appendLine(); + result.appendIndent(); + result.append("carryReduce(r, "); + for (int i = 0; i < 2 * params.getNumLimbs() - 1; i++) { + result.append("c" + i); + if (i < 2 * params.getNumLimbs() - 2) { + result.append(", "); + } + } + result.append(");\n"); + result.decrIndent(); + result.appendLine("}"); + + result.appendLine("@Override"); + result.appendLine("protected void reduce(long[] a) {"); + result.incrIndent(); + result.appendIndent(); + result.append("carryReduce(a, "); + for (int i = 0; i < params.getNumLimbs(); i++) { + result.append("a[" + i + "]"); + if (i < params.getNumLimbs() - 1) { + result.append(", "); + } + } + result.append(");\n"); + result.decrIndent(); + result.appendLine("}"); + + result.appendLine("@Override"); + result.appendLine("protected void square(long[] a, long[] r) {"); + result.incrIndent(); + for (int i = 0; i < 2 * params.getNumLimbs() - 1; i++) { + result.appendIndent(); + result.append("long c" + i + " = "); + int startJ = Math.max(i + 1 - params.getNumLimbs(), 0); + int endJ = Math.min(params.getNumLimbs(), i + 1); + int jDiff = endJ - startJ; + if (jDiff > 1) { + result.append("2 * ("); + } + for (int j = 0; j < jDiff / 2; j++) { + int aIndex = j + startJ; + int bIndex = i - aIndex; + result.append("(a[" + aIndex + "] * a[" + bIndex + "])"); + if (j < (jDiff / 2) - 1) { + result.append(" + "); + } + } + if (jDiff > 1) { + result.append(")"); + } + if (jDiff % 2 == 1) { + int aIndex = i / 2; + if (jDiff > 1) { + result.append(" + "); + } + result.append("(a[" + aIndex + "] * a[" + aIndex + "])"); + } + result.append(";\n"); + } + result.appendLine(); + result.appendIndent(); + result.append("carryReduce(r, "); + for (int i = 0; i < 2 * params.getNumLimbs() - 1; i++) { + result.append("c" + i); + if (i < 2 * params.getNumLimbs() - 2) { + result.append(", "); + } + } + result.append(");\n"); + result.decrIndent(); + result.appendLine("}"); + + result.decrIndent(); + result.appendLine("}"); // end class + + return result.toString(); + } + + private static void write(CodeBuffer out, List sequence, + FieldParams params, String prefix, int numLimbs) { + + out.startCrSequence(numLimbs); + for (int i = 0; i < sequence.size(); i++) { + CarryReduce cr = sequence.get(i); + Iterator remainingIter = sequence.listIterator(i + 1); + List remaining = new ArrayList(); + remainingIter.forEachRemaining(remaining::add); + cr.write(out, params, prefix, remaining); + } + } + + private static void reduce(CodeBuffer out, FieldParams params, + String prefix, int index, Iterable remaining) { + + out.record(Reduce.class); + + out.appendLine("//reduce from position " + index); + String reduceFrom = indexedExpr(false, prefix, index); + boolean referenced = false; + for (CarryReduce cr : remaining) { + if (cr.index == index) { + referenced = true; + } + } + for (Term t : params.getTerms()) { + int reduceBits = params.getPower() - t.getPower(); + int negatedCoefficient = -1 * t.getCoefficient(); + modReduceInBits(out, params, false, prefix, index, reduceBits, + negatedCoefficient, reduceFrom); + } + if (referenced) { + out.appendLine(reduceFrom + " = 0;"); + } + } + + private static void carry(CodeBuffer out, FieldParams params, + String prefix, int index) { + + out.record(Carry.class); + + out.appendLine("//carry from position " + index); + String carryFrom = prefix + index; + String carryTo = prefix + (index + 1); + String carry = "(" + carryFrom + " + CARRY_ADD) >> " + + params.getBitsPerLimb(); + String temp = out.getTemporary("long", carry); + out.appendLine(carryFrom + " -= (" + temp + " << " + + params.getBitsPerLimb() + ");"); + out.appendLine(carryTo + " += " + temp + ";"); + out.freeTemporary(temp); + } + + private static String indexedExpr( + boolean isArray, String prefix, int index) { + String result = prefix + index; + if (isArray) { + result = prefix + "[" + index + "]"; + } + return result; + } + + private static void modReduceInBits(CodeBuffer result, FieldParams params, + boolean isArray, String prefix, int index, int reduceBits, + int coefficient, String c) { + + String x = coefficient + " * " + c; + String accOp = "+="; + String temp = null; + if (coefficient == 1) { + x = c; + } else if (coefficient == -1) { + x = c; + accOp = "-="; + } else { + temp = result.getTemporary("long", x); + x = temp; + } + + if (reduceBits % params.getBitsPerLimb() == 0) { + int pos = reduceBits / params.getBitsPerLimb(); + result.appendLine(indexedExpr(isArray, prefix, (index - pos)) + + " " + accOp + " " + x + ";"); + } else { + int secondPos = reduceBits / params.getBitsPerLimb(); + int bitOffset = (secondPos + 1) * params.getBitsPerLimb() + - reduceBits; + int rightBitOffset = params.getBitsPerLimb() - bitOffset; + result.appendLine(indexedExpr(isArray, prefix, + (index - (secondPos + 1))) + " " + accOp + + " (" + x + " << " + bitOffset + ") & LIMB_MASK;"); + result.appendLine(indexedExpr(isArray, prefix, + (index - secondPos)) + " " + accOp + " " + x + + " >> " + rightBitOffset + ";"); + } + + if (temp != null) { + result.freeTemporary(temp); + } + } + + private String readHeader() throws IOException { + BufferedReader reader + = Files.newBufferedReader(headerPath); + StringBuffer result = new StringBuffer(); + reader.lines().forEach(s -> result.append(s + "\n")); + return result.toString(); + } +} --- old/make/jdk/src/classes/build/tools/intpoly/header.txt 2020-03-23 19:56:54.175962572 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2018, 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 generated by FieldGen.java. Do not modify it directly. - */ --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.base/share/tools/org/openjdk/buildtools/intpoly/header.txt 2020-03-23 19:56:53.807962575 +0100 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018, 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 generated by FieldGen.java. Do not modify it directly. + */ --- old/make/jdk/src/classes/build/tools/makejavasecurity/MakeJavaSecurity.java 2020-03-23 19:56:54.859962567 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,198 +0,0 @@ -/* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.makejavasecurity; - -import java.io.*; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.*; - -/** - * Builds the java.security file, including - * - * 1. Adds additional packages to the package.access and - * package.definition security properties. - * 2. Filter out platform-unrelated parts. - * 3. Set the JCE jurisdiction policy directory. - * - * In order to easily maintain platform-related entries, every item - * (including the last line) in package.access and package.definition - * MUST end with ',\'. A blank line MUST exist after the last line. - */ -public class MakeJavaSecurity { - - private static final String PKG_ACC = "package.access"; - private static final String PKG_DEF = "package.definition"; - private static final int PKG_ACC_INDENT = 15; - private static final int PKG_DEF_INDENT = 19; - - public static void main(String[] args) throws Exception { - - if (args.length < 5) { - System.err.println("Usage: java MakeJavaSecurity " + - "[input java.security file name] " + - "[output java.security file name] " + - "[openjdk target os] " + - "[openjdk target cpu architecture]" + - "[JCE jurisdiction policy directory]" + - "[more restricted packages file name?]"); - - System.exit(1); - } - - // more restricted packages - List extraLines; - if (args.length == 6) { - extraLines = Files.readAllLines(Paths.get(args[5])); - } else { - extraLines = Collections.emptyList(); - } - - List lines = new ArrayList<>(); - - // read raw java.security and add more restricted packages - try (FileReader fr = new FileReader(args[0]); - BufferedReader br = new BufferedReader(fr)) { - // looking for pkg access properties - String line = br.readLine(); - while (line != null) { - if (line.startsWith(PKG_ACC)) { - addPackages(br, lines, line, PKG_ACC_INDENT, extraLines); - } else if (line.startsWith(PKG_DEF)) { - addPackages(br, lines, line, PKG_DEF_INDENT, extraLines); - } else { - lines.add(line); - } - line = br.readLine(); - } - } - - // Filter out platform-unrelated ones. We only support - // #ifdef, #ifndef, #else, and #endif. Nesting not supported (yet). - int mode = 0; // 0: out of block, 1: in match, 2: in non-match - Iterator iter = lines.iterator(); - while (iter.hasNext()) { - String line = iter.next(); - if (line.startsWith("#endif")) { - mode = 0; - iter.remove(); - } else if (line.startsWith("#ifdef ")) { - if (line.indexOf('-') > 0) { - mode = line.endsWith(args[2]+"-"+args[3]) ? 1 : 2; - } else { - mode = line.endsWith(args[2]) ? 1 : 2; - } - iter.remove(); - } else if (line.startsWith("#ifndef ")) { - if (line.indexOf('-') > 0) { - mode = line.endsWith(args[2]+"-"+args[3]) ? 2 : 1; - } else { - mode = line.endsWith(args[2]) ? 2 : 1; - } - iter.remove(); - } else if (line.startsWith("#else")) { - if (mode == 0) { - throw new IllegalStateException("#else not in #if block"); - } - mode = 3 - mode; - iter.remove(); - } else { - if (mode == 2) iter.remove(); - } - } - - // Update .tbd to .1, .2, etc. - Map count = new HashMap<>(); - for (int i=0; i= 0) { - String prefix = line.substring(0, index); - int n = count.getOrDefault(prefix, 1); - count.put(prefix, n+1); - lines.set(i, prefix + "." + n + line.substring(index+4)); - } - } - - // Set the JCE policy value - for (int i = 0; i < lines.size(); i++) { - String line = lines.get(i); - int index = line.indexOf("crypto.policydir-tbd"); - if (index >= 0) { - String prefix = line.substring(0, index); - lines.set(i, prefix + args[4]); - } - } - - // Clean up the last line of PKG_ACC and PKG_DEF blocks. - // Not really necessary since a blank line follows. - boolean inBlock = false; - for (int i=0; i lines, - String line, int numSpaces, - List args) throws IOException { - // parse property until EOL, not including line breaks - boolean first = true; - while (line != null && !line.isEmpty()) { - if (!line.startsWith("#")) { - if (!line.endsWith(",\\") || - (!first && line.contains("="))) { - throw new IOException("Invalid line: " + line); - } - } - lines.add(line); - line = br.readLine(); - first = false; - } - // add new packages, one per line - for (String arg: args) { - if (arg.startsWith("#")) { - lines.add(arg); - } else { - lines.add(String.format("%"+numSpaces+"s", "") + arg + ",\\"); - } - } - if (line != null) { - lines.add(line); - } - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.base/share/tools/org/openjdk/buildtools/makejavasecurity/MakeJavaSecurity.java 2020-03-23 19:56:54.395962571 +0100 @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.makejavasecurity; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.*; + +/** + * Builds the java.security file, including + * + * 1. Adds additional packages to the package.access and + * package.definition security properties. + * 2. Filter out platform-unrelated parts. + * 3. Set the JCE jurisdiction policy directory. + * + * In order to easily maintain platform-related entries, every item + * (including the last line) in package.access and package.definition + * MUST end with ',\'. A blank line MUST exist after the last line. + */ +public class MakeJavaSecurity { + + private static final String PKG_ACC = "package.access"; + private static final String PKG_DEF = "package.definition"; + private static final int PKG_ACC_INDENT = 15; + private static final int PKG_DEF_INDENT = 19; + + public static void main(String[] args) throws Exception { + + if (args.length < 5) { + System.err.println("Usage: java MakeJavaSecurity " + + "[input java.security file name] " + + "[output java.security file name] " + + "[openjdk target os] " + + "[openjdk target cpu architecture]" + + "[JCE jurisdiction policy directory]" + + "[more restricted packages file name?]"); + + System.exit(1); + } + + // more restricted packages + List extraLines; + if (args.length == 6) { + extraLines = Files.readAllLines(Paths.get(args[5])); + } else { + extraLines = Collections.emptyList(); + } + + List lines = new ArrayList<>(); + + // read raw java.security and add more restricted packages + try (FileReader fr = new FileReader(args[0]); + BufferedReader br = new BufferedReader(fr)) { + // looking for pkg access properties + String line = br.readLine(); + while (line != null) { + if (line.startsWith(PKG_ACC)) { + addPackages(br, lines, line, PKG_ACC_INDENT, extraLines); + } else if (line.startsWith(PKG_DEF)) { + addPackages(br, lines, line, PKG_DEF_INDENT, extraLines); + } else { + lines.add(line); + } + line = br.readLine(); + } + } + + // Filter out platform-unrelated ones. We only support + // #ifdef, #ifndef, #else, and #endif. Nesting not supported (yet). + int mode = 0; // 0: out of block, 1: in match, 2: in non-match + Iterator iter = lines.iterator(); + while (iter.hasNext()) { + String line = iter.next(); + if (line.startsWith("#endif")) { + mode = 0; + iter.remove(); + } else if (line.startsWith("#ifdef ")) { + if (line.indexOf('-') > 0) { + mode = line.endsWith(args[2]+"-"+args[3]) ? 1 : 2; + } else { + mode = line.endsWith(args[2]) ? 1 : 2; + } + iter.remove(); + } else if (line.startsWith("#ifndef ")) { + if (line.indexOf('-') > 0) { + mode = line.endsWith(args[2]+"-"+args[3]) ? 2 : 1; + } else { + mode = line.endsWith(args[2]) ? 2 : 1; + } + iter.remove(); + } else if (line.startsWith("#else")) { + if (mode == 0) { + throw new IllegalStateException("#else not in #if block"); + } + mode = 3 - mode; + iter.remove(); + } else { + if (mode == 2) iter.remove(); + } + } + + // Update .tbd to .1, .2, etc. + Map count = new HashMap<>(); + for (int i=0; i= 0) { + String prefix = line.substring(0, index); + int n = count.getOrDefault(prefix, 1); + count.put(prefix, n+1); + lines.set(i, prefix + "." + n + line.substring(index+4)); + } + } + + // Set the JCE policy value + for (int i = 0; i < lines.size(); i++) { + String line = lines.get(i); + int index = line.indexOf("crypto.policydir-tbd"); + if (index >= 0) { + String prefix = line.substring(0, index); + lines.set(i, prefix + args[4]); + } + } + + // Clean up the last line of PKG_ACC and PKG_DEF blocks. + // Not really necessary since a blank line follows. + boolean inBlock = false; + for (int i=0; i lines, + String line, int numSpaces, + List args) throws IOException { + // parse property until EOL, not including line breaks + boolean first = true; + while (line != null && !line.isEmpty()) { + if (!line.startsWith("#")) { + if (!line.endsWith(",\\") || + (!first && line.contains("="))) { + throw new IOException("Invalid line: " + line); + } + } + lines.add(line); + line = br.readLine(); + first = false; + } + // add new packages, one per line + for (String arg: args) { + if (arg.startsWith("#")) { + lines.add(arg); + } else { + lines.add(String.format("%"+numSpaces+"s", "") + arg + ",\\"); + } + } + if (line != null) { + lines.add(line); + } + } +} --- old/make/jdk/src/classes/build/tools/module/GenModuleLoaderMap.java 2020-03-23 19:56:55.695962561 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.module; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.PrintWriter; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class GenModuleLoaderMap { - private static final String USAGE = - "GenModuleLoaderMap -o -boot m1[,m2]* -platform m3[,m4]* "; - - public static void main(String... args) throws Exception { - // default set of boot modules and ext modules - Stream bootModules = Stream.empty(); - Stream platformModules = Stream.empty(); - Path outfile = null; - Path source = null; - for (int i=0; i < args.length; i++) { - String option = args[i]; - if (option.startsWith("-")) { - String arg = args[++i]; - if (option.equals("-boot")) { - String[] mns = arg.split(","); - bootModules = Stream.concat(bootModules, Arrays.stream(mns)); - } else if (option.equals("-platform")) { - String[] mns = arg.split(","); - platformModules = Stream.concat(platformModules, Arrays.stream(mns)); - } else if (option.equals("-o")) { - outfile = Paths.get(arg); - } else { - throw new IllegalArgumentException("invalid option: " + option); - } - } else { - source = Paths.get(option); - } - } - - if (outfile == null) { - throw new IllegalArgumentException("-o must be specified"); - } - if (Files.notExists(source)) { - throw new IllegalArgumentException(source + " not exist"); - } - - try (BufferedWriter bw = Files.newBufferedWriter(outfile, StandardCharsets.UTF_8); - PrintWriter writer = new PrintWriter(bw)) { - for (String line : Files.readAllLines(source)) { - if (line.contains("@@BOOT_MODULE_NAMES@@")) { - line = patch(line, "@@BOOT_MODULE_NAMES@@", bootModules); - } else if (line.contains("@@PLATFORM_MODULE_NAMES@@")) { - line = patch(line, "@@PLATFORM_MODULE_NAMES@@", platformModules); - } - writer.println(line); - } - } - } - - private static String patch(String s, String tag, Stream stream) { - String mns = stream.sorted() - .collect(Collectors.joining("\",\n \"")); - return s.replace(tag, mns); - } - - /** - * Reads the contents of the given modules file. - */ - private static Set readModuleSet(String name) throws IOException { - try (InputStream is = GenModuleLoaderMap.class.getResourceAsStream(name); - BufferedReader reader = new BufferedReader(new InputStreamReader(is))) { - return reader.lines().collect(Collectors.toSet()); - } - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.base/share/tools/org/openjdk/buildtools/moduleloadermap/GenModuleLoaderMap.java 2020-03-23 19:56:55.259962564 +0100 @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.moduleloadermap; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class GenModuleLoaderMap { + private static final String USAGE = + "GenModuleLoaderMap -o -boot m1[,m2]* -platform m3[,m4]* "; + + public static void main(String... args) throws Exception { + // default set of boot modules and ext modules + Stream bootModules = Stream.empty(); + Stream platformModules = Stream.empty(); + Path outfile = null; + Path source = null; + for (int i=0; i < args.length; i++) { + String option = args[i]; + if (option.startsWith("-")) { + String arg = args[++i]; + if (option.equals("-boot")) { + String[] mns = arg.split(","); + bootModules = Stream.concat(bootModules, Arrays.stream(mns)); + } else if (option.equals("-platform")) { + String[] mns = arg.split(","); + platformModules = Stream.concat(platformModules, Arrays.stream(mns)); + } else if (option.equals("-o")) { + outfile = Paths.get(arg); + } else { + throw new IllegalArgumentException("invalid option: " + option); + } + } else { + source = Paths.get(option); + } + } + + if (outfile == null) { + throw new IllegalArgumentException("-o must be specified"); + } + if (Files.notExists(source)) { + throw new IllegalArgumentException(source + " not exist"); + } + + try (BufferedWriter bw = Files.newBufferedWriter(outfile, StandardCharsets.UTF_8); + PrintWriter writer = new PrintWriter(bw)) { + for (String line : Files.readAllLines(source)) { + if (line.contains("@@BOOT_MODULE_NAMES@@")) { + line = patch(line, "@@BOOT_MODULE_NAMES@@", bootModules); + } else if (line.contains("@@PLATFORM_MODULE_NAMES@@")) { + line = patch(line, "@@PLATFORM_MODULE_NAMES@@", platformModules); + } + writer.println(line); + } + } + } + + private static String patch(String s, String tag, Stream stream) { + String mns = stream.sorted() + .collect(Collectors.joining("\",\n \"")); + return s.replace(tag, mns); + } + + /** + * Reads the contents of the given modules file. + */ + private static Set readModuleSet(String name) throws IOException { + try (InputStream is = GenModuleLoaderMap.class.getResourceAsStream(name); + BufferedReader reader = new BufferedReader(new InputStreamReader(is))) { + return reader.lines().collect(Collectors.toSet()); + } + } +} --- old/make/jdk/src/classes/build/tools/publicsuffixlist/GeneratePublicSuffixList.java 2020-03-23 19:56:56.571962555 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,154 +0,0 @@ -/* - * Copyright (c) 2017, 2018, 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.publicsuffixlist; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.InputStreamReader; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.nio.file.attribute.FileTime; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; - -/** - * This tool takes the original Mozilla public suffix rule list as input - * and slices it into a set of files, one for each top-level domain. - * Each file contains only the rules for that domain. Lines containing comments - * or only whitespace are not copied. Each of these files are then combined - * into the target zipfile. - * - * Usage: java GeneratePublicSuffixList mozilla_file destination_zipfile - */ -public final class GeneratePublicSuffixList { - // patterns - private static final String COMMENT = "//"; - private static final String BEGIN_PRIVATE = "// ===BEGIN PRIVATE DOMAINS==="; - private static final Pattern WHITESPACE = Pattern.compile("\\s*"); - private static final byte ICANN = 0x00; - private static final byte PRIVATE = 0x01; - - private static class Domain { - final String name; - final byte type; - Domain(String name, byte type) { - this.name = name; - this.type = type; - } - } - - public static void main(String[] args) throws Exception { - if (args.length != 2) { - throw new Exception("2 args required: input_file output_file"); - } - try (FileInputStream fis = new FileInputStream(args[0]); - ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(args[1]))) - { - BufferedReader br = - new BufferedReader(new InputStreamReader(fis, "UTF-8")); - - List domains = new LinkedList<>(); - byte type = ICANN; - String line; - while ((line = br.readLine()) != null) { - if (line.startsWith(COMMENT)) { - if (line.startsWith(BEGIN_PRIVATE)) { - type = PRIVATE; - } - continue; - } - if (WHITESPACE.matcher(line).matches()) { - continue; - } - domains.add(new Domain(line, type)); - } - // have a list of rules now - - // Map of TLD names to rules with the same TLD - Map> rules = addDomains(domains); - - // stream for writing the file contents - BufferedWriter bw = - new BufferedWriter(new OutputStreamWriter(zos, "UTF-8")); - - // now output each map entry to its own file, - // whose filename is the TLD - writeRules(zos, bw, rules); - } - } - - private static Map> addDomains(List domains) { - Map> rules = new HashMap<>(); - for (Domain domain : domains) { - String tld = getTLD(domain.name); - - rules.compute(tld, (k, v) -> { - if (v == null) { - List newV = new LinkedList<>(); - newV.add(domain); - return newV; - } else { - v.add(domain); - return v; - } - }); - } - return rules; - } - - private static void writeRules(ZipOutputStream zos, BufferedWriter bw, - Map> rules) - throws IOException { - // Sort keys for deterministic output - List tlds = rules.keySet().stream().sorted().collect(Collectors.toList()); - for (String tld : tlds) { - List entries = rules.get(tld); - ZipEntry ze = new ZipEntry(tld); - ze.setLastModifiedTime(FileTime.fromMillis(0)); - zos.putNextEntry(ze); - for (Domain entry : entries) { - bw.write(entry.type); - bw.write(entry.name, 0, entry.name.length()); - bw.newLine(); - } - bw.flush(); - } - } - - private static String getTLD(String line) { - int dotIndex = line.lastIndexOf('.'); - return (dotIndex == -1) ? line : line.substring(dotIndex + 1); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.base/share/tools/org/openjdk/buildtools/publicsuffixlist/GeneratePublicSuffixList.java 2020-03-23 19:56:56.135962558 +0100 @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.publicsuffixlist; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.nio.file.attribute.FileTime; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +/** + * This tool takes the original Mozilla public suffix rule list as input + * and slices it into a set of files, one for each top-level domain. + * Each file contains only the rules for that domain. Lines containing comments + * or only whitespace are not copied. Each of these files are then combined + * into the target zipfile. + * + * Usage: java GeneratePublicSuffixList mozilla_file destination_zipfile + */ +public final class GeneratePublicSuffixList { + // patterns + private static final String COMMENT = "//"; + private static final String BEGIN_PRIVATE = "// ===BEGIN PRIVATE DOMAINS==="; + private static final Pattern WHITESPACE = Pattern.compile("\\s*"); + private static final byte ICANN = 0x00; + private static final byte PRIVATE = 0x01; + + private static class Domain { + final String name; + final byte type; + Domain(String name, byte type) { + this.name = name; + this.type = type; + } + } + + public static void main(String[] args) throws Exception { + if (args.length != 2) { + throw new Exception("2 args required: input_file output_file"); + } + try (FileInputStream fis = new FileInputStream(args[0]); + ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(args[1]))) + { + BufferedReader br = + new BufferedReader(new InputStreamReader(fis, "UTF-8")); + + List domains = new LinkedList<>(); + byte type = ICANN; + String line; + while ((line = br.readLine()) != null) { + if (line.startsWith(COMMENT)) { + if (line.startsWith(BEGIN_PRIVATE)) { + type = PRIVATE; + } + continue; + } + if (WHITESPACE.matcher(line).matches()) { + continue; + } + domains.add(new Domain(line, type)); + } + // have a list of rules now + + // Map of TLD names to rules with the same TLD + Map> rules = addDomains(domains); + + // stream for writing the file contents + BufferedWriter bw = + new BufferedWriter(new OutputStreamWriter(zos, "UTF-8")); + + // now output each map entry to its own file, + // whose filename is the TLD + writeRules(zos, bw, rules); + } + } + + private static Map> addDomains(List domains) { + Map> rules = new HashMap<>(); + for (Domain domain : domains) { + String tld = getTLD(domain.name); + + rules.compute(tld, (k, v) -> { + if (v == null) { + List newV = new LinkedList<>(); + newV.add(domain); + return newV; + } else { + v.add(domain); + return v; + } + }); + } + return rules; + } + + private static void writeRules(ZipOutputStream zos, BufferedWriter bw, + Map> rules) + throws IOException { + // Sort keys for deterministic output + List tlds = rules.keySet().stream().sorted().collect(Collectors.toList()); + for (String tld : tlds) { + List entries = rules.get(tld); + ZipEntry ze = new ZipEntry(tld); + ze.setLastModifiedTime(FileTime.fromMillis(0)); + zos.putNextEntry(ze); + for (Domain entry : entries) { + bw.write(entry.type); + bw.write(entry.name, 0, entry.name.length()); + bw.newLine(); + } + bw.flush(); + } + } + + private static String getTLD(String line) { + int dotIndex = line.lastIndexOf('.'); + return (dotIndex == -1) ? line : line.substring(dotIndex + 1); + } +} --- old/make/jdk/src/classes/build/tools/spp/Spp.java 2020-03-23 19:56:57.451962548 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,203 +0,0 @@ -/* - * Copyright (c) 2008, 2019, 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.spp; - -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.util.*; -import java.util.regex.*; - -/* - * Spp: A simple regex-based stream preprocessor based on Mark Reinhold's - * sed-based spp.sh - * - * Usage: - * java build.tools.spp.Spp [-be] [-nel] [-Kkey] -Dvar=value ... -iin -oout - * - * If -nel is declared then empty lines will not be substituted for lines of - * text in the template that do not appear in the output. - * - * Meaningful only at beginning of line, works with any number of keys: - * - * #if[key] Includes text between #if/#end if -Kkey specified, - * #else[key] otherwise changes text to blank lines; key test - * #end[key] may be negated by prefixing !, e.g., #if[!key] - * - * #begin If -be is specified then lines up to and including - * #end #begin, and from #end to EOF, are deleted - * - * #warn Changed into warning that file is generated - * - * // ## Changed into blank line - * - * Meaningful anywhere in line - * - * {#if[key]?yes} Expands to yes if -Kkey specified - * {#if[key]?yes:no} Expands to yes if -Kkey, otherwise no - * {#if[!key]?yes} Expands to yes if -Kother - * {#if[!key]?yes:no} Expands to yes if -Kother, otherwise no - * $var$ Expands to value if -Dvar=value given - * - * yes, no must not contain whitespace - * - * @author Xueming Shen - */ - -public class Spp { - public static void main(String args[]) throws Exception { - Map vars = new HashMap<>(); - Set keys = new HashSet<>(); - boolean be = false; - boolean el = true; - String inputFile = null; - String outputFile = null; - - for (String arg:args) { - if (arg.startsWith("-D")) { - int i = arg.indexOf('='); - vars.put(arg.substring(2, i),arg.substring(i+1)); - } else if (arg.startsWith("-K")) { - keys.add(arg.substring(2)); - } else if (arg.startsWith("-i")) { - inputFile = arg.substring(2); - } else if (arg.startsWith("-o")) { - outputFile = arg.substring(2); - } else if ("-be".equals(arg)) { - be = true; - } else if ("-nel".equals(arg)) { - el = false; - } else { - System.err.println("Usage: java build.tools.spp.Spp [-be] [-nel] [-Kkey] -Dvar=value ... out"); - System.exit(-1); - } - } - - StringBuffer out = new StringBuffer(); - new Spp().spp(new Scanner(new FileInputStream(inputFile)), - out, "", - keys, vars, be, el, - false); - new FileOutputStream(outputFile, true).write(out.toString().getBytes()); - } - - static final String LNSEP = System.getProperty("line.separator"); - static final String KEY = "([a-zA-Z0-9]+)"; - static final String VAR = "([a-zA-Z0-9_\\-]+)"; - static final String TEXT = "([a-zA-Z0-9&;,.<>/#() \\?\\[\\]\\$]+)"; // $ -- hack embedded $var$ - - static final int GN_NOT = 1; - static final int GN_KEY = 2; - static final int GN_YES = 3; - static final int GN_NO = 5; - static final int GN_VAR = 6; - - final Matcher ifkey = Pattern.compile("^#if\\[(!)?" + KEY + "\\]").matcher(""); - final Matcher elsekey = Pattern.compile("^#else\\[(!)?" + KEY + "\\]").matcher(""); - final Matcher endkey = Pattern.compile("^#end\\[(!)?" + KEY + "\\]").matcher(""); - final Matcher vardef = Pattern.compile("\\{#if\\[(!)?" + KEY + "\\]\\?" + TEXT + "(:"+ TEXT + ")?\\}|\\$" + VAR + "\\$").matcher(""); - final Matcher vardef2 = Pattern.compile("\\$" + VAR + "\\$").matcher(""); - - void append(StringBuffer buf, String ln, - Set keys, Map vars) { - vardef.reset(ln); - while (vardef.find()) { - String repl = ""; - if (vardef.group(GN_VAR) != null) - repl = vars.get(vardef.group(GN_VAR)); - else { - boolean test = keys.contains(vardef.group(GN_KEY)); - if (vardef.group(GN_NOT) != null) - test = !test; - repl = test?vardef.group(GN_YES):vardef.group(GN_NO); - if (repl == null) - repl = ""; - else { // embedded $var$ - while (vardef2.reset(repl).find()) { - repl = vardef2.replaceFirst(vars.get(vardef2.group(1))); - } - } - } - vardef.appendReplacement(buf, repl); - } - vardef.appendTail(buf); - } - - // return true if #end[key], #end or EOF reached - boolean spp(Scanner in, StringBuffer buf, String key, - Set keys, Map vars, - boolean be, boolean el, boolean skip) { - while (in.hasNextLine()) { - String ln = in.nextLine(); - if (be) { - if (ln.startsWith("#begin")) { - buf.setLength(0); //clean up to this line - continue; - } - if (ln.equals("#end")) { - while (in.hasNextLine()) - in.nextLine(); - return true; //discard the rest to EOF - } - } - if (ifkey.reset(ln).find()) { - String k = ifkey.group(GN_KEY); - boolean test = keys.contains(k); - if (ifkey.group(GN_NOT) != null) - test = !test; - if (el) buf.append(LNSEP); - if (!spp(in, buf, k, keys, vars, be, el, skip || !test)) { - spp(in, buf, k, keys, vars, be, el, skip || test); - } - continue; - } - if (elsekey.reset(ln).find()) { - if (!key.equals(elsekey.group(GN_KEY))) { - throw new Error("Mis-matched #if-else-end at line <" + ln + ">"); - } - if (el) buf.append(LNSEP); - return false; - } - if (endkey.reset(ln).find()) { - if (!key.equals(endkey.group(GN_KEY))) { - throw new Error("Mis-matched #if-else-end at line <" + ln + ">"); - } - if (el) buf.append(LNSEP); - return true; - } - if (ln.startsWith("#warn")) { - ln = "// -- This file was mechanically generated: Do not edit! -- //"; - } else if (ln.trim().startsWith("// ##")) { - ln = ""; - } - if (!skip) { - append(buf, ln, keys, vars); - if (!el) buf.append(LNSEP); - } - if (el) buf.append(LNSEP); - } - return true; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.base/share/tools/org/openjdk/buildtools/spp/Spp.java 2020-03-23 19:56:57.015962551 +0100 @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.spp; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.util.*; +import java.util.regex.*; + +/* + * Spp: A simple regex-based stream preprocessor based on Mark Reinhold's + * sed-based spp.sh + * + * Usage: + * java build.tools.spp.Spp [-be] [-nel] [-Kkey] -Dvar=value ... -iin -oout + * + * If -nel is declared then empty lines will not be substituted for lines of + * text in the template that do not appear in the output. + * + * Meaningful only at beginning of line, works with any number of keys: + * + * #if[key] Includes text between #if/#end if -Kkey specified, + * #else[key] otherwise changes text to blank lines; key test + * #end[key] may be negated by prefixing !, e.g., #if[!key] + * + * #begin If -be is specified then lines up to and including + * #end #begin, and from #end to EOF, are deleted + * + * #warn Changed into warning that file is generated + * + * // ## Changed into blank line + * + * Meaningful anywhere in line + * + * {#if[key]?yes} Expands to yes if -Kkey specified + * {#if[key]?yes:no} Expands to yes if -Kkey, otherwise no + * {#if[!key]?yes} Expands to yes if -Kother + * {#if[!key]?yes:no} Expands to yes if -Kother, otherwise no + * $var$ Expands to value if -Dvar=value given + * + * yes, no must not contain whitespace + * + * @author Xueming Shen + */ + +public class Spp { + public static void main(String args[]) throws Exception { + Map vars = new HashMap<>(); + Set keys = new HashSet<>(); + boolean be = false; + boolean el = true; + String inputFile = null; + String outputFile = null; + + for (String arg:args) { + if (arg.startsWith("-D")) { + int i = arg.indexOf('='); + vars.put(arg.substring(2, i),arg.substring(i+1)); + } else if (arg.startsWith("-K")) { + keys.add(arg.substring(2)); + } else if (arg.startsWith("-i")) { + inputFile = arg.substring(2); + } else if (arg.startsWith("-o")) { + outputFile = arg.substring(2); + } else if ("-be".equals(arg)) { + be = true; + } else if ("-nel".equals(arg)) { + el = false; + } else { + System.err.println("Usage: java build.tools.spp.Spp [-be] [-nel] [-Kkey] -Dvar=value ... out"); + System.exit(-1); + } + } + + StringBuffer out = new StringBuffer(); + new Spp().spp(new Scanner(new FileInputStream(inputFile)), + out, "", + keys, vars, be, el, + false); + new FileOutputStream(outputFile, true).write(out.toString().getBytes()); + } + + static final String LNSEP = System.getProperty("line.separator"); + static final String KEY = "([a-zA-Z0-9]+)"; + static final String VAR = "([a-zA-Z0-9_\\-]+)"; + static final String TEXT = "([a-zA-Z0-9&;,.<>/#() \\?\\[\\]\\$]+)"; // $ -- hack embedded $var$ + + static final int GN_NOT = 1; + static final int GN_KEY = 2; + static final int GN_YES = 3; + static final int GN_NO = 5; + static final int GN_VAR = 6; + + final Matcher ifkey = Pattern.compile("^#if\\[(!)?" + KEY + "\\]").matcher(""); + final Matcher elsekey = Pattern.compile("^#else\\[(!)?" + KEY + "\\]").matcher(""); + final Matcher endkey = Pattern.compile("^#end\\[(!)?" + KEY + "\\]").matcher(""); + final Matcher vardef = Pattern.compile("\\{#if\\[(!)?" + KEY + "\\]\\?" + TEXT + "(:"+ TEXT + ")?\\}|\\$" + VAR + "\\$").matcher(""); + final Matcher vardef2 = Pattern.compile("\\$" + VAR + "\\$").matcher(""); + + void append(StringBuffer buf, String ln, + Set keys, Map vars) { + vardef.reset(ln); + while (vardef.find()) { + String repl = ""; + if (vardef.group(GN_VAR) != null) + repl = vars.get(vardef.group(GN_VAR)); + else { + boolean test = keys.contains(vardef.group(GN_KEY)); + if (vardef.group(GN_NOT) != null) + test = !test; + repl = test?vardef.group(GN_YES):vardef.group(GN_NO); + if (repl == null) + repl = ""; + else { // embedded $var$ + while (vardef2.reset(repl).find()) { + repl = vardef2.replaceFirst(vars.get(vardef2.group(1))); + } + } + } + vardef.appendReplacement(buf, repl); + } + vardef.appendTail(buf); + } + + // return true if #end[key], #end or EOF reached + boolean spp(Scanner in, StringBuffer buf, String key, + Set keys, Map vars, + boolean be, boolean el, boolean skip) { + while (in.hasNextLine()) { + String ln = in.nextLine(); + if (be) { + if (ln.startsWith("#begin")) { + buf.setLength(0); //clean up to this line + continue; + } + if (ln.equals("#end")) { + while (in.hasNextLine()) + in.nextLine(); + return true; //discard the rest to EOF + } + } + if (ifkey.reset(ln).find()) { + String k = ifkey.group(GN_KEY); + boolean test = keys.contains(k); + if (ifkey.group(GN_NOT) != null) + test = !test; + if (el) buf.append(LNSEP); + if (!spp(in, buf, k, keys, vars, be, el, skip || !test)) { + spp(in, buf, k, keys, vars, be, el, skip || test); + } + continue; + } + if (elsekey.reset(ln).find()) { + if (!key.equals(elsekey.group(GN_KEY))) { + throw new Error("Mis-matched #if-else-end at line <" + ln + ">"); + } + if (el) buf.append(LNSEP); + return false; + } + if (endkey.reset(ln).find()) { + if (!key.equals(endkey.group(GN_KEY))) { + throw new Error("Mis-matched #if-else-end at line <" + ln + ">"); + } + if (el) buf.append(LNSEP); + return true; + } + if (ln.startsWith("#warn")) { + ln = "// -- This file was mechanically generated: Do not edit! -- //"; + } else if (ln.trim().startsWith("// ##")) { + ln = ""; + } + if (!skip) { + append(buf, ln, keys, vars); + if (!el) buf.append(LNSEP); + } + if (el) buf.append(LNSEP); + } + return true; + } +} --- old/make/jdk/src/classes/build/tools/tzdb/TzdbZoneRulesCompiler.java 2020-03-23 19:56:58.299962542 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,315 +0,0 @@ -/* - * Copyright (c) 2012, 2019, 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) 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.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.text.ParsePosition; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Scanner; -import java.util.SortedMap; -import java.util.TreeMap; -import java.util.regex.Matcher; -import java.util.regex.MatchResult; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -/** - * A compiler that reads a set of TZDB time-zone files and builds a single - * combined TZDB data file. - * - * @since 1.8 - */ -public final class TzdbZoneRulesCompiler { - - public static void main(String[] args) { - new TzdbZoneRulesCompiler().compile(args); - } - - private void compile(String[] args) { - if (args.length < 2) { - outputHelp(); - return; - } - Path srcDir = null; - Path dstFile = null; - String version = null; - // parse args/options - int i; - for (i = 0; i < args.length; i++) { - String arg = args[i]; - if (!arg.startsWith("-")) { - break; - } - if ("-srcdir".equals(arg)) { - if (srcDir == null && ++i < args.length) { - srcDir = Paths.get(args[i]); - continue; - } - } else if ("-dstfile".equals(arg)) { - if (dstFile == null && ++i < args.length) { - dstFile = Paths.get(args[i]); - continue; - } - } else if ("-verbose".equals(arg)) { - if (!verbose) { - verbose = true; - continue; - } - } else if (!"-help".equals(arg)) { - System.out.println("Unrecognised option: " + arg); - } - outputHelp(); - return; - } - // check source directory - if (srcDir == null) { - System.err.println("Source directory must be specified using -srcdir"); - System.exit(1); - } - if (!Files.isDirectory(srcDir)) { - System.err.println("Source does not exist or is not a directory: " + srcDir); - System.exit(1); - } - // parse source file names - if (i == args.length) { - i = 0; - args = new String[] {"africa", "antarctica", "asia", "australasia", "europe", - "northamerica","southamerica", "backward", "etcetera" }; - System.out.println("Source filenames not specified, using default set ( "); - for (String name : args) { - System.out.printf(name + " "); - } - System.out.println(")"); - } - // source files in this directory - List srcFiles = new ArrayList<>(); - for (; i < args.length; i++) { - Path file = srcDir.resolve(args[i]); - if (Files.exists(file)) { - srcFiles.add(file); - } else { - System.err.println("Source directory does not contain source file: " + args[i]); - System.exit(1); - } - } - // check destination file - if (dstFile == null) { - dstFile = srcDir.resolve("tzdb.dat"); - } else { - Path parent = dstFile.getParent(); - if (parent != null && !Files.exists(parent)) { - System.err.println("Destination directory does not exist: " + parent); - System.exit(1); - } - } - try { - // get tzdb source version - Matcher m = Pattern.compile("tzdata(?[0-9]{4}[A-z])") - .matcher(new String(Files.readAllBytes(srcDir.resolve("VERSION")), - "ISO-8859-1")); - if (m.find()) { - version = m.group("ver"); - } else { - System.exit(1); - System.err.println("Source directory does not contain file: VERSION"); - } - - // load source files - printVerbose("Compiling TZDB version " + version); - TzdbZoneRulesProvider provider = new TzdbZoneRulesProvider(srcFiles); - - // build zone rules - printVerbose("Building rules"); - - // Build the rules, zones and links into real zones. - SortedMap builtZones = new TreeMap<>(); - - // build zones - for (String zoneId : provider.getZoneIds()) { - printVerbose("Building zone " + zoneId); - builtZones.put(zoneId, provider.getZoneRules(zoneId)); - } - - // build aliases - Map 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); - } catch (Exception ex) { - System.out.println("Failed: " + ex.toString()); - ex.printStackTrace(); - System.exit(1); - } - System.exit(0); - } - - /** - * Output usage text for the command line. - */ - private static void outputHelp() { - System.out.println("Usage: TzdbZoneRulesCompiler "); - System.out.println("where options include:"); - System.out.println(" -srcdir Where to find tzdb source directory (required)"); - System.out.println(" -dstfile Where to output generated file (default srcdir/tzdb.dat)"); - System.out.println(" -help Print this usage message"); - System.out.println(" -verbose Output verbose information during compilation"); - System.out.println(" The source directory must contain the unpacked tzdb files, such as asia or europe"); - } - - /** - * Outputs the file. - */ - private void outputFile(Path dstFile, String version, - SortedMap builtZones, - Map links) { - try (DataOutputStream out = new DataOutputStream(Files.newOutputStream(dstFile))) { - // file version - out.writeByte(1); - // group - out.writeUTF("TZDB"); - // versions - out.writeShort(1); - out.writeUTF(version); - // regions - String[] regionArray = builtZones.keySet().toArray(new String[builtZones.size()]); - out.writeShort(regionArray.length); - for (String regionId : regionArray) { - out.writeUTF(regionId); - } - // rules -- remove the dup - List rulesList = builtZones.values().stream() - .distinct() - .collect(Collectors.toList()); - out.writeShort(rulesList.size()); - ByteArrayOutputStream baos = new ByteArrayOutputStream(1024); - for (ZoneRules rules : rulesList) { - baos.reset(); - DataOutputStream dataos = new DataOutputStream(baos); - Ser.write(rules, dataos); - dataos.close(); - byte[] bytes = baos.toByteArray(); - out.writeShort(bytes.length); - out.write(bytes); - } - // link version-region-rules - out.writeShort(builtZones.size()); - for (Map.Entry entry : builtZones.entrySet()) { - int regionIndex = Arrays.binarySearch(regionArray, entry.getKey()); - int rulesIndex = rulesList.indexOf(entry.getValue()); - out.writeShort(regionIndex); - out.writeShort(rulesIndex); - } - // alias-region - out.writeShort(links.size()); - for (Map.Entry entry : links.entrySet()) { - int aliasIndex = Arrays.binarySearch(regionArray, entry.getKey()); - int regionIndex = Arrays.binarySearch(regionArray, entry.getValue()); - out.writeShort(aliasIndex); - out.writeShort(regionIndex); - } - out.flush(); - } catch (Exception ex) { - System.out.println("Failed: " + ex.toString()); - ex.printStackTrace(); - System.exit(1); - } - } - - /** Whether to output verbose messages. */ - private boolean verbose; - - /** - * private contructor - */ - private TzdbZoneRulesCompiler() {} - - /** - * Prints a verbose message. - * - * @param message the message, not null - */ - private void printVerbose(String message) { - if (verbose) { - System.out.println(message); - } - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.base/share/tools/org/openjdk/buildtools/tzdb/TzdbZoneRulesCompiler.java 2020-03-23 19:56:57.863962545 +0100 @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2012, 2019, 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) 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 org.openjdk.buildtools.tzdb; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.ParsePosition; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Scanner; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.regex.Matcher; +import java.util.regex.MatchResult; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * A compiler that reads a set of TZDB time-zone files and builds a single + * combined TZDB data file. + * + * @since 1.8 + */ +public final class TzdbZoneRulesCompiler { + + public static void main(String[] args) { + new TzdbZoneRulesCompiler().compile(args); + } + + private void compile(String[] args) { + if (args.length < 2) { + outputHelp(); + return; + } + Path srcDir = null; + Path dstFile = null; + String version = null; + // parse args/options + int i; + for (i = 0; i < args.length; i++) { + String arg = args[i]; + if (!arg.startsWith("-")) { + break; + } + if ("-srcdir".equals(arg)) { + if (srcDir == null && ++i < args.length) { + srcDir = Paths.get(args[i]); + continue; + } + } else if ("-dstfile".equals(arg)) { + if (dstFile == null && ++i < args.length) { + dstFile = Paths.get(args[i]); + continue; + } + } else if ("-verbose".equals(arg)) { + if (!verbose) { + verbose = true; + continue; + } + } else if (!"-help".equals(arg)) { + System.out.println("Unrecognised option: " + arg); + } + outputHelp(); + return; + } + // check source directory + if (srcDir == null) { + System.err.println("Source directory must be specified using -srcdir"); + System.exit(1); + } + if (!Files.isDirectory(srcDir)) { + System.err.println("Source does not exist or is not a directory: " + srcDir); + System.exit(1); + } + // parse source file names + if (i == args.length) { + i = 0; + args = new String[] {"africa", "antarctica", "asia", "australasia", "europe", + "northamerica","southamerica", "backward", "etcetera" }; + System.out.println("Source filenames not specified, using default set ( "); + for (String name : args) { + System.out.printf(name + " "); + } + System.out.println(")"); + } + // source files in this directory + List srcFiles = new ArrayList<>(); + for (; i < args.length; i++) { + Path file = srcDir.resolve(args[i]); + if (Files.exists(file)) { + srcFiles.add(file); + } else { + System.err.println("Source directory does not contain source file: " + args[i]); + System.exit(1); + } + } + // check destination file + if (dstFile == null) { + dstFile = srcDir.resolve("tzdb.dat"); + } else { + Path parent = dstFile.getParent(); + if (parent != null && !Files.exists(parent)) { + System.err.println("Destination directory does not exist: " + parent); + System.exit(1); + } + } + try { + // get tzdb source version + Matcher m = Pattern.compile("tzdata(?[0-9]{4}[A-z])") + .matcher(new String(Files.readAllBytes(srcDir.resolve("VERSION")), + "ISO-8859-1")); + if (m.find()) { + version = m.group("ver"); + } else { + System.exit(1); + System.err.println("Source directory does not contain file: VERSION"); + } + + // load source files + printVerbose("Compiling TZDB version " + version); + TzdbZoneRulesProvider provider = new TzdbZoneRulesProvider(srcFiles); + + // build zone rules + printVerbose("Building rules"); + + // Build the rules, zones and links into real zones. + SortedMap builtZones = new TreeMap<>(); + + // build zones + for (String zoneId : provider.getZoneIds()) { + printVerbose("Building zone " + zoneId); + builtZones.put(zoneId, provider.getZoneRules(zoneId)); + } + + // build aliases + Map 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); + } catch (Exception ex) { + System.out.println("Failed: " + ex.toString()); + ex.printStackTrace(); + System.exit(1); + } + System.exit(0); + } + + /** + * Output usage text for the command line. + */ + private static void outputHelp() { + System.out.println("Usage: TzdbZoneRulesCompiler "); + System.out.println("where options include:"); + System.out.println(" -srcdir Where to find tzdb source directory (required)"); + System.out.println(" -dstfile Where to output generated file (default srcdir/tzdb.dat)"); + System.out.println(" -help Print this usage message"); + System.out.println(" -verbose Output verbose information during compilation"); + System.out.println(" The source directory must contain the unpacked tzdb files, such as asia or europe"); + } + + /** + * Outputs the file. + */ + private void outputFile(Path dstFile, String version, + SortedMap builtZones, + Map links) { + try (DataOutputStream out = new DataOutputStream(Files.newOutputStream(dstFile))) { + // file version + out.writeByte(1); + // group + out.writeUTF("TZDB"); + // versions + out.writeShort(1); + out.writeUTF(version); + // regions + String[] regionArray = builtZones.keySet().toArray(new String[builtZones.size()]); + out.writeShort(regionArray.length); + for (String regionId : regionArray) { + out.writeUTF(regionId); + } + // rules -- remove the dup + List rulesList = builtZones.values().stream() + .distinct() + .collect(Collectors.toList()); + out.writeShort(rulesList.size()); + ByteArrayOutputStream baos = new ByteArrayOutputStream(1024); + for (ZoneRules rules : rulesList) { + baos.reset(); + DataOutputStream dataos = new DataOutputStream(baos); + Ser.write(rules, dataos); + dataos.close(); + byte[] bytes = baos.toByteArray(); + out.writeShort(bytes.length); + out.write(bytes); + } + // link version-region-rules + out.writeShort(builtZones.size()); + for (Map.Entry entry : builtZones.entrySet()) { + int regionIndex = Arrays.binarySearch(regionArray, entry.getKey()); + int rulesIndex = rulesList.indexOf(entry.getValue()); + out.writeShort(regionIndex); + out.writeShort(rulesIndex); + } + // alias-region + out.writeShort(links.size()); + for (Map.Entry entry : links.entrySet()) { + int aliasIndex = Arrays.binarySearch(regionArray, entry.getKey()); + int regionIndex = Arrays.binarySearch(regionArray, entry.getValue()); + out.writeShort(aliasIndex); + out.writeShort(regionIndex); + } + out.flush(); + } catch (Exception ex) { + System.out.println("Failed: " + ex.toString()); + ex.printStackTrace(); + System.exit(1); + } + } + + /** Whether to output verbose messages. */ + private boolean verbose; + + /** + * private contructor + */ + private TzdbZoneRulesCompiler() {} + + /** + * Prints a verbose message. + * + * @param message the message, not null + */ + private void printVerbose(String message) { + if (verbose) { + System.out.println(message); + } + } +} --- old/make/jdk/src/classes/build/tools/tzdb/TzdbZoneRulesProvider.java 2020-03-23 19:56:59.203962535 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,905 +0,0 @@ -/* - * Copyright (c) 2014, 2020, 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.*; -import java.util.Map.Entry; -import java.util.concurrent.ConcurrentSkipListMap; -import java.time.*; -import java.time.Year; -import java.time.chrono.IsoChronology; -import java.time.temporal.TemporalAdjusters; -import build.tools.tzdb.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 9 - */ - -class TzdbZoneRulesProvider { - - /** - * Creates an instance. - * - * @throws ZoneRulesException if unable to load - */ - public TzdbZoneRulesProvider(List files) { - try { - load(files); - } catch (Exception ex) { - throw new ZoneRulesException("Unable to load TZDB time-zone rules", ex); - } - } - - public Set getZoneIds() { - return new TreeSet(regionIds); - } - - public Map 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) { - // Timezone link can be located in 'backward' file and it - // can refer to another link, so we need to check for - // link one more time, before throwing an exception - String zoneIdBack = zoneId; - if (links.containsKey(zoneId)) { - zoneId = links.get(zoneId); - obj = zones.get(zoneId); - } - if (obj == null) { - throw new ZoneRulesException("Unknown time-zone ID: " + zoneIdBack); - } - } - } - if (obj instanceof ZoneRules) { - return (ZoneRules)obj; - } - try { - @SuppressWarnings("unchecked") - ZoneRules zrules = buildRules(zoneId, (List)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 regionIds = new ArrayList<>(600); - - /** - * Zone region to rules mapping - */ - private final Map zones = new ConcurrentSkipListMap<>(); - - /** - * compatibility list - */ - private static Set 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 TreeSet<>(); - excludedZones.add("EST"); - excludedZones.add("HST"); - excludedZones.add("MST"); - excludedZones.add("GMT+0"); - excludedZones.add("GMT-0"); - excludedZones.add("ROC"); - } - - private Map links = new TreeMap<>(); - private Map> rules = new TreeMap<>(); - - private void load(List files) throws IOException { - - for (Path file : files) { - List 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(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 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 definition 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; - } else if (secsOfDay < 0 || secsOfDay > 86400) { - // beyond 0:00-24:00 range. Adjust the cutover date. - int beyondDays = secsOfDay / 86400; - secsOfDay %= 86400; - if (secsOfDay < 0) { - secsOfDay = 86400 + secsOfDay; - beyondDays -= 1; - } - LocalDate date = LocalDate.of(2004, month, dayOfMonth).plusDays(beyondDays); // leap-year - month = date.getMonth(); - dayOfMonth = date.getDayOfMonth(); - if (dayOfWeek != null) { - dayOfWeek = dayOfWeek.plus(beyondDays); - } - } - 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 - * @param negativeSavings minimum savings in the rule, usually zero, but negative if negative DST is - * in effect. - * @return the transition, not null - */ - ZoneOffsetTransitionRule toTransitionRule(ZoneOffset stdOffset, int savingsBefore, int negativeSavings) { - // 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 - negativeSavings)); - } - - RuleLine parse(String[] tokens) { - startYear = parseYear(tokens[2], 0); - endYear = parseYear(tokens[3], startYear); - if (startYear > endYear) { - throw new IllegalArgumentException( - "Invalid 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 - { - 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, int negativeSavings) { - // copy of code in ZoneOffsetTransitionRule to avoid infinite loop - ZoneOffset wallOffset = ZoneOffset.ofTotalSeconds( - standardOffset.getTotalSeconds() + savingsBeforeSecs); - ZoneOffset offsetAfter = ZoneOffset.ofTotalSeconds( - standardOffset.getTotalSeconds() + rule.savingsAmount - negativeSavings); - 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 - * @param negativeSavings minimum savings in the rule, usually zero, but negative if negative DST is - * in effect. - * @return true, if savings changes - */ - boolean isTransition(int savingsBefore, int negativeSavings) { - return rule.savingsAmount - negativeSavings != savingsBefore; - } - - public int compareTo(TransRule other) { - return (ldtSecs < other.ldtSecs)? -1 : ((ldtSecs == other.ldtSecs) ? 0 : 1); - } - } - - private ZoneRules buildRules(String zoneId, List zones) { - if (zones.isEmpty()) { - throw new IllegalStateException("No available zone window"); - } - final List standardTransitionList = new ArrayList<>(4); - final List transitionList = new ArrayList<>(256); - final List 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 standard offset - ZoneOffset firstStdOffset = stdOffset; - // first wall offset - ZoneOffset firstWallOffset = wallOffset; - - for (ZoneLine zone : zones) { - // Adjust stdOffset, if negative DST is observed. It should be either - // fixed amount, or expressed in the named Rules. - int negativeSavings = Math.min(zone.fixedSavingsSecs, findNegativeSavings(zoneStart, zone)); - if (negativeSavings < 0) { - zone.stdOffsetSecs += negativeSavings; - if (zone.fixedSavingsSecs < 0) { - zone.fixedSavingsSecs = 0; - } - } - - // 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 trules = null; - List lastRules = null; - - int effectiveSavings = zone.fixedSavingsSecs; - if (zone.savingsRule != null) { - List tzdbRules = rules.get(zone.savingsRule); - if (tzdbRules == null) { - throw new IllegalArgumentException(" 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 = -negativeSavings; - 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 - negativeSavings; - } - } - // 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, negativeSavings)) { - long epochSecs = trule.toEpochSecond(stdOffset, savings); - if (epochSecs < zoneStartEpochSecs || - epochSecs >= zone.toDateTimeEpochSecond(savings)) { - continue; - } - transitionList.add(trule.toTransition(stdOffset, savings, negativeSavings)); - savings = trule.rule.savingsAmount - negativeSavings; - } - } - } - if (lastRules != null) { - for (TransRule trule : lastRules) { - lastTransitionRuleList.add(trule.rule.toTransitionRule(stdOffset, savings, negativeSavings)); - savings = trule.rule.savingsAmount - negativeSavings; - } - } - - // 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); - } - - /** - * Find the minimum negative savings in named Rules for a Zone. Savings are only - * looked at for the period of the subject Zone. - * - * @param zoneStart start LDT of the zone - * @param zl ZoneLine to look at - */ - private int findNegativeSavings(LocalDateTime zoneStart, ZoneLine zl) { - int negativeSavings = 0; - LocalDateTime zoneEnd = zl.toDateTime(); - - if (zl.savingsRule != null) { - List rlines = rules.get(zl.savingsRule); - if (rlines == null) { - throw new IllegalArgumentException(" not found: " + - zl.savingsRule); - } - - negativeSavings = Math.min(0, rlines.stream() - .filter(l -> windowOverlap(l, zoneStart.getYear(), zoneEnd.getYear())) - .map(l -> l.savingsAmount) - .min(Comparator.naturalOrder()) - .orElse(0)); - } - - return negativeSavings; - } - - private boolean windowOverlap(RuleLine ruleLine, int zoneStartYear, int zoneEndYear) { - boolean overlap = zoneStartYear <= ruleLine.startYear && zoneEndYear >= ruleLine.startYear || - zoneStartYear <= ruleLine.endYear && zoneEndYear >= ruleLine.endYear; - - return overlap; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.base/share/tools/org/openjdk/buildtools/tzdb/TzdbZoneRulesProvider.java 2020-03-23 19:56:58.767962538 +0100 @@ -0,0 +1,905 @@ +/* + * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.openjdk.buildtools.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.*; +import java.util.Map.Entry; +import java.util.concurrent.ConcurrentSkipListMap; +import java.time.*; +import java.time.Year; +import java.time.chrono.IsoChronology; +import java.time.temporal.TemporalAdjusters; +import org.openjdk.buildtools.tzdb.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 9 + */ + +class TzdbZoneRulesProvider { + + /** + * Creates an instance. + * + * @throws ZoneRulesException if unable to load + */ + public TzdbZoneRulesProvider(List files) { + try { + load(files); + } catch (Exception ex) { + throw new ZoneRulesException("Unable to load TZDB time-zone rules", ex); + } + } + + public Set getZoneIds() { + return new TreeSet(regionIds); + } + + public Map 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) { + // Timezone link can be located in 'backward' file and it + // can refer to another link, so we need to check for + // link one more time, before throwing an exception + String zoneIdBack = zoneId; + if (links.containsKey(zoneId)) { + zoneId = links.get(zoneId); + obj = zones.get(zoneId); + } + if (obj == null) { + throw new ZoneRulesException("Unknown time-zone ID: " + zoneIdBack); + } + } + } + if (obj instanceof ZoneRules) { + return (ZoneRules)obj; + } + try { + @SuppressWarnings("unchecked") + ZoneRules zrules = buildRules(zoneId, (List)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 regionIds = new ArrayList<>(600); + + /** + * Zone region to rules mapping + */ + private final Map zones = new ConcurrentSkipListMap<>(); + + /** + * compatibility list + */ + private static Set 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 TreeSet<>(); + excludedZones.add("EST"); + excludedZones.add("HST"); + excludedZones.add("MST"); + excludedZones.add("GMT+0"); + excludedZones.add("GMT-0"); + excludedZones.add("ROC"); + } + + private Map links = new TreeMap<>(); + private Map> rules = new TreeMap<>(); + + private void load(List files) throws IOException { + + for (Path file : files) { + List 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(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 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 definition 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; + } else if (secsOfDay < 0 || secsOfDay > 86400) { + // beyond 0:00-24:00 range. Adjust the cutover date. + int beyondDays = secsOfDay / 86400; + secsOfDay %= 86400; + if (secsOfDay < 0) { + secsOfDay = 86400 + secsOfDay; + beyondDays -= 1; + } + LocalDate date = LocalDate.of(2004, month, dayOfMonth).plusDays(beyondDays); // leap-year + month = date.getMonth(); + dayOfMonth = date.getDayOfMonth(); + if (dayOfWeek != null) { + dayOfWeek = dayOfWeek.plus(beyondDays); + } + } + 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 + * @param negativeSavings minimum savings in the rule, usually zero, but negative if negative DST is + * in effect. + * @return the transition, not null + */ + ZoneOffsetTransitionRule toTransitionRule(ZoneOffset stdOffset, int savingsBefore, int negativeSavings) { + // 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 - negativeSavings)); + } + + RuleLine parse(String[] tokens) { + startYear = parseYear(tokens[2], 0); + endYear = parseYear(tokens[3], startYear); + if (startYear > endYear) { + throw new IllegalArgumentException( + "Invalid 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 + { + 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, int negativeSavings) { + // copy of code in ZoneOffsetTransitionRule to avoid infinite loop + ZoneOffset wallOffset = ZoneOffset.ofTotalSeconds( + standardOffset.getTotalSeconds() + savingsBeforeSecs); + ZoneOffset offsetAfter = ZoneOffset.ofTotalSeconds( + standardOffset.getTotalSeconds() + rule.savingsAmount - negativeSavings); + 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 + * @param negativeSavings minimum savings in the rule, usually zero, but negative if negative DST is + * in effect. + * @return true, if savings changes + */ + boolean isTransition(int savingsBefore, int negativeSavings) { + return rule.savingsAmount - negativeSavings != savingsBefore; + } + + public int compareTo(TransRule other) { + return (ldtSecs < other.ldtSecs)? -1 : ((ldtSecs == other.ldtSecs) ? 0 : 1); + } + } + + private ZoneRules buildRules(String zoneId, List zones) { + if (zones.isEmpty()) { + throw new IllegalStateException("No available zone window"); + } + final List standardTransitionList = new ArrayList<>(4); + final List transitionList = new ArrayList<>(256); + final List 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 standard offset + ZoneOffset firstStdOffset = stdOffset; + // first wall offset + ZoneOffset firstWallOffset = wallOffset; + + for (ZoneLine zone : zones) { + // Adjust stdOffset, if negative DST is observed. It should be either + // fixed amount, or expressed in the named Rules. + int negativeSavings = Math.min(zone.fixedSavingsSecs, findNegativeSavings(zoneStart, zone)); + if (negativeSavings < 0) { + zone.stdOffsetSecs += negativeSavings; + if (zone.fixedSavingsSecs < 0) { + zone.fixedSavingsSecs = 0; + } + } + + // 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 trules = null; + List lastRules = null; + + int effectiveSavings = zone.fixedSavingsSecs; + if (zone.savingsRule != null) { + List tzdbRules = rules.get(zone.savingsRule); + if (tzdbRules == null) { + throw new IllegalArgumentException(" 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 = -negativeSavings; + 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 - negativeSavings; + } + } + // 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, negativeSavings)) { + long epochSecs = trule.toEpochSecond(stdOffset, savings); + if (epochSecs < zoneStartEpochSecs || + epochSecs >= zone.toDateTimeEpochSecond(savings)) { + continue; + } + transitionList.add(trule.toTransition(stdOffset, savings, negativeSavings)); + savings = trule.rule.savingsAmount - negativeSavings; + } + } + } + if (lastRules != null) { + for (TransRule trule : lastRules) { + lastTransitionRuleList.add(trule.rule.toTransitionRule(stdOffset, savings, negativeSavings)); + savings = trule.rule.savingsAmount - negativeSavings; + } + } + + // 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); + } + + /** + * Find the minimum negative savings in named Rules for a Zone. Savings are only + * looked at for the period of the subject Zone. + * + * @param zoneStart start LDT of the zone + * @param zl ZoneLine to look at + */ + private int findNegativeSavings(LocalDateTime zoneStart, ZoneLine zl) { + int negativeSavings = 0; + LocalDateTime zoneEnd = zl.toDateTime(); + + if (zl.savingsRule != null) { + List rlines = rules.get(zl.savingsRule); + if (rlines == null) { + throw new IllegalArgumentException(" not found: " + + zl.savingsRule); + } + + negativeSavings = Math.min(0, rlines.stream() + .filter(l -> windowOverlap(l, zoneStart.getYear(), zoneEnd.getYear())) + .map(l -> l.savingsAmount) + .min(Comparator.naturalOrder()) + .orElse(0)); + } + + return negativeSavings; + } + + private boolean windowOverlap(RuleLine ruleLine, int zoneStartYear, int zoneEndYear) { + boolean overlap = zoneStartYear <= ruleLine.startYear && zoneEndYear >= ruleLine.startYear || + zoneStartYear <= ruleLine.endYear && zoneEndYear >= ruleLine.endYear; + + return overlap; + } +} --- old/make/jdk/src/classes/build/tools/compilefontconfig/CompileFontConfig.java 2020-03-23 19:57:00.099962529 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2004, 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 build.tools.compilefontconfig; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import sun.awt.FontConfiguration; - -public class CompileFontConfig { - public static void main(String[] argv) { - boolean verbose = false; - if (argv.length != 0 && "-verbose".equals(argv[0])) { - verbose = true; - } - if (verbose) { - if (argv.length != 3) - System.out.println("Usage: java CompileFontConfig [-verbose] propertiesFileName binaryFileName"); - else - new CompileFontConfig(argv[1], argv[2], true); - } else { - if (argv.length != 2) - System.out.println("Usage: java CompileFontConfig [-verbose] propertiesFileName binaryFileNme"); - else - new CompileFontConfig(argv[0], argv[1], false); - } - } - - CompileFontConfig(String inFile, String outFile, boolean verbose) { - try { - FileInputStream in = new FileInputStream(inFile); - FileOutputStream out = new FileOutputStream(outFile); - FontConfiguration.verbose = verbose; - FontConfiguration.loadProperties(in); - FontConfiguration.saveBinary(out); - } catch (Exception e) { - e.printStackTrace(); - } - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/compilefontconfig/CompileFontConfig.java 2020-03-23 19:56:59.663962532 +0100 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2004, 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 org.openjdk.buildtools.compilefontconfig; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import sun.awt.FontConfiguration; + +public class CompileFontConfig { + public static void main(String[] argv) { + boolean verbose = false; + if (argv.length != 0 && "-verbose".equals(argv[0])) { + verbose = true; + } + if (verbose) { + if (argv.length != 3) + System.out.println("Usage: java CompileFontConfig [-verbose] propertiesFileName binaryFileName"); + else + new CompileFontConfig(argv[1], argv[2], true); + } else { + if (argv.length != 2) + System.out.println("Usage: java CompileFontConfig [-verbose] propertiesFileName binaryFileNme"); + else + new CompileFontConfig(argv[0], argv[1], false); + } + } + + CompileFontConfig(String inFile, String outFile, boolean verbose) { + try { + FileInputStream in = new FileInputStream(inFile); + FileOutputStream out = new FileOutputStream(outFile); + FontConfiguration.verbose = verbose; + FontConfiguration.loadProperties(in); + FontConfiguration.saveBinary(out); + } catch (Exception e) { + e.printStackTrace(); + } + } +} --- old/make/jdk/src/classes/build/tools/dtdbuilder/DTDBuilder.java 2020-03-23 19:57:00.931962522 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,313 +0,0 @@ -/* - * Copyright (c) 1998, 2020, 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.dtdbuilder; - -import javax.swing.text.html.parser.*; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.FileNotFoundException; -import java.io.BufferedInputStream; -import java.io.OutputStream; -import java.util.Hashtable; -import java.util.Vector; -import java.util.BitSet; -import java.util.StringTokenizer; -import java.util.Enumeration; -import java.util.Properties; -import java.util.zip.DeflaterOutputStream; -import java.util.zip.Deflater; -import java.net.URL; - -/** - * The representation of an SGML DTD. This is produced by the DTDParser. - * The resulting DTD object describes a document syntax and is needed - * to parse HTML documents using the Parser. It contains a list of - * elements and their attributes as well as a list of entities defined - * in the DTD. - * - * @see Element - * @see AttributeList - * @see ContentModel - * @see DTDParser - * @see Parser - * @author Arthur van Hoff - */ -public -class DTDBuilder extends DTD { - - static PublicMapping mapping = null; - - // Hash from name to Integer - private Hashtable namesHash = new Hashtable<>(); - // Vector of all names - private Vector namesVector = new Vector<>(); - - /** - * Create a new DTD. - */ - protected DTDBuilder(String name) { - super(name); - } - - - /** - * Save to a stream as a Java class. Instantiating this class will - * reproduce a (virtually) identical DTD. - */ - void save(DataOutputStream out, String className) throws IOException { - - out.writeInt(DTD.FILE_VERSION); - - buildNamesTable(); - int numNames = namesVector.size(); - out.writeShort((short) (namesVector.size())); - for (int i = 0; i < namesVector.size(); i++) { - String nm = namesVector.elementAt(i); - out.writeUTF(nm); - } - - saveEntities(out); - - out.writeShort((short) (elements.size())); - for (Enumeration e = elements.elements() ; e.hasMoreElements() ; ) { - saveElement(out, e.nextElement()); - } - - if (namesVector.size() != numNames) { - System.err.println("!!! ERROR! Names were added to the list!"); - Thread.dumpStack(); - System.exit(1); - } - } - - private void buildNamesTable() { - for (Enumeration e = entityHash.elements() ; e.hasMoreElements() ; ) { - Entity ent = e.nextElement(); - // Do even if not isGeneral(). That way, exclusions and inclusions - // will definitely have their element. - getNameId(ent.getName()); - } - for (Enumeration e = elements.elements() ; e.hasMoreElements() ; ) { - Element el = e.nextElement(); - getNameId(el.getName()); - for (AttributeList atts = el.getAttributes() ; atts != null ; atts = atts.getNext()) { - getNameId(atts.getName()); - if (atts.getValue() != null) { - getNameId(atts.getValue()); - } - Enumeration vals = atts.getValues(); - while (vals != null && vals.hasMoreElements()) { - String s = (String) vals.nextElement(); - getNameId(s); - } - } - } - } - - // - // The the id of a name from the list of names - // - private short getNameId(String name) { - Integer o = namesHash.get(name); - if (o != null) { - return (short) o.intValue(); - } - int i = namesVector.size(); - namesVector.addElement(name); - namesHash.put(name, i); - return (short) i; - } - - - /** - * Save an entity to a stream. - */ - void saveEntities(DataOutputStream out) throws IOException { - int num = 0; - for (Enumeration e = entityHash.elements() ; e.hasMoreElements() ; ) { - Entity ent = e.nextElement(); - if (ent.isGeneral()) { - num++; - } - } - - out.writeShort((short) num); - for (Enumeration e = entityHash.elements() ; e.hasMoreElements() ; ) { - Entity ent = e.nextElement(); - if (ent.isGeneral()) { - out.writeShort(getNameId(ent.getName())); - out.writeByte(ent.getType() & ~GENERAL); - out.writeUTF(ent.getString()); - } - } - } - - - /** - * Save an element to a stream. - */ - - public void saveElement(DataOutputStream out, Element elem) throws IOException { - - out.writeShort(getNameId(elem.getName())); - out.writeByte(elem.getType()); - - byte flags = 0; - if (elem.omitStart()) { - flags |= 0x01; - } - if (elem.omitEnd()) { - flags |= 0x02; - } - out.writeByte(flags); - saveContentModel(out, elem.getContent()); - - // Exclusions - if (elem.exclusions == null) { - out.writeShort(0); - } else { - short num = 0; - for (int i = 0 ; i < elem.exclusions.size() ; i++) { - if (elem.exclusions.get(i)) { - num++; - } - } - out.writeShort(num); - for (int i = 0 ; i < elem.exclusions.size() ; i++) { - if (elem.exclusions.get(i)) { - out.writeShort(getNameId(getElement(i).getName())); - } - } - } - - // Inclusions - if (elem.inclusions == null) { - out.writeShort(0); - } else { - short num = 0; - for (int i = 0 ; i < elem.inclusions.size() ; i++) { - if (elem.inclusions.get(i)) { - num++; - } - } - out.writeShort(num); - for (int i = 0 ; i < elem.inclusions.size() ; i++) { - if (elem.inclusions.get(i)) { - out.writeShort(getNameId(getElement(i).getName())); - } - } - } - - // Attributes - { - short numAtts = 0; - for (AttributeList atts = elem.getAttributes() ; atts != null ; atts = atts.getNext()) { - numAtts++; - } - out.writeByte(numAtts); - for (AttributeList atts = elem.getAttributes() ; atts != null ; atts = atts.getNext()) { - out.writeShort(getNameId(atts.getName())); - out.writeByte(atts.getType()); - out.writeByte(atts.getModifier()); - if (atts.getValue() == null) { - out.writeShort(-1); - } else { - out.writeShort(getNameId(atts.getValue())); - } - if (atts.values == null) { - out.writeShort(0); - } else { - out.writeShort((short) atts.values.size()); - for (int i = 0; i < atts.values.size(); i++) { - String s = (String) atts.values.elementAt(i); - out.writeShort(getNameId(s)); - } - } - } - } - } - - - /** - * Save a content model to a stream. This does a - * recursive decent of the entire model. - */ - public void saveContentModel(DataOutputStream out, ContentModel model) throws IOException { - if (model == null) { - out.writeByte(0); - } else if (model.content instanceof ContentModel) { - out.writeByte(1); - out.writeByte(model.type); - saveContentModel(out, (ContentModel)model.content); - - saveContentModel(out, model.next); - } else if (model.content instanceof Element) { - out.writeByte(2); - out.writeByte(model.type); - out.writeShort(getNameId(((Element) model.content).getName())); - - saveContentModel(out, model.next); - } - } - - - /** - * Generate a class representing this DTD. - */ - - public static void main(String argv[]) { - - String dtd_home = System.getProperty("dtd_home") + File.separator; - if (dtd_home == null) { - System.err.println("Must set property 'dtd_home'"); - return; - } - - DTDBuilder dtd = null; - try { - dtd = new DTDBuilder(argv[0]); - mapping = new PublicMapping(dtd_home, "public.map"); - String path = mapping.get(argv[0]); - new DTDParser().parse(new FileInputStream(path), dtd); - - } catch (IOException e) { - System.err.println("Could not open DTD file "+argv[0]); - e.printStackTrace(System.err); - System.exit(1); - } - try { - DataOutputStream str = new DataOutputStream(System.out); - dtd.save(str, argv[0]); - str.close(); - } catch (IOException ex) { - ex.printStackTrace(); - System.exit(1); - } - } - -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/dtdbuilder/DTDBuilder.java 2020-03-23 19:57:00.491962526 +0100 @@ -0,0 +1,313 @@ +/* + * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.dtdbuilder; + +import javax.swing.text.html.parser.*; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.FileNotFoundException; +import java.io.BufferedInputStream; +import java.io.OutputStream; +import java.util.Hashtable; +import java.util.Vector; +import java.util.BitSet; +import java.util.StringTokenizer; +import java.util.Enumeration; +import java.util.Properties; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.Deflater; +import java.net.URL; + +/** + * The representation of an SGML DTD. This is produced by the DTDParser. + * The resulting DTD object describes a document syntax and is needed + * to parse HTML documents using the Parser. It contains a list of + * elements and their attributes as well as a list of entities defined + * in the DTD. + * + * @see Element + * @see AttributeList + * @see ContentModel + * @see DTDParser + * @see Parser + * @author Arthur van Hoff + */ +public +class DTDBuilder extends DTD { + + static PublicMapping mapping = null; + + // Hash from name to Integer + private Hashtable namesHash = new Hashtable<>(); + // Vector of all names + private Vector namesVector = new Vector<>(); + + /** + * Create a new DTD. + */ + protected DTDBuilder(String name) { + super(name); + } + + + /** + * Save to a stream as a Java class. Instantiating this class will + * reproduce a (virtually) identical DTD. + */ + void save(DataOutputStream out, String className) throws IOException { + + out.writeInt(DTD.FILE_VERSION); + + buildNamesTable(); + int numNames = namesVector.size(); + out.writeShort((short) (namesVector.size())); + for (int i = 0; i < namesVector.size(); i++) { + String nm = namesVector.elementAt(i); + out.writeUTF(nm); + } + + saveEntities(out); + + out.writeShort((short) (elements.size())); + for (Enumeration e = elements.elements() ; e.hasMoreElements() ; ) { + saveElement(out, e.nextElement()); + } + + if (namesVector.size() != numNames) { + System.err.println("!!! ERROR! Names were added to the list!"); + Thread.dumpStack(); + System.exit(1); + } + } + + private void buildNamesTable() { + for (Enumeration e = entityHash.elements() ; e.hasMoreElements() ; ) { + Entity ent = e.nextElement(); + // Do even if not isGeneral(). That way, exclusions and inclusions + // will definitely have their element. + getNameId(ent.getName()); + } + for (Enumeration e = elements.elements() ; e.hasMoreElements() ; ) { + Element el = e.nextElement(); + getNameId(el.getName()); + for (AttributeList atts = el.getAttributes() ; atts != null ; atts = atts.getNext()) { + getNameId(atts.getName()); + if (atts.getValue() != null) { + getNameId(atts.getValue()); + } + Enumeration vals = atts.getValues(); + while (vals != null && vals.hasMoreElements()) { + String s = (String) vals.nextElement(); + getNameId(s); + } + } + } + } + + // + // The the id of a name from the list of names + // + private short getNameId(String name) { + Integer o = namesHash.get(name); + if (o != null) { + return (short) o.intValue(); + } + int i = namesVector.size(); + namesVector.addElement(name); + namesHash.put(name, i); + return (short) i; + } + + + /** + * Save an entity to a stream. + */ + void saveEntities(DataOutputStream out) throws IOException { + int num = 0; + for (Enumeration e = entityHash.elements() ; e.hasMoreElements() ; ) { + Entity ent = e.nextElement(); + if (ent.isGeneral()) { + num++; + } + } + + out.writeShort((short) num); + for (Enumeration e = entityHash.elements() ; e.hasMoreElements() ; ) { + Entity ent = e.nextElement(); + if (ent.isGeneral()) { + out.writeShort(getNameId(ent.getName())); + out.writeByte(ent.getType() & ~GENERAL); + out.writeUTF(ent.getString()); + } + } + } + + + /** + * Save an element to a stream. + */ + + public void saveElement(DataOutputStream out, Element elem) throws IOException { + + out.writeShort(getNameId(elem.getName())); + out.writeByte(elem.getType()); + + byte flags = 0; + if (elem.omitStart()) { + flags |= 0x01; + } + if (elem.omitEnd()) { + flags |= 0x02; + } + out.writeByte(flags); + saveContentModel(out, elem.getContent()); + + // Exclusions + if (elem.exclusions == null) { + out.writeShort(0); + } else { + short num = 0; + for (int i = 0 ; i < elem.exclusions.size() ; i++) { + if (elem.exclusions.get(i)) { + num++; + } + } + out.writeShort(num); + for (int i = 0 ; i < elem.exclusions.size() ; i++) { + if (elem.exclusions.get(i)) { + out.writeShort(getNameId(getElement(i).getName())); + } + } + } + + // Inclusions + if (elem.inclusions == null) { + out.writeShort(0); + } else { + short num = 0; + for (int i = 0 ; i < elem.inclusions.size() ; i++) { + if (elem.inclusions.get(i)) { + num++; + } + } + out.writeShort(num); + for (int i = 0 ; i < elem.inclusions.size() ; i++) { + if (elem.inclusions.get(i)) { + out.writeShort(getNameId(getElement(i).getName())); + } + } + } + + // Attributes + { + short numAtts = 0; + for (AttributeList atts = elem.getAttributes() ; atts != null ; atts = atts.getNext()) { + numAtts++; + } + out.writeByte(numAtts); + for (AttributeList atts = elem.getAttributes() ; atts != null ; atts = atts.getNext()) { + out.writeShort(getNameId(atts.getName())); + out.writeByte(atts.getType()); + out.writeByte(atts.getModifier()); + if (atts.getValue() == null) { + out.writeShort(-1); + } else { + out.writeShort(getNameId(atts.getValue())); + } + if (atts.values == null) { + out.writeShort(0); + } else { + out.writeShort((short) atts.values.size()); + for (int i = 0; i < atts.values.size(); i++) { + String s = (String) atts.values.elementAt(i); + out.writeShort(getNameId(s)); + } + } + } + } + } + + + /** + * Save a content model to a stream. This does a + * recursive decent of the entire model. + */ + public void saveContentModel(DataOutputStream out, ContentModel model) throws IOException { + if (model == null) { + out.writeByte(0); + } else if (model.content instanceof ContentModel) { + out.writeByte(1); + out.writeByte(model.type); + saveContentModel(out, (ContentModel)model.content); + + saveContentModel(out, model.next); + } else if (model.content instanceof Element) { + out.writeByte(2); + out.writeByte(model.type); + out.writeShort(getNameId(((Element) model.content).getName())); + + saveContentModel(out, model.next); + } + } + + + /** + * Generate a class representing this DTD. + */ + + public static void main(String argv[]) { + + String dtd_home = System.getProperty("dtd_home") + File.separator; + if (dtd_home == null) { + System.err.println("Must set property 'dtd_home'"); + return; + } + + DTDBuilder dtd = null; + try { + dtd = new DTDBuilder(argv[0]); + mapping = new PublicMapping(dtd_home, "public.map"); + String path = mapping.get(argv[0]); + new DTDParser().parse(new FileInputStream(path), dtd); + + } catch (IOException e) { + System.err.println("Could not open DTD file "+argv[0]); + e.printStackTrace(System.err); + System.exit(1); + } + try { + DataOutputStream str = new DataOutputStream(System.out); + dtd.save(str, argv[0]); + str.close(); + } catch (IOException ex) { + ex.printStackTrace(); + System.exit(1); + } + } + +} --- old/make/jdk/src/classes/build/tools/dtdbuilder/DTDInputStream.java 2020-03-23 19:57:01.811962516 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,206 +0,0 @@ -/* - * Copyright (c) 1998, 2020, 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.dtdbuilder; - -import javax.swing.text.html.parser.*; -import java.io.IOException; -import java.io.FileInputStream; -import java.io.InputStream; -import java.io.Reader; -import java.io.InputStreamReader; -import java.io.CharArrayReader; -import java.io.FilterReader; -import java.util.Stack; -import java.net.URL; - -/** - * A stream for reading HTML files. This stream takes care - * of \r\n conversions and parameter entity expansion. - * - * @see DTD - * @see DTDParser - * @author Arthur van Hoff - * @author Steven B. Byrne - */ -public final -class DTDInputStream extends FilterReader implements DTDConstants { - public DTD dtd; - public Stack stack = new Stack<>(); - public char str[] = new char[64]; - public int replace = 0; - public int ln = 1; - public int ch; - - /** - * Create the stream. - */ - public DTDInputStream(InputStream in, DTD dtd) throws IOException { - super(new InputStreamReader(in)); - this.dtd = dtd; - this.ch = in.read(); - } - - /** - * Error - */ - public void error(String msg) { - System.out.println("line " + ln + ": dtd input error: " + msg); - } - - /** - * Push a single character - */ - public void push(int ch) throws IOException { - char data[] = {(char)ch}; - push(new CharArrayReader(data)); - } - - - /** - * Push an array of bytes. - */ - public void push(char data[]) throws IOException { - if (data.length > 0) { - push(new CharArrayReader(data)); - } - } - - /** - * Push an entire input stream - */ - void push(Reader in) throws IOException { - stack.push(Integer.valueOf(ln)); - stack.push(Integer.valueOf(ch)); - stack.push(this.in); - this.in = in; - ch = in.read(); - } - - /** - * Read a character from the input. Automatically pop - * a stream of the stack if the EOF is reached. Also replaces - * parameter entities. - * [60] 350:22 - */ - @SuppressWarnings("fallthrough") - public int read() throws IOException { - switch (ch) { - case '%': { - ch = in.read(); - if (replace > 0) { - return '%'; - } - - int pos = 0; - while (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) || - ((ch >= '0') && (ch <= '9')) || (ch == '.') || (ch == '-')) { - str[pos++] = (char)ch; - ch = in.read(); - } - if (pos == 0) { - return '%'; - } - - String nm = new String(str, 0, pos); - Entity ent = dtd.getEntity(nm); - if (ent == null) { - error("undefined entity reference: " + nm); - return read(); - } - - // Skip ; or RE - switch (ch) { - case '\r': - ln++; - /* fall through */ - case ';': - ch = in.read(); - break; - case '\n': - ln++; - if ((ch = in.read()) == '\r') { - ch = in.read(); - } - break; - } - - // Push the entity. - try { - push(getEntityInputReader(ent)); - } catch (Exception e) { - error("entity data not found: " + ent + ", " + ent.getString()); - } - return read(); - } - - case '\n': - ln++; - if ((ch = in.read()) == '\r') { - ch = in.read(); - } - return '\n'; - - case '\r': - ln++; - ch = in.read(); - return '\n'; - - case -1: - if (stack.size() > 0) { - in = (Reader)stack.pop(); - ch = ((Integer)stack.pop()).intValue(); - ln = ((Integer)stack.pop()).intValue(); - return read(); - } - return -1; - - default: - int c = ch; - ch = in.read(); - return c; - } - } - - /** - * Return the data as a stream. - */ - private Reader getEntityInputReader(Entity ent) throws IOException { - if ((ent.type & Entity.PUBLIC) != 0) { - // InputStream is = DTDBuilder.mapping.get(ent.getString()).openStream(); - // return new InputStreamReader(is); - String path = DTDBuilder.mapping.get(ent.getString()); - - return new InputStreamReader(new FileInputStream(path)); - } - if ((ent.type & Entity.SYSTEM) != 0) { - //InputStream is = new URL(DTDBuilder.mapping.base, ent.getString()).openStream(); - String path = DTDBuilder.mapping.baseStr + ent.getString(); - return new InputStreamReader(new FileInputStream(path)); - } - return new CharArrayReader(ent.data); - } - -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/dtdbuilder/DTDInputStream.java 2020-03-23 19:57:01.375962519 +0100 @@ -0,0 +1,206 @@ +/* + * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.dtdbuilder; + +import javax.swing.text.html.parser.*; +import java.io.IOException; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.Reader; +import java.io.InputStreamReader; +import java.io.CharArrayReader; +import java.io.FilterReader; +import java.util.Stack; +import java.net.URL; + +/** + * A stream for reading HTML files. This stream takes care + * of \r\n conversions and parameter entity expansion. + * + * @see DTD + * @see DTDParser + * @author Arthur van Hoff + * @author Steven B. Byrne + */ +public final +class DTDInputStream extends FilterReader implements DTDConstants { + public DTD dtd; + public Stack stack = new Stack<>(); + public char str[] = new char[64]; + public int replace = 0; + public int ln = 1; + public int ch; + + /** + * Create the stream. + */ + public DTDInputStream(InputStream in, DTD dtd) throws IOException { + super(new InputStreamReader(in)); + this.dtd = dtd; + this.ch = in.read(); + } + + /** + * Error + */ + public void error(String msg) { + System.out.println("line " + ln + ": dtd input error: " + msg); + } + + /** + * Push a single character + */ + public void push(int ch) throws IOException { + char data[] = {(char)ch}; + push(new CharArrayReader(data)); + } + + + /** + * Push an array of bytes. + */ + public void push(char data[]) throws IOException { + if (data.length > 0) { + push(new CharArrayReader(data)); + } + } + + /** + * Push an entire input stream + */ + void push(Reader in) throws IOException { + stack.push(Integer.valueOf(ln)); + stack.push(Integer.valueOf(ch)); + stack.push(this.in); + this.in = in; + ch = in.read(); + } + + /** + * Read a character from the input. Automatically pop + * a stream of the stack if the EOF is reached. Also replaces + * parameter entities. + * [60] 350:22 + */ + @SuppressWarnings("fallthrough") + public int read() throws IOException { + switch (ch) { + case '%': { + ch = in.read(); + if (replace > 0) { + return '%'; + } + + int pos = 0; + while (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) || + ((ch >= '0') && (ch <= '9')) || (ch == '.') || (ch == '-')) { + str[pos++] = (char)ch; + ch = in.read(); + } + if (pos == 0) { + return '%'; + } + + String nm = new String(str, 0, pos); + Entity ent = dtd.getEntity(nm); + if (ent == null) { + error("undefined entity reference: " + nm); + return read(); + } + + // Skip ; or RE + switch (ch) { + case '\r': + ln++; + /* fall through */ + case ';': + ch = in.read(); + break; + case '\n': + ln++; + if ((ch = in.read()) == '\r') { + ch = in.read(); + } + break; + } + + // Push the entity. + try { + push(getEntityInputReader(ent)); + } catch (Exception e) { + error("entity data not found: " + ent + ", " + ent.getString()); + } + return read(); + } + + case '\n': + ln++; + if ((ch = in.read()) == '\r') { + ch = in.read(); + } + return '\n'; + + case '\r': + ln++; + ch = in.read(); + return '\n'; + + case -1: + if (stack.size() > 0) { + in = (Reader)stack.pop(); + ch = ((Integer)stack.pop()).intValue(); + ln = ((Integer)stack.pop()).intValue(); + return read(); + } + return -1; + + default: + int c = ch; + ch = in.read(); + return c; + } + } + + /** + * Return the data as a stream. + */ + private Reader getEntityInputReader(Entity ent) throws IOException { + if ((ent.type & Entity.PUBLIC) != 0) { + // InputStream is = DTDBuilder.mapping.get(ent.getString()).openStream(); + // return new InputStreamReader(is); + String path = DTDBuilder.mapping.get(ent.getString()); + + return new InputStreamReader(new FileInputStream(path)); + } + if ((ent.type & Entity.SYSTEM) != 0) { + //InputStream is = new URL(DTDBuilder.mapping.base, ent.getString()).openStream(); + String path = DTDBuilder.mapping.baseStr + ent.getString(); + return new InputStreamReader(new FileInputStream(path)); + } + return new CharArrayReader(ent.data); + } + +} --- old/make/jdk/src/classes/build/tools/dtdbuilder/DTDParser.java 2020-03-23 19:57:02.563962510 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,927 +0,0 @@ -/* - * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.dtdbuilder; - -import javax.swing.text.html.parser.*; -import java.net.URL; -import java.io.IOException; -import java.io.InputStream; -import java.util.Enumeration; -import java.util.Vector; -import java.util.Hashtable; -import java.util.BitSet; -import java.text.MessageFormat; - -/** - * A parser for DTDs. This parser roughly corresponds to the - * rules specified in "The SGML Handbook" by Charles F. Goldfarb. - * The end result of parsing the stream is a DTD object. - * - * - * @see DTD - * @see DTDInputStream - * @author Arthur van Hoff - */ -final -class DTDParser implements DTDConstants { - DTDBuilder dtd; - DTDInputStream in; - int ch; - char str[] = new char[128]; - int strpos = 0; - int nerrors = 0; - - /** - * Report an error. - */ - void error(String err, String arg1, String arg2, String arg3) { - nerrors++; - - String msgParams[] = {arg1, arg2, arg3}; - - String str = getSubstProp("dtderr." + err, msgParams); - if (str == null) { - str = err + "[" + arg1 + "," + arg2 + "," + arg3 + "]"; - } - System.err.println("line " + in.ln + ", dtd " + dtd + ": " + str); - } - void error(String err, String arg1, String arg2) { - error(err, arg1, arg2, "?"); - } - void error(String err, String arg1) { - error(err, arg1, "?", "?"); - } - void error(String err) { - error(err, "?", "?", "?"); - } - - private String getSubstProp(String propName, String args[]) { - String prop = System.getProperty(propName); - - if (prop == null) { - return null; - } - - return MessageFormat.format(prop, (Object[])args); - } - - /** - * Expect a character. - */ - boolean expect(int c) throws IOException { - if (ch != c) { - char str[] = {(char)c}; - error("expected", "'" + new String(str) + "'"); - return false; - } - ch = in.read(); - return true; - } - - /** - * Add a char to the string buffer. - */ - void addString(int c) { - if (strpos == str.length) { - char newstr[] = new char[str.length * 2]; - System.arraycopy(str, 0, newstr, 0, str.length); - str = newstr; - } - str[strpos++] = (char)c; - } - - /** - * Get the string which was accumulated in the buffer. - * Pos is the starting position of the string. - */ - String getString(int pos) { - char newstr[] = new char[strpos - pos]; - System.arraycopy(str, pos, newstr, 0, strpos - pos); - strpos = pos; - return new String(newstr); - } - - /** - * Get the chars which were accumulated in the buffer. - * Pos is the starting position of the string. - */ - char[] getChars(int pos) { - char newstr[] = new char[strpos - pos]; - System.arraycopy(str, pos, newstr, 0, strpos - pos); - strpos = pos; - return newstr; - } - - /** - * Skip spaces. [5] 297:23 - */ - void skipSpace() throws IOException { - while (true) { - switch (ch) { - case '\n': - case ' ': - case '\t': - ch = in.read(); - break; - - default: - return; - } - } - } - - /** - * Skip tag spaces (includes comments). [65] 372:1 - */ - void skipParameterSpace() throws IOException { - while (true) { - switch (ch) { - case '\n': - case ' ': - case '\t': - ch = in.read(); - break; - case '-': - if ((ch = in.read()) != '-') { - in.push(ch); - ch = '-'; - return; - } - - in.replace++; - while (true) { - switch (ch = in.read()) { - case '-': - if ((ch = in.read()) == '-') { - ch = in.read(); - in.replace--; - skipParameterSpace(); - return; - } - break; - - case -1: - error("eof.arg", "comment"); - in.replace--; - return; - } - } - default: - return; - } - } - } - - /** - * Parse identifier. Uppercase characters are automatically - * folded to lowercase. Returns falsed if no identifier is found. - */ - @SuppressWarnings("fallthrough") - boolean parseIdentifier(boolean lower) throws IOException { - switch (ch) { - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': - case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': - case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': - case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': - case 'Y': case 'Z': - if (lower) { - ch = 'a' + (ch - 'A'); - } - /* fall through */ - - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': - case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': - case 's': case 't': case 'u': case 'v': case 'w': case 'x': - case 'y': case 'z': - break; - - default: - return false; - } - - addString(ch); - ch = in.read(); - parseNameToken(lower); - return true; - } - - /** - * Parses name token. If lower is true, upper case letters - * are folded to lower case. Returns falsed if no token is found. - */ - @SuppressWarnings("fallthrough") - boolean parseNameToken(boolean lower) throws IOException { - boolean first = true; - - while (true) { - switch (ch) { - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': - case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': - case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': - case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': - case 'Y': case 'Z': - if (lower) { - ch = 'a' + (ch - 'A'); - } - /* fall through */ - - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': - case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': - case 's': case 't': case 'u': case 'v': case 'w': case 'x': - case 'y': case 'z': - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - - case '.': case '-': - addString(ch); - ch = in.read(); - first = false; - break; - - default: - return !first; - } - } - } - - /** - * Parse a list of identifiers. - */ - Vector parseIdentifierList(boolean lower) throws IOException { - Vector elems = new Vector<>(); - skipSpace(); - switch (ch) { - case '(': - ch = in.read(); - skipParameterSpace(); - while (parseNameToken(lower)) { - elems.addElement(getString(0)); - skipParameterSpace(); - if (ch == '|') { - ch = in.read(); - skipParameterSpace(); - } - } - expect(')'); - skipParameterSpace(); - break; - - default: - if (!parseIdentifier(lower)) { - error("expected", "identifier"); - break; - } - elems.addElement(getString(0)); - skipParameterSpace(); - break; - } - return elems; - } - - /** - * Parse and Entity reference. Should be called when - * a & is encountered. The data is put in the string buffer. - * [59] 350:17 - */ - private void parseEntityReference() throws IOException { - int pos = strpos; - - if ((ch = in.read()) == '#') { - int n = 0; - ch = in.read(); - if (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z'))) { - addString('#'); - } else { - while ((ch >= '0') && (ch <= '9')) { - n = (n * 10) + ch - '0'; - ch = in.read(); - } - if ((ch == ';') || (ch == '\n')) { - ch = in.read(); - } - addString(n); - return; - } - } - - while (true) { - switch (ch) { - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': - case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': - case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': - case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': - case 'Y': case 'Z': - - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': - case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': - case 's': case 't': case 'u': case 'v': case 'w': case 'x': - case 'y': case 'z': - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - - case '.': case '-': - addString(ch); - ch = in.read(); - break; - - default: - if (strpos == pos) { - addString('&'); - return; - } - String nm = getString(pos); - Entity ent = dtd.getEntity(nm); - if (ent == null) { - error("undef.entref" + nm); - return; - } - if ((ch == ';') || (ch == '\n')) { - ch = in.read(); - } - char data[] = ent.getData(); - for (int i = 0 ; i < data.length ; i++) { - addString(data[i]); - } - return; - } - } - } - - /** - * Parse an entity declaration. - * [101] 394:18 - * REMIND: external entity type - */ - private void parseEntityDeclaration() throws IOException { - int type = GENERAL; - - skipSpace(); - if (ch == '%') { - ch = in.read(); - type = PARAMETER; - skipSpace(); - } - if (ch == '#') { - addString('#'); - ch = in.read(); - } - if (!parseIdentifier(false)) { - error("expected", "identifier"); - return; - } - String nm = getString(0); - skipParameterSpace(); - if (parseIdentifier(false)) { - String tnm = getString(0); - int t = Entity.name2type(tnm); - if (t == 0) { - error("invalid.arg", "entity type", tnm); - } else { - type |= t; - } - skipParameterSpace(); - } - - if ((ch != '"') && (ch != '\'')) { - error("expected", "entity value"); - skipParameterSpace(); - if (ch == '>') { - ch = in.read(); - } - return; - } - - int term = ch; - ch = in.read(); - while ((ch != -1) && (ch != term)) { - if (ch == '&') { - parseEntityReference(); - } else { - addString(ch & 0xFF); - ch = in.read(); - } - } - if (ch == term) { - ch = in.read(); - } - if (in.replace == 0) { - char data[] = getChars(0); - dtd.defineEntity(nm, type, data); - } else { - strpos = 0; - } - skipParameterSpace(); - expect('>'); - } - - /** - * Parse content model. - * [126] 410:1 - * REMIND: data tag group - */ - ContentModel parseContentModel() throws IOException { - ContentModel m = null; - - switch (ch) { - case '(': - ch = in.read(); - skipParameterSpace(); - ContentModel e = parseContentModel(); - - if (ch != ')') { - m = new ContentModel(ch, e); - do { - ch = in.read(); - skipParameterSpace(); - e.next = parseContentModel(); - if (e.next.type == m.type) { - e.next = (ContentModel)e.next.content; - } - for (; e.next != null ; e = e.next); - } while (ch == m.type); - } else { - m = new ContentModel(',', e); - } - expect(')'); - break; - - case '#': - ch = in.read(); - if (parseIdentifier(true)) { - m = new ContentModel('*', new ContentModel(dtd.getElement("#" + getString(0)))); - } else { - error("invalid", "content model"); - } - break; - - default: - if (parseIdentifier(true)) { - m = new ContentModel(dtd.getElement(getString(0))); - } else { - error("invalid", "content model"); - } - break; - } - - switch (ch) { - case '?': - case '*': - case '+': - m = new ContentModel(ch, m); - ch = in.read(); - break; - } - skipParameterSpace(); - - return m; - } - - /** - * Parse element declaration. - * [116] 405:6 - */ - void parseElementDeclaration() throws IOException { - Vector elems = parseIdentifierList(true); - BitSet inclusions = null; - BitSet exclusions = null; - boolean omitStart = false; - boolean omitEnd = false; - - if ((ch == '-') || (ch == 'O')) { - omitStart = ch == 'O'; - ch = in.read(); - skipParameterSpace(); - - if ((ch == '-') || (ch == 'O')) { - omitEnd = ch == 'O'; - ch = in.read(); - skipParameterSpace(); - } else { - expect('-'); - } - } - - int type = MODEL; - ContentModel content = null; - if (parseIdentifier(false)) { - String nm = getString(0); - type = Element.name2type(nm); - if (type == 0) { - error("invalid.arg", "content type", nm); - type = EMPTY; - } - skipParameterSpace(); - } else { - content = parseContentModel(); - } - - if ((type == MODEL) || (type == ANY)) { - if (ch == '-') { - ch = in.read(); - Vector v = parseIdentifierList(true); - exclusions = new BitSet(); - for (Enumeration e = v.elements() ; e.hasMoreElements() ;) { - exclusions.set(dtd.getElement(e.nextElement()).getIndex()); - } - } - if (ch == '+') { - ch = in.read(); - Vector v = parseIdentifierList(true); - inclusions = new BitSet(); - for (Enumeration e = v.elements() ; e.hasMoreElements() ;) { - inclusions.set(dtd.getElement(e.nextElement()).getIndex()); - } - } - } - expect('>'); - - if (in.replace == 0) { - for (Enumeration e = elems.elements() ; e.hasMoreElements() ;) { - dtd.defineElement(e.nextElement(), type, omitStart, omitEnd, content, exclusions, inclusions, null); - } - } - } - - /** - * Parse an attribute declared value. - * [145] 422:6 - */ - void parseAttributeDeclaredValue(AttributeList atts) throws IOException { - if (ch == '(') { - atts.values = parseIdentifierList(true); - atts.type = NMTOKEN; - return; - } - if (!parseIdentifier(false)) { - error("invalid", "attribute value"); - return; - } - atts.type = AttributeList.name2type(getString(0)); - skipParameterSpace(); - if (atts.type == NOTATION) { - atts.values = parseIdentifierList(true); - } - } - - /** - * Parse an attribute value specification. - * [33] 331:1 - */ - @SuppressWarnings("fallthrough") - String parseAttributeValueSpecification() throws IOException { - int delim = -1; - switch (ch) { - case '\'': - case '"': - delim = ch; - ch = in.read(); - } - while (true) { - switch (ch) { - case -1: - error("eof.arg", "attribute value"); - return getString(0); - - case '&': - parseEntityReference(); - break; - - case ' ': - case '\t': - case '\n': - if (delim == -1) { - return getString(0); - } - addString(' '); - ch = in.read(); - break; - - case '\'': - case '"': - if (delim == ch) { - ch = in.read(); - return getString(0); - } - /* fall through */ - - default: - addString(ch & 0xFF); - ch = in.read(); - break; - } - } - } - - /** - * Parse an attribute default value. - * [147] 425:1 - */ - void parseAttributeDefaultValue(AttributeList atts) throws IOException { - if (ch == '#') { - ch = in.read(); - if (!parseIdentifier(true)) { - error("invalid", "attribute value"); - return; - } - skipParameterSpace(); - atts.modifier = AttributeList.name2type(getString(0)); - if (atts.modifier != FIXED) { - return; - } - } - atts.value = parseAttributeValueSpecification(); - skipParameterSpace(); - } - - /** - * Parse an attribute definition list declaration. - * [141] 420:15 - * REMIND: associated notation name - */ - void parseAttlistDeclaration() throws IOException { - Vector elems = parseIdentifierList(true); - AttributeList attlist = null, atts = null; - - while (parseIdentifier(true)) { - if (atts == null) { - attlist = atts = new AttributeList(getString(0)); - } else { - atts.next = new AttributeList(getString(0)); - atts = atts.next; - } - skipParameterSpace(); - parseAttributeDeclaredValue(atts); - parseAttributeDefaultValue(atts); - - if ((atts.modifier == IMPLIED) && (atts.values != null) && (atts.values.size() == 1)) { - atts.value = (String)atts.values.elementAt(0); - } - } - - expect('>'); - - if (in.replace == 0) { - for (Enumeration e = elems.elements() ; e.hasMoreElements() ;) { - dtd.defineAttributes(e.nextElement(), attlist); - } - } - } - - /** - * Parse an ignored section until ]]> is encountered. - */ - void parseIgnoredSection() throws IOException { - int depth = 1; - in.replace++; - while (true) { - switch (ch) { - case '<': - if ((ch = in.read()) == '!') { - if ((ch = in.read()) == '[') { - ch = in.read(); - depth++; - } - } - break; - case ']': - if ((ch = in.read()) == ']') { - if ((ch = in.read()) == '>') { - ch = in.read(); - if (--depth == 0) { - in.replace--; - return; - } - } - } - break; - case -1: - error("eof"); - in.replace--; - return; - - default: - ch = in.read(); - break; - } - } - } - - /** - * Parse a marked section declaration. - * [93] 391:13 - * REMIND: deal with all status keywords - */ - void parseMarkedSectionDeclaration() throws IOException { - ch = in.read(); - skipSpace(); - if (!parseIdentifier(true)) { - error("expected", "section status keyword"); - return; - } - String str = getString(0); - skipSpace(); - expect('['); - if ("ignore".equals(str)) { - parseIgnoredSection(); - } else { - if (!"include".equals(str)) { - error("invalid.arg", "section status keyword", str); - } - parseSection(); - expect(']'); - expect(']'); - expect('>'); - } - } - - /** - * Parse an external identifier - * [73] 379:1 - */ - void parseExternalIdentifier() throws IOException { - if (parseIdentifier(false)) { - String id = getString(0); - skipParameterSpace(); - - if (id.equals("PUBLIC")) { - if ((ch == '\'') || (ch == '"')) { - parseAttributeValueSpecification(); - } else { - error("expected", "public identifier"); - } - skipParameterSpace(); - } else if (!id.equals("SYSTEM")) { - error("invalid", "external identifier"); - } - if ((ch == '\'') || (ch == '"')) { - parseAttributeValueSpecification(); - } - skipParameterSpace(); - } - } - - /** - * Parse document type declaration. - * [110] 403:1 - */ - void parseDocumentTypeDeclaration() throws IOException { - skipParameterSpace(); - if (!parseIdentifier(true)) { - error("expected", "identifier"); - } else { - skipParameterSpace(); - } - strpos = 0; - parseExternalIdentifier(); - - if (ch == '[') { - ch = in.read(); - parseSection(); - expect(']'); - skipParameterSpace(); - } - expect('>'); - } - - /** - * Parse a section of the input upto EOF or ']'. - */ - @SuppressWarnings("fallthrough") - void parseSection() throws IOException { - while (true) { - switch (ch) { - case ']': - return; - - case '<': - switch (ch = in.read()) { - case '!': - switch (ch = in.read()) { - case '[': - parseMarkedSectionDeclaration(); - break; - - case '-': - skipParameterSpace(); - expect('>'); - break; - - default: - if (parseIdentifier(true)) { - String str = getString(0); - - if (str.equals("element")) { - parseElementDeclaration(); - - } else if (str.equals("entity")) { - parseEntityDeclaration(); - - } else if (str.equals("attlist")) { - parseAttlistDeclaration(); - - } else if (str.equals("doctype")) { - parseDocumentTypeDeclaration(); - - } else if (str.equals("usemap")) { - error("ignoring", "usemap"); - while ((ch != -1) && (ch != '>')) { - ch = in.read(); - } - expect('>'); - } else if (str.equals("shortref")) { - error("ignoring", "shortref"); - while ((ch != -1) && (ch != '>')) { - ch = in.read(); - } - expect('>'); - } else if (str.equals("notation")) { - error("ignoring", "notation"); - while ((ch != -1) && (ch != '>')) { - ch = in.read(); - } - expect('>'); - } else { - error("markup"); - } - } else { - error("markup"); - while ((ch != -1) && (ch != '>')) { - ch = in.read(); - } - expect('>'); - } - } - } - break; - - case -1: - return; - - default: - char str[] = {(char)ch}; - error("invalid.arg", "character", "'" + new String(str) + "' / " + ch); - /* fall through */ - - case ' ': - case '\t': - case '\n': - ch = in.read(); - break; - } - } - } - - /** - * Parse a DTD. - * @return the dtd or null if an error occurred. - */ - DTD parse(InputStream in, DTDBuilder dtd) { - try { - this.dtd = dtd; - this.in = new DTDInputStream(in, dtd); - - ch = this.in.read(); - parseSection(); - - if (ch != -1) { - error("premature"); - } - } catch (IOException e) { - error("ioexception"); - } catch (Exception e) { - error("exception", e.getClass().getName(), e.getMessage()); - e.printStackTrace(); - } catch (ThreadDeath e) { - error("terminated"); - } - return (nerrors > 0) ? null : dtd; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/dtdbuilder/DTDParser.java 2020-03-23 19:57:02.195962513 +0100 @@ -0,0 +1,927 @@ +/* + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.dtdbuilder; + +import javax.swing.text.html.parser.*; +import java.net.URL; +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.Vector; +import java.util.Hashtable; +import java.util.BitSet; +import java.text.MessageFormat; + +/** + * A parser for DTDs. This parser roughly corresponds to the + * rules specified in "The SGML Handbook" by Charles F. Goldfarb. + * The end result of parsing the stream is a DTD object. + * + * + * @see DTD + * @see DTDInputStream + * @author Arthur van Hoff + */ +final +class DTDParser implements DTDConstants { + DTDBuilder dtd; + DTDInputStream in; + int ch; + char str[] = new char[128]; + int strpos = 0; + int nerrors = 0; + + /** + * Report an error. + */ + void error(String err, String arg1, String arg2, String arg3) { + nerrors++; + + String msgParams[] = {arg1, arg2, arg3}; + + String str = getSubstProp("dtderr." + err, msgParams); + if (str == null) { + str = err + "[" + arg1 + "," + arg2 + "," + arg3 + "]"; + } + System.err.println("line " + in.ln + ", dtd " + dtd + ": " + str); + } + void error(String err, String arg1, String arg2) { + error(err, arg1, arg2, "?"); + } + void error(String err, String arg1) { + error(err, arg1, "?", "?"); + } + void error(String err) { + error(err, "?", "?", "?"); + } + + private String getSubstProp(String propName, String args[]) { + String prop = System.getProperty(propName); + + if (prop == null) { + return null; + } + + return MessageFormat.format(prop, (Object[])args); + } + + /** + * Expect a character. + */ + boolean expect(int c) throws IOException { + if (ch != c) { + char str[] = {(char)c}; + error("expected", "'" + new String(str) + "'"); + return false; + } + ch = in.read(); + return true; + } + + /** + * Add a char to the string buffer. + */ + void addString(int c) { + if (strpos == str.length) { + char newstr[] = new char[str.length * 2]; + System.arraycopy(str, 0, newstr, 0, str.length); + str = newstr; + } + str[strpos++] = (char)c; + } + + /** + * Get the string which was accumulated in the buffer. + * Pos is the starting position of the string. + */ + String getString(int pos) { + char newstr[] = new char[strpos - pos]; + System.arraycopy(str, pos, newstr, 0, strpos - pos); + strpos = pos; + return new String(newstr); + } + + /** + * Get the chars which were accumulated in the buffer. + * Pos is the starting position of the string. + */ + char[] getChars(int pos) { + char newstr[] = new char[strpos - pos]; + System.arraycopy(str, pos, newstr, 0, strpos - pos); + strpos = pos; + return newstr; + } + + /** + * Skip spaces. [5] 297:23 + */ + void skipSpace() throws IOException { + while (true) { + switch (ch) { + case '\n': + case ' ': + case '\t': + ch = in.read(); + break; + + default: + return; + } + } + } + + /** + * Skip tag spaces (includes comments). [65] 372:1 + */ + void skipParameterSpace() throws IOException { + while (true) { + switch (ch) { + case '\n': + case ' ': + case '\t': + ch = in.read(); + break; + case '-': + if ((ch = in.read()) != '-') { + in.push(ch); + ch = '-'; + return; + } + + in.replace++; + while (true) { + switch (ch = in.read()) { + case '-': + if ((ch = in.read()) == '-') { + ch = in.read(); + in.replace--; + skipParameterSpace(); + return; + } + break; + + case -1: + error("eof.arg", "comment"); + in.replace--; + return; + } + } + default: + return; + } + } + } + + /** + * Parse identifier. Uppercase characters are automatically + * folded to lowercase. Returns falsed if no identifier is found. + */ + @SuppressWarnings("fallthrough") + boolean parseIdentifier(boolean lower) throws IOException { + switch (ch) { + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': + case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': + case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': + case 'Y': case 'Z': + if (lower) { + ch = 'a' + (ch - 'A'); + } + /* fall through */ + + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': + case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': + case 's': case 't': case 'u': case 'v': case 'w': case 'x': + case 'y': case 'z': + break; + + default: + return false; + } + + addString(ch); + ch = in.read(); + parseNameToken(lower); + return true; + } + + /** + * Parses name token. If lower is true, upper case letters + * are folded to lower case. Returns falsed if no token is found. + */ + @SuppressWarnings("fallthrough") + boolean parseNameToken(boolean lower) throws IOException { + boolean first = true; + + while (true) { + switch (ch) { + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': + case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': + case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': + case 'Y': case 'Z': + if (lower) { + ch = 'a' + (ch - 'A'); + } + /* fall through */ + + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': + case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': + case 's': case 't': case 'u': case 'v': case 'w': case 'x': + case 'y': case 'z': + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + + case '.': case '-': + addString(ch); + ch = in.read(); + first = false; + break; + + default: + return !first; + } + } + } + + /** + * Parse a list of identifiers. + */ + Vector parseIdentifierList(boolean lower) throws IOException { + Vector elems = new Vector<>(); + skipSpace(); + switch (ch) { + case '(': + ch = in.read(); + skipParameterSpace(); + while (parseNameToken(lower)) { + elems.addElement(getString(0)); + skipParameterSpace(); + if (ch == '|') { + ch = in.read(); + skipParameterSpace(); + } + } + expect(')'); + skipParameterSpace(); + break; + + default: + if (!parseIdentifier(lower)) { + error("expected", "identifier"); + break; + } + elems.addElement(getString(0)); + skipParameterSpace(); + break; + } + return elems; + } + + /** + * Parse and Entity reference. Should be called when + * a & is encountered. The data is put in the string buffer. + * [59] 350:17 + */ + private void parseEntityReference() throws IOException { + int pos = strpos; + + if ((ch = in.read()) == '#') { + int n = 0; + ch = in.read(); + if (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z'))) { + addString('#'); + } else { + while ((ch >= '0') && (ch <= '9')) { + n = (n * 10) + ch - '0'; + ch = in.read(); + } + if ((ch == ';') || (ch == '\n')) { + ch = in.read(); + } + addString(n); + return; + } + } + + while (true) { + switch (ch) { + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': + case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': + case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': + case 'Y': case 'Z': + + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': + case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': + case 's': case 't': case 'u': case 'v': case 'w': case 'x': + case 'y': case 'z': + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + + case '.': case '-': + addString(ch); + ch = in.read(); + break; + + default: + if (strpos == pos) { + addString('&'); + return; + } + String nm = getString(pos); + Entity ent = dtd.getEntity(nm); + if (ent == null) { + error("undef.entref" + nm); + return; + } + if ((ch == ';') || (ch == '\n')) { + ch = in.read(); + } + char data[] = ent.getData(); + for (int i = 0 ; i < data.length ; i++) { + addString(data[i]); + } + return; + } + } + } + + /** + * Parse an entity declaration. + * [101] 394:18 + * REMIND: external entity type + */ + private void parseEntityDeclaration() throws IOException { + int type = GENERAL; + + skipSpace(); + if (ch == '%') { + ch = in.read(); + type = PARAMETER; + skipSpace(); + } + if (ch == '#') { + addString('#'); + ch = in.read(); + } + if (!parseIdentifier(false)) { + error("expected", "identifier"); + return; + } + String nm = getString(0); + skipParameterSpace(); + if (parseIdentifier(false)) { + String tnm = getString(0); + int t = Entity.name2type(tnm); + if (t == 0) { + error("invalid.arg", "entity type", tnm); + } else { + type |= t; + } + skipParameterSpace(); + } + + if ((ch != '"') && (ch != '\'')) { + error("expected", "entity value"); + skipParameterSpace(); + if (ch == '>') { + ch = in.read(); + } + return; + } + + int term = ch; + ch = in.read(); + while ((ch != -1) && (ch != term)) { + if (ch == '&') { + parseEntityReference(); + } else { + addString(ch & 0xFF); + ch = in.read(); + } + } + if (ch == term) { + ch = in.read(); + } + if (in.replace == 0) { + char data[] = getChars(0); + dtd.defineEntity(nm, type, data); + } else { + strpos = 0; + } + skipParameterSpace(); + expect('>'); + } + + /** + * Parse content model. + * [126] 410:1 + * REMIND: data tag group + */ + ContentModel parseContentModel() throws IOException { + ContentModel m = null; + + switch (ch) { + case '(': + ch = in.read(); + skipParameterSpace(); + ContentModel e = parseContentModel(); + + if (ch != ')') { + m = new ContentModel(ch, e); + do { + ch = in.read(); + skipParameterSpace(); + e.next = parseContentModel(); + if (e.next.type == m.type) { + e.next = (ContentModel)e.next.content; + } + for (; e.next != null ; e = e.next); + } while (ch == m.type); + } else { + m = new ContentModel(',', e); + } + expect(')'); + break; + + case '#': + ch = in.read(); + if (parseIdentifier(true)) { + m = new ContentModel('*', new ContentModel(dtd.getElement("#" + getString(0)))); + } else { + error("invalid", "content model"); + } + break; + + default: + if (parseIdentifier(true)) { + m = new ContentModel(dtd.getElement(getString(0))); + } else { + error("invalid", "content model"); + } + break; + } + + switch (ch) { + case '?': + case '*': + case '+': + m = new ContentModel(ch, m); + ch = in.read(); + break; + } + skipParameterSpace(); + + return m; + } + + /** + * Parse element declaration. + * [116] 405:6 + */ + void parseElementDeclaration() throws IOException { + Vector elems = parseIdentifierList(true); + BitSet inclusions = null; + BitSet exclusions = null; + boolean omitStart = false; + boolean omitEnd = false; + + if ((ch == '-') || (ch == 'O')) { + omitStart = ch == 'O'; + ch = in.read(); + skipParameterSpace(); + + if ((ch == '-') || (ch == 'O')) { + omitEnd = ch == 'O'; + ch = in.read(); + skipParameterSpace(); + } else { + expect('-'); + } + } + + int type = MODEL; + ContentModel content = null; + if (parseIdentifier(false)) { + String nm = getString(0); + type = Element.name2type(nm); + if (type == 0) { + error("invalid.arg", "content type", nm); + type = EMPTY; + } + skipParameterSpace(); + } else { + content = parseContentModel(); + } + + if ((type == MODEL) || (type == ANY)) { + if (ch == '-') { + ch = in.read(); + Vector v = parseIdentifierList(true); + exclusions = new BitSet(); + for (Enumeration e = v.elements() ; e.hasMoreElements() ;) { + exclusions.set(dtd.getElement(e.nextElement()).getIndex()); + } + } + if (ch == '+') { + ch = in.read(); + Vector v = parseIdentifierList(true); + inclusions = new BitSet(); + for (Enumeration e = v.elements() ; e.hasMoreElements() ;) { + inclusions.set(dtd.getElement(e.nextElement()).getIndex()); + } + } + } + expect('>'); + + if (in.replace == 0) { + for (Enumeration e = elems.elements() ; e.hasMoreElements() ;) { + dtd.defineElement(e.nextElement(), type, omitStart, omitEnd, content, exclusions, inclusions, null); + } + } + } + + /** + * Parse an attribute declared value. + * [145] 422:6 + */ + void parseAttributeDeclaredValue(AttributeList atts) throws IOException { + if (ch == '(') { + atts.values = parseIdentifierList(true); + atts.type = NMTOKEN; + return; + } + if (!parseIdentifier(false)) { + error("invalid", "attribute value"); + return; + } + atts.type = AttributeList.name2type(getString(0)); + skipParameterSpace(); + if (atts.type == NOTATION) { + atts.values = parseIdentifierList(true); + } + } + + /** + * Parse an attribute value specification. + * [33] 331:1 + */ + @SuppressWarnings("fallthrough") + String parseAttributeValueSpecification() throws IOException { + int delim = -1; + switch (ch) { + case '\'': + case '"': + delim = ch; + ch = in.read(); + } + while (true) { + switch (ch) { + case -1: + error("eof.arg", "attribute value"); + return getString(0); + + case '&': + parseEntityReference(); + break; + + case ' ': + case '\t': + case '\n': + if (delim == -1) { + return getString(0); + } + addString(' '); + ch = in.read(); + break; + + case '\'': + case '"': + if (delim == ch) { + ch = in.read(); + return getString(0); + } + /* fall through */ + + default: + addString(ch & 0xFF); + ch = in.read(); + break; + } + } + } + + /** + * Parse an attribute default value. + * [147] 425:1 + */ + void parseAttributeDefaultValue(AttributeList atts) throws IOException { + if (ch == '#') { + ch = in.read(); + if (!parseIdentifier(true)) { + error("invalid", "attribute value"); + return; + } + skipParameterSpace(); + atts.modifier = AttributeList.name2type(getString(0)); + if (atts.modifier != FIXED) { + return; + } + } + atts.value = parseAttributeValueSpecification(); + skipParameterSpace(); + } + + /** + * Parse an attribute definition list declaration. + * [141] 420:15 + * REMIND: associated notation name + */ + void parseAttlistDeclaration() throws IOException { + Vector elems = parseIdentifierList(true); + AttributeList attlist = null, atts = null; + + while (parseIdentifier(true)) { + if (atts == null) { + attlist = atts = new AttributeList(getString(0)); + } else { + atts.next = new AttributeList(getString(0)); + atts = atts.next; + } + skipParameterSpace(); + parseAttributeDeclaredValue(atts); + parseAttributeDefaultValue(atts); + + if ((atts.modifier == IMPLIED) && (atts.values != null) && (atts.values.size() == 1)) { + atts.value = (String)atts.values.elementAt(0); + } + } + + expect('>'); + + if (in.replace == 0) { + for (Enumeration e = elems.elements() ; e.hasMoreElements() ;) { + dtd.defineAttributes(e.nextElement(), attlist); + } + } + } + + /** + * Parse an ignored section until ]]> is encountered. + */ + void parseIgnoredSection() throws IOException { + int depth = 1; + in.replace++; + while (true) { + switch (ch) { + case '<': + if ((ch = in.read()) == '!') { + if ((ch = in.read()) == '[') { + ch = in.read(); + depth++; + } + } + break; + case ']': + if ((ch = in.read()) == ']') { + if ((ch = in.read()) == '>') { + ch = in.read(); + if (--depth == 0) { + in.replace--; + return; + } + } + } + break; + case -1: + error("eof"); + in.replace--; + return; + + default: + ch = in.read(); + break; + } + } + } + + /** + * Parse a marked section declaration. + * [93] 391:13 + * REMIND: deal with all status keywords + */ + void parseMarkedSectionDeclaration() throws IOException { + ch = in.read(); + skipSpace(); + if (!parseIdentifier(true)) { + error("expected", "section status keyword"); + return; + } + String str = getString(0); + skipSpace(); + expect('['); + if ("ignore".equals(str)) { + parseIgnoredSection(); + } else { + if (!"include".equals(str)) { + error("invalid.arg", "section status keyword", str); + } + parseSection(); + expect(']'); + expect(']'); + expect('>'); + } + } + + /** + * Parse an external identifier + * [73] 379:1 + */ + void parseExternalIdentifier() throws IOException { + if (parseIdentifier(false)) { + String id = getString(0); + skipParameterSpace(); + + if (id.equals("PUBLIC")) { + if ((ch == '\'') || (ch == '"')) { + parseAttributeValueSpecification(); + } else { + error("expected", "public identifier"); + } + skipParameterSpace(); + } else if (!id.equals("SYSTEM")) { + error("invalid", "external identifier"); + } + if ((ch == '\'') || (ch == '"')) { + parseAttributeValueSpecification(); + } + skipParameterSpace(); + } + } + + /** + * Parse document type declaration. + * [110] 403:1 + */ + void parseDocumentTypeDeclaration() throws IOException { + skipParameterSpace(); + if (!parseIdentifier(true)) { + error("expected", "identifier"); + } else { + skipParameterSpace(); + } + strpos = 0; + parseExternalIdentifier(); + + if (ch == '[') { + ch = in.read(); + parseSection(); + expect(']'); + skipParameterSpace(); + } + expect('>'); + } + + /** + * Parse a section of the input upto EOF or ']'. + */ + @SuppressWarnings("fallthrough") + void parseSection() throws IOException { + while (true) { + switch (ch) { + case ']': + return; + + case '<': + switch (ch = in.read()) { + case '!': + switch (ch = in.read()) { + case '[': + parseMarkedSectionDeclaration(); + break; + + case '-': + skipParameterSpace(); + expect('>'); + break; + + default: + if (parseIdentifier(true)) { + String str = getString(0); + + if (str.equals("element")) { + parseElementDeclaration(); + + } else if (str.equals("entity")) { + parseEntityDeclaration(); + + } else if (str.equals("attlist")) { + parseAttlistDeclaration(); + + } else if (str.equals("doctype")) { + parseDocumentTypeDeclaration(); + + } else if (str.equals("usemap")) { + error("ignoring", "usemap"); + while ((ch != -1) && (ch != '>')) { + ch = in.read(); + } + expect('>'); + } else if (str.equals("shortref")) { + error("ignoring", "shortref"); + while ((ch != -1) && (ch != '>')) { + ch = in.read(); + } + expect('>'); + } else if (str.equals("notation")) { + error("ignoring", "notation"); + while ((ch != -1) && (ch != '>')) { + ch = in.read(); + } + expect('>'); + } else { + error("markup"); + } + } else { + error("markup"); + while ((ch != -1) && (ch != '>')) { + ch = in.read(); + } + expect('>'); + } + } + } + break; + + case -1: + return; + + default: + char str[] = {(char)ch}; + error("invalid.arg", "character", "'" + new String(str) + "' / " + ch); + /* fall through */ + + case ' ': + case '\t': + case '\n': + ch = in.read(); + break; + } + } + } + + /** + * Parse a DTD. + * @return the dtd or null if an error occurred. + */ + DTD parse(InputStream in, DTDBuilder dtd) { + try { + this.dtd = dtd; + this.in = new DTDInputStream(in, dtd); + + ch = this.in.read(); + parseSection(); + + if (ch != -1) { + error("premature"); + } + } catch (IOException e) { + error("ioexception"); + } catch (Exception e) { + error("exception", e.getClass().getName(), e.getMessage()); + e.printStackTrace(); + } catch (ThreadDeath e) { + error("terminated"); + } + return (nerrors > 0) ? null : dtd; + } +} --- old/make/jdk/src/classes/build/tools/dtdbuilder/PublicMapping.java 2020-03-23 19:57:03.431962504 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,108 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.dtdbuilder; - -import javax.swing.text.html.parser.*; -import java.io.File; -import java.io.IOException; -import java.io.FileInputStream; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.BufferedReader; -import java.util.Hashtable; - -/** - * A class for mapping public identifiers to locations. - * Note: I'm not sure if there is a more natural mapping - * then this. Maybe we should use properties instead? - * - * @author Arthur van Hoff - */ -final class PublicMapping { - - String baseStr; - Hashtable tab = new Hashtable<>(); - - /** - * Create a mapping. - */ - public PublicMapping (String baseStr, String mapFile) throws IOException { - // System.err.println("start loading " + baseStr); - this.baseStr = baseStr; - load(new FileInputStream(baseStr+mapFile)); - // System.err.println("stop loading"); - } - - /** - * Load a set of mappings from a stream. - */ - public void load(InputStream in) throws IOException { - InputStreamReader reader = new InputStreamReader(in); - BufferedReader data = new BufferedReader(reader); - - for (String ln = data.readLine() ; ln != null ; ln = data.readLine()) { - if (ln.startsWith("PUBLIC")) { - int len = ln.length(); - int i = 6; - while ((i < len) && (ln.charAt(i) != '"')) i++; - int j = ++i; - while ((j < len) && (ln.charAt(j) != '"')) j++; - String id = ln.substring(i, j); - i = ++j; - while ((i < len) && ((ln.charAt(i) == ' ') || (ln.charAt(i) == '\t'))) i++; - j = i + 1; - while ((j < len) && (ln.charAt(j) != ' ') && (ln.charAt(j) != '\t')) j++; - String where = ln.substring(i, j); - put(id, baseStr + where); - } - } - data.close(); - } - - /** - * Add a mapping from a public identifier to a path. - */ - public void put(String id, String str) { - - // System.err.println("ADD = '" + id + "' = " + str); - tab.put(id, str); - if (str.endsWith(".dtd")) { - int i = str.lastIndexOf(File.separator); - if (i >= 0) { - tab.put(str.substring(i + 1, str.length() - 4), str); - } - } - } - - /** - * Map a public identifier to a path.. You can also map - * a DTD file name (without the .dtd) to its path. - */ - public String get(String id) { - // System.err.println(" id = "+id); - return tab.get(id); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/dtdbuilder/PublicMapping.java 2020-03-23 19:57:02.995962507 +0100 @@ -0,0 +1,108 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.dtdbuilder; + +import javax.swing.text.html.parser.*; +import java.io.File; +import java.io.IOException; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.BufferedReader; +import java.util.Hashtable; + +/** + * A class for mapping public identifiers to locations. + * Note: I'm not sure if there is a more natural mapping + * then this. Maybe we should use properties instead? + * + * @author Arthur van Hoff + */ +final class PublicMapping { + + String baseStr; + Hashtable tab = new Hashtable<>(); + + /** + * Create a mapping. + */ + public PublicMapping (String baseStr, String mapFile) throws IOException { + // System.err.println("start loading " + baseStr); + this.baseStr = baseStr; + load(new FileInputStream(baseStr+mapFile)); + // System.err.println("stop loading"); + } + + /** + * Load a set of mappings from a stream. + */ + public void load(InputStream in) throws IOException { + InputStreamReader reader = new InputStreamReader(in); + BufferedReader data = new BufferedReader(reader); + + for (String ln = data.readLine() ; ln != null ; ln = data.readLine()) { + if (ln.startsWith("PUBLIC")) { + int len = ln.length(); + int i = 6; + while ((i < len) && (ln.charAt(i) != '"')) i++; + int j = ++i; + while ((j < len) && (ln.charAt(j) != '"')) j++; + String id = ln.substring(i, j); + i = ++j; + while ((i < len) && ((ln.charAt(i) == ' ') || (ln.charAt(i) == '\t'))) i++; + j = i + 1; + while ((j < len) && (ln.charAt(j) != ' ') && (ln.charAt(j) != '\t')) j++; + String where = ln.substring(i, j); + put(id, baseStr + where); + } + } + data.close(); + } + + /** + * Add a mapping from a public identifier to a path. + */ + public void put(String id, String str) { + + // System.err.println("ADD = '" + id + "' = " + str); + tab.put(id, str); + if (str.endsWith(".dtd")) { + int i = str.lastIndexOf(File.separator); + if (i >= 0) { + tab.put(str.substring(i + 1, str.length() - 4), str); + } + } + } + + /** + * Map a public identifier to a path.. You can also map + * a DTD file name (without the .dtd) to its path. + */ + public String get(String id) { + // System.err.println(" id = "+id); + return tab.get(id); + } +} --- old/make/jdk/src/classes/build/tools/dtdbuilder/README.txt 2020-03-23 19:57:04.275962498 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,37 +0,0 @@ -README: - -This directory contains a program to read a DTD, and produce a compressed -representation of it. It's intended that this program be run at build -time, and the resultant .bdtd binary DTD file be read at program startup. - - - .dtdb FILE FORMAT - -file ::= version_no:int num_names:short name[]:string num_entities entity[] - num_elements element[] - -entity ::= name_id:short type:byte data:string - -element ::= name_id:short type:byte - flags:byte (&0x01 = omit start, &0x02 = omit end) - content_model - num_exclusions:byte name_id[] - num_inclusions:byte name_id[] - num_attributes:byte attribute[] - -attribute ::= name_id:short type:byte modifier:byte - value:name_id (or -1 for null) - num_values:short name_id[] - -content_model ::= content_c | content_e | content_null - -content_null ::= flag:byte=0 - -content_c ::= flag:byte=1 type:int content:content_model next:content_model - -content_e ::= flag:byte=2 type:int element_name_id next:content_model - -string ::= modified UTF-8 encoding of a string - -See the java.io.InputStream class description for the specification of modified -UTF-8. --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/dtdbuilder/README.txt 2020-03-23 19:57:03.843962501 +0100 @@ -0,0 +1,37 @@ +README: + +This directory contains a program to read a DTD, and produce a compressed +representation of it. It's intended that this program be run at build +time, and the resultant .bdtd binary DTD file be read at program startup. + + + .dtdb FILE FORMAT + +file ::= version_no:int num_names:short name[]:string num_entities entity[] + num_elements element[] + +entity ::= name_id:short type:byte data:string + +element ::= name_id:short type:byte + flags:byte (&0x01 = omit start, &0x02 = omit end) + content_model + num_exclusions:byte name_id[] + num_inclusions:byte name_id[] + num_attributes:byte attribute[] + +attribute ::= name_id:short type:byte modifier:byte + value:name_id (or -1 for null) + num_values:short name_id[] + +content_model ::= content_c | content_e | content_null + +content_null ::= flag:byte=0 + +content_c ::= flag:byte=1 type:int content:content_model next:content_model + +content_e ::= flag:byte=2 type:int element_name_id next:content_model + +string ::= modified UTF-8 encoding of a string + +See the java.io.InputStream class description for the specification of modified +UTF-8. --- old/make/jdk/src/classes/build/tools/generatenimbus/AbstractGradient.java 2020-03-23 19:57:04.927962493 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; -import java.util.ArrayList; -import java.util.List; - -class AbstractGradient extends Paint { - public enum CycleMethod { - NO_CYCLE, REFLECT, REPEAT - } - - private ArrayList stops; - public List getStops() { return stops; } - - AbstractGradient(XMLStreamReader reader) throws XMLStreamException { - stops = new ArrayList<>(); - while (reader.hasNext()) { - int eventType = reader.next(); - switch (eventType) { - case XMLStreamReader.START_ELEMENT: - switch (reader.getLocalName()) { - case "stop": - stops.add(new GradientStop(reader)); - break; - } - break; - case XMLStreamReader.END_ELEMENT: - switch (reader.getLocalName()) { - case "stop": - break; - default: - return; - } - break; - } - } - - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/AbstractGradient.java 2020-03-23 19:57:04.471962496 +0100 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import java.util.ArrayList; +import java.util.List; + +class AbstractGradient extends Paint { + public enum CycleMethod { + NO_CYCLE, REFLECT, REPEAT + } + + private ArrayList stops; + public List getStops() { return stops; } + + AbstractGradient(XMLStreamReader reader) throws XMLStreamException { + stops = new ArrayList<>(); + while (reader.hasNext()) { + int eventType = reader.next(); + switch (eventType) { + case XMLStreamReader.START_ELEMENT: + switch (reader.getLocalName()) { + case "stop": + stops.add(new GradientStop(reader)); + break; + } + break; + case XMLStreamReader.END_ELEMENT: + switch (reader.getLocalName()) { + case "stop": + break; + default: + return; + } + break; + } + } + + } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/Border.java 2020-03-23 19:57:05.807962486 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -import javax.xml.stream.XMLStreamReader; - -class Border { - enum BorderType { - EMPTY, - PAINTER - } - - private BorderType type; - - private String painter; - - private int top; - - private int left; - - private int bottom; - - private int right; - - Border(XMLStreamReader reader) { - switch (reader.getAttributeValue(null, "type")) { - case "empty": - type = BorderType.EMPTY; - break; - case "painter": - type =BorderType.PAINTER; - break; - } - painter = reader.getAttributeValue(null, "painter"); - top = Integer.parseInt(reader.getAttributeValue(null, "top")); - left = Integer.parseInt(reader.getAttributeValue(null, "left")); - bottom = Integer.parseInt(reader.getAttributeValue(null, "bottom")); - right = Integer.parseInt(reader.getAttributeValue(null, "right")); - } - - public String write() { - switch (type) { - case PAINTER: - return String.format("new PainterBorder(\"%s\", new Insets(%d, %d, %d, %d))", - painter, top, left, bottom, right); - case EMPTY: - return String.format("BorderFactory.createEmptyBorder(%d, %d, %d, %d)", - top, left, bottom, right); - default: - return "### Look, here's an unknown border! $$$"; - } - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/Border.java 2020-03-23 19:57:05.379962490 +0100 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +import javax.xml.stream.XMLStreamReader; + +class Border { + enum BorderType { + EMPTY, + PAINTER + } + + private BorderType type; + + private String painter; + + private int top; + + private int left; + + private int bottom; + + private int right; + + Border(XMLStreamReader reader) { + switch (reader.getAttributeValue(null, "type")) { + case "empty": + type = BorderType.EMPTY; + break; + case "painter": + type =BorderType.PAINTER; + break; + } + painter = reader.getAttributeValue(null, "painter"); + top = Integer.parseInt(reader.getAttributeValue(null, "top")); + left = Integer.parseInt(reader.getAttributeValue(null, "left")); + bottom = Integer.parseInt(reader.getAttributeValue(null, "bottom")); + right = Integer.parseInt(reader.getAttributeValue(null, "right")); + } + + public String write() { + switch (type) { + case PAINTER: + return String.format("new PainterBorder(\"%s\", new Insets(%d, %d, %d, %d))", + painter, top, left, bottom, right); + case EMPTY: + return String.format("BorderFactory.createEmptyBorder(%d, %d, %d, %d)", + top, left, bottom, right); + default: + return "### Look, here's an unknown border! $$$"; + } + } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/Canvas.java 2020-03-23 19:57:06.619962480 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; -import java.util.ArrayList; -import java.util.List; - -class Canvas { - private Dimension size; - - public Dimension getSize() { return size; } - - private List layers; - public List getLayers() { return layers; } - - private Insets stretchingInsets = null; - - Canvas(XMLStreamReader reader) throws XMLStreamException { - layers = new ArrayList<>(); - while (reader.hasNext()) { - int eventType = reader.next(); - switch (eventType) { - case XMLStreamReader.START_ELEMENT: - switch (reader.getLocalName()) { - case "size": - size = new Dimension(reader); - break; - case "layer": - layers.add(new Layer(reader)); - break; - case "stretchingInsets": - stretchingInsets = new Insets(reader); - break; - } - break; - case XMLStreamReader.END_ELEMENT: - switch (reader.getLocalName()) { - case "canvas": - return; - } - break; - } - } - } - - public Insets getStretchingInsets() { return stretchingInsets; } - - public boolean isBlank() { - return layers.size() == 0 || (layers.size() == 1 && layers.get(0).isEmpty()); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/Canvas.java 2020-03-23 19:57:06.223962483 +0100 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import java.util.ArrayList; +import java.util.List; + +class Canvas { + private Dimension size; + + public Dimension getSize() { return size; } + + private List layers; + public List getLayers() { return layers; } + + private Insets stretchingInsets = null; + + Canvas(XMLStreamReader reader) throws XMLStreamException { + layers = new ArrayList<>(); + while (reader.hasNext()) { + int eventType = reader.next(); + switch (eventType) { + case XMLStreamReader.START_ELEMENT: + switch (reader.getLocalName()) { + case "size": + size = new Dimension(reader); + break; + case "layer": + layers.add(new Layer(reader)); + break; + case "stretchingInsets": + stretchingInsets = new Insets(reader); + break; + } + break; + case XMLStreamReader.END_ELEMENT: + switch (reader.getLocalName()) { + case "canvas": + return; + } + break; + } + } + } + + public Insets getStretchingInsets() { return stretchingInsets; } + + public boolean isBlank() { + return layers.size() == 0 || (layers.size() == 1 && layers.get(0).isEmpty()); + } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/ComponentColor.java 2020-03-23 19:57:07.431962474 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -class ComponentColor { - private String propertyName; - private String defaultColorVariableName; - private float saturationOffset = 0, brightnessOffset = 0; - private int alphaOffset = 0; - - ComponentColor(String propertyName, - String defaultColorVariableName, - float saturationOffset, - float brightnessOffset, - int alphaOffset) { - this.propertyName = propertyName; - this.defaultColorVariableName = defaultColorVariableName; - this.saturationOffset = saturationOffset; - this.brightnessOffset = brightnessOffset; - this.alphaOffset = alphaOffset; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - ComponentColor c = (ComponentColor) o; - if (alphaOffset != c.alphaOffset) { - return false; - } - if (Float.compare(saturationOffset, c.saturationOffset) != 0) { - return false; - } - if (Float.compare(brightnessOffset, c.brightnessOffset) != 0) { - return false; - } - if (defaultColorVariableName != null ? !defaultColorVariableName.equals(c.defaultColorVariableName) : c.defaultColorVariableName != null) { - return false; - } - if (propertyName != null ? !propertyName.equals(c.propertyName) : c.propertyName != null) { - return false; - } - return true; - } - - @Override - public int hashCode() { - int hash = 5; - hash = 61 * hash + (this.propertyName != null ? this.propertyName.hashCode() : 0); - hash = 61 * hash + (this.defaultColorVariableName != null ? this.defaultColorVariableName.hashCode() : 0); - hash = 61 * hash + Float.floatToIntBits(this.saturationOffset); - hash = 61 * hash + Float.floatToIntBits(this.brightnessOffset); - hash = 61 * hash + this.alphaOffset; - return hash; - } - - public void write(StringBuilder sb) { - sb.append(" getComponentColor(c, \""). - append(propertyName).append("\", "). - append(defaultColorVariableName).append(", "). - append(saturationOffset).append("f, "). - append(brightnessOffset).append("f, "). - append(alphaOffset); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/ComponentColor.java 2020-03-23 19:57:07.031962477 +0100 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +class ComponentColor { + private String propertyName; + private String defaultColorVariableName; + private float saturationOffset = 0, brightnessOffset = 0; + private int alphaOffset = 0; + + ComponentColor(String propertyName, + String defaultColorVariableName, + float saturationOffset, + float brightnessOffset, + int alphaOffset) { + this.propertyName = propertyName; + this.defaultColorVariableName = defaultColorVariableName; + this.saturationOffset = saturationOffset; + this.brightnessOffset = brightnessOffset; + this.alphaOffset = alphaOffset; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + ComponentColor c = (ComponentColor) o; + if (alphaOffset != c.alphaOffset) { + return false; + } + if (Float.compare(saturationOffset, c.saturationOffset) != 0) { + return false; + } + if (Float.compare(brightnessOffset, c.brightnessOffset) != 0) { + return false; + } + if (defaultColorVariableName != null ? !defaultColorVariableName.equals(c.defaultColorVariableName) : c.defaultColorVariableName != null) { + return false; + } + if (propertyName != null ? !propertyName.equals(c.propertyName) : c.propertyName != null) { + return false; + } + return true; + } + + @Override + public int hashCode() { + int hash = 5; + hash = 61 * hash + (this.propertyName != null ? this.propertyName.hashCode() : 0); + hash = 61 * hash + (this.defaultColorVariableName != null ? this.defaultColorVariableName.hashCode() : 0); + hash = 61 * hash + Float.floatToIntBits(this.saturationOffset); + hash = 61 * hash + Float.floatToIntBits(this.brightnessOffset); + hash = 61 * hash + this.alphaOffset; + return hash; + } + + public void write(StringBuilder sb) { + sb.append(" getComponentColor(c, \""). + append(propertyName).append("\", "). + append(defaultColorVariableName).append(", "). + append(saturationOffset).append("f, "). + append(brightnessOffset).append("f, "). + append(alphaOffset); + } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/Dimension.java 2020-03-23 19:57:08.267962468 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -import javax.xml.stream.XMLStreamReader; - -class Dimension { - int width; - int height; - - Dimension(XMLStreamReader reader) { - width = Integer.parseInt(reader.getAttributeValue(null, "width")); - height = Integer.parseInt(reader.getAttributeValue(null, "height")); - } - - public String write(boolean uiResource) { - String uiSuffix = (uiResource ? "UIResource" : ""); - return String.format("new Dimension%s(%d, %d)", uiSuffix, width, height); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/Dimension.java 2020-03-23 19:57:07.843962471 +0100 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +import javax.xml.stream.XMLStreamReader; + +class Dimension { + int width; + int height; + + Dimension(XMLStreamReader reader) { + width = Integer.parseInt(reader.getAttributeValue(null, "width")); + height = Integer.parseInt(reader.getAttributeValue(null, "height")); + } + + public String write(boolean uiResource) { + String uiSuffix = (uiResource ? "UIResource" : ""); + return String.format("new Dimension%s(%d, %d)", uiSuffix, width, height); + } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/Ellipse.java 2020-03-23 19:57:09.075962462 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; - -class Ellipse extends Shape { - private double x1; - - public double getX1() { return x1; } - - private double x2; - public double getX2() { return x2; } - - private double y1; - public double getY1() { return y1; } - - private double y2; - public double getY2() { return y2; } - - Ellipse(XMLStreamReader reader) throws XMLStreamException { - x1 = Double.parseDouble(reader.getAttributeValue(null, "x1")); - x2 = Double.parseDouble(reader.getAttributeValue(null, "x2")); - y1 = Double.parseDouble(reader.getAttributeValue(null, "y1")); - y2 = Double.parseDouble(reader.getAttributeValue(null, "y2")); - while (reader.hasNext()) { - int eventType = reader.next(); - switch (eventType) { - case XMLStreamReader.START_ELEMENT: - switch (reader.getLocalName()) { - case "matte": - paint = new Matte(reader); - break; - case "gradient": - paint = new Gradient(reader); - break; - case "radialGradient": - paint = new RadialGradient(reader); - break; - case "paintPoints": - paintPoints = new PaintPoints(reader); - break; - } - break; - case XMLStreamReader.END_ELEMENT: - switch (reader.getLocalName()) { - case "ellipse": - return; - } - break; - } - } - } - -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/Ellipse.java 2020-03-23 19:57:08.679962465 +0100 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +class Ellipse extends Shape { + private double x1; + + public double getX1() { return x1; } + + private double x2; + public double getX2() { return x2; } + + private double y1; + public double getY1() { return y1; } + + private double y2; + public double getY2() { return y2; } + + Ellipse(XMLStreamReader reader) throws XMLStreamException { + x1 = Double.parseDouble(reader.getAttributeValue(null, "x1")); + x2 = Double.parseDouble(reader.getAttributeValue(null, "x2")); + y1 = Double.parseDouble(reader.getAttributeValue(null, "y1")); + y2 = Double.parseDouble(reader.getAttributeValue(null, "y2")); + while (reader.hasNext()) { + int eventType = reader.next(); + switch (eventType) { + case XMLStreamReader.START_ELEMENT: + switch (reader.getLocalName()) { + case "matte": + paint = new Matte(reader); + break; + case "gradient": + paint = new Gradient(reader); + break; + case "radialGradient": + paint = new RadialGradient(reader); + break; + case "paintPoints": + paintPoints = new PaintPoints(reader); + break; + } + break; + case XMLStreamReader.END_ELEMENT: + switch (reader.getLocalName()) { + case "ellipse": + return; + } + break; + } + } + } + +} --- old/make/jdk/src/classes/build/tools/generatenimbus/Generator.java 2020-03-23 19:57:09.939962456 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,273 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package build.tools.generatenimbus; - -import javax.xml.stream.XMLInputFactory; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; -import java.io.*; -import java.util.HashMap; -import java.util.Map; - -/** - * Generates the various Java artifacts based on a SynthModel. - *

    - * Generated source files are split up among two different locations. There are those source files that are meant to be - * edited (generally, only the LookAndFeel class itself) and those that are autogenerated (everything else). - *

    - * All autogenerated files are placed in "buildPackageRoot" and are package private. A LAF author (one who has access to - * the generated sources) will be able to access any of the generated classes. Those referencing the library, however, - * will only be able to access the main LookAndFeel class itself (since everything else is package private). - * - * @author Richard Bair - * @author Jasper Potts - */ -public class Generator { - private static Generator instance; - - /** A map of variables that are used for variable substitution in the template files. */ - private Map variables; - private boolean full = false; - private File buildPackageRoot; - private String packageNamePrefix; - private String lafName; - private SynthModel model; - - /** - * MAIN APPLICATION - *

    - * This is for using the generator as part of the java build process - * - * @param args The commandline arguments - */ - public static void main(String[] args) throws Exception { - if (args.length == 0 || (args.length % 2) != 0) { - System.out.println("Usage: generator [-options]\n" + - " -full True if we should build the whole LAF or false for building just states and painters.\n" + - " -skinFile Path to the skin.laf file for the LAF to be generated from.\n" + - " -buildDir The directory beneath which the build-controlled artifacts (such as the Painters) should\n" + - " be placed. This is the root directory beneath which the necessary packages and source\n" + - " files will be created.\n" + - " -resourcesDir The resources directory containing templates and images.\n" + - " -packagePrefix The package name associated with this synth look and feel. For example,\n" + - " \"org.mypackage.mylaf\"\n" + - " -lafName The name of the laf, such as \"MyLAF\".\n"); - } else { - boolean full = false; - File skinFile = new File(System.getProperty("user.dir")); - File buildDir = new File(System.getProperty("user.dir")); - File resourcesDir = new File(System.getProperty("user.dir")); - String packagePrefix = "org.mypackage.mylaf"; - String lafName = "MyLAF"; - for (int i = 0; i < args.length; i += 2) { - String key = args[i].trim().toLowerCase(); - String value = args[i + 1].trim(); - if ("-full".equals(key)) { - full = Boolean.parseBoolean(value); - } else if ("-skinfile".equals(key)) { - skinFile = new File(value); - } else if ("-builddir".equals(key)) { - buildDir = new File(value); - } else if ("-resourcesdir".equals(key)) { - resourcesDir = new File(value); - } else if ("-packageprefix".equals(key)) { - packagePrefix = value; - } else if ("-lafname".equals(key)) { - lafName = value; - } - } - System.out.println("### GENERATING LAF CODE ################################"); - System.out.println(" full :" + full); - System.out.println(" skinFile :" + skinFile.getAbsolutePath()); - System.out.println(" buildDir :" + buildDir.getAbsolutePath()); - System.out.println(" resourcesDir :" + resourcesDir.getAbsolutePath()); - System.out.println(" packagePrefix :" +packagePrefix); - System.out.println(" lafName :" +lafName); - - SynthModel model; - XMLInputFactory inputFactory = XMLInputFactory.newInstance(); - XMLStreamReader reader; - try( InputStream fis = new FileInputStream(skinFile); - InputStream is = new BufferedInputStream(fis)) { - reader = inputFactory.createXMLStreamReader(is); - model = new SynthModel(reader); - } - Generator.init(full, buildDir, packagePrefix, lafName, model); - Generator.getInstance().generate(); - } - } - - /** - * Creates a new Generator, capable of outputting the source code artifacts related to a given SynthModel. It is - * capable of generating the one-time artifacts in addition to the regeneration of build-controlled artifacts. - * - * @param full True if we should build the whole LAF or false for building just states and painters. - * @param buildDir The directory beneath which the build-controlled artifacts (such as the Painters) should - * be placed. This is the root directory beneath which the necessary packages and source - * files will be created. - * @param srcDir The directory beneath which the normal user-controlled artifacts (such as the core - * LookAndFeel file) should be placed. These are one-time generated files. This is the root - * directory beneath which the necessary packages and source files will be created. - * @param packageNamePrefix The package name associated with this synth look and feel. For example, - * org.mypackage.mylaf - * @param lafName The name of the laf, such as MyLAF. - * @param model The actual SynthModel to base these generated files on. - */ - private Generator(boolean full, File buildDir, - String packageNamePrefix, String lafName, SynthModel model) { - this.full = full; - //validate the input variables - if (packageNamePrefix == null) { - throw new IllegalArgumentException("You must specify a package name prefix"); - } - if (buildDir == null) { - throw new IllegalArgumentException("You must specify the build directory"); - } - if (model == null) { - throw new IllegalArgumentException("You must specify the SynthModel"); - } - if (lafName == null) { - throw new IllegalArgumentException("You must specify the name of the look and feel"); - } - - //construct the map which is used to do variable substitution of the template - //files - variables = new HashMap(); - variables.put("PACKAGE", packageNamePrefix); - variables.put("LAF_NAME", lafName); - - //generate and save references to the package-root directories. - //(That is, given the buildDir and srcDir, generate references to the - //org.mypackage.mylaf subdirectories) - buildPackageRoot = new File(buildDir, packageNamePrefix.replaceAll("\\.", "\\/")); - buildPackageRoot.mkdirs(); - - //save the variables - this.packageNamePrefix = packageNamePrefix; - this.lafName = lafName; - this.model = model; - } - - public static void init(boolean full, File buildDir, - String packageNamePrefix, String lafName, SynthModel model) { - instance = new Generator(full, buildDir, packageNamePrefix, lafName, model); - model.initStyles(); - } - - public static Generator getInstance() { - return instance; - } - - public static Map getVariables() { - return new HashMap(instance.variables); - } - - public void generate() { - if (full) { - //create the LookAndFeel file - writeSrcFileImpl("LookAndFeel", variables, lafName + "LookAndFeel"); - - writeSrcFileImpl("AbstractRegionPainter", variables); - writeSrcFileImpl("BlendingMode", variables); - writeSrcFileImpl("SynthPainterImpl", variables); - writeSrcFileImpl("IconImpl", variables, lafName + "Icon.java"); - writeSrcFileImpl("StyleImpl", variables, lafName + "Style.java"); - writeSrcFileImpl("Effect", variables); - writeSrcFileImpl("EffectUtils", variables); - writeSrcFileImpl("ShadowEffect", variables); - writeSrcFileImpl("DropShadowEffect", variables); - writeSrcFileImpl("InnerShadowEffect", variables); - writeSrcFileImpl("InnerGlowEffect", variables); - writeSrcFileImpl("OuterGlowEffect", variables); - writeSrcFileImpl("State", variables); - writeSrcFileImpl("ImageCache", variables); - writeSrcFileImpl("ImageScalingHelper", variables); - } - //next, populate the first set of ui defaults based on what is in the - //various palettes of the synth model - StringBuilder defBuffer = new StringBuilder(); - StringBuilder styleBuffer = new StringBuilder(); - model.write(defBuffer, styleBuffer, packageNamePrefix); - - Map vars = getVariables(); - vars.put("UI_DEFAULT_INIT", defBuffer.toString()); - vars.put("STYLE_INIT", styleBuffer.toString()); - writeSrcFile("Defaults", vars, lafName + "Defaults"); - } - - private void writeSrcFileImpl(String name, Map variables) { - writeSrcFileImpl(name, variables, name); - } - - private void writeSrcFileImpl(String templateName, - Map variables, String outputName) { - PrintWriter out = null; - try { - InputStream stream = getClass().getResourceAsStream( - "resources/" + templateName + ".template"); - TemplateReader in = new TemplateReader(variables, stream); - - out = new PrintWriter(new File(buildPackageRoot, outputName + ".java")); - String line = in.readLine(); - while (line != null) { - out.println(line); - line = in.readLine(); - } - } catch (IOException e) { - throw new RuntimeException("IOException in writer", e); - } finally { - if (out != null) out.close(); - } - } - - public static void writeSrcFile(String templateName, - Map variables, String outputName) { - instance.writeSrcFileImpl(templateName, variables, outputName); - } - - /** A BufferedReader implementation that automatically performs - * string replacements as needed. - */ - private static final class TemplateReader extends BufferedReader { - private Map variables; - - TemplateReader(Map variables, InputStream template) { - super(new InputStreamReader(template)); - this.variables = variables; - } - - @Override public String readLine() throws IOException { - return substituteVariables(super.readLine()); - } - - private String substituteVariables(String input) { - if (input == null) return null; - for (Map.Entry variable : variables.entrySet()) { - input = input.replace("${" + variable.getKey() + "}", variable.getValue()); - } - return input; - } - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/Generator.java 2020-03-23 19:57:09.515962459 +0100 @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.buildtools.generatenimbus; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import java.io.*; +import java.util.HashMap; +import java.util.Map; + +/** + * Generates the various Java artifacts based on a SynthModel. + *

    + * Generated source files are split up among two different locations. There are those source files that are meant to be + * edited (generally, only the LookAndFeel class itself) and those that are autogenerated (everything else). + *

    + * All autogenerated files are placed in "buildPackageRoot" and are package private. A LAF author (one who has access to + * the generated sources) will be able to access any of the generated classes. Those referencing the library, however, + * will only be able to access the main LookAndFeel class itself (since everything else is package private). + * + * @author Richard Bair + * @author Jasper Potts + */ +public class Generator { + private static Generator instance; + + /** A map of variables that are used for variable substitution in the template files. */ + private Map variables; + private boolean full = false; + private File buildPackageRoot; + private String packageNamePrefix; + private String lafName; + private SynthModel model; + + /** + * MAIN APPLICATION + *

    + * This is for using the generator as part of the java build process + * + * @param args The commandline arguments + */ + public static void main(String[] args) throws Exception { + if (args.length == 0 || (args.length % 2) != 0) { + System.out.println("Usage: generator [-options]\n" + + " -full True if we should build the whole LAF or false for building just states and painters.\n" + + " -skinFile Path to the skin.laf file for the LAF to be generated from.\n" + + " -buildDir The directory beneath which the build-controlled artifacts (such as the Painters) should\n" + + " be placed. This is the root directory beneath which the necessary packages and source\n" + + " files will be created.\n" + + " -resourcesDir The resources directory containing templates and images.\n" + + " -packagePrefix The package name associated with this synth look and feel. For example,\n" + + " \"org.mypackage.mylaf\"\n" + + " -lafName The name of the laf, such as \"MyLAF\".\n"); + } else { + boolean full = false; + File skinFile = new File(System.getProperty("user.dir")); + File buildDir = new File(System.getProperty("user.dir")); + File resourcesDir = new File(System.getProperty("user.dir")); + String packagePrefix = "org.mypackage.mylaf"; + String lafName = "MyLAF"; + for (int i = 0; i < args.length; i += 2) { + String key = args[i].trim().toLowerCase(); + String value = args[i + 1].trim(); + if ("-full".equals(key)) { + full = Boolean.parseBoolean(value); + } else if ("-skinfile".equals(key)) { + skinFile = new File(value); + } else if ("-builddir".equals(key)) { + buildDir = new File(value); + } else if ("-resourcesdir".equals(key)) { + resourcesDir = new File(value); + } else if ("-packageprefix".equals(key)) { + packagePrefix = value; + } else if ("-lafname".equals(key)) { + lafName = value; + } + } + System.out.println("### GENERATING LAF CODE ################################"); + System.out.println(" full :" + full); + System.out.println(" skinFile :" + skinFile.getAbsolutePath()); + System.out.println(" buildDir :" + buildDir.getAbsolutePath()); + System.out.println(" resourcesDir :" + resourcesDir.getAbsolutePath()); + System.out.println(" packagePrefix :" +packagePrefix); + System.out.println(" lafName :" +lafName); + + SynthModel model; + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + XMLStreamReader reader; + try( InputStream fis = new FileInputStream(skinFile); + InputStream is = new BufferedInputStream(fis)) { + reader = inputFactory.createXMLStreamReader(is); + model = new SynthModel(reader); + } + Generator.init(full, buildDir, packagePrefix, lafName, model); + Generator.getInstance().generate(); + } + } + + /** + * Creates a new Generator, capable of outputting the source code artifacts related to a given SynthModel. It is + * capable of generating the one-time artifacts in addition to the regeneration of build-controlled artifacts. + * + * @param full True if we should build the whole LAF or false for building just states and painters. + * @param buildDir The directory beneath which the build-controlled artifacts (such as the Painters) should + * be placed. This is the root directory beneath which the necessary packages and source + * files will be created. + * @param srcDir The directory beneath which the normal user-controlled artifacts (such as the core + * LookAndFeel file) should be placed. These are one-time generated files. This is the root + * directory beneath which the necessary packages and source files will be created. + * @param packageNamePrefix The package name associated with this synth look and feel. For example, + * org.mypackage.mylaf + * @param lafName The name of the laf, such as MyLAF. + * @param model The actual SynthModel to base these generated files on. + */ + private Generator(boolean full, File buildDir, + String packageNamePrefix, String lafName, SynthModel model) { + this.full = full; + //validate the input variables + if (packageNamePrefix == null) { + throw new IllegalArgumentException("You must specify a package name prefix"); + } + if (buildDir == null) { + throw new IllegalArgumentException("You must specify the build directory"); + } + if (model == null) { + throw new IllegalArgumentException("You must specify the SynthModel"); + } + if (lafName == null) { + throw new IllegalArgumentException("You must specify the name of the look and feel"); + } + + //construct the map which is used to do variable substitution of the template + //files + variables = new HashMap(); + variables.put("PACKAGE", packageNamePrefix); + variables.put("LAF_NAME", lafName); + + //generate and save references to the package-root directories. + //(That is, given the buildDir and srcDir, generate references to the + //org.mypackage.mylaf subdirectories) + buildPackageRoot = new File(buildDir, packageNamePrefix.replaceAll("\\.", "\\/")); + buildPackageRoot.mkdirs(); + + //save the variables + this.packageNamePrefix = packageNamePrefix; + this.lafName = lafName; + this.model = model; + } + + public static void init(boolean full, File buildDir, + String packageNamePrefix, String lafName, SynthModel model) { + instance = new Generator(full, buildDir, packageNamePrefix, lafName, model); + model.initStyles(); + } + + public static Generator getInstance() { + return instance; + } + + public static Map getVariables() { + return new HashMap(instance.variables); + } + + public void generate() { + if (full) { + //create the LookAndFeel file + writeSrcFileImpl("LookAndFeel", variables, lafName + "LookAndFeel"); + + writeSrcFileImpl("AbstractRegionPainter", variables); + writeSrcFileImpl("BlendingMode", variables); + writeSrcFileImpl("SynthPainterImpl", variables); + writeSrcFileImpl("IconImpl", variables, lafName + "Icon.java"); + writeSrcFileImpl("StyleImpl", variables, lafName + "Style.java"); + writeSrcFileImpl("Effect", variables); + writeSrcFileImpl("EffectUtils", variables); + writeSrcFileImpl("ShadowEffect", variables); + writeSrcFileImpl("DropShadowEffect", variables); + writeSrcFileImpl("InnerShadowEffect", variables); + writeSrcFileImpl("InnerGlowEffect", variables); + writeSrcFileImpl("OuterGlowEffect", variables); + writeSrcFileImpl("State", variables); + writeSrcFileImpl("ImageCache", variables); + writeSrcFileImpl("ImageScalingHelper", variables); + } + //next, populate the first set of ui defaults based on what is in the + //various palettes of the synth model + StringBuilder defBuffer = new StringBuilder(); + StringBuilder styleBuffer = new StringBuilder(); + model.write(defBuffer, styleBuffer, packageNamePrefix); + + Map vars = getVariables(); + vars.put("UI_DEFAULT_INIT", defBuffer.toString()); + vars.put("STYLE_INIT", styleBuffer.toString()); + writeSrcFile("Defaults", vars, lafName + "Defaults"); + } + + private void writeSrcFileImpl(String name, Map variables) { + writeSrcFileImpl(name, variables, name); + } + + private void writeSrcFileImpl(String templateName, + Map variables, String outputName) { + PrintWriter out = null; + try { + InputStream stream = getClass().getResourceAsStream( + "resources/" + templateName + ".template"); + TemplateReader in = new TemplateReader(variables, stream); + + out = new PrintWriter(new File(buildPackageRoot, outputName + ".java")); + String line = in.readLine(); + while (line != null) { + out.println(line); + line = in.readLine(); + } + } catch (IOException e) { + throw new RuntimeException("IOException in writer", e); + } finally { + if (out != null) out.close(); + } + } + + public static void writeSrcFile(String templateName, + Map variables, String outputName) { + instance.writeSrcFileImpl(templateName, variables, outputName); + } + + /** A BufferedReader implementation that automatically performs + * string replacements as needed. + */ + private static final class TemplateReader extends BufferedReader { + private Map variables; + + TemplateReader(Map variables, InputStream template) { + super(new InputStreamReader(template)); + this.variables = variables; + } + + @Override public String readLine() throws IOException { + return substituteVariables(super.readLine()); + } + + private String substituteVariables(String input) { + if (input == null) return null; + for (Map.Entry variable : variables.entrySet()) { + input = input.replace("${" + variable.getKey() + "}", variable.getValue()); + } + return input; + } + } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/Gradient.java 2020-03-23 19:57:10.819962449 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; - -class Gradient extends AbstractGradient { - Gradient(XMLStreamReader reader) throws XMLStreamException { - super(reader); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/Gradient.java 2020-03-23 19:57:10.355962453 +0100 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +class Gradient extends AbstractGradient { + Gradient(XMLStreamReader reader) throws XMLStreamException { + super(reader); + } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/GradientStop.java 2020-03-23 19:57:11.683962443 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; - -class GradientStop { - private float position; - - public float getPosition() { return position; } - - private float midpoint; - public float getMidpoint() { return midpoint; } - - private Matte matte; - public Matte getColor() { return matte; } - - GradientStop(XMLStreamReader reader) throws XMLStreamException { - position = Float.parseFloat(reader.getAttributeValue(null, "position")); - midpoint = Float.parseFloat(reader.getAttributeValue(null, "midpoint")); - while (reader.hasNext()) { - int eventType = reader.next(); - switch (eventType) { - case XMLStreamReader.START_ELEMENT: - matte = new Matte(reader); - break; - case XMLStreamReader.END_ELEMENT: - return; - } - } - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/GradientStop.java 2020-03-23 19:57:11.251962446 +0100 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +class GradientStop { + private float position; + + public float getPosition() { return position; } + + private float midpoint; + public float getMidpoint() { return midpoint; } + + private Matte matte; + public Matte getColor() { return matte; } + + GradientStop(XMLStreamReader reader) throws XMLStreamException { + position = Float.parseFloat(reader.getAttributeValue(null, "position")); + midpoint = Float.parseFloat(reader.getAttributeValue(null, "midpoint")); + while (reader.hasNext()) { + int eventType = reader.next(); + switch (eventType) { + case XMLStreamReader.START_ELEMENT: + matte = new Matte(reader); + break; + case XMLStreamReader.END_ELEMENT: + return; + } + } + } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/Insets.java 2020-03-23 19:57:12.563962437 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -import javax.xml.stream.XMLStreamReader; - -class Insets { - int top; - int left; - int bottom; - int right; - - public Insets() { - this(0, 0, 0, 0); - } - - public Insets(int top, int left, int bottom, int right) { - this.top = top; - this.left = left; - this.bottom = bottom; - this.right = right; - } - - Insets(XMLStreamReader reader) { - top = Integer.parseInt(reader.getAttributeValue(null, "top")); - left = Integer.parseInt(reader.getAttributeValue(null, "left")); - bottom = Integer.parseInt(reader.getAttributeValue(null, "bottom")); - right = Integer.parseInt(reader.getAttributeValue(null, "right")); - } - - public String write(boolean uiResource) { - String uiSuffix = (uiResource ? "UIResource" : ""); - return String.format("new Insets%s(%d, %d, %d, %d)", - uiSuffix, top, left, bottom, right); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/Insets.java 2020-03-23 19:57:12.127962440 +0100 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +import javax.xml.stream.XMLStreamReader; + +class Insets { + int top; + int left; + int bottom; + int right; + + public Insets() { + this(0, 0, 0, 0); + } + + public Insets(int top, int left, int bottom, int right) { + this.top = top; + this.left = left; + this.bottom = bottom; + this.right = right; + } + + Insets(XMLStreamReader reader) { + top = Integer.parseInt(reader.getAttributeValue(null, "top")); + left = Integer.parseInt(reader.getAttributeValue(null, "left")); + bottom = Integer.parseInt(reader.getAttributeValue(null, "bottom")); + right = Integer.parseInt(reader.getAttributeValue(null, "right")); + } + + public String write(boolean uiResource) { + String uiSuffix = (uiResource ? "UIResource" : ""); + return String.format("new Insets%s(%d, %d, %d, %d)", + uiSuffix, top, left, bottom, right); + } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/Layer.java 2020-03-23 19:57:13.391962430 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; -import java.util.ArrayList; -import java.util.List; - -class Layer { - /** List of shapes in this layer, first shape is painted on top */ - private List shapes = new ArrayList(); - - Layer(XMLStreamReader reader) throws XMLStreamException { - while (reader.hasNext()) { - int eventType = reader.next(); - switch (eventType) { - case XMLStreamReader.START_ELEMENT: - switch (reader.getLocalName()) { - case "shapes": - shapes = new ArrayList<>(); - break; - case "ellipse": - shapes.add(new Ellipse(reader)); - break; - case "path": - shapes.add(new Path(reader)); - break; - case "rectangle": - shapes.add(new Rectangle(reader)); - break; - } - break; - case XMLStreamReader.END_ELEMENT: - switch (reader.getLocalName()) { - case "layer": - return; - } - break; - } - } - } - - public List getShapes() { return shapes; } - - public boolean isEmpty() { - return shapes.isEmpty(); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/Layer.java 2020-03-23 19:57:12.947962434 +0100 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import java.util.ArrayList; +import java.util.List; + +class Layer { + /** List of shapes in this layer, first shape is painted on top */ + private List shapes = new ArrayList(); + + Layer(XMLStreamReader reader) throws XMLStreamException { + while (reader.hasNext()) { + int eventType = reader.next(); + switch (eventType) { + case XMLStreamReader.START_ELEMENT: + switch (reader.getLocalName()) { + case "shapes": + shapes = new ArrayList<>(); + break; + case "ellipse": + shapes.add(new Ellipse(reader)); + break; + case "path": + shapes.add(new Path(reader)); + break; + case "rectangle": + shapes.add(new Rectangle(reader)); + break; + } + break; + case XMLStreamReader.END_ELEMENT: + switch (reader.getLocalName()) { + case "layer": + return; + } + break; + } + } + } + + public List getShapes() { return shapes; } + + public boolean isEmpty() { + return shapes.isEmpty(); + } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/Matte.java 2020-03-23 19:57:14.251962424 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -import javax.xml.stream.XMLStreamReader; -import java.util.Optional; - -class Matte extends Paint { - private int red; - private int green; - private int blue; - private int alpha; - - private String uiDefaultParentName = null; - private float hueOffset = 0; - private float saturationOffset = 0; - private float brightnessOffset = 0; - private int alphaOffset = 0; - - private String componentPropertyName = null; - - public String getComponentPropertyName() { return componentPropertyName; } - - private boolean uiResource = true; - - Matte(XMLStreamReader reader) { - red = Integer.parseInt(reader.getAttributeValue(null, "red")); - green = Integer.parseInt(reader.getAttributeValue(null, "green")); - blue = Integer.parseInt(reader.getAttributeValue(null, "blue")); - alpha = Integer.parseInt(reader.getAttributeValue(null, "alpha")); - uiDefaultParentName = reader.getAttributeValue(null, - "uiDefaultParentName"); - hueOffset = Float.parseFloat(reader.getAttributeValue(null, - "hueOffset")); - saturationOffset = Float.parseFloat(reader.getAttributeValue(null, - "saturationOffset")); - brightnessOffset = Float.parseFloat(reader.getAttributeValue(null, - "brightnessOffset")); - alphaOffset = Integer.parseInt(reader.getAttributeValue(null, - "alphaOffset")); - componentPropertyName = reader.getAttributeValue(null, - "componentPropertyName"); - uiResource = Boolean.parseBoolean(Optional.ofNullable( - reader.getAttributeValue(null, "uiResource")).orElse("true")); - } - - public boolean isAbsolute() { - return uiDefaultParentName == null; - } - - public String getDeclaration() { - if (isAbsolute()) { - return String.format("new Color(%d, %d, %d, %d)", - red, green, blue, alpha); - } else { - return String.format("decodeColor(\"%s\", %sf, %sf, %sf, %d)", - uiDefaultParentName, String.valueOf(hueOffset), - String.valueOf(saturationOffset), - String.valueOf(brightnessOffset), alphaOffset); - } - } - - public String write() { - if (isAbsolute()) { - return String.format("%s, %s, %s, %s", red, green, blue, alpha); - } else { - String s = String.format("\"%s\", %sf, %sf, %sf, %d", - uiDefaultParentName, String.valueOf(hueOffset), - String.valueOf(saturationOffset), - String.valueOf(brightnessOffset), alphaOffset); - if (! uiResource) { - s += ", false"; - } - return s; - } - } - - public ComponentColor createComponentColor(String variableName) { - return new ComponentColor(componentPropertyName, variableName, - saturationOffset, brightnessOffset, alphaOffset); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/Matte.java 2020-03-23 19:57:13.807962427 +0100 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +import javax.xml.stream.XMLStreamReader; +import java.util.Optional; + +class Matte extends Paint { + private int red; + private int green; + private int blue; + private int alpha; + + private String uiDefaultParentName = null; + private float hueOffset = 0; + private float saturationOffset = 0; + private float brightnessOffset = 0; + private int alphaOffset = 0; + + private String componentPropertyName = null; + + public String getComponentPropertyName() { return componentPropertyName; } + + private boolean uiResource = true; + + Matte(XMLStreamReader reader) { + red = Integer.parseInt(reader.getAttributeValue(null, "red")); + green = Integer.parseInt(reader.getAttributeValue(null, "green")); + blue = Integer.parseInt(reader.getAttributeValue(null, "blue")); + alpha = Integer.parseInt(reader.getAttributeValue(null, "alpha")); + uiDefaultParentName = reader.getAttributeValue(null, + "uiDefaultParentName"); + hueOffset = Float.parseFloat(reader.getAttributeValue(null, + "hueOffset")); + saturationOffset = Float.parseFloat(reader.getAttributeValue(null, + "saturationOffset")); + brightnessOffset = Float.parseFloat(reader.getAttributeValue(null, + "brightnessOffset")); + alphaOffset = Integer.parseInt(reader.getAttributeValue(null, + "alphaOffset")); + componentPropertyName = reader.getAttributeValue(null, + "componentPropertyName"); + uiResource = Boolean.parseBoolean(Optional.ofNullable( + reader.getAttributeValue(null, "uiResource")).orElse("true")); + } + + public boolean isAbsolute() { + return uiDefaultParentName == null; + } + + public String getDeclaration() { + if (isAbsolute()) { + return String.format("new Color(%d, %d, %d, %d)", + red, green, blue, alpha); + } else { + return String.format("decodeColor(\"%s\", %sf, %sf, %sf, %d)", + uiDefaultParentName, String.valueOf(hueOffset), + String.valueOf(saturationOffset), + String.valueOf(brightnessOffset), alphaOffset); + } + } + + public String write() { + if (isAbsolute()) { + return String.format("%s, %s, %s, %s", red, green, blue, alpha); + } else { + String s = String.format("\"%s\", %sf, %sf, %sf, %d", + uiDefaultParentName, String.valueOf(hueOffset), + String.valueOf(saturationOffset), + String.valueOf(brightnessOffset), alphaOffset); + if (! uiResource) { + s += ", false"; + } + return s; + } + } + + public ComponentColor createComponentColor(String variableName) { + return new ComponentColor(componentPropertyName, variableName, + saturationOffset, brightnessOffset, alphaOffset); + } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/Paint.java 2020-03-23 19:57:15.095962418 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - - -public abstract class Paint { -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/Paint.java 2020-03-23 19:57:14.667962421 +0100 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + + +public abstract class Paint { +} --- old/make/jdk/src/classes/build/tools/generatenimbus/PainterGenerator.java 2020-03-23 19:57:15.959962412 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,638 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package build.tools.generatenimbus; - -import java.awt.geom.Point2D; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - - -/** - * PainterGenerator - Class for generating Painter class java source from a Canvas - * - * Following in the general theory that is used to generate a Painter file. - * - * Each Painter file represents a Region. So there is one painter file per region. In - * skin.laf we support Icon subregions, which are really just hacked versions of the - * parent region. - * - * In order to generate the most compact and efficient bytecode possible for the - * Painters, we actually perform the generation sequence in two steps. The first - * step is the analysis phase, where we walk through the SynthModel for the region - * and discover commonality among the different states in the region. For example, - * do they have common paths? Do they have common colors? Gradients? Is the painting - * code for the different states identical other than for colors? - * - * We gather this information up. On the second pass, we use this data to determine the - * methods that need to be generated, and the class variables that need to be generated. - * We try to keep the actual bytecode count as small as possible so that we may reduce - * the overall size of the look and feel significantly. - * - * @author Richard Bair - * @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 :-) - private int colorCounter = 1; - private int gradientCounter = 1; - private int radialCounter = 1; - private int pathCounter = 1; - private int rectCounter = 1; - private int roundRectCounter = 1; - private int ellipseCounter = 1; - - private int stateTypeCounter = 1; - - //during the first pass, we will construct these maps - private Map colors = new HashMap(); - /** - * Code=>method name. - */ - private Map methods = new HashMap(); - - //these variables hold the generated code - /** - * The source code in this variable will be used to define the various state types - */ - private StringBuilder stateTypeCode = new StringBuilder(); - /** - * The source code in this variable will be used to define the switch statement for painting - */ - private StringBuilder switchCode = new StringBuilder(); - /** - * The source code in this variable will be used to define the methods for painting each state - */ - private StringBuilder paintingCode = new StringBuilder(); - /** - * The source code in this variable will be used to add getExtendedCacheKeys - * implementation if needed. - */ - private StringBuilder getExtendedCacheKeysCode = new StringBuilder(); - /** - * The source code in this variable will be used to define the methods for decoding gradients - * and shapes. - */ - private StringBuilder gradientsCode = new StringBuilder(); - private StringBuilder colorCode = new StringBuilder(); - private StringBuilder shapesCode = new StringBuilder(); - /** - * Map of component colors keyed by state constant name - */ - private Map> componentColorsMap = - new LinkedHashMap>(); - /** - * For the current state the list of all component colors used by this - * painter, the index in this list is also the index in the runtime array - * of defaults and keys. - */ - private List componentColors = null; - - PainterGenerator(UIRegion r) { - generate(r); - } - - private void generate(UIRegion r) { - for (UIState state : r.getBackgroundStates()) { - Canvas canvas = state.getCanvas(); - String type = (r instanceof UIIconRegion ? r.getKey() : "Background"); - generate(state, canvas, type); - } - for (UIState state : r.getForegroundStates()) { - Canvas canvas = state.getCanvas(); - generate(state, canvas, "Foreground"); - } - for (UIState state : r.getBorderStates()) { - Canvas canvas = state.getCanvas(); - generate(state, canvas, "Border"); - } - //now check for any uiIconRegions, since these are collapsed together. - for (UIRegion sub : r.getSubRegions()) { - if (sub instanceof UIIconRegion) { - generate(sub); - } - } - //generate all the code for component colors - if (!componentColorsMap.isEmpty()) { - getExtendedCacheKeysCode - .append(" protected Object[] getExtendedCacheKeys(JComponent c) {\n") - .append(" Object[] extendedCacheKeys = null;\n") - .append(" switch(state) {\n"); - for (Map.Entry> entry : componentColorsMap.entrySet()) { - getExtendedCacheKeysCode - .append(" case ") - .append(entry.getKey()).append(":\n") - .append(" extendedCacheKeys = new Object[] {\n"); - for (int i=0; i(); - - stateTypeCode.append(" static final int ").append(stateType).append(" = ").append(stateTypeCounter++).append(";\n"); - - if (canvas.isBlank()) { - return; - } - - switchCode.append(" case ").append(stateType).append(": ").append(paintMethodName).append("(g); break;\n"); - paintingCode.append(" private void ").append(paintMethodName).append("(Graphics2D g) {\n"); - - //start by setting up common info needed to encode the control points - Insets in = canvas.getStretchingInsets(); - float a = in.left; - float b = canvas.getSize().width - in.right; - float c = in.top; - float d = canvas.getSize().height - in.bottom; - float width = canvas.getSize().width; - float height = canvas.getSize().height; - float cw = b - a; - float ch = d - c; - - Layer[] layers = canvas.getLayers().toArray(new Layer[0]); - for (int index=layers.length-1; index >= 0; index--) { - Layer layer = layers[index]; - - //shapes must be painted in reverse order - List shapes = layer.getShapes(); - for (int i=shapes.size()-1; i>=0; i--) { - Shape shape = shapes.get(i); - Paint paint = shape.getPaint(); - - /* - We attempt to write the minimal number of bytecodes as possible when - generating code. Due to the inherit complexities in determining what - is extraneous, we use the following system: - - We first generate the code for the shape. Then, we check to see if - this shape has already been generated. If so, then we defer to an - existing method. If not, then we will create a new methods, stick - the code in it, and refer to that method. - */ - - String shapeMethodName = null; // will contain the name of the method which creates the shape - String shapeVariable = null; // will be one of rect, roundRect, ellipse, or path. - String shapeMethodBody = null; - - if (shape instanceof Rectangle) { - Rectangle rshape = (Rectangle) shape; - float x1 = encode((float)rshape.getX1(), a, b, width); - float y1 = encode((float)rshape.getY1(), c, d, height); - float x2 = encode((float)rshape.getX2(), a, b, width); - float y2 = encode((float)rshape.getY2(), c, d, height); - if (rshape.isRounded()) { - //it is a rounded rectangle - float rounding = (float)rshape.getRounding(); - - shapeMethodBody = - " roundRect.setRoundRect(" + - writeDecodeX(x1) + ", //x\n" + - " " + writeDecodeY(y1) + ", //y\n" + - " " + writeDecodeX(x2) + " - " + writeDecodeX(x1) + ", //width\n" + - " " + writeDecodeY(y2) + " - " + writeDecodeY(y1) + ", //height\n" + - " " + rounding + "f, " + rounding + "f); //rounding"; - shapeVariable = "roundRect"; - } else { - shapeMethodBody = - " rect.setRect(" + - writeDecodeX(x1) + ", //x\n" + - " " + writeDecodeY(y1) + ", //y\n" + - " " + writeDecodeX(x2) + " - " + writeDecodeX(x1) + ", //width\n" + - " " + writeDecodeY(y2) + " - " + writeDecodeY(y1) + "); //height"; - shapeVariable = "rect"; - } - } else if (shape instanceof Ellipse) { - Ellipse eshape = (Ellipse) shape; - float x1 = encode((float)eshape.getX1(), a, b, width); - float y1 = encode((float)eshape.getY1(), c, d, height); - float x2 = encode((float)eshape.getX2(), a, b, width); - float y2 = encode((float)eshape.getY2(), c, d, height); - shapeMethodBody = - " ellipse.setFrame(" + - writeDecodeX(x1) + ", //x\n" + - " " + writeDecodeY(y1) + ", //y\n" + - " " + writeDecodeX(x2) + " - " + writeDecodeX(x1) + ", //width\n" + - " " + writeDecodeY(y2) + " - " + writeDecodeY(y1) + "); //height"; - shapeVariable = "ellipse"; - } else if (shape instanceof Path) { - Path pshape = (Path) shape; - List controlPoints = pshape.getControlPoints(); - Point first, last; - first = last = controlPoints.get(0); - StringBuilder buffer = new StringBuilder(); - buffer.append(" path.reset();\n"); - buffer.append(" path.moveTo(" + writeDecodeX(encode((float)first.getX(), a, b, width)) + ", " + writeDecodeY(encode((float)first.getY(), c, d, height)) + ");\n"); - for (int j=1; j b) { - r = 2 + ((x - b) / (w - b)); - } else if (x == a && x == b) { - return 1.5f; - } else { - r = 1 + ((x - a) / (b - a)); - } - - if (Float.isNaN(r)) { - if (debug) { - System.err.println("[Error] Encountered NaN: encode(" + x + ", " + a + ", " + b + ", " + w + ")"); - } - return 0; - } else if (Float.isInfinite(r)) { - if (debug) { - System.err.println("[Error] Encountered Infinity: encode(" + x + ", " + a + ", " + b + ", " + w + ")"); - } - return 0; - } else if (r < 0) { - if (debug) { - System.err.println("[Error] encoded value was less than 0: encode(" + x + ", " + a + ", " + b + ", " + w + ")"); - } - return 0; - } else if (r > 3) { - if (debug) { - System.err.println("[Error] encoded value was greater than 3: encode(" + x + ", " + a + ", " + b + ", " + w + ")"); - } - return 3; - } else { - return r; - } - } - - private String writeDecodeX(float encodedX) { - return "decodeX(" + encodedX + "f)"; - } - - private String writeDecodeY(float encodedY) { - return "decodeY(" + encodedY + "f)"; - } - - /** - * - * @param ex encoded x value - * @param x unencoded x value - * @param cpx unencoded cpx value - * @return - */ - private static String writeDecodeBezierX(double ex, double x, double cpx) { - return "decodeAnchorX(" + ex + "f, " + (cpx - x) + "f)"; - } - - /** - * - * @param ey encoded y value - * @param y unencoded y value - * @param cpy unencoded cpy value - * @return - */ - private static String writeDecodeBezierY(double ey, double y, double cpy) { - return "decodeAnchorY(" + ey + "f, " + (cpy - y) + "f)"; - } - - private String encodeMatte(Matte m) { - String declaration = m.getDeclaration(); - String variableName = colors.get(declaration); - if (variableName == null) { - variableName = "color" + colorCounter++; - colors.put(declaration, variableName); - colorCode.append(String.format(" private Color %s = %s;\n", - variableName, declaration)); - } - // handle component colors - if (m.getComponentPropertyName() != null) { - ComponentColor cc = m.createComponentColor(variableName); - int index = componentColors.indexOf(cc); - if (index == -1) { - index = componentColors.size(); - componentColors.add(cc); - } - return "(Color)componentColors[" + index + "]"; - } else { - return variableName; - } - } - - private String encodeGradient(Shape ps, Gradient g) { - StringBuilder b = new StringBuilder(); - float x1 = (float)ps.getPaintX1(); - float y1 = (float)ps.getPaintY1(); - float x2 = (float)ps.getPaintX2(); - float y2 = (float)ps.getPaintY2(); - b.append(" return decodeGradient(("); - b.append(x1); - b.append("f * w) + x, ("); - b.append(y1); - b.append("f * h) + y, ("); - b.append(x2); - b.append("f * w) + x, ("); - b.append(y2); - b.append("f * h) + y,\n"); - encodeGradientColorsAndFractions(g,b); - b.append(");"); - - String methodBody = b.toString(); - String methodName = methods.get(methodBody); - if (methodName == null) { - methodName = "decodeGradient" + gradientCounter++; - gradientsCode.append(" private Paint ").append(methodName).append("(Shape s) {\n"); - gradientsCode.append(" Rectangle2D bounds = s.getBounds2D();\n"); - gradientsCode.append(" float x = (float)bounds.getX();\n"); - gradientsCode.append(" float y = (float)bounds.getY();\n"); - gradientsCode.append(" float w = (float)bounds.getWidth();\n"); - gradientsCode.append(" float h = (float)bounds.getHeight();\n"); - gradientsCode.append(methodBody); - gradientsCode.append("\n }\n\n"); - methods.put(methodBody, methodName); - } - return methodName; - } - - /** - * Takes a abstract gradient and creates the code for the fractions float - * array and the colors array that can be used in the constructors of linear - * and radial gradients. - * - * @param g The abstract gradient to get stops from - * @param b Append code string of the form "new float[]{...}, - * new Color[]{...}" to this StringBuilder - */ - private void encodeGradientColorsAndFractions(AbstractGradient g, - StringBuilder b) { - List stops = g.getStops(); - // there are stops.size() number of main stops. Between each is a - // fractional stop. Thus, there are: stops.size() + stops.size() - 1 - // number of fractions and colors. - float[] fractions = new float[stops.size() + stops.size() - 1]; - String[] colors = new String[fractions.length]; - //for each stop, create the stop and it's associated fraction - int index = 0; // the index into fractions and colors - for (int i = 0; i < stops.size(); i++) { - GradientStop s = stops.get(i); - //copy over the stop's data - colors[index] = encodeMatte(s.getColor()); - fractions[index] = s.getPosition(); - - //If this isn't the last stop, then add in the fraction - if (index < fractions.length - 1) { - float f1 = s.getPosition(); - float f2 = stops.get(i + 1).getPosition(); - index++; - fractions[index] = f1 + (f2 - f1) * s.getMidpoint(); - colors[index] = "decodeColor("+ - colors[index - 1]+","+ - encodeMatte(stops.get(i + 1).getColor())+",0.5f)"; - } - index++; - } - // Check boundry conditions - for (int i = 1; i < fractions.length; i++) { - //to avoid an error with LinearGradientPaint where two fractions - //are identical, bump up the fraction value by a miniscule amount - //if it is identical to the previous one - //NOTE: The <= is critical because the previous value may already - //have been bumped up - if (fractions[i] <= fractions[i - 1]) { - fractions[i] = fractions[i - 1] + .000001f; - } - } - //another boundary condition where multiple stops are all at the end. The - //previous loop bumped all but one of these past 1.0, which is bad. - //so remove any fractions (and their colors!) that are beyond 1.0 - int outOfBoundsIndex = -1; - for (int i = 0; i < fractions.length; i++) { - if (fractions[i] > 1) { - outOfBoundsIndex = i; - break; - } - } - if (outOfBoundsIndex >= 0) { - float[] f = fractions; - String[] c = colors; - fractions = new float[outOfBoundsIndex]; - colors = new String[outOfBoundsIndex]; - System.arraycopy(f, 0, fractions, 0, outOfBoundsIndex); - System.arraycopy(c, 0, colors, 0, outOfBoundsIndex); - } - // build string - b.append(" new float[] { "); - for (int i = 0; i < fractions.length; i++) { - if (i>0)b.append(','); - b.append(fractions[i]); - b.append('f'); - } - b.append(" },\n new Color[] { "); - for (int i = 0; i < colors.length; i++) { - if (i>0) b.append(",\n "); - b.append(colors[i]); - } - b.append("}"); - } - - private String encodeRadial(Shape ps, RadialGradient g) { - float centerX1 = (float)ps.getPaintX1(); - float centerY1 = (float)ps.getPaintY1(); - float x2 = (float)ps.getPaintX2(); - float y2 = (float)ps.getPaintY2(); - float radius = (float)Point2D.distance(centerX1, centerY1, x2, y2); - StringBuilder b = new StringBuilder(); - - b.append(" return decodeRadialGradient(("); - b.append(centerX1); - b.append("f * w) + x, ("); - b.append(centerY1); - b.append("f * h) + y, "); - b.append(radius); - b.append("f,\n"); - encodeGradientColorsAndFractions(g,b); - b.append(");"); - - String methodBody = b.toString(); - String methodName = methods.get(methodBody); - if (methodName == null) { - methodName = "decodeRadial" + radialCounter++; - gradientsCode.append(" private Paint ").append(methodName).append("(Shape s) {\n"); - gradientsCode.append(" Rectangle2D bounds = s.getBounds2D();\n"); - gradientsCode.append(" float x = (float)bounds.getX();\n"); - gradientsCode.append(" float y = (float)bounds.getY();\n"); - gradientsCode.append(" float w = (float)bounds.getWidth();\n"); - gradientsCode.append(" float h = (float)bounds.getHeight();\n"); - gradientsCode.append(methodBody); - gradientsCode.append("\n }\n\n"); - methods.put(methodBody, methodName); - } - return methodName; - } - - //note that this method is not thread-safe. In fact, none of this class is. - public static void writePainter(UIRegion r, String painterName) { - //Need only write out the stuff for this region, don't need to worry about subregions - //since this method will be called for each of those (and they go in their own file, anyway). - //The only subregion that we compound into this is the one for icons. - PainterGenerator gen = new PainterGenerator(r); - System.out.println("Generating source file: " + painterName + ".java"); - - Map variables = Generator.getVariables(); - variables.put("PAINTER_NAME", painterName); - variables.put("STATIC_DECL", gen.stateTypeCode.toString()); - variables.put("COLORS_DECL", gen.colorCode.toString()); - variables.put("DO_PAINT_SWITCH_BODY", gen.switchCode.toString()); - variables.put("PAINTING_DECL", gen.paintingCode.toString()); - variables.put("GET_EXTENDED_CACHE_KEYS", gen.getExtendedCacheKeysCode.toString()); - variables.put("SHAPES_DECL", gen.shapesCode.toString()); - variables.put("GRADIENTS_DECL", gen.gradientsCode.toString()); - - Generator.writeSrcFile("PainterImpl", variables, painterName); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/PainterGenerator.java 2020-03-23 19:57:15.527962415 +0100 @@ -0,0 +1,638 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.buildtools.generatenimbus; + +import java.awt.geom.Point2D; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + + +/** + * PainterGenerator - Class for generating Painter class java source from a Canvas + * + * Following in the general theory that is used to generate a Painter file. + * + * Each Painter file represents a Region. So there is one painter file per region. In + * skin.laf we support Icon subregions, which are really just hacked versions of the + * parent region. + * + * In order to generate the most compact and efficient bytecode possible for the + * Painters, we actually perform the generation sequence in two steps. The first + * step is the analysis phase, where we walk through the SynthModel for the region + * and discover commonality among the different states in the region. For example, + * do they have common paths? Do they have common colors? Gradients? Is the painting + * code for the different states identical other than for colors? + * + * We gather this information up. On the second pass, we use this data to determine the + * methods that need to be generated, and the class variables that need to be generated. + * We try to keep the actual bytecode count as small as possible so that we may reduce + * the overall size of the look and feel significantly. + * + * @author Richard Bair + * @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 :-) + private int colorCounter = 1; + private int gradientCounter = 1; + private int radialCounter = 1; + private int pathCounter = 1; + private int rectCounter = 1; + private int roundRectCounter = 1; + private int ellipseCounter = 1; + + private int stateTypeCounter = 1; + + //during the first pass, we will construct these maps + private Map colors = new HashMap(); + /** + * Code=>method name. + */ + private Map methods = new HashMap(); + + //these variables hold the generated code + /** + * The source code in this variable will be used to define the various state types + */ + private StringBuilder stateTypeCode = new StringBuilder(); + /** + * The source code in this variable will be used to define the switch statement for painting + */ + private StringBuilder switchCode = new StringBuilder(); + /** + * The source code in this variable will be used to define the methods for painting each state + */ + private StringBuilder paintingCode = new StringBuilder(); + /** + * The source code in this variable will be used to add getExtendedCacheKeys + * implementation if needed. + */ + private StringBuilder getExtendedCacheKeysCode = new StringBuilder(); + /** + * The source code in this variable will be used to define the methods for decoding gradients + * and shapes. + */ + private StringBuilder gradientsCode = new StringBuilder(); + private StringBuilder colorCode = new StringBuilder(); + private StringBuilder shapesCode = new StringBuilder(); + /** + * Map of component colors keyed by state constant name + */ + private Map> componentColorsMap = + new LinkedHashMap>(); + /** + * For the current state the list of all component colors used by this + * painter, the index in this list is also the index in the runtime array + * of defaults and keys. + */ + private List componentColors = null; + + PainterGenerator(UIRegion r) { + generate(r); + } + + private void generate(UIRegion r) { + for (UIState state : r.getBackgroundStates()) { + Canvas canvas = state.getCanvas(); + String type = (r instanceof UIIconRegion ? r.getKey() : "Background"); + generate(state, canvas, type); + } + for (UIState state : r.getForegroundStates()) { + Canvas canvas = state.getCanvas(); + generate(state, canvas, "Foreground"); + } + for (UIState state : r.getBorderStates()) { + Canvas canvas = state.getCanvas(); + generate(state, canvas, "Border"); + } + //now check for any uiIconRegions, since these are collapsed together. + for (UIRegion sub : r.getSubRegions()) { + if (sub instanceof UIIconRegion) { + generate(sub); + } + } + //generate all the code for component colors + if (!componentColorsMap.isEmpty()) { + getExtendedCacheKeysCode + .append(" protected Object[] getExtendedCacheKeys(JComponent c) {\n") + .append(" Object[] extendedCacheKeys = null;\n") + .append(" switch(state) {\n"); + for (Map.Entry> entry : componentColorsMap.entrySet()) { + getExtendedCacheKeysCode + .append(" case ") + .append(entry.getKey()).append(":\n") + .append(" extendedCacheKeys = new Object[] {\n"); + for (int i=0; i(); + + stateTypeCode.append(" static final int ").append(stateType).append(" = ").append(stateTypeCounter++).append(";\n"); + + if (canvas.isBlank()) { + return; + } + + switchCode.append(" case ").append(stateType).append(": ").append(paintMethodName).append("(g); break;\n"); + paintingCode.append(" private void ").append(paintMethodName).append("(Graphics2D g) {\n"); + + //start by setting up common info needed to encode the control points + Insets in = canvas.getStretchingInsets(); + float a = in.left; + float b = canvas.getSize().width - in.right; + float c = in.top; + float d = canvas.getSize().height - in.bottom; + float width = canvas.getSize().width; + float height = canvas.getSize().height; + float cw = b - a; + float ch = d - c; + + Layer[] layers = canvas.getLayers().toArray(new Layer[0]); + for (int index=layers.length-1; index >= 0; index--) { + Layer layer = layers[index]; + + //shapes must be painted in reverse order + List shapes = layer.getShapes(); + for (int i=shapes.size()-1; i>=0; i--) { + Shape shape = shapes.get(i); + Paint paint = shape.getPaint(); + + /* + We attempt to write the minimal number of bytecodes as possible when + generating code. Due to the inherit complexities in determining what + is extraneous, we use the following system: + + We first generate the code for the shape. Then, we check to see if + this shape has already been generated. If so, then we defer to an + existing method. If not, then we will create a new methods, stick + the code in it, and refer to that method. + */ + + String shapeMethodName = null; // will contain the name of the method which creates the shape + String shapeVariable = null; // will be one of rect, roundRect, ellipse, or path. + String shapeMethodBody = null; + + if (shape instanceof Rectangle) { + Rectangle rshape = (Rectangle) shape; + float x1 = encode((float)rshape.getX1(), a, b, width); + float y1 = encode((float)rshape.getY1(), c, d, height); + float x2 = encode((float)rshape.getX2(), a, b, width); + float y2 = encode((float)rshape.getY2(), c, d, height); + if (rshape.isRounded()) { + //it is a rounded rectangle + float rounding = (float)rshape.getRounding(); + + shapeMethodBody = + " roundRect.setRoundRect(" + + writeDecodeX(x1) + ", //x\n" + + " " + writeDecodeY(y1) + ", //y\n" + + " " + writeDecodeX(x2) + " - " + writeDecodeX(x1) + ", //width\n" + + " " + writeDecodeY(y2) + " - " + writeDecodeY(y1) + ", //height\n" + + " " + rounding + "f, " + rounding + "f); //rounding"; + shapeVariable = "roundRect"; + } else { + shapeMethodBody = + " rect.setRect(" + + writeDecodeX(x1) + ", //x\n" + + " " + writeDecodeY(y1) + ", //y\n" + + " " + writeDecodeX(x2) + " - " + writeDecodeX(x1) + ", //width\n" + + " " + writeDecodeY(y2) + " - " + writeDecodeY(y1) + "); //height"; + shapeVariable = "rect"; + } + } else if (shape instanceof Ellipse) { + Ellipse eshape = (Ellipse) shape; + float x1 = encode((float)eshape.getX1(), a, b, width); + float y1 = encode((float)eshape.getY1(), c, d, height); + float x2 = encode((float)eshape.getX2(), a, b, width); + float y2 = encode((float)eshape.getY2(), c, d, height); + shapeMethodBody = + " ellipse.setFrame(" + + writeDecodeX(x1) + ", //x\n" + + " " + writeDecodeY(y1) + ", //y\n" + + " " + writeDecodeX(x2) + " - " + writeDecodeX(x1) + ", //width\n" + + " " + writeDecodeY(y2) + " - " + writeDecodeY(y1) + "); //height"; + shapeVariable = "ellipse"; + } else if (shape instanceof Path) { + Path pshape = (Path) shape; + List controlPoints = pshape.getControlPoints(); + Point first, last; + first = last = controlPoints.get(0); + StringBuilder buffer = new StringBuilder(); + buffer.append(" path.reset();\n"); + buffer.append(" path.moveTo(" + writeDecodeX(encode((float)first.getX(), a, b, width)) + ", " + writeDecodeY(encode((float)first.getY(), c, d, height)) + ");\n"); + for (int j=1; j b) { + r = 2 + ((x - b) / (w - b)); + } else if (x == a && x == b) { + return 1.5f; + } else { + r = 1 + ((x - a) / (b - a)); + } + + if (Float.isNaN(r)) { + if (debug) { + System.err.println("[Error] Encountered NaN: encode(" + x + ", " + a + ", " + b + ", " + w + ")"); + } + return 0; + } else if (Float.isInfinite(r)) { + if (debug) { + System.err.println("[Error] Encountered Infinity: encode(" + x + ", " + a + ", " + b + ", " + w + ")"); + } + return 0; + } else if (r < 0) { + if (debug) { + System.err.println("[Error] encoded value was less than 0: encode(" + x + ", " + a + ", " + b + ", " + w + ")"); + } + return 0; + } else if (r > 3) { + if (debug) { + System.err.println("[Error] encoded value was greater than 3: encode(" + x + ", " + a + ", " + b + ", " + w + ")"); + } + return 3; + } else { + return r; + } + } + + private String writeDecodeX(float encodedX) { + return "decodeX(" + encodedX + "f)"; + } + + private String writeDecodeY(float encodedY) { + return "decodeY(" + encodedY + "f)"; + } + + /** + * + * @param ex encoded x value + * @param x unencoded x value + * @param cpx unencoded cpx value + * @return + */ + private static String writeDecodeBezierX(double ex, double x, double cpx) { + return "decodeAnchorX(" + ex + "f, " + (cpx - x) + "f)"; + } + + /** + * + * @param ey encoded y value + * @param y unencoded y value + * @param cpy unencoded cpy value + * @return + */ + private static String writeDecodeBezierY(double ey, double y, double cpy) { + return "decodeAnchorY(" + ey + "f, " + (cpy - y) + "f)"; + } + + private String encodeMatte(Matte m) { + String declaration = m.getDeclaration(); + String variableName = colors.get(declaration); + if (variableName == null) { + variableName = "color" + colorCounter++; + colors.put(declaration, variableName); + colorCode.append(String.format(" private Color %s = %s;\n", + variableName, declaration)); + } + // handle component colors + if (m.getComponentPropertyName() != null) { + ComponentColor cc = m.createComponentColor(variableName); + int index = componentColors.indexOf(cc); + if (index == -1) { + index = componentColors.size(); + componentColors.add(cc); + } + return "(Color)componentColors[" + index + "]"; + } else { + return variableName; + } + } + + private String encodeGradient(Shape ps, Gradient g) { + StringBuilder b = new StringBuilder(); + float x1 = (float)ps.getPaintX1(); + float y1 = (float)ps.getPaintY1(); + float x2 = (float)ps.getPaintX2(); + float y2 = (float)ps.getPaintY2(); + b.append(" return decodeGradient(("); + b.append(x1); + b.append("f * w) + x, ("); + b.append(y1); + b.append("f * h) + y, ("); + b.append(x2); + b.append("f * w) + x, ("); + b.append(y2); + b.append("f * h) + y,\n"); + encodeGradientColorsAndFractions(g,b); + b.append(");"); + + String methodBody = b.toString(); + String methodName = methods.get(methodBody); + if (methodName == null) { + methodName = "decodeGradient" + gradientCounter++; + gradientsCode.append(" private Paint ").append(methodName).append("(Shape s) {\n"); + gradientsCode.append(" Rectangle2D bounds = s.getBounds2D();\n"); + gradientsCode.append(" float x = (float)bounds.getX();\n"); + gradientsCode.append(" float y = (float)bounds.getY();\n"); + gradientsCode.append(" float w = (float)bounds.getWidth();\n"); + gradientsCode.append(" float h = (float)bounds.getHeight();\n"); + gradientsCode.append(methodBody); + gradientsCode.append("\n }\n\n"); + methods.put(methodBody, methodName); + } + return methodName; + } + + /** + * Takes a abstract gradient and creates the code for the fractions float + * array and the colors array that can be used in the constructors of linear + * and radial gradients. + * + * @param g The abstract gradient to get stops from + * @param b Append code string of the form "new float[]{...}, + * new Color[]{...}" to this StringBuilder + */ + private void encodeGradientColorsAndFractions(AbstractGradient g, + StringBuilder b) { + List stops = g.getStops(); + // there are stops.size() number of main stops. Between each is a + // fractional stop. Thus, there are: stops.size() + stops.size() - 1 + // number of fractions and colors. + float[] fractions = new float[stops.size() + stops.size() - 1]; + String[] colors = new String[fractions.length]; + //for each stop, create the stop and it's associated fraction + int index = 0; // the index into fractions and colors + for (int i = 0; i < stops.size(); i++) { + GradientStop s = stops.get(i); + //copy over the stop's data + colors[index] = encodeMatte(s.getColor()); + fractions[index] = s.getPosition(); + + //If this isn't the last stop, then add in the fraction + if (index < fractions.length - 1) { + float f1 = s.getPosition(); + float f2 = stops.get(i + 1).getPosition(); + index++; + fractions[index] = f1 + (f2 - f1) * s.getMidpoint(); + colors[index] = "decodeColor("+ + colors[index - 1]+","+ + encodeMatte(stops.get(i + 1).getColor())+",0.5f)"; + } + index++; + } + // Check boundry conditions + for (int i = 1; i < fractions.length; i++) { + //to avoid an error with LinearGradientPaint where two fractions + //are identical, bump up the fraction value by a miniscule amount + //if it is identical to the previous one + //NOTE: The <= is critical because the previous value may already + //have been bumped up + if (fractions[i] <= fractions[i - 1]) { + fractions[i] = fractions[i - 1] + .000001f; + } + } + //another boundary condition where multiple stops are all at the end. The + //previous loop bumped all but one of these past 1.0, which is bad. + //so remove any fractions (and their colors!) that are beyond 1.0 + int outOfBoundsIndex = -1; + for (int i = 0; i < fractions.length; i++) { + if (fractions[i] > 1) { + outOfBoundsIndex = i; + break; + } + } + if (outOfBoundsIndex >= 0) { + float[] f = fractions; + String[] c = colors; + fractions = new float[outOfBoundsIndex]; + colors = new String[outOfBoundsIndex]; + System.arraycopy(f, 0, fractions, 0, outOfBoundsIndex); + System.arraycopy(c, 0, colors, 0, outOfBoundsIndex); + } + // build string + b.append(" new float[] { "); + for (int i = 0; i < fractions.length; i++) { + if (i>0)b.append(','); + b.append(fractions[i]); + b.append('f'); + } + b.append(" },\n new Color[] { "); + for (int i = 0; i < colors.length; i++) { + if (i>0) b.append(",\n "); + b.append(colors[i]); + } + b.append("}"); + } + + private String encodeRadial(Shape ps, RadialGradient g) { + float centerX1 = (float)ps.getPaintX1(); + float centerY1 = (float)ps.getPaintY1(); + float x2 = (float)ps.getPaintX2(); + float y2 = (float)ps.getPaintY2(); + float radius = (float)Point2D.distance(centerX1, centerY1, x2, y2); + StringBuilder b = new StringBuilder(); + + b.append(" return decodeRadialGradient(("); + b.append(centerX1); + b.append("f * w) + x, ("); + b.append(centerY1); + b.append("f * h) + y, "); + b.append(radius); + b.append("f,\n"); + encodeGradientColorsAndFractions(g,b); + b.append(");"); + + String methodBody = b.toString(); + String methodName = methods.get(methodBody); + if (methodName == null) { + methodName = "decodeRadial" + radialCounter++; + gradientsCode.append(" private Paint ").append(methodName).append("(Shape s) {\n"); + gradientsCode.append(" Rectangle2D bounds = s.getBounds2D();\n"); + gradientsCode.append(" float x = (float)bounds.getX();\n"); + gradientsCode.append(" float y = (float)bounds.getY();\n"); + gradientsCode.append(" float w = (float)bounds.getWidth();\n"); + gradientsCode.append(" float h = (float)bounds.getHeight();\n"); + gradientsCode.append(methodBody); + gradientsCode.append("\n }\n\n"); + methods.put(methodBody, methodName); + } + return methodName; + } + + //note that this method is not thread-safe. In fact, none of this class is. + public static void writePainter(UIRegion r, String painterName) { + //Need only write out the stuff for this region, don't need to worry about subregions + //since this method will be called for each of those (and they go in their own file, anyway). + //The only subregion that we compound into this is the one for icons. + PainterGenerator gen = new PainterGenerator(r); + System.out.println("Generating source file: " + painterName + ".java"); + + Map variables = Generator.getVariables(); + variables.put("PAINTER_NAME", painterName); + variables.put("STATIC_DECL", gen.stateTypeCode.toString()); + variables.put("COLORS_DECL", gen.colorCode.toString()); + variables.put("DO_PAINT_SWITCH_BODY", gen.switchCode.toString()); + variables.put("PAINTING_DECL", gen.paintingCode.toString()); + variables.put("GET_EXTENDED_CACHE_KEYS", gen.getExtendedCacheKeysCode.toString()); + variables.put("SHAPES_DECL", gen.shapesCode.toString()); + variables.put("GRADIENTS_DECL", gen.gradientsCode.toString()); + + Generator.writeSrcFile("PainterImpl", variables, painterName); + } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/Path.java 2020-03-23 19:57:16.779962405 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; -import java.util.ArrayList; -import java.util.List; - -class Path extends Shape { - private List controlPoints = new ArrayList(); - - Path(XMLStreamReader reader) throws XMLStreamException { - while (reader.hasNext()) { - int eventType = reader.next(); - switch (eventType) { - case XMLStreamReader.START_ELEMENT: - switch (reader.getLocalName()) { - case "points": - controlPoints = new ArrayList<>(); - break; - case "point": - controlPoints.add(new Point(reader)); - break; - case "matte": - paint = new Matte(reader); - break; - case "gradient": - paint = new Gradient(reader); - break; - case "radialGradient": - paint = new RadialGradient(reader); - break; - case "paintPoints": - paintPoints = new PaintPoints(reader); - break; - } - break; - case XMLStreamReader.END_ELEMENT: - switch (reader.getLocalName()) { - case "path": - return; - } - break; - } - } - } - - public List getControlPoints() { return controlPoints; } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/Path.java 2020-03-23 19:57:16.407962408 +0100 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import java.util.ArrayList; +import java.util.List; + +class Path extends Shape { + private List controlPoints = new ArrayList(); + + Path(XMLStreamReader reader) throws XMLStreamException { + while (reader.hasNext()) { + int eventType = reader.next(); + switch (eventType) { + case XMLStreamReader.START_ELEMENT: + switch (reader.getLocalName()) { + case "points": + controlPoints = new ArrayList<>(); + break; + case "point": + controlPoints.add(new Point(reader)); + break; + case "matte": + paint = new Matte(reader); + break; + case "gradient": + paint = new Gradient(reader); + break; + case "radialGradient": + paint = new RadialGradient(reader); + break; + case "paintPoints": + paintPoints = new PaintPoints(reader); + break; + } + break; + case XMLStreamReader.END_ELEMENT: + switch (reader.getLocalName()) { + case "path": + return; + } + break; + } + } + } + + public List getControlPoints() { return controlPoints; } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/Point.java 2020-03-23 19:57:17.615962399 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -import javax.xml.stream.XMLStreamReader; - -class Point { - private double x; - - public double getX() { return x; } - - private double y; - public double getY() { return y; } - - private double cp1x; - public double getCp1X() { return cp1x; } - - private double cp1y; - public double getCp1Y() { return cp1y; } - - private double cp2x; - public double getCp2X() { return cp2x; } - - private double cp2y; - public double getCp2Y() { return cp2y; } - - Point(XMLStreamReader reader) { - x = Double.parseDouble(reader.getAttributeValue(null, "x")); - y = Double.parseDouble(reader.getAttributeValue(null, "y")); - cp1x = Double.parseDouble(reader.getAttributeValue(null, "cp1x")); - cp1y = Double.parseDouble(reader.getAttributeValue(null, "cp1y")); - cp2x = Double.parseDouble(reader.getAttributeValue(null, "cp2x")); - cp2y = Double.parseDouble(reader.getAttributeValue(null, "cp2y")); - } - - public boolean isP1Sharp() { - return cp1x == x && cp1y == y; - } - - public boolean isP2Sharp() { - return cp2x == x && cp2y == y; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/Point.java 2020-03-23 19:57:17.191962402 +0100 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +import javax.xml.stream.XMLStreamReader; + +class Point { + private double x; + + public double getX() { return x; } + + private double y; + public double getY() { return y; } + + private double cp1x; + public double getCp1X() { return cp1x; } + + private double cp1y; + public double getCp1Y() { return cp1y; } + + private double cp2x; + public double getCp2X() { return cp2x; } + + private double cp2y; + public double getCp2Y() { return cp2y; } + + Point(XMLStreamReader reader) { + x = Double.parseDouble(reader.getAttributeValue(null, "x")); + y = Double.parseDouble(reader.getAttributeValue(null, "y")); + cp1x = Double.parseDouble(reader.getAttributeValue(null, "cp1x")); + cp1y = Double.parseDouble(reader.getAttributeValue(null, "cp1y")); + cp2x = Double.parseDouble(reader.getAttributeValue(null, "cp2x")); + cp2y = Double.parseDouble(reader.getAttributeValue(null, "cp2y")); + } + + public boolean isP1Sharp() { + return cp1x == x && cp1y == y; + } + + public boolean isP2Sharp() { + return cp2x == x && cp2y == y; + } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/RadialGradient.java 2020-03-23 19:57:18.455962393 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; - -class RadialGradient extends AbstractGradient { - RadialGradient(XMLStreamReader reader) throws XMLStreamException { - super(reader); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/RadialGradient.java 2020-03-23 19:57:18.059962396 +0100 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +class RadialGradient extends AbstractGradient { + RadialGradient(XMLStreamReader reader) throws XMLStreamException { + super(reader); + } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/Rectangle.java 2020-03-23 19:57:19.271962387 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; - -class Rectangle extends Shape { - private double x1; - - public double getX1() { return x1; } - - private double x2; - public double getX2() { return x2; } - - private double y1; - public double getY1() { return y1; } - - private double y2; - public double getY2() { return y2; } - - public double getRounding() { - double rounding = Math.abs(roundingX - x1) * 2; - return rounding > 2 ? rounding : 0; - } - - public void setRounding(double rounding) { - if (rounding > 0 && rounding < 2) { - rounding = 0; - } - roundingX = rounding / 2d + x1; - } - private double roundingX; - - public boolean isRounded() { - return getRounding() > 0; - } - - Rectangle(XMLStreamReader reader) throws XMLStreamException { - x1 = Double.parseDouble(reader.getAttributeValue(null, "x1")); - x2 = Double.parseDouble(reader.getAttributeValue(null, "x2")); - y1 = Double.parseDouble(reader.getAttributeValue(null, "y1")); - y2 = Double.parseDouble(reader.getAttributeValue(null, "y2")); - setRounding(Double.parseDouble(reader.getAttributeValue(null, "rounding"))); - while (reader.hasNext()) { - int eventType = reader.next(); - switch (eventType) { - case XMLStreamReader.START_ELEMENT: - switch (reader.getLocalName()) { - case "matte": - paint = new Matte(reader); - break; - case "gradient": - paint = new Gradient(reader); - break; - case "radialGradient": - paint = new RadialGradient(reader); - break; - case "paintPoints": - paintPoints = new PaintPoints(reader); - break; - } - break; - case XMLStreamReader.END_ELEMENT: - switch (reader.getLocalName()) { - case "rectangle": - return; - } - break; - } - } - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/Rectangle.java 2020-03-23 19:57:18.835962390 +0100 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +class Rectangle extends Shape { + private double x1; + + public double getX1() { return x1; } + + private double x2; + public double getX2() { return x2; } + + private double y1; + public double getY1() { return y1; } + + private double y2; + public double getY2() { return y2; } + + public double getRounding() { + double rounding = Math.abs(roundingX - x1) * 2; + return rounding > 2 ? rounding : 0; + } + + public void setRounding(double rounding) { + if (rounding > 0 && rounding < 2) { + rounding = 0; + } + roundingX = rounding / 2d + x1; + } + private double roundingX; + + public boolean isRounded() { + return getRounding() > 0; + } + + Rectangle(XMLStreamReader reader) throws XMLStreamException { + x1 = Double.parseDouble(reader.getAttributeValue(null, "x1")); + x2 = Double.parseDouble(reader.getAttributeValue(null, "x2")); + y1 = Double.parseDouble(reader.getAttributeValue(null, "y1")); + y2 = Double.parseDouble(reader.getAttributeValue(null, "y2")); + setRounding(Double.parseDouble(reader.getAttributeValue(null, "rounding"))); + while (reader.hasNext()) { + int eventType = reader.next(); + switch (eventType) { + case XMLStreamReader.START_ELEMENT: + switch (reader.getLocalName()) { + case "matte": + paint = new Matte(reader); + break; + case "gradient": + paint = new Gradient(reader); + break; + case "radialGradient": + paint = new RadialGradient(reader); + break; + case "paintPoints": + paintPoints = new PaintPoints(reader); + break; + } + break; + case XMLStreamReader.END_ELEMENT: + switch (reader.getLocalName()) { + case "rectangle": + return; + } + break; + } + } + } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/Shape.java 2020-03-23 19:57:20.031962381 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -import javax.xml.stream.XMLStreamReader; - -public abstract class Shape { - PaintPoints paintPoints; - - public double getPaintX1() { return paintPoints.x1; } - public double getPaintX2() { return paintPoints.x2; } - public double getPaintY1() { return paintPoints.y1; } - public double getPaintY2() { return paintPoints.y2; } - - Paint paint; - public Paint getPaint() { return paint; } - - static class PaintPoints { - double x1; - double y1; - double x2; - double y2; - - PaintPoints(XMLStreamReader reader) { - x1 = Double.parseDouble(reader.getAttributeValue(null, "x1")); - x2 = Double.parseDouble(reader.getAttributeValue(null, "x2")); - y1 = Double.parseDouble(reader.getAttributeValue(null, "y1")); - y2 = Double.parseDouble(reader.getAttributeValue(null, "y2")); - } - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/Shape.java 2020-03-23 19:57:19.655962384 +0100 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +import javax.xml.stream.XMLStreamReader; + +public abstract class Shape { + PaintPoints paintPoints; + + public double getPaintX1() { return paintPoints.x1; } + public double getPaintX2() { return paintPoints.x2; } + public double getPaintY1() { return paintPoints.y1; } + public double getPaintY2() { return paintPoints.y2; } + + Paint paint; + public Paint getPaint() { return paint; } + + static class PaintPoints { + double x1; + double y1; + double x2; + double y2; + + PaintPoints(XMLStreamReader reader) { + x1 = Double.parseDouble(reader.getAttributeValue(null, "x1")); + x2 = Double.parseDouble(reader.getAttributeValue(null, "x2")); + y1 = Double.parseDouble(reader.getAttributeValue(null, "y1")); + y2 = Double.parseDouble(reader.getAttributeValue(null, "y2")); + } + } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/SynthModel.java 2020-03-23 19:57:20.871962375 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; -import java.util.ArrayList; - -public class SynthModel { - private UIStyle style; - - private ArrayList colors; - - private ArrayList fonts; - - private ArrayList components; - - SynthModel(XMLStreamReader reader) throws XMLStreamException { - while (reader.hasNext()) { - int eventType = reader.next(); - switch (eventType) { - case XMLStreamReader.START_ELEMENT: - switch (reader.getLocalName()) { - case "style": - style = new UIStyle(reader); - break; - case "colors": - colors = new ArrayList<>(); - break; - case "fonts": - fonts = new ArrayList<>(); - break; - case "components": - components = new ArrayList<>(); - break; - case "uiColor": - colors.add(new UIColor(reader)); - break; - case "uiFont": - fonts.add(new UIFont(reader)); - break; - case "uiComponent": - components.add(new UIComponent(reader)); - break; - } - break; - case XMLStreamReader.END_ELEMENT: - break; - } - } - } - - public void initStyles() { - for (UIComponent c: components) { - c.initStyles(this.style); - } - } - - public void write(StringBuilder defBuffer, StringBuilder styleBuffer, String packageName) { - defBuffer.append(" //Color palette\n"); - for (UIColor c: colors) defBuffer.append(c.write()); - defBuffer.append('\n'); - - defBuffer.append(" //Font palette\n"); - defBuffer.append(" d.put(\"defaultFont\", new FontUIResource(defaultFont));\n"); - for (UIFont f: fonts) defBuffer.append(f.write()); - defBuffer.append('\n'); - - defBuffer.append(" //Border palette\n"); - defBuffer.append('\n'); - - defBuffer.append(" //The global style definition\n"); - defBuffer.append(style.write("")); - defBuffer.append('\n'); - - for (UIComponent c: components) { - String prefix = Utils.escape(c.getKey()); - defBuffer.append(" //Initialize ").append(prefix).append("\n"); - c.write(defBuffer, styleBuffer, c, prefix, packageName); - defBuffer.append('\n'); - } - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/SynthModel.java 2020-03-23 19:57:20.471962378 +0100 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import java.util.ArrayList; + +public class SynthModel { + private UIStyle style; + + private ArrayList colors; + + private ArrayList fonts; + + private ArrayList components; + + SynthModel(XMLStreamReader reader) throws XMLStreamException { + while (reader.hasNext()) { + int eventType = reader.next(); + switch (eventType) { + case XMLStreamReader.START_ELEMENT: + switch (reader.getLocalName()) { + case "style": + style = new UIStyle(reader); + break; + case "colors": + colors = new ArrayList<>(); + break; + case "fonts": + fonts = new ArrayList<>(); + break; + case "components": + components = new ArrayList<>(); + break; + case "uiColor": + colors.add(new UIColor(reader)); + break; + case "uiFont": + fonts.add(new UIFont(reader)); + break; + case "uiComponent": + components.add(new UIComponent(reader)); + break; + } + break; + case XMLStreamReader.END_ELEMENT: + break; + } + } + } + + public void initStyles() { + for (UIComponent c: components) { + c.initStyles(this.style); + } + } + + public void write(StringBuilder defBuffer, StringBuilder styleBuffer, String packageName) { + defBuffer.append(" //Color palette\n"); + for (UIColor c: colors) defBuffer.append(c.write()); + defBuffer.append('\n'); + + defBuffer.append(" //Font palette\n"); + defBuffer.append(" d.put(\"defaultFont\", new FontUIResource(defaultFont));\n"); + for (UIFont f: fonts) defBuffer.append(f.write()); + defBuffer.append('\n'); + + defBuffer.append(" //Border palette\n"); + defBuffer.append('\n'); + + defBuffer.append(" //The global style definition\n"); + defBuffer.append(style.write("")); + defBuffer.append('\n'); + + for (UIComponent c: components) { + String prefix = Utils.escape(c.getKey()); + defBuffer.append(" //Initialize ").append(prefix).append("\n"); + c.write(defBuffer, styleBuffer, c, prefix, packageName); + defBuffer.append('\n'); + } + } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/Typeface.java 2020-03-23 19:57:21.755962369 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -import javax.xml.stream.XMLStreamReader; -import java.awt.*; - -class Typeface { - - public enum DeriveStyle { - Default, Off, On; - - @Override public String toString() { - switch (this) { - default: return "null"; - case On: return "true"; - case Off: return "false"; - } - } - } - - private String uiDefaultParentName; - private String name; - private int size; - private DeriveStyle bold = DeriveStyle.Default; - private DeriveStyle italic = DeriveStyle.Default; - private float sizeOffset = 1f; - - Typeface(XMLStreamReader reader) { - uiDefaultParentName = reader.getAttributeValue(null, "uiDefaultParentName"); - name = reader.getAttributeValue(null, "family"); - try { - size = Integer.parseInt(reader.getAttributeValue(null, "size")); - } catch (Exception e) {} - try { - bold = DeriveStyle.valueOf(reader.getAttributeValue(null, "bold")); - } catch (Exception e) {} - try { - italic = DeriveStyle.valueOf(reader.getAttributeValue(null, "italic")); - } catch (Exception e) {} - try { - sizeOffset = Float.parseFloat(reader.getAttributeValue(null, "sizeOffset")); - } catch (Exception e) {} - } - - - public boolean isAbsolute() { - return uiDefaultParentName == null; - } - - public String write() { - if (isAbsolute()) { - int style = Font.PLAIN; - if (bold == DeriveStyle.On) { - style = style | Font.BOLD; - } - if (italic == DeriveStyle.On) { - style = style | Font.ITALIC; - } - - return String.format( - "new javax.swing.plaf.FontUIResource(\"%s\", %d, %d)", - name, style, size); - } else { - return String.format( - "new DerivedFont(\"%s\", %sf, %s, %s)", - uiDefaultParentName, String.valueOf(sizeOffset), bold, italic); - } - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/Typeface.java 2020-03-23 19:57:21.315962372 +0100 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +import javax.xml.stream.XMLStreamReader; +import java.awt.*; + +class Typeface { + + public enum DeriveStyle { + Default, Off, On; + + @Override public String toString() { + switch (this) { + default: return "null"; + case On: return "true"; + case Off: return "false"; + } + } + } + + private String uiDefaultParentName; + private String name; + private int size; + private DeriveStyle bold = DeriveStyle.Default; + private DeriveStyle italic = DeriveStyle.Default; + private float sizeOffset = 1f; + + Typeface(XMLStreamReader reader) { + uiDefaultParentName = reader.getAttributeValue(null, "uiDefaultParentName"); + name = reader.getAttributeValue(null, "family"); + try { + size = Integer.parseInt(reader.getAttributeValue(null, "size")); + } catch (Exception e) {} + try { + bold = DeriveStyle.valueOf(reader.getAttributeValue(null, "bold")); + } catch (Exception e) {} + try { + italic = DeriveStyle.valueOf(reader.getAttributeValue(null, "italic")); + } catch (Exception e) {} + try { + sizeOffset = Float.parseFloat(reader.getAttributeValue(null, "sizeOffset")); + } catch (Exception e) {} + } + + + public boolean isAbsolute() { + return uiDefaultParentName == null; + } + + public String write() { + if (isAbsolute()) { + int style = Font.PLAIN; + if (bold == DeriveStyle.On) { + style = style | Font.BOLD; + } + if (italic == DeriveStyle.On) { + style = style | Font.ITALIC; + } + + return String.format( + "new javax.swing.plaf.FontUIResource(\"%s\", %d, %d)", + name, style, size); + } else { + return String.format( + "new DerivedFont(\"%s\", %sf, %s, %s)", + uiDefaultParentName, String.valueOf(sizeOffset), bold, italic); + } + } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/UIColor.java 2020-03-23 19:57:22.571962363 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; - -class UIColor extends UIDefault { - - UIColor(XMLStreamReader reader) throws XMLStreamException { - name = reader.getAttributeValue(null, "name"); - while (reader.hasNext()) { - int eventType = reader.next(); - switch (eventType) { - case XMLStreamReader.START_ELEMENT: - setValue(new Matte(reader)); - break; - case XMLStreamReader.END_ELEMENT: - return; - } - } - } - - public String write() { - return String.format(" addColor(d, \"%s\", %s);\n", - getName(), getValue().write()); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/UIColor.java 2020-03-23 19:57:22.135962366 +0100 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +class UIColor extends UIDefault { + + UIColor(XMLStreamReader reader) throws XMLStreamException { + name = reader.getAttributeValue(null, "name"); + while (reader.hasNext()) { + int eventType = reader.next(); + switch (eventType) { + case XMLStreamReader.START_ELEMENT: + setValue(new Matte(reader)); + break; + case XMLStreamReader.END_ELEMENT: + return; + } + } + } + + public String write() { + return String.format(" addColor(d, \"%s\", %s);\n", + getName(), getValue().write()); + } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/UIComponent.java 2020-03-23 19:57:23.411962357 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; -import java.util.ArrayList; -import java.util.List; - -class UIComponent extends UIRegion { - private String componentName; - - private List stateTypes = new ArrayList<>(); - - UIComponent(XMLStreamReader reader) throws XMLStreamException { - super(reader, false); - componentName = reader.getAttributeValue(null, "componentName"); - while (reader.hasNext()) { - int eventType = reader.next(); - switch (eventType) { - case XMLStreamReader.START_ELEMENT: - switch (reader.getLocalName()) { - case "stateType": - stateTypes.add(new UIStateType(reader)); - break; - default: - parse(reader); - } - break; - case XMLStreamReader.END_ELEMENT: - switch (reader.getLocalName()) { - case "uiComponent": - return; - } - break; - } - } - } - - public List getStateTypes() { return stateTypes; } - - @Override public String getKey() { - if (key == null || "".equals(key)) { - if (componentName == null || "".equals(componentName)) { - return name; - } else { - return "\"" + componentName + "\""; - } - } else { - return key; - } - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/UIComponent.java 2020-03-23 19:57:23.015962359 +0100 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import java.util.ArrayList; +import java.util.List; + +class UIComponent extends UIRegion { + private String componentName; + + private List stateTypes = new ArrayList<>(); + + UIComponent(XMLStreamReader reader) throws XMLStreamException { + super(reader, false); + componentName = reader.getAttributeValue(null, "componentName"); + while (reader.hasNext()) { + int eventType = reader.next(); + switch (eventType) { + case XMLStreamReader.START_ELEMENT: + switch (reader.getLocalName()) { + case "stateType": + stateTypes.add(new UIStateType(reader)); + break; + default: + parse(reader); + } + break; + case XMLStreamReader.END_ELEMENT: + switch (reader.getLocalName()) { + case "uiComponent": + return; + } + break; + } + } + } + + public List getStateTypes() { return stateTypes; } + + @Override public String getKey() { + if (key == null || "".equals(key)) { + if (componentName == null || "".equals(componentName)) { + return name; + } else { + return "\"" + componentName + "\""; + } + } else { + return key; + } + } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/UIDefault.java 2020-03-23 19:57:24.279962350 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -public class UIDefault { - String name; - private T value; - - public String getName() { - return name; - } - - public T getValue() { - return value; - } - - public void setValue(T value) { - this.value = value; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/UIDefault.java 2020-03-23 19:57:23.855962353 +0100 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +public class UIDefault { + String name; + private T value; + + public String getName() { + return name; + } + + public T getValue() { + return value; + } + + public void setValue(T value) { + this.value = value; + } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/UIFont.java 2020-03-23 19:57:25.147962344 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; - -class UIFont extends UIDefault { - UIFont(XMLStreamReader reader) throws XMLStreamException { - name = reader.getAttributeValue(null, "name"); - while (reader.hasNext()) { - int eventType = reader.next(); - switch (eventType) { - case XMLStreamReader.START_ELEMENT: - setValue(new Typeface(reader)); - break; - case XMLStreamReader.END_ELEMENT: - return; - } - } - } - - public String write() { - return String.format(" d.put(\"%s\", %s);\n", - getName(), getValue().write()); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/UIFont.java 2020-03-23 19:57:24.723962347 +0100 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +class UIFont extends UIDefault { + UIFont(XMLStreamReader reader) throws XMLStreamException { + name = reader.getAttributeValue(null, "name"); + while (reader.hasNext()) { + int eventType = reader.next(); + switch (eventType) { + case XMLStreamReader.START_ELEMENT: + setValue(new Typeface(reader)); + break; + case XMLStreamReader.END_ELEMENT: + return; + } + } + } + + public String write() { + return String.format(" d.put(\"%s\", %s);\n", + getName(), getValue().write()); + } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/UIIconRegion.java 2020-03-23 19:57:25.975962338 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; - -class UIIconRegion extends UIRegion { - private String basicKey; - - UIIconRegion(XMLStreamReader reader) throws XMLStreamException { - super(reader, false); - basicKey = reader.getAttributeValue(null, "basicKey"); - while (reader.hasNext()) { - int eventType = reader.next(); - switch (eventType) { - case XMLStreamReader.START_ELEMENT: - parse(reader); - break; - case XMLStreamReader.END_ELEMENT: - switch (reader.getLocalName()) { - case "uiIconRegion": - return; - } - break; - } - } - - } - - @Override public void write(StringBuilder sb, StringBuilder styleBuffer, UIComponent comp, String prefix, String pkg) { - Dimension size = null; - String fileNamePrefix = Utils.normalize(prefix) + "Painter"; - // write states ui defaults - for (UIState state : backgroundStates) { - Canvas canvas = state.getCanvas(); - if (!canvas.isBlank()) { - state.write(sb, prefix, pkg, fileNamePrefix, getKey()); - size = canvas.getSize(); - } - } - - if (size != null) { - // Put SynthIconImpl wrapper in UiDefaults - String k = (basicKey == null ? prefix + "." + getKey() : basicKey); - sb.append(String.format( - " d.put(\"%s\", new NimbusIcon(\"%s\", \"%sPainter\", %d, %d));\n", - k, prefix, getKey(), size.width, size.height)); - } - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/UIIconRegion.java 2020-03-23 19:57:25.563962341 +0100 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +class UIIconRegion extends UIRegion { + private String basicKey; + + UIIconRegion(XMLStreamReader reader) throws XMLStreamException { + super(reader, false); + basicKey = reader.getAttributeValue(null, "basicKey"); + while (reader.hasNext()) { + int eventType = reader.next(); + switch (eventType) { + case XMLStreamReader.START_ELEMENT: + parse(reader); + break; + case XMLStreamReader.END_ELEMENT: + switch (reader.getLocalName()) { + case "uiIconRegion": + return; + } + break; + } + } + + } + + @Override public void write(StringBuilder sb, StringBuilder styleBuffer, UIComponent comp, String prefix, String pkg) { + Dimension size = null; + String fileNamePrefix = Utils.normalize(prefix) + "Painter"; + // write states ui defaults + for (UIState state : backgroundStates) { + Canvas canvas = state.getCanvas(); + if (!canvas.isBlank()) { + state.write(sb, prefix, pkg, fileNamePrefix, getKey()); + size = canvas.getSize(); + } + } + + if (size != null) { + // Put SynthIconImpl wrapper in UiDefaults + String k = (basicKey == null ? prefix + "." + getKey() : basicKey); + sb.append(String.format( + " d.put(\"%s\", new NimbusIcon(\"%s\", \"%sPainter\", %d, %d));\n", + k, prefix, getKey(), size.width, size.height)); + } + } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/UIProperty.java 2020-03-23 19:57:26.759962332 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; - -class UIProperty extends UIDefault { - public enum PropertyType { - BOOLEAN, INT, FLOAT, DOUBLE, STRING, FONT, COLOR, INSETS, DIMENSION, BORDER - } - private PropertyType type; - - private Border border; - private Dimension dimension; - private Insets insets; - private Matte matte; - private Typeface typeface; - - UIProperty(XMLStreamReader reader) throws XMLStreamException { - name = reader.getAttributeValue(null, "name"); - setValue(reader.getAttributeValue(null, "value")); - try { - type = PropertyType.valueOf(reader.getAttributeValue(null, "type")); - } catch (Exception e) {} - - while (reader.hasNext()) { - int eventType = reader.next(); - switch (eventType) { - case XMLStreamReader.START_ELEMENT: - switch (reader.getLocalName()) { - case "border": - border = new Border(reader); - break; - case "dimension": - dimension = new Dimension(reader); - break; - case "insets": - insets = new Insets(reader); - break; - case "matte": - matte = new Matte(reader); - break; - case "typeface": - typeface = new Typeface(reader); - break; - } - break; - case XMLStreamReader.END_ELEMENT: - switch (reader.getLocalName()) { - case "uiProperty": - return; - } - break; - } - } - } - - @Override public void setValue(String value) { - super.setValue(value); - } - - public String write(String prefix) { - switch (type) { - case BOOLEAN: - return String.format(" d.put(\"%s%s\", Boolean.%s);\n", - prefix, getName(), getValue().toUpperCase()); ///autobox - case STRING: - return String.format(" d.put(\"%s%s\", \"%s\");\n", - prefix, getName(), getValue()); - case INT: - return String.format(" d.put(\"%s%s\", Integer.valueOf(%s));\n", - prefix, getName(), getValue()); - case FLOAT: - return String.format(" d.put(\"%s%s\", Float.valueOf(%sf));\n", - prefix, getName(), getValue()); - case DOUBLE: - return String.format(" d.put(\"%s%s\", Double.valueOf(%s));\n", - prefix, getName(), getValue()); - case COLOR: - return String.format(" addColor(d, \"%s%s\", %s);\n", - prefix, getName(), matte.write()); - case FONT: - return String.format(" d.put(\"%s%s\", %s);\n", - prefix, getName(), typeface.write()); - case INSETS: - return String.format(" d.put(\"%s%s\", %s);\n", - prefix, getName(), insets.write(true)); - case DIMENSION: - return String.format(" d.put(\"%s%s\", new DimensionUIResource(%d, %d));\n", - prefix, getName(), dimension.width, dimension.height); - case BORDER: - return String.format(" d.put(\"%s%s\", new BorderUIResource(%s));\n", - prefix, getName(), border.write()); - default: - return "### Look, something's wrong with UIProperty.write() $$$"; - } - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/UIProperty.java 2020-03-23 19:57:26.391962335 +0100 @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +class UIProperty extends UIDefault { + public enum PropertyType { + BOOLEAN, INT, FLOAT, DOUBLE, STRING, FONT, COLOR, INSETS, DIMENSION, BORDER + } + private PropertyType type; + + private Border border; + private Dimension dimension; + private Insets insets; + private Matte matte; + private Typeface typeface; + + UIProperty(XMLStreamReader reader) throws XMLStreamException { + name = reader.getAttributeValue(null, "name"); + setValue(reader.getAttributeValue(null, "value")); + try { + type = PropertyType.valueOf(reader.getAttributeValue(null, "type")); + } catch (Exception e) {} + + while (reader.hasNext()) { + int eventType = reader.next(); + switch (eventType) { + case XMLStreamReader.START_ELEMENT: + switch (reader.getLocalName()) { + case "border": + border = new Border(reader); + break; + case "dimension": + dimension = new Dimension(reader); + break; + case "insets": + insets = new Insets(reader); + break; + case "matte": + matte = new Matte(reader); + break; + case "typeface": + typeface = new Typeface(reader); + break; + } + break; + case XMLStreamReader.END_ELEMENT: + switch (reader.getLocalName()) { + case "uiProperty": + return; + } + break; + } + } + } + + @Override public void setValue(String value) { + super.setValue(value); + } + + public String write(String prefix) { + switch (type) { + case BOOLEAN: + return String.format(" d.put(\"%s%s\", Boolean.%s);\n", + prefix, getName(), getValue().toUpperCase()); ///autobox + case STRING: + return String.format(" d.put(\"%s%s\", \"%s\");\n", + prefix, getName(), getValue()); + case INT: + return String.format(" d.put(\"%s%s\", Integer.valueOf(%s));\n", + prefix, getName(), getValue()); + case FLOAT: + return String.format(" d.put(\"%s%s\", Float.valueOf(%sf));\n", + prefix, getName(), getValue()); + case DOUBLE: + return String.format(" d.put(\"%s%s\", Double.valueOf(%s));\n", + prefix, getName(), getValue()); + case COLOR: + return String.format(" addColor(d, \"%s%s\", %s);\n", + prefix, getName(), matte.write()); + case FONT: + return String.format(" d.put(\"%s%s\", %s);\n", + prefix, getName(), typeface.write()); + case INSETS: + return String.format(" d.put(\"%s%s\", %s);\n", + prefix, getName(), insets.write(true)); + case DIMENSION: + return String.format(" d.put(\"%s%s\", new DimensionUIResource(%d, %d));\n", + prefix, getName(), dimension.width, dimension.height); + case BORDER: + return String.format(" d.put(\"%s%s\", new BorderUIResource(%s));\n", + prefix, getName(), border.write()); + default: + return "### Look, something's wrong with UIProperty.write() $$$"; + } + } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/UIRegion.java 2020-03-23 19:57:27.599962326 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,244 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -class UIRegion { - String name; - String key; - private boolean opaque = false; - - private Insets contentMargins = new Insets(0, 0, 0, 0); - - protected List backgroundStates = new ArrayList(); - - public List getBackgroundStates() { return backgroundStates; } - - protected List foregroundStates = new ArrayList(); - public List getForegroundStates() { return foregroundStates; } - - protected List borderStates = new ArrayList(); - public List getBorderStates() { return borderStates; } - - UIStyle style = new UIStyle(); - - List subRegions = new ArrayList<>(); - public List getSubRegions() { return subRegions; } - - UIRegion(XMLStreamReader reader, boolean parse) - throws XMLStreamException { - name = reader.getAttributeValue(null, "name"); - key = reader.getAttributeValue(null, "key"); - opaque = Boolean.parseBoolean(reader.getAttributeValue(null, "opaque")); - if (!parse) { - return; - } - while (reader.hasNext()) { - int eventType = reader.next(); - switch (eventType) { - case XMLStreamReader.START_ELEMENT: - parse(reader); - break; - case XMLStreamReader.END_ELEMENT: - switch (reader.getLocalName()) { - case "region": - return; - } - break; - } - } - } - - private List states = new ArrayList(); - - void parse(XMLStreamReader reader) throws XMLStreamException { - switch (reader.getLocalName()) { - case "backgroundStates": - backgroundStates = states = new ArrayList<>(); - break; - case "foregroundStates": - foregroundStates = states = new ArrayList<>(); - break; - case "borderStates": - borderStates = states = new ArrayList<>(); - break; - case "style": - style = new UIStyle(reader); - break; - case "region": - subRegions.add(new UIRegion(reader, true)); - break; - case "uiComponent": - subRegions.add(new UIComponent(reader)); - break; - case "uiIconRegion": - subRegions.add(new UIIconRegion(reader)); - break; - case "contentMargins": - contentMargins = new Insets(reader); - break; - case "state": - states.add(new UIState(reader)); - break; - } - } - - protected void initStyles(UIStyle parentStyle) { - style.setParentStyle(parentStyle); - for (UIState state: backgroundStates) { - state.getStyle().setParentStyle(this.style); - } - for (UIState state: foregroundStates) { - state.getStyle().setParentStyle(this.style); - } - for (UIState state: borderStates) { - state.getStyle().setParentStyle(this.style); - } - for (UIRegion region: subRegions) { - region.initStyles(this.style); - } - } - - public String getKey() { - return key == null || "".equals(key) ? name : key; - } - - private boolean hasCanvas() { - for (UIState s : backgroundStates) { - if (s.hasCanvas()) return true; - } - for (UIState s : borderStates) { - if (s.hasCanvas()) return true; - } - for (UIState s : foregroundStates) { - if (s.hasCanvas()) return true; - } - for (UIRegion r: subRegions) { - if (r.hasCanvas()) return true; - } - return false; - } - - public void write(StringBuilder sb, StringBuilder styleBuffer, - UIComponent comp, String prefix, String pkg) { - // write content margins - sb.append(String.format(" d.put(\"%s.contentMargins\", %s);\n", - prefix, contentMargins.write(true))); - // write opaque if true - if (opaque) { - sb.append(String.format(" d.put(\"%s.opaque\", Boolean.TRUE);\n", prefix)); - } - - // register component with LAF - String regionCode = "Region." + Utils.regionNameToCaps(name); - styleBuffer.append(String.format(" register(%s, \"%s\");\n", - regionCode, prefix)); - - //write the State, if necessary - StringBuffer regString = new StringBuffer(); - List types = comp.getStateTypes(); - if (types != null && types.size() > 0) { - for (UIStateType type : types) { - regString.append(type.getKey()); - regString.append(","); - } - //remove the last "," - regString.deleteCharAt(regString.length() - 1); - } - - if (! regString.equals("Enabled,MouseOver,Pressed,Disabled,Focused,Selected,Default") && types.size() > 0) { - //there were either custom states, or the normal states were in a custom order - //so go ahead and write out prefix.State - sb.append(String.format(" d.put(\"%s.States\", \"%s\");\n", - prefix, regString)); - } - - // write out any custom states, if necessary - for (UIStateType type : types) { - String synthState = type.getKey(); - if (! "Enabled".equals(synthState) && - ! "MouseOver".equals(synthState) && - ! "Pressed".equals(synthState) && - ! "Disabled".equals(synthState) && - ! "Focused".equals(synthState) && - ! "Selected".equals(synthState) && - ! "Default".equals(synthState)) { - - //what we have here, gentlemen, is a bona-fide custom state. - //if the type is not one of the standard types, then construct a name for - //the new type, and write out a new subclass of State. - String className = Utils.normalize(prefix) + synthState + "State"; - sb.append(String.format(" d.put(\"%s.%s\", new %s());\n", - prefix, synthState, className)); - - String body = type.getCodeSnippet(); - Map variables = Generator.getVariables(); - variables.put("STATE_NAME", className); - variables.put("STATE_KEY", synthState); - variables.put("BODY", body); - - Generator.writeSrcFile("StateImpl", variables, className); - } - } - - // write style - sb.append(style.write(prefix + '.')); - - String fileName = Utils.normalize(prefix) + "Painter"; - boolean hasCanvas = hasCanvas(); - if (hasCanvas) { - PainterGenerator.writePainter(this, fileName); - } - // write states ui defaults - for (UIState state : backgroundStates) { - state.write(sb, prefix, pkg, fileName, "background"); - } - for (UIState state : foregroundStates) { - state.write(sb, prefix, pkg, fileName, "foreground"); - } - for (UIState state : borderStates) { - state.write(sb, prefix, pkg, fileName, "border"); - } - - // handle sub regions - for (UIRegion subreg : subRegions) { - String p = prefix; - if (! (subreg instanceof UIIconRegion)) { - p = prefix + ":" + Utils.escape(subreg.getKey()); - } - UIComponent c = comp; - if (subreg instanceof UIComponent) { - c = (UIComponent) subreg; - } - subreg.write(sb, styleBuffer, c, p, pkg); - } - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/UIRegion.java 2020-03-23 19:57:27.179962329 +0100 @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +class UIRegion { + String name; + String key; + private boolean opaque = false; + + private Insets contentMargins = new Insets(0, 0, 0, 0); + + protected List backgroundStates = new ArrayList(); + + public List getBackgroundStates() { return backgroundStates; } + + protected List foregroundStates = new ArrayList(); + public List getForegroundStates() { return foregroundStates; } + + protected List borderStates = new ArrayList(); + public List getBorderStates() { return borderStates; } + + UIStyle style = new UIStyle(); + + List subRegions = new ArrayList<>(); + public List getSubRegions() { return subRegions; } + + UIRegion(XMLStreamReader reader, boolean parse) + throws XMLStreamException { + name = reader.getAttributeValue(null, "name"); + key = reader.getAttributeValue(null, "key"); + opaque = Boolean.parseBoolean(reader.getAttributeValue(null, "opaque")); + if (!parse) { + return; + } + while (reader.hasNext()) { + int eventType = reader.next(); + switch (eventType) { + case XMLStreamReader.START_ELEMENT: + parse(reader); + break; + case XMLStreamReader.END_ELEMENT: + switch (reader.getLocalName()) { + case "region": + return; + } + break; + } + } + } + + private List states = new ArrayList(); + + void parse(XMLStreamReader reader) throws XMLStreamException { + switch (reader.getLocalName()) { + case "backgroundStates": + backgroundStates = states = new ArrayList<>(); + break; + case "foregroundStates": + foregroundStates = states = new ArrayList<>(); + break; + case "borderStates": + borderStates = states = new ArrayList<>(); + break; + case "style": + style = new UIStyle(reader); + break; + case "region": + subRegions.add(new UIRegion(reader, true)); + break; + case "uiComponent": + subRegions.add(new UIComponent(reader)); + break; + case "uiIconRegion": + subRegions.add(new UIIconRegion(reader)); + break; + case "contentMargins": + contentMargins = new Insets(reader); + break; + case "state": + states.add(new UIState(reader)); + break; + } + } + + protected void initStyles(UIStyle parentStyle) { + style.setParentStyle(parentStyle); + for (UIState state: backgroundStates) { + state.getStyle().setParentStyle(this.style); + } + for (UIState state: foregroundStates) { + state.getStyle().setParentStyle(this.style); + } + for (UIState state: borderStates) { + state.getStyle().setParentStyle(this.style); + } + for (UIRegion region: subRegions) { + region.initStyles(this.style); + } + } + + public String getKey() { + return key == null || "".equals(key) ? name : key; + } + + private boolean hasCanvas() { + for (UIState s : backgroundStates) { + if (s.hasCanvas()) return true; + } + for (UIState s : borderStates) { + if (s.hasCanvas()) return true; + } + for (UIState s : foregroundStates) { + if (s.hasCanvas()) return true; + } + for (UIRegion r: subRegions) { + if (r.hasCanvas()) return true; + } + return false; + } + + public void write(StringBuilder sb, StringBuilder styleBuffer, + UIComponent comp, String prefix, String pkg) { + // write content margins + sb.append(String.format(" d.put(\"%s.contentMargins\", %s);\n", + prefix, contentMargins.write(true))); + // write opaque if true + if (opaque) { + sb.append(String.format(" d.put(\"%s.opaque\", Boolean.TRUE);\n", prefix)); + } + + // register component with LAF + String regionCode = "Region." + Utils.regionNameToCaps(name); + styleBuffer.append(String.format(" register(%s, \"%s\");\n", + regionCode, prefix)); + + //write the State, if necessary + StringBuffer regString = new StringBuffer(); + List types = comp.getStateTypes(); + if (types != null && types.size() > 0) { + for (UIStateType type : types) { + regString.append(type.getKey()); + regString.append(","); + } + //remove the last "," + regString.deleteCharAt(regString.length() - 1); + } + + if (! regString.equals("Enabled,MouseOver,Pressed,Disabled,Focused,Selected,Default") && types.size() > 0) { + //there were either custom states, or the normal states were in a custom order + //so go ahead and write out prefix.State + sb.append(String.format(" d.put(\"%s.States\", \"%s\");\n", + prefix, regString)); + } + + // write out any custom states, if necessary + for (UIStateType type : types) { + String synthState = type.getKey(); + if (! "Enabled".equals(synthState) && + ! "MouseOver".equals(synthState) && + ! "Pressed".equals(synthState) && + ! "Disabled".equals(synthState) && + ! "Focused".equals(synthState) && + ! "Selected".equals(synthState) && + ! "Default".equals(synthState)) { + + //what we have here, gentlemen, is a bona-fide custom state. + //if the type is not one of the standard types, then construct a name for + //the new type, and write out a new subclass of State. + String className = Utils.normalize(prefix) + synthState + "State"; + sb.append(String.format(" d.put(\"%s.%s\", new %s());\n", + prefix, synthState, className)); + + String body = type.getCodeSnippet(); + Map variables = Generator.getVariables(); + variables.put("STATE_NAME", className); + variables.put("STATE_KEY", synthState); + variables.put("BODY", body); + + Generator.writeSrcFile("StateImpl", variables, className); + } + } + + // write style + sb.append(style.write(prefix + '.')); + + String fileName = Utils.normalize(prefix) + "Painter"; + boolean hasCanvas = hasCanvas(); + if (hasCanvas) { + PainterGenerator.writePainter(this, fileName); + } + // write states ui defaults + for (UIState state : backgroundStates) { + state.write(sb, prefix, pkg, fileName, "background"); + } + for (UIState state : foregroundStates) { + state.write(sb, prefix, pkg, fileName, "foreground"); + } + for (UIState state : borderStates) { + state.write(sb, prefix, pkg, fileName, "border"); + } + + // handle sub regions + for (UIRegion subreg : subRegions) { + String p = prefix; + if (! (subreg instanceof UIIconRegion)) { + p = prefix + ":" + Utils.escape(subreg.getKey()); + } + UIComponent c = comp; + if (subreg instanceof UIComponent) { + c = (UIComponent) subreg; + } + subreg.write(sb, styleBuffer, c, p, pkg); + } + } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/UIState.java 2020-03-23 19:57:28.391962320 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; -import java.util.Arrays; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - -class UIState { - private String stateKeys; - - public String getStateKeys() { return stateKeys; } - - /** Indicates whether to invert the meaning of the 9-square stretching insets */ - private boolean inverted; - - /** A cached string representing the list of stateKeys deliminated with "+" */ - private String cachedName = null; - - private Canvas canvas; - public Canvas getCanvas() { return canvas; } - - private UIStyle style; - public UIStyle getStyle() { return style; } - - UIState(XMLStreamReader reader) throws XMLStreamException { - stateKeys = reader.getAttributeValue(null, "stateKeys"); - inverted = Boolean.parseBoolean(reader.getAttributeValue(null, "inverted")); - while (reader.hasNext()) { - int eventType = reader.next(); - switch (eventType) { - case XMLStreamReader.START_ELEMENT: - switch (reader.getLocalName()) { - case "canvas": - canvas = new Canvas(reader); - break; - case "style": - style = new UIStyle(reader); - break; - } - break; - case XMLStreamReader.END_ELEMENT: - switch (reader.getLocalName()) { - case "state": - return; - } - break; - } - } - } - - public boolean hasCanvas() { - return ! canvas.isBlank(); - } - - public static List stringToKeys(String keysString) { - return Arrays.asList(keysString.split("\\+")); - } - - public String getName() { - if (cachedName == null) { - StringBuilder buf = new StringBuilder(); - List keys = stringToKeys(stateKeys); - Collections.sort(keys); - for (Iterator iter = keys.iterator(); iter.hasNext();) { - buf.append(iter.next()); - if (iter.hasNext()) { - buf.append('+'); - } - } - cachedName = buf.toString(); - } - return cachedName; - } - - public void write(StringBuilder sb, String prefix, String pkg, String fileNamePrefix, String painterPrefix) { - String statePrefix = prefix + "[" + getName() + "]"; - // write state style - sb.append(style.write(statePrefix + '.')); - // write painter - if (hasCanvas()) { - writeLazyPainter(sb, statePrefix, pkg, fileNamePrefix, painterPrefix); - } - } - - private void writeLazyPainter(StringBuilder sb, String statePrefix, String packageNamePrefix, String fileNamePrefix, String painterPrefix) { - String cacheModeString = "AbstractRegionPainter.PaintContext.CacheMode." + style.getCacheMode(); - String stateConstant = Utils.statesToConstantName(painterPrefix + "_" + stateKeys); - sb.append(String.format( - " d.put(\"%s.%sPainter\", new LazyPainter(\"%s.%s\", %s.%s, %s, %s, %b, %s, %s, %s));\n", - statePrefix, painterPrefix, packageNamePrefix, fileNamePrefix, - fileNamePrefix, stateConstant, canvas.getStretchingInsets().write(false), - canvas.getSize().write(false), inverted, cacheModeString, - Utils.formatDouble(style.getMaxHozCachedImgScaling()), - Utils.formatDouble(style.getMaxVertCachedImgScaling()))); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/UIState.java 2020-03-23 19:57:28.019962323 +0100 @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +class UIState { + private String stateKeys; + + public String getStateKeys() { return stateKeys; } + + /** Indicates whether to invert the meaning of the 9-square stretching insets */ + private boolean inverted; + + /** A cached string representing the list of stateKeys deliminated with "+" */ + private String cachedName = null; + + private Canvas canvas; + public Canvas getCanvas() { return canvas; } + + private UIStyle style; + public UIStyle getStyle() { return style; } + + UIState(XMLStreamReader reader) throws XMLStreamException { + stateKeys = reader.getAttributeValue(null, "stateKeys"); + inverted = Boolean.parseBoolean(reader.getAttributeValue(null, "inverted")); + while (reader.hasNext()) { + int eventType = reader.next(); + switch (eventType) { + case XMLStreamReader.START_ELEMENT: + switch (reader.getLocalName()) { + case "canvas": + canvas = new Canvas(reader); + break; + case "style": + style = new UIStyle(reader); + break; + } + break; + case XMLStreamReader.END_ELEMENT: + switch (reader.getLocalName()) { + case "state": + return; + } + break; + } + } + } + + public boolean hasCanvas() { + return ! canvas.isBlank(); + } + + public static List stringToKeys(String keysString) { + return Arrays.asList(keysString.split("\\+")); + } + + public String getName() { + if (cachedName == null) { + StringBuilder buf = new StringBuilder(); + List keys = stringToKeys(stateKeys); + Collections.sort(keys); + for (Iterator iter = keys.iterator(); iter.hasNext();) { + buf.append(iter.next()); + if (iter.hasNext()) { + buf.append('+'); + } + } + cachedName = buf.toString(); + } + return cachedName; + } + + public void write(StringBuilder sb, String prefix, String pkg, String fileNamePrefix, String painterPrefix) { + String statePrefix = prefix + "[" + getName() + "]"; + // write state style + sb.append(style.write(statePrefix + '.')); + // write painter + if (hasCanvas()) { + writeLazyPainter(sb, statePrefix, pkg, fileNamePrefix, painterPrefix); + } + } + + private void writeLazyPainter(StringBuilder sb, String statePrefix, String packageNamePrefix, String fileNamePrefix, String painterPrefix) { + String cacheModeString = "AbstractRegionPainter.PaintContext.CacheMode." + style.getCacheMode(); + String stateConstant = Utils.statesToConstantName(painterPrefix + "_" + stateKeys); + sb.append(String.format( + " d.put(\"%s.%sPainter\", new LazyPainter(\"%s.%s\", %s.%s, %s, %s, %b, %s, %s, %s));\n", + statePrefix, painterPrefix, packageNamePrefix, fileNamePrefix, + fileNamePrefix, stateConstant, canvas.getStretchingInsets().write(false), + canvas.getSize().write(false), inverted, cacheModeString, + Utils.formatDouble(style.getMaxHozCachedImgScaling()), + Utils.formatDouble(style.getMaxVertCachedImgScaling()))); + } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/UIStateType.java 2020-03-23 19:57:29.203962314 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; - -class UIStateType { - private String key; - - public String - getKey() { return key; } - - private String codeSnippet; - public String getCodeSnippet() { return codeSnippet; } - - UIStateType(XMLStreamReader reader) throws XMLStreamException { - key = reader.getAttributeValue(null, "key"); - while (reader.hasNext()) { - int eventType = reader.next(); - switch (eventType) { - case XMLStreamReader.START_ELEMENT: - switch (reader.getLocalName()) { - case "codeSnippet": - codeSnippet = reader.getElementText(); - break; - } - break; - case XMLStreamReader.END_ELEMENT: - switch (reader.getLocalName()) { - case "stateType": - return; - } - break; - } - } - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/UIStateType.java 2020-03-23 19:57:28.803962317 +0100 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +class UIStateType { + private String key; + + public String + getKey() { return key; } + + private String codeSnippet; + public String getCodeSnippet() { return codeSnippet; } + + UIStateType(XMLStreamReader reader) throws XMLStreamException { + key = reader.getAttributeValue(null, "key"); + while (reader.hasNext()) { + int eventType = reader.next(); + switch (eventType) { + case XMLStreamReader.START_ELEMENT: + switch (reader.getLocalName()) { + case "codeSnippet": + codeSnippet = reader.getElementText(); + break; + } + break; + case XMLStreamReader.END_ELEMENT: + switch (reader.getLocalName()) { + case "stateType": + return; + } + break; + } + } + } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/UIStyle.java 2020-03-23 19:57:30.051962308 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,160 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; -import java.util.ArrayList; -import java.util.List; - -class UIStyle { - - public enum CacheMode { - NO_CACHING, FIXED_SIZES, NINE_SQUARE_SCALE - } - - private UIColor textForeground = null; - private boolean textForegroundInherited = true; - - private UIColor textBackground = null; - private boolean textBackgroundInherited = true; - - private UIColor background = null; - private boolean backgroundInherited = true; - - private boolean cacheSettingsInherited = true; - CacheMode cacheMode = CacheMode.FIXED_SIZES; - String maxHozCachedImgScaling = "1.0"; - String maxVertCachedImgScaling = "1.0"; - - private List uiProperties = new ArrayList<>(); - - UIStyle() { - } - - UIStyle(XMLStreamReader reader) throws XMLStreamException { - while (reader.hasNext()) { - int eventType = reader.next(); - switch (eventType) { - case XMLStreamReader.START_ELEMENT: - switch (reader.getLocalName()) { - case "textForeground": - textForeground = new UIColor(reader); - break; - case "textBackground": - textBackground = new UIColor(reader); - break; - case "background": - background = new UIColor(reader); - break; - case "uiProperty": - uiProperties.add(new UIProperty(reader)); - break; - case "inherit-textForeground": - textForegroundInherited = Boolean.parseBoolean(reader.getElementText()); - break; - case "inherit-textBackground": - textBackgroundInherited = Boolean.parseBoolean(reader.getElementText()); - break; - case "cacheSettingsInherited": - cacheSettingsInherited = Boolean.parseBoolean(reader.getElementText()); - break; - case "inherit-background": - backgroundInherited = Boolean.parseBoolean(reader.getElementText()); - break; - case "cacheMode": - cacheMode = CacheMode.valueOf(reader.getElementText()); - break; - case "maxHozCachedImgScaling": - maxHozCachedImgScaling = reader.getElementText(); - break; - case "maxVertCachedImgScaling": - maxVertCachedImgScaling = reader.getElementText(); - break; - } - break; - case XMLStreamReader.END_ELEMENT: - switch (reader.getLocalName()) { - case "style": - return; - } - break; - } - } - } - - private UIStyle parentStyle = null; - public void setParentStyle(UIStyle parentStyle) { - this.parentStyle = parentStyle; - } - - public CacheMode getCacheMode() { - if (cacheSettingsInherited) { - return (parentStyle == null ? - CacheMode.FIXED_SIZES : parentStyle.getCacheMode()); - } else { - return cacheMode; - } - } - - public String getMaxHozCachedImgScaling() { - if (cacheSettingsInherited) { - return (parentStyle == null ? - "1.0" : parentStyle.getMaxHozCachedImgScaling()); - } else { - return maxHozCachedImgScaling; - } - } - - public String getMaxVertCachedImgScaling() { - if (cacheSettingsInherited) { - return (parentStyle == null ? - "1.0" : parentStyle.getMaxVertCachedImgScaling()); - } else { - return maxVertCachedImgScaling; - } - } - - public String write(String prefix) { - StringBuilder sb = new StringBuilder(); - if (! textForegroundInherited) { - sb.append(String.format(" addColor(d, \"%s%s\", %s);\n", - prefix, "textForeground", textForeground.getValue().write())); - } - if (! textBackgroundInherited) { - sb.append(String.format(" addColor(d, \"%s%s\", %s);\n", - prefix, "textBackground", textBackground.getValue().write())); - } - if (! backgroundInherited) { - sb.append(String.format(" addColor(d, \"%s%s\", %s);\n", - prefix, "background", background.getValue().write())); - } - for (UIProperty property : uiProperties) { - sb.append(property.write(prefix)); - } - return sb.toString(); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/UIStyle.java 2020-03-23 19:57:29.623962311 +0100 @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import java.util.ArrayList; +import java.util.List; + +class UIStyle { + + public enum CacheMode { + NO_CACHING, FIXED_SIZES, NINE_SQUARE_SCALE + } + + private UIColor textForeground = null; + private boolean textForegroundInherited = true; + + private UIColor textBackground = null; + private boolean textBackgroundInherited = true; + + private UIColor background = null; + private boolean backgroundInherited = true; + + private boolean cacheSettingsInherited = true; + CacheMode cacheMode = CacheMode.FIXED_SIZES; + String maxHozCachedImgScaling = "1.0"; + String maxVertCachedImgScaling = "1.0"; + + private List uiProperties = new ArrayList<>(); + + UIStyle() { + } + + UIStyle(XMLStreamReader reader) throws XMLStreamException { + while (reader.hasNext()) { + int eventType = reader.next(); + switch (eventType) { + case XMLStreamReader.START_ELEMENT: + switch (reader.getLocalName()) { + case "textForeground": + textForeground = new UIColor(reader); + break; + case "textBackground": + textBackground = new UIColor(reader); + break; + case "background": + background = new UIColor(reader); + break; + case "uiProperty": + uiProperties.add(new UIProperty(reader)); + break; + case "inherit-textForeground": + textForegroundInherited = Boolean.parseBoolean(reader.getElementText()); + break; + case "inherit-textBackground": + textBackgroundInherited = Boolean.parseBoolean(reader.getElementText()); + break; + case "cacheSettingsInherited": + cacheSettingsInherited = Boolean.parseBoolean(reader.getElementText()); + break; + case "inherit-background": + backgroundInherited = Boolean.parseBoolean(reader.getElementText()); + break; + case "cacheMode": + cacheMode = CacheMode.valueOf(reader.getElementText()); + break; + case "maxHozCachedImgScaling": + maxHozCachedImgScaling = reader.getElementText(); + break; + case "maxVertCachedImgScaling": + maxVertCachedImgScaling = reader.getElementText(); + break; + } + break; + case XMLStreamReader.END_ELEMENT: + switch (reader.getLocalName()) { + case "style": + return; + } + break; + } + } + } + + private UIStyle parentStyle = null; + public void setParentStyle(UIStyle parentStyle) { + this.parentStyle = parentStyle; + } + + public CacheMode getCacheMode() { + if (cacheSettingsInherited) { + return (parentStyle == null ? + CacheMode.FIXED_SIZES : parentStyle.getCacheMode()); + } else { + return cacheMode; + } + } + + public String getMaxHozCachedImgScaling() { + if (cacheSettingsInherited) { + return (parentStyle == null ? + "1.0" : parentStyle.getMaxHozCachedImgScaling()); + } else { + return maxHozCachedImgScaling; + } + } + + public String getMaxVertCachedImgScaling() { + if (cacheSettingsInherited) { + return (parentStyle == null ? + "1.0" : parentStyle.getMaxVertCachedImgScaling()); + } else { + return maxVertCachedImgScaling; + } + } + + public String write(String prefix) { + StringBuilder sb = new StringBuilder(); + if (! textForegroundInherited) { + sb.append(String.format(" addColor(d, \"%s%s\", %s);\n", + prefix, "textForeground", textForeground.getValue().write())); + } + if (! textBackgroundInherited) { + sb.append(String.format(" addColor(d, \"%s%s\", %s);\n", + prefix, "textBackground", textBackground.getValue().write())); + } + if (! backgroundInherited) { + sb.append(String.format(" addColor(d, \"%s%s\", %s);\n", + prefix, "background", background.getValue().write())); + } + for (UIProperty property : uiProperties) { + sb.append(property.write(prefix)); + } + return sb.toString(); + } +} --- old/make/jdk/src/classes/build/tools/generatenimbus/Utils.java 2020-03-23 19:57:30.835962302 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,215 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.generatenimbus; - -import java.util.ArrayList; -import java.util.List; -import javax.swing.plaf.synth.Region; - -public class Utils { - - public static String escape(String s) { - return s.replace("\"", "\\\""); - } - - public static String normalize(String s) { - char[] src = s.toCharArray(); - StringBuilder buf = new StringBuilder(); - List parts = new ArrayList(); - boolean capitalize = false; - - for (int i = 0; i < src.length; i++) { - switch (src[i]) { - case '\\': - case '"': - break; - case '.': - capitalize = true; - break; - case ':': - parts.add(buf.toString()); - buf.delete(0, buf.length()); - capitalize = true; - break; - default: - buf.append(capitalize ? Character.toUpperCase(src[i]) : src[i]); - capitalize = false; - break; - } - } - parts.add(buf.toString()); - - // Try to optimize long class names by omitting repeating prefixes, e.g. - // SliderTrackPainter.java instead of SliderSliderTrackPainter.java - String result = parts.get(0); - for (int i = 1; i < parts.size(); i++) { - String part = parts.get(i); - if (part.startsWith(result)) { - result = part; - } else { - result += part; - } - } - return result; - } - - public static String regionNameToCaps(String regionName) { - if (Region.ARROW_BUTTON.getName().equals(regionName)) { - return "ARROW_BUTTON"; - } else if (Region.BUTTON.getName().equals(regionName)) { - return "BUTTON"; - } else if (Region.CHECK_BOX.getName().equals(regionName)) { - return "CHECK_BOX"; - } else if (Region.CHECK_BOX_MENU_ITEM.getName().equals(regionName)) { - return "CHECK_BOX_MENU_ITEM"; - } else if (Region.COLOR_CHOOSER.getName().equals(regionName)) { - return "COLOR_CHOOSER"; - } else if (Region.COMBO_BOX.getName().equals(regionName)) { - return "COMBO_BOX"; - } else if (Region.DESKTOP_ICON.getName().equals(regionName)) { - return "DESKTOP_ICON"; - } else if (Region.DESKTOP_PANE.getName().equals(regionName)) { - return "DESKTOP_PANE"; - } else if (Region.EDITOR_PANE.getName().equals(regionName)) { - return "EDITOR_PANE"; - } else if (Region.FILE_CHOOSER.getName().equals(regionName)) { - return "FILE_CHOOSER"; - } else if (Region.FORMATTED_TEXT_FIELD.getName().equals(regionName)) { - return "FORMATTED_TEXT_FIELD"; - } else if (Region.INTERNAL_FRAME.getName().equals(regionName)) { - return "INTERNAL_FRAME"; - } else if (Region.INTERNAL_FRAME_TITLE_PANE.getName().equals(regionName)) { - return "INTERNAL_FRAME_TITLE_PANE"; - } else if (Region.LABEL.getName().equals(regionName)) { - return "LABEL"; - } else if (Region.LIST.getName().equals(regionName)) { - return "LIST"; - } else if (Region.MENU.getName().equals(regionName)) { - return "MENU"; - } else if (Region.MENU_BAR.getName().equals(regionName)) { - return "MENU_BAR"; - } else if (Region.MENU_ITEM.getName().equals(regionName)) { - return "MENU_ITEM"; - } else if (Region.MENU_ITEM_ACCELERATOR.getName().equals(regionName)) { - return "MENU_ITEM_ACCELERATOR"; - } else if (Region.OPTION_PANE.getName().equals(regionName)) { - return "OPTION_PANE"; - } else if (Region.PANEL.getName().equals(regionName)) { - return "PANEL"; - } else if (Region.PASSWORD_FIELD.getName().equals(regionName)) { - return "PASSWORD_FIELD"; - } else if (Region.POPUP_MENU.getName().equals(regionName)) { - return "POPUP_MENU"; - } else if (Region.POPUP_MENU_SEPARATOR.getName().equals(regionName)) { - return "POPUP_MENU_SEPARATOR"; - } else if (Region.PROGRESS_BAR.getName().equals(regionName)) { - return "PROGRESS_BAR"; - } else if (Region.RADIO_BUTTON.getName().equals(regionName)) { - return "RADIO_BUTTON"; - } else if (Region.RADIO_BUTTON_MENU_ITEM.getName().equals(regionName)) { - return "RADIO_BUTTON_MENU_ITEM"; - } else if (Region.ROOT_PANE.getName().equals(regionName)) { - return "ROOT_PANE"; - } else if (Region.SCROLL_BAR.getName().equals(regionName)) { - return "SCROLL_BAR"; - } else if (Region.SCROLL_BAR_THUMB.getName().equals(regionName)) { - return "SCROLL_BAR_THUMB"; - } else if (Region.SCROLL_BAR_TRACK.getName().equals(regionName)) { - return "SCROLL_BAR_TRACK"; - } else if (Region.SCROLL_PANE.getName().equals(regionName)) { - return "SCROLL_PANE"; - } else if (Region.SEPARATOR.getName().equals(regionName)) { - return "SEPARATOR"; - } else if (Region.SLIDER.getName().equals(regionName)) { - return "SLIDER"; - } else if (Region.SLIDER_THUMB.getName().equals(regionName)) { - return "SLIDER_THUMB"; - } else if (Region.SLIDER_TRACK.getName().equals(regionName)) { - return "SLIDER_TRACK"; - } else if (Region.SPINNER.getName().equals(regionName)) { - return "SPINNER"; - } else if (Region.SPLIT_PANE.getName().equals(regionName)) { - return "SPLIT_PANE"; - } else if (Region.SPLIT_PANE_DIVIDER.getName().equals(regionName)) { - return "SPLIT_PANE_DIVIDER"; - } else if (Region.TABBED_PANE.getName().equals(regionName)) { - return "TABBED_PANE"; - } else if (Region.TABBED_PANE_CONTENT.getName().equals(regionName)) { - return "TABBED_PANE_CONTENT"; - } else if (Region.TABBED_PANE_TAB.getName().equals(regionName)) { - return "TABBED_PANE_TAB"; - } else if (Region.TABBED_PANE_TAB_AREA.getName().equals(regionName)) { - return "TABBED_PANE_TAB_AREA"; - } else if (Region.TABLE.getName().equals(regionName)) { - return "TABLE"; - } else if (Region.TABLE_HEADER.getName().equals(regionName)) { - return "TABLE_HEADER"; - } else if (Region.TEXT_AREA.getName().equals(regionName)) { - return "TEXT_AREA"; - } else if (Region.TEXT_FIELD.getName().equals(regionName)) { - return "TEXT_FIELD"; - } else if (Region.TEXT_PANE.getName().equals(regionName)) { - return "TEXT_PANE"; - } else if (Region.TOGGLE_BUTTON.getName().equals(regionName)) { - return "TOGGLE_BUTTON"; - } else if (Region.TOOL_BAR.getName().equals(regionName)) { - return "TOOL_BAR"; - } else if (Region.TOOL_BAR_CONTENT.getName().equals(regionName)) { - return "TOOL_BAR_CONTENT"; - } else if (Region.TOOL_BAR_DRAG_WINDOW.getName().equals(regionName)) { - return "TOOL_BAR_DRAG_WINDOW"; - } else if (Region.TOOL_BAR_SEPARATOR.getName().equals(regionName)) { - return "TOOL_BAR_SEPARATOR"; - } else if (Region.TOOL_TIP.getName().equals(regionName)) { - return "TOOL_TIP"; - } else if (Region.TREE.getName().equals(regionName)) { - return "TREE"; - } else if (Region.TREE_CELL.getName().equals(regionName)) { - return "TREE_CELL"; - } else if (Region.VIEWPORT.getName().equals(regionName)) { - return "VIEWPORT"; - } - throw new RuntimeException("Bad Region name " + regionName); - } - - public static String statesToConstantName(String states) { - String s = states.replace(" ", ""); - s = states.replace("+", "_"); - return s.toUpperCase(); - } - - //takes a states string of the form Enabled+Foo+Bar. - //removes any whitespace. Replaces the + signs with And. - public static String statesToClassName(String states) { - String s = states.replace(" ", ""); - s = states.replace("+", "And"); - return s; - } - - public static String formatDouble(String doubleValue) { - return doubleValue.replace("INF", "Double.POSITIVE_INFINITY"); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/generatenimbus/Utils.java 2020-03-23 19:57:30.435962305 +0100 @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.generatenimbus; + +import java.util.ArrayList; +import java.util.List; +import javax.swing.plaf.synth.Region; + +public class Utils { + + public static String escape(String s) { + return s.replace("\"", "\\\""); + } + + public static String normalize(String s) { + char[] src = s.toCharArray(); + StringBuilder buf = new StringBuilder(); + List parts = new ArrayList(); + boolean capitalize = false; + + for (int i = 0; i < src.length; i++) { + switch (src[i]) { + case '\\': + case '"': + break; + case '.': + capitalize = true; + break; + case ':': + parts.add(buf.toString()); + buf.delete(0, buf.length()); + capitalize = true; + break; + default: + buf.append(capitalize ? Character.toUpperCase(src[i]) : src[i]); + capitalize = false; + break; + } + } + parts.add(buf.toString()); + + // Try to optimize long class names by omitting repeating prefixes, e.g. + // SliderTrackPainter.java instead of SliderSliderTrackPainter.java + String result = parts.get(0); + for (int i = 1; i < parts.size(); i++) { + String part = parts.get(i); + if (part.startsWith(result)) { + result = part; + } else { + result += part; + } + } + return result; + } + + public static String regionNameToCaps(String regionName) { + if (Region.ARROW_BUTTON.getName().equals(regionName)) { + return "ARROW_BUTTON"; + } else if (Region.BUTTON.getName().equals(regionName)) { + return "BUTTON"; + } else if (Region.CHECK_BOX.getName().equals(regionName)) { + return "CHECK_BOX"; + } else if (Region.CHECK_BOX_MENU_ITEM.getName().equals(regionName)) { + return "CHECK_BOX_MENU_ITEM"; + } else if (Region.COLOR_CHOOSER.getName().equals(regionName)) { + return "COLOR_CHOOSER"; + } else if (Region.COMBO_BOX.getName().equals(regionName)) { + return "COMBO_BOX"; + } else if (Region.DESKTOP_ICON.getName().equals(regionName)) { + return "DESKTOP_ICON"; + } else if (Region.DESKTOP_PANE.getName().equals(regionName)) { + return "DESKTOP_PANE"; + } else if (Region.EDITOR_PANE.getName().equals(regionName)) { + return "EDITOR_PANE"; + } else if (Region.FILE_CHOOSER.getName().equals(regionName)) { + return "FILE_CHOOSER"; + } else if (Region.FORMATTED_TEXT_FIELD.getName().equals(regionName)) { + return "FORMATTED_TEXT_FIELD"; + } else if (Region.INTERNAL_FRAME.getName().equals(regionName)) { + return "INTERNAL_FRAME"; + } else if (Region.INTERNAL_FRAME_TITLE_PANE.getName().equals(regionName)) { + return "INTERNAL_FRAME_TITLE_PANE"; + } else if (Region.LABEL.getName().equals(regionName)) { + return "LABEL"; + } else if (Region.LIST.getName().equals(regionName)) { + return "LIST"; + } else if (Region.MENU.getName().equals(regionName)) { + return "MENU"; + } else if (Region.MENU_BAR.getName().equals(regionName)) { + return "MENU_BAR"; + } else if (Region.MENU_ITEM.getName().equals(regionName)) { + return "MENU_ITEM"; + } else if (Region.MENU_ITEM_ACCELERATOR.getName().equals(regionName)) { + return "MENU_ITEM_ACCELERATOR"; + } else if (Region.OPTION_PANE.getName().equals(regionName)) { + return "OPTION_PANE"; + } else if (Region.PANEL.getName().equals(regionName)) { + return "PANEL"; + } else if (Region.PASSWORD_FIELD.getName().equals(regionName)) { + return "PASSWORD_FIELD"; + } else if (Region.POPUP_MENU.getName().equals(regionName)) { + return "POPUP_MENU"; + } else if (Region.POPUP_MENU_SEPARATOR.getName().equals(regionName)) { + return "POPUP_MENU_SEPARATOR"; + } else if (Region.PROGRESS_BAR.getName().equals(regionName)) { + return "PROGRESS_BAR"; + } else if (Region.RADIO_BUTTON.getName().equals(regionName)) { + return "RADIO_BUTTON"; + } else if (Region.RADIO_BUTTON_MENU_ITEM.getName().equals(regionName)) { + return "RADIO_BUTTON_MENU_ITEM"; + } else if (Region.ROOT_PANE.getName().equals(regionName)) { + return "ROOT_PANE"; + } else if (Region.SCROLL_BAR.getName().equals(regionName)) { + return "SCROLL_BAR"; + } else if (Region.SCROLL_BAR_THUMB.getName().equals(regionName)) { + return "SCROLL_BAR_THUMB"; + } else if (Region.SCROLL_BAR_TRACK.getName().equals(regionName)) { + return "SCROLL_BAR_TRACK"; + } else if (Region.SCROLL_PANE.getName().equals(regionName)) { + return "SCROLL_PANE"; + } else if (Region.SEPARATOR.getName().equals(regionName)) { + return "SEPARATOR"; + } else if (Region.SLIDER.getName().equals(regionName)) { + return "SLIDER"; + } else if (Region.SLIDER_THUMB.getName().equals(regionName)) { + return "SLIDER_THUMB"; + } else if (Region.SLIDER_TRACK.getName().equals(regionName)) { + return "SLIDER_TRACK"; + } else if (Region.SPINNER.getName().equals(regionName)) { + return "SPINNER"; + } else if (Region.SPLIT_PANE.getName().equals(regionName)) { + return "SPLIT_PANE"; + } else if (Region.SPLIT_PANE_DIVIDER.getName().equals(regionName)) { + return "SPLIT_PANE_DIVIDER"; + } else if (Region.TABBED_PANE.getName().equals(regionName)) { + return "TABBED_PANE"; + } else if (Region.TABBED_PANE_CONTENT.getName().equals(regionName)) { + return "TABBED_PANE_CONTENT"; + } else if (Region.TABBED_PANE_TAB.getName().equals(regionName)) { + return "TABBED_PANE_TAB"; + } else if (Region.TABBED_PANE_TAB_AREA.getName().equals(regionName)) { + return "TABBED_PANE_TAB_AREA"; + } else if (Region.TABLE.getName().equals(regionName)) { + return "TABLE"; + } else if (Region.TABLE_HEADER.getName().equals(regionName)) { + return "TABLE_HEADER"; + } else if (Region.TEXT_AREA.getName().equals(regionName)) { + return "TEXT_AREA"; + } else if (Region.TEXT_FIELD.getName().equals(regionName)) { + return "TEXT_FIELD"; + } else if (Region.TEXT_PANE.getName().equals(regionName)) { + return "TEXT_PANE"; + } else if (Region.TOGGLE_BUTTON.getName().equals(regionName)) { + return "TOGGLE_BUTTON"; + } else if (Region.TOOL_BAR.getName().equals(regionName)) { + return "TOOL_BAR"; + } else if (Region.TOOL_BAR_CONTENT.getName().equals(regionName)) { + return "TOOL_BAR_CONTENT"; + } else if (Region.TOOL_BAR_DRAG_WINDOW.getName().equals(regionName)) { + return "TOOL_BAR_DRAG_WINDOW"; + } else if (Region.TOOL_BAR_SEPARATOR.getName().equals(regionName)) { + return "TOOL_BAR_SEPARATOR"; + } else if (Region.TOOL_TIP.getName().equals(regionName)) { + return "TOOL_TIP"; + } else if (Region.TREE.getName().equals(regionName)) { + return "TREE"; + } else if (Region.TREE_CELL.getName().equals(regionName)) { + return "TREE_CELL"; + } else if (Region.VIEWPORT.getName().equals(regionName)) { + return "VIEWPORT"; + } + throw new RuntimeException("Bad Region name " + regionName); + } + + public static String statesToConstantName(String states) { + String s = states.replace(" ", ""); + s = states.replace("+", "_"); + return s.toUpperCase(); + } + + //takes a states string of the form Enabled+Foo+Bar. + //removes any whitespace. Replaces the + signs with And. + public static String statesToClassName(String states) { + String s = states.replace(" ", ""); + s = states.replace("+", "And"); + return s; + } + + public static String formatDouble(String doubleValue) { + return doubleValue.replace("INF", "Double.POSITIVE_INFINITY"); + } +} --- old/make/jdk/src/classes/build/tools/icondata/awt/ToBin.java 2020-03-23 19:57:31.683962296 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2005, 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 build.tools.icondata.awt; - -import java.io.*; -import java.awt.image.*; -import javax.imageio.*; -import java.awt.*; - -public class ToBin { - public static void main(String[] args) throws Exception { - BufferedImage im = ImageIO.read(System.in); - BufferedImage bi = null; - int iconWidth = im.getWidth(null); - int iconHeight = im.getHeight(null); - if (im != null && iconHeight != 0 && iconWidth != 0) { - bi = new BufferedImage(iconWidth, iconHeight, BufferedImage.TYPE_INT_ARGB); - Graphics g = bi.getGraphics(); - try { - g.drawImage(im, 0, 0, iconWidth, iconHeight, null); - } finally { - g.dispose(); - } - } - DataBuffer srcBuf = bi.getData().getDataBuffer(); - int[] buf = ((DataBufferInt)srcBuf).getData(); - System.out.print(iconWidth + ","); - System.out.println(iconHeight + ","); - for (int i = 0; i < buf.length; i++) { - System.out.print("0x" + Integer.toHexString(buf[i]) + ", "); - if (i % 10 == 0) { - System.out.println(); - } - } - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/icondataawt/ToBin.java 2020-03-23 19:57:31.247962299 +0100 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2005, 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 org.openjdk.buildtools.icondataawt; + +import java.io.*; +import java.awt.image.*; +import javax.imageio.*; +import java.awt.*; + +public class ToBin { + public static void main(String[] args) throws Exception { + BufferedImage im = ImageIO.read(System.in); + BufferedImage bi = null; + int iconWidth = im.getWidth(null); + int iconHeight = im.getHeight(null); + if (im != null && iconHeight != 0 && iconWidth != 0) { + bi = new BufferedImage(iconWidth, iconHeight, BufferedImage.TYPE_INT_ARGB); + Graphics g = bi.getGraphics(); + try { + g.drawImage(im, 0, 0, iconWidth, iconHeight, null); + } finally { + g.dispose(); + } + } + DataBuffer srcBuf = bi.getData().getDataBuffer(); + int[] buf = ((DataBufferInt)srcBuf).getData(); + System.out.print(iconWidth + ","); + System.out.println(iconHeight + ","); + for (int i = 0; i < buf.length; i++) { + System.out.print("0x" + Integer.toHexString(buf[i]) + ", "); + if (i % 10 == 0) { + System.out.println(); + } + } + } +} --- old/make/jdk/src/classes/build/tools/icondata/osxapp/ToBin.java 2020-03-23 19:57:32.547962289 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,50 +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. - */ - -package build.tools.icondata.osxapp; - -import java.io.*; - -public class ToBin { - public static void main(String[] args) throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - int nRead; - byte[] data = new byte[4096]; - - while ((nRead = System.in.read(data, 0, data.length)) != -1) { - baos.write(data, 0, nRead); - } - - baos.flush(); - - byte[] buf = baos.toByteArray(); - for (int i = 0; i < buf.length; i++) { - System.out.print(String.format("0x%1$02X", buf[i]) + ", "); - if (i % 20 == 0) { - System.out.println(); - } - } - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/icondataosx/ToBin.java 2020-03-23 19:57:32.099962292 +0100 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.icondataosx; + +import java.io.*; + +public class ToBin { + public static void main(String[] args) throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + int nRead; + byte[] data = new byte[4096]; + + while ((nRead = System.in.read(data, 0, data.length)) != -1) { + baos.write(data, 0, nRead); + } + + baos.flush(); + + byte[] buf = baos.toByteArray(); + for (int i = 0; i < buf.length; i++) { + System.out.print(String.format("0x%1$02X", buf[i]) + ", "); + if (i % 20 == 0) { + System.out.println(); + } + } + } +} --- old/make/jdk/src/classes/build/tools/x11wrappergen/WrapperGenerator.java 2020-03-23 19:57:33.335962283 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,1351 +0,0 @@ -/* - * Copyright (c) 2003, 2020, 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.x11wrappergen; - -import java.util.*; -import java.io.*; -import java.nio.charset.*; -import java.text.MessageFormat; -import java.util.logging.Level; -import java.util.logging.Logger; - -public class WrapperGenerator { - /* XLibParser converts Xlib.h to a Java Object that encapsulates the - * X11 API and data structures */ - // Charset and decoder for ISO-8859-15 - private final static Logger log = Logger.getLogger("WrapperGenerator"); - boolean generateLog = true; - boolean wide; - private static Charset charset = Charset.forName("ISO-8859-15"); - - String package_name = "sun.awt.X11"; - String package_path = "sun/awt/X11"; - String sizerFileName = "sizer.c"; - String defaultBaseClass = "XWrapperBase"; - - String compile_options = "-lX11"; - static Hashtable symbolTable = new Hashtable<>(); - static Hashtable sizeTable32bit = new Hashtable<>(); - static Hashtable sizeTable64bit = new Hashtable<>(); - static Hashtable knownSizes32 = new Hashtable<>(); - static Hashtable knownSizes64 = new Hashtable<>(); - static { -/* - knownSizes64.put("", Integer.valueOf()); - knownSizes32.put("", Integer.valueOf()); -*/ - knownSizes64.put("XComposeStatus", Integer.valueOf(16)); - knownSizes64.put("XTimeCoord", Integer.valueOf(16)); - knownSizes64.put("XExtData", Integer.valueOf(32)); - knownSizes64.put("XWindowChanges", Integer.valueOf(40)); - knownSizes64.put("XOMCharSetList", Integer.valueOf(16)); - knownSizes64.put("XModifierKeymap", Integer.valueOf(16)); - knownSizes32.put("XIMValuesList", Integer.valueOf(8)); - knownSizes32.put("XGCValues", Integer.valueOf(92)); -// knownSizes32.put("XIMStringConversionCallbackStruct", Integer.valueOf(16)); - } - - private static abstract class BaseType { - - String real_type; - String name; - - - public String getName() { - return name; - } - public String getRealType() { - return real_type; - } - - public String toString() { - return name; - } - } - - private static class AtomicType extends BaseType { - - private boolean alias; - private String aliasName; - - static final int TYPE_INT=0; - static final int TYPE_CHAR=1; - static final int TYPE_LONG=2; - static final int TYPE_LONG_LONG=3; - static final int TYPE_DOUBLE=4; - static final int TYPE_FLOAT=5; - static final int TYPE_PTR=6; - static final int TYPE_SHORT=7; - static final int TYPE_BOOL = 8; - static final int TYPE_STRUCT = 9; - static final int TYPE_ARRAY = 10; - static final int TYPE_BYTE=11; - static final int TYPE_ATOM = 12; - static final int TYPE_ULONG = 13; - static int getTypeForString(String str) { - int type=-1; - if (str.equals("int")) - type = AtomicType.TYPE_INT; - else if (str.equals("long")) - type = AtomicType.TYPE_LONG; - else if (str.equals("byte")) - type = AtomicType.TYPE_BYTE; - else if (str.equals("char")) - type = AtomicType.TYPE_CHAR; - else if (str.equals("long long")) - type = AtomicType.TYPE_LONG_LONG; - else if (str.equals("double")) - type = AtomicType.TYPE_DOUBLE; - else if (str.equals("float")) - type = AtomicType.TYPE_FLOAT; - else if (str.equals("pointer")) - type = AtomicType.TYPE_PTR; - else if (str.equals("short")) - type = AtomicType.TYPE_SHORT; - else if (str.equals("Bool")) - type = AtomicType.TYPE_BOOL; - else if (str.equals("struct")) - type = AtomicType.TYPE_STRUCT; - else if (str.equals("Atom")) - type = AtomicType.TYPE_ATOM; - else if (str.equals("array")) - type = TYPE_ARRAY; - else if (str.equals("ulong")) - type = TYPE_ULONG; - else throw new IllegalArgumentException("Uknown type string: " + str); - - return type; - } - String getJavaType() { - if (referencedType != null) { - if (referencedType instanceof AtomicType) { - return ((AtomicType)referencedType).getJavaType(); - } else { - return referencedType.getName(); - } - } else { - return getJavaTypeForType(type); - } - } - static String getJavaTypeForType(int type) { - switch (type) { - case TYPE_INT: - return "int"; - case TYPE_CHAR: - return "char"; - case TYPE_BYTE: - return "byte"; - case TYPE_LONG: - case TYPE_LONG_LONG: - case TYPE_PTR: - case TYPE_ULONG: - return "long"; - case TYPE_DOUBLE: - return "double"; - case TYPE_FLOAT: - return "float"; - case TYPE_SHORT: - return "short"; - case TYPE_BOOL: - return "boolean"; - case TYPE_ATOM: - return "long"; - default: - throw new IllegalArgumentException("Unknown type: " + type); - } - } - String getItemSize() { - if (referencedType != null) { - if (referencedType instanceof StructType) { - return ((StructType)referencedType).getSize(); - } else { - return ((AtomicType)referencedType).getItemSize(); - } - } else { - int i32 = getNativeSizeForAccess(getJavaAccess(false)); - int i64 = getNativeSizeForAccess(getJavaAccess(true)); - if (i32 != i64) { - return "Native.get" + getNativeAccess() + "Size()"; - } else { - return Integer.toString(i32); - } - } - } - - String getJavaResult(String offset, String base) { - String res = null; - switch (type) { - case TYPE_STRUCT: - res = "pData + " + offset; - break; - case TYPE_PTR: - if (referencedType == null || referencedType instanceof StructType) { - res = base + "+" + offset; - } else if (referencedType instanceof AtomicType) { - res = MessageFormat.format("Native.get{0}({1})", - new Object[] {getNativeAccessForType(((AtomicType)referencedType).type), - base + "+" + offset}); - } - break; - case TYPE_ARRAY: - if (referencedType instanceof StructType) { - res = "pData + " + offset; - } else if (referencedType instanceof AtomicType) { - res = MessageFormat.format("Native.get{0}(pData + {1})", - new Object[] {getNativeAccessForType(((AtomicType)referencedType).type), - offset}); - } - break; - default: - res = MessageFormat.format("(Native.get{0}(pData+{1}))", - new Object[] {getNativeAccess(), offset}); - } - return getJavaResultConversion(res, base); - } - String getJavaResultConversion(String value, String base) { - if (referencedType != null) { - if (referencedType instanceof StructType) { - if (type == TYPE_PTR) { - return MessageFormat.format("({2} != 0)?(new {0}({1})):(null)", new Object[] {referencedType.getName(),value, base}); - } else { - return MessageFormat.format("new {0}({1})", new Object[] {referencedType.getName(),value}); - } - } else { - return value; - } - } else { - return getJavaResultConversionForType(type, value); - } - } - static String getJavaResultConversionForType(int type, String value) { - return value; - } - String getNativeAccess() { - return getNativeAccessForType(type); - } - String getJavaAccess(boolean wide) { - return getJavaAccessForType(type, wide); - } - static String getJavaAccessForType(int type, boolean wide) { - switch (type) { - case TYPE_INT: - return "Int"; - case TYPE_CHAR: - return "Char"; - case TYPE_BYTE: - return "Byte"; - case TYPE_LONG: - case TYPE_PTR: - case TYPE_ARRAY: - case TYPE_STRUCT: - case TYPE_ATOM: - return (wide?"Long":"Int"); - case TYPE_LONG_LONG: - return "Long"; - case TYPE_ULONG: - return (wide?"ULong":"UInt"); - case TYPE_DOUBLE: - return "Double"; - case TYPE_FLOAT: - return "Float"; - case TYPE_SHORT: - return "Short"; - case TYPE_BOOL: - return "Int"; - default: - throw new IllegalArgumentException("Unknown type: " + type); - } - } - static String getNativeAccessForType(int type) { - switch (type) { - case TYPE_INT: - return "Int"; - case TYPE_CHAR: - return "Char"; - case TYPE_BYTE: - return "Byte"; - case TYPE_LONG: - case TYPE_PTR: - case TYPE_ARRAY: - case TYPE_STRUCT: - return "Long"; - case TYPE_LONG_LONG: - return "Long"; - case TYPE_ULONG: - return "ULong"; - case TYPE_DOUBLE: - return "Double"; - case TYPE_FLOAT: - return "Float"; - case TYPE_SHORT: - return "Short"; - case TYPE_BOOL: - return "Bool"; - case TYPE_ATOM: - return "Long"; - default: - throw new IllegalArgumentException("Unknown type: " + type); - } - } - - static int getNativeSizeForAccess(String access) { - if (access.equals("Int")) return 4; - else if (access.equals("Byte")) return 1; - else if (access.equals("Long")) return 8; - else if (access.equals("Double")) return 8; - else if (access.equals("Float")) return 4; - else if (access.equals("Char")) return 2; - else if (access.equals("Short")) return 2; - else if (access.equals("ULong")) return 8; - else if (access.equals("UInt")) return 4; - else throw new IllegalArgumentException("Unknow access type: " + access); - } - - String getJavaConversion(String offset, String value) { - if (referencedType != null) { - if (referencedType instanceof StructType) { - return getJavaConversionForType(TYPE_PTR, offset, value + ".pData"); - } else { - if (type == TYPE_ARRAY) { - return getJavaConversionForType(((AtomicType)referencedType).type, offset, value); - } else { // TYPE_PTR - return getJavaConversionForType(TYPE_PTR, offset, value); - } - } - } else { - return getJavaConversionForType(type, offset, value); - } - } - static String getJavaConversionForType(int type, String offset, String value) { - return MessageFormat.format("Native.put{0}({2}, {1})", new Object[] {getNativeAccessForType(type), value, offset}); - } - - - int type; - int offset; - int direction; - BaseType referencedType; - int arrayLength = -1; - boolean autoFree = false; - public AtomicType(int _type,String _name, String _real_type) { - name = _name.replaceAll("[* \t]",""); - if ((name.indexOf("[") != -1) || (name.indexOf("]") != -1)) - { - name = name.replaceAll("\\[.*\\]",""); - } - type = _type; - real_type = _real_type; - if (real_type == null) - { - System.out.println(" real type is null"); - - } - } - public boolean isIn() { - return direction == 0; - } - public boolean isOut() { - return direction == 1; - } - public boolean isInOut() { - return direction == 2; - } - public boolean isAutoFree() { - return autoFree; - } - public void setAttributes(String[] attributes) { - String mod = attributes[3]; - if ("in".equals(mod)) { - direction = 0; - } else if ("out".equals(mod)) { - direction = 1; - if (attributes.length > 4 && "free".equals(attributes[4])) { - autoFree = true; - } - } else if ("inout".equals(mod)) { - direction = 2; - } else if ("alias".equals(mod)) { - alias = true; - aliasName = attributes[4]; - } else if (type == TYPE_ARRAY || type == TYPE_PTR || type == TYPE_STRUCT) { - referencedType = symbolTable.get(mod); - if (referencedType == null) { - log.warning("Can't find type for name " + mod); - } - if (attributes.length > 4) { // array length - try { - arrayLength = Integer.parseInt(attributes[4]); - } catch (Exception e) { - } - } - } - } - public BaseType getReferencedType() { - return referencedType; - } - public int getArrayLength() { - return arrayLength; - } - public void setOffset(int o) - { - offset = o; - } - public int getType() { - return type; - } - public String getTypeUpperCase() { - switch (type) { - case TYPE_INT: - return "Int"; - case TYPE_CHAR: - return "Char"; - case TYPE_BYTE: - return "Byte"; - case TYPE_LONG: - case TYPE_LONG_LONG: - case TYPE_PTR: - return "Long"; - case TYPE_DOUBLE: - return "Double"; - case TYPE_FLOAT: - return "Float"; - case TYPE_SHORT: - return "Short"; - case TYPE_BOOL: - return "Int"; - case TYPE_ATOM: - return "Long"; - case TYPE_ULONG: - return "ULong"; - default: throw new IllegalArgumentException("Uknown type"); - } - } - public int getOffset() - { - return offset; - } - public boolean isAlias() { - return alias; - } - public String getAliasName() { - return aliasName; - } - } - - private static class StructType extends BaseType { - - Vector members; - String description; - boolean packed; - int size; - String baseClass, interfaces; - boolean isInterface; - String javaClassName; - - /** - * Construct new structured type. - * Description is used for name and type definition and has the following format: - * structName [ '[' base classe ']' ] [ '{' interfaces '}' ] [ '|' javaClassName ] - */ - public StructType(String _desc) - { - members = new Vector<>(); - parseDescription(_desc); - } - public int getNumFields() - { - return members.size(); - } - public void setName(String _name) - { - _name = _name.replaceAll("[* \t]",""); - parseDescription(_name); - } - - public void setSize(int i) - { - size = i; - } - - public String getDescription() - { - return description; - } - - public Enumeration getMembers() - { - return members.elements(); - } - - public void addMember(BaseType tp) - { - members.add(tp); - } - public String getBaseClass() { - return baseClass; - } - public String getInterfaces() { - return interfaces; - } - public boolean getIsInterface() { - return isInterface; - } - public String getJavaClassName() { - return javaClassName; - } - void parseDescription(String _desc) { - if (_desc.indexOf('[') != -1) { // Has base class - baseClass = _desc.substring(_desc.indexOf('[')+1, _desc.indexOf(']')); - _desc = _desc.substring(0, _desc.indexOf('[')) + _desc.substring(_desc.indexOf(']')+1); - } - if (_desc.indexOf('{') != -1) { // Has base class - interfaces = _desc.substring(_desc.indexOf('{')+1, _desc.indexOf('}')); - _desc = _desc.substring(0, _desc.indexOf('{')) + _desc.substring(_desc.indexOf('}')+1); - } - if (_desc.startsWith("-")) { // Interface - isInterface = true; - _desc = _desc.substring(1, _desc.length()); - } - if (_desc.indexOf("|") != -1) { - javaClassName = _desc.substring(_desc.indexOf('|')+1, _desc.length()); - _desc = _desc.substring(0, _desc.indexOf('|')); - } - name = _desc; - if (javaClassName == null) { - javaClassName = name; - } - description = _desc; -// System.out.println("Struct " + name + " extends " + baseClass + " implements " + interfaces); - } - - /** - * Returns String containing Java code calculating size of the structure depending on the data model - */ - public String getSize() { - String s32 = WrapperGenerator.sizeTable32bit.get(getName()); - String s64 = WrapperGenerator.sizeTable64bit.get(getName()); - if (s32 == null || s64 == null) { - return (s32 == null)?(s64):(s32); - } - if (s32.equals(s64)) { - return s32; - } else { - return MessageFormat.format("((XlibWrapper.dataModel == 32)?({0}):({1}))", new Object[] {s32, s64}); - } - } - public String getOffset(AtomicType atp) { - String key = getName()+"."+(atp.isAlias() ? atp.getAliasName() : atp.getName()); - String s64 = WrapperGenerator.sizeTable64bit.get(key); - String s32 = WrapperGenerator.sizeTable32bit.get(key); - if (s32 == null || s64 == null) { - return (s32 == null)?(s64):(s32); - } - if (s32.equals(s64)) { - return s32; - } else { - return MessageFormat.format("((XlibWrapper.dataModel == 32)?({0}):({1}))", new Object[]{s32, s64}); - } - } - } - - private static class FunctionType extends BaseType { - - Vector args; - String description; - boolean packed; - String returnType; - - int alignment; - - public FunctionType(String _desc) - { - args = new Vector<>(); - description = _desc; - setName(_desc); - } - boolean isVoid() { - return (returnType == null); - } - String getReturnType() { - if (returnType == null) { - return "void"; - } else { - return returnType; - } - } - - public int getNumArgs() - { - return args.size(); - } - public void setName(String _name) - { - if (_name.startsWith("!")) { - _name = _name.substring(1, _name.length()); - } - if (_name.indexOf("|") != -1) { - returnType = _name.substring(_name.indexOf("|")+1, _name.length()); - _name = _name.substring(0, _name.indexOf("|")); - } - name = _name.replaceAll("[* \t]",""); - } - - public String getDescription() - { - return description; - } - - public Collection getArguments() - { - return args; - } - public void addArgument(BaseType tp) - { - args.add(tp); - } - } - - public String makeComment(String str) - { - StringTokenizer st = new StringTokenizer(str,"\r\n"); - String ret=""; - - while (st.hasMoreTokens()) - { - ret = ret + "//" + st.nextToken() + "\n"; - } - - return ret; - } - - public String getJavaTypeForSize(int size) { - switch(size) { - case 1: return "byte"; - case 2: return "short"; - case 4: return "int"; - case 8: return "long"; - default: throw new RuntimeException("Unsupported size: " + size); - } - } - public String getOffsets(StructType stp,AtomicType atp, boolean wide) - { - String key = stp.getName()+"."+atp.getName(); - return wide == true ? sizeTable64bit.get(key) : sizeTable32bit.get(key); - } - - public String getStructSize(StructType stp, boolean wide) - { - return wide == true ? sizeTable64bit.get(stp.getName()) : sizeTable32bit.get(stp.getName()); - } - - public int getLongSize(boolean wide) - { - return Integer.parseInt(wide == true ? sizeTable64bit.get("long") : sizeTable32bit.get("long")); - } - - public int getPtrSize(boolean wide) - { - return Integer.parseInt(wide == true ? sizeTable64bit.get("ptr") : sizeTable32bit.get("ptr")); - } - public int getBoolSize(boolean wide) { - return getOrdinalSize("Bool", wide); - } - public int getOrdinalSize(String ordinal, boolean wide) { - return Integer.parseInt(wide == true ? sizeTable64bit.get(ordinal) : sizeTable32bit.get(ordinal)); - } - - public void writeToString(StructType stp, PrintWriter pw) { - int type; - pw.println("\n\n\tString getName() {\n\t\treturn \"" + stp.getName()+ "\"; \n\t}"); - pw.println("\n\n\tString getFieldsAsString() {\n\t\tStringBuilder ret = new StringBuilder(" + stp.getNumFields() * 40 + ");\n"); - - for (Enumeration e = stp.getMembers() ; e.hasMoreElements() ;) { - AtomicType tp = (AtomicType) e.nextElement(); - - type = tp.getType(); - String name = tp.getName().replace('.', '_'); - if ((name != null) && (name.length() > 0)) - { - if (type == AtomicType.TYPE_ATOM) { - pw.println("\t\tret.append(\"" + name + " = \" ).append( XAtom.get(get_" + name + "()) ).append(\", \");"); - } else if (name.equals("type")) { - pw.println("\t\tret.append(\"type = \").append( XlibWrapper.eventToString[get_type()] ).append(\", \");"); - } else if (name.equals("window")){ - pw.println("\t\tret.append(\"window = \" ).append( getWindow(get_window()) ).append(\", \");"); - } else if (type == AtomicType.TYPE_ARRAY) { - pw.print("\t\tret.append(\"{\")"); - for (int i = 0; i < tp.getArrayLength(); i++) { - pw.print("\n\t\t.append( get_" + name + "(" + i + ") ).append(\" \")"); - } - pw.println(".append( \"}\");"); - } else { - pw.println("\t\tret.append(\"" + name +" = \").append( get_"+ name+"() ).append(\", \");"); - } - } - - } - pw.println("\t\treturn ret.toString();\n\t}\n\n"); - } - - public void writeStubs(StructType stp, PrintWriter pw) { - int type; - String prefix = ""; - if (!stp.getIsInterface()) { - prefix = "\t\tabstract "; - } else { - prefix = "\t"; - } - for (Enumeration e = stp.getMembers() ; e.hasMoreElements() ;) { - AtomicType tp = (AtomicType) e.nextElement(); - - type = tp.getType(); - String name = tp.getName().replace('.','_'); - if ((name != null) && (name.length() > 0)) - { - if (type == AtomicType.TYPE_ARRAY) { - // Returns pointer to the start of the array - pw.println(prefix + "long get_" +name +"();"); - - pw.println(prefix + tp.getJavaType() + " get_" +name +"(int index);"); - pw.println(prefix + "void set_" +name +"(int index, " + tp.getJavaType() + " v);"); - } else { - pw.println(prefix + tp.getJavaType() + " get_" +name +"();"); - if (type != AtomicType.TYPE_STRUCT) pw.println(prefix + "void set_" +name +"(" + tp.getJavaType() + " v);"); - } - } - } - } - - private int padSize(int size, int wordLength) { - int bytesPerWord = wordLength / 8; - // Make size dividable by bytesPerWord - return (size + bytesPerWord / 2) / bytesPerWord * bytesPerWord; - } - - public void writeAccessorImpls(StructType stp, PrintWriter pw) { - int type; - int i=0; - String s_size_32 = getStructSize(stp, false); - String s_size_64 = getStructSize(stp, true); - int acc_size_32 = 0; - int acc_size_64 = 0; - String s_log = (generateLog?"log.finest(\"\");":""); - for (Enumeration e = stp.getMembers() ; e.hasMoreElements() ;) { - AtomicType tp = (AtomicType) e.nextElement(); - - type = tp.getType(); - String name = tp.getName().replace('.','_'); - String pref = "\tpublic " ; - if ((name != null) && (name.length() > 0)) - { - String jt = tp.getJavaType(); - String ja_32 = tp.getJavaAccess(false); - String ja_64 = tp.getJavaAccess(true); - String ja = ja_32; - int elemSize_32 = AtomicType.getNativeSizeForAccess(ja_32); - int elemSize_64 = AtomicType.getNativeSizeForAccess(ja_64); - String elemSize = tp.getItemSize(); - if (type == AtomicType.TYPE_ARRAY) { - acc_size_32 += elemSize_32 * tp.getArrayLength(); - acc_size_64 += elemSize_64 * tp.getArrayLength(); - pw.println(pref + tp.getJavaType() + " get_" +name + "(int index) { " +s_log+"return " + - tp.getJavaResult(stp.getOffset(tp) + "+index*" + elemSize, null) + "; }"); - if (tp.getReferencedType() instanceof AtomicType) { // Set for StructType is forbidden - pw.println(MessageFormat.format(pref + "void set_{0}(int index, {1} v) '{' {3} {2}; '}'", - new Object[] { - name, jt, - tp.getJavaConversion("pData+"+stp.getOffset(tp)+" + index*" + elemSize, "v"), - s_log})); - } - // Returns pointer to the start of the array - pw.println(pref + "long get_" +name+ "() { "+s_log+"return pData+"+stp.getOffset(tp)+"; }"); - } else if (type == AtomicType.TYPE_PTR) { - pw.println(MessageFormat.format(pref + "{0} get_{1}(int index) '{' {3} return {2}; '}'", - new Object[] { - jt, name, - tp.getJavaResult("index*" + elemSize, "Native.getLong(pData+"+stp.getOffset(tp)+")"), - s_log - })); - pw.println(pref + "long get_" +name+ "() { "+s_log+"return Native.getLong(pData+"+stp.getOffset(tp)+"); }"); - pw.println(MessageFormat.format(pref + "void set_{0}({1} v) '{' {3} {2}; '}'", - new Object[] {name, "long", "Native.putLong(pData + " + stp.getOffset(tp) + ", v)", s_log})); - acc_size_32 += elemSize_32; - acc_size_64 += elemSize_64; - } else { - acc_size_32 += elemSize_32; - acc_size_64 += elemSize_64; - pw.println(pref + tp.getJavaType() + " get_" +name + - "() { "+s_log+"return " + tp.getJavaResult(stp.getOffset(tp), null) + "; }"); - if (type != AtomicType.TYPE_STRUCT) { - pw.println(MessageFormat.format(pref + "void set_{0}({1} v) '{' {3} {2}; '}'", - new Object[] {name, jt, tp.getJavaConversion("pData+"+stp.getOffset(tp), "v"), s_log})); - } - } - i++; - } - } - if (s_size_32 != null && !s_size_32.equals(Integer.toString(acc_size_32))) { - if (log.isLoggable(Level.FINE)) { - log.fine("32 bits: The size of the structure " + stp.getName() + " " + s_size_32 + - " is not equal to the accumulated size " +acc_size_32 + " of the fields"); - } - } else if (s_size_64 != null && !s_size_64.equals(Integer.toString(acc_size_64))) { - if (log.isLoggable(Level.FINE)) { - log.fine("64 bits: The size of the structure " + stp.getName() + " " +s_size_64+ - " is not equal to the accumulated size " +acc_size_64+" of the fields"); - } - } - } - - public void writeWrapperSubclass(StructType stp, PrintWriter pw, boolean wide) { - - - pw.println("class " + stp.getJavaClassName() + "AccessorImpl" + " extends " + stp.getJavaClassName() + "Accessor {"); - pw.println("/*\nThis class serves as a Wrapper for the following X Struct \nsThe offsets here are calculated based on actual compiler.\n\n" +stp.getDescription() + "\n\n */"); - - writeAccessorImpls(stp, pw); - - pw.println("\n\n } \n\n"); - } - - public void writeWrapper(String outputDir, StructType stp) - { - if (stp.getNumFields() > 0) { - - try { - FileOutputStream fs = new FileOutputStream(outputDir + "/"+stp.getJavaClassName()+".java"); - PrintWriter pw = new PrintWriter(fs); - pw.println("// This file is an automatically generated file, please do not edit this file, modify the WrapperGenerator.java file instead !\n" ); - - pw.println("package "+package_name+";\n"); - pw.println("import jdk.internal.misc.Unsafe;\n"); - pw.println("import sun.util.logging.PlatformLogger;"); - String baseClass = stp.getBaseClass(); - if (baseClass == null) { - baseClass = defaultBaseClass; - } - if (stp.getIsInterface()) { - pw.print("public interface "); - pw.print(stp.getJavaClassName()); - } else { - pw.print("public class "); - pw.print(stp.getJavaClassName() + " extends " + baseClass); - } - if (stp.getInterfaces() != null) { - pw.print(" implements " + stp.getInterfaces()); - } - pw.println(" { "); - if (!stp.getIsInterface()) { - pw.println("\tprivate Unsafe unsafe = XlibWrapper.unsafe; "); - pw.println("\tprivate final boolean should_free_memory;"); - pw.println("\tpublic static int getSize() { return " + stp.getSize() + "; }"); - pw.println("\tpublic int getDataSize() { return getSize(); }"); - pw.println("\n\tlong pData;"); - pw.println("\n\tpublic long getPData() { return pData; }"); - - pw.println("\n\n\tpublic " + stp.getJavaClassName() + "(long addr) {"); - if (generateLog) { - pw.println("\t\tlog.finest(\"Creating\");"); - } - pw.println("\t\tpData=addr;"); - pw.println("\t\tshould_free_memory = false;"); - pw.println("\t}"); - pw.println("\n\n\tpublic " + stp.getJavaClassName() + "() {"); - if (generateLog) { - pw.println("\t\tlog.finest(\"Creating\");"); - } - pw.println("\t\tpData = unsafe.allocateMemory(getSize());"); - pw.println("\t\tshould_free_memory = true;"); - pw.println("\t}"); - - pw.println("\n\n\tpublic void dispose() {"); - if (generateLog) { - pw.println("\t\tlog.finest(\"Disposing\");"); - } - pw.println("\t\tif (should_free_memory) {"); - if (generateLog) { - pw.println("\t\t\tlog.finest(\"freeing memory\");"); - } - pw.println("\t\t\tunsafe.freeMemory(pData); \n\t}"); - pw.println("\t\t}"); - writeAccessorImpls(stp, pw); - writeToString(stp,pw); - } else { - pw.println("\n\n\tvoid dispose();"); - pw.println("\n\tlong getPData();"); - writeStubs(stp,pw); - } - - - pw.println("}\n\n\n"); - pw.close(); - } - catch (Exception e) - { - e.printStackTrace(); - } - } - } - - private boolean readSizeInfo(InputStream is, boolean wide) { - String line; - String splits[]; - BufferedReader in = new BufferedReader(new InputStreamReader(is)); - try { - while ((line = in.readLine()) != null) - { - splits = line.split("\\p{Space}"); - if (splits.length == 2) - { - if (wide) { - sizeTable64bit.put(splits[0],splits[1]); - } else { - sizeTable32bit.put(splits[0],splits[1]); - } - } - } - return true; - } catch (Exception e) { - e.printStackTrace(); - return false; - } - } - - public void writeFunctionCallWrapper(String outputDir, FunctionType ft) { - try { - FileOutputStream fs = new FileOutputStream(outputDir + "/" + ft.getName()+".java"); - PrintWriter pw = new PrintWriter(fs); - pw.println("// This file is an automatically generated file, please do not edit this file, modify the WrapperGenerator.java file instead !\n" ); - - pw.println("package "+package_name+";\n"); - pw.println("import jdk.internal.misc.Unsafe;\n"); - pw.println("class " + ft.getName() + " {"); - pw.println("\tprivate static Unsafe unsafe = XlibWrapper.unsafe;"); - pw.println("\tprivate boolean __executed = false;"); - pw.println("\tprivate boolean __disposed = false;"); - Iterator iter = ft.getArguments().iterator(); - while (iter.hasNext()) { - AtomicType at = (AtomicType)iter.next(); - if (at.isIn()) { - pw.println("\t" + at.getJavaType() + " _" + at.getName() + ";"); - } else { - pw.println("\tlong " + at.getName() + "_ptr = unsafe.allocateMemory(Native.get" + at.getTypeUpperCase() + "Size());"); - } - } - pw.println("\tpublic " + ft.getName() + "("); - iter = ft.getArguments().iterator(); - boolean first = true; - while (iter.hasNext()) { - AtomicType at = (AtomicType)iter.next(); - if (at.isIn() || at.isInOut()) { - if (!first) { - pw.println(","); - } - first = false; - pw.print("\t\t" + at.getJavaType() + " " + at.getName()); - } - } - pw.println("\t)"); - pw.println("\t{"); - iter = ft.getArguments().iterator(); - while (iter.hasNext()) { - AtomicType at = (AtomicType)iter.next(); - if (at.isIn() || at.isInOut()) { - pw.println("\t\tset_" + at.getName() + "(" + at.getName() + ");"); - } - } - pw.println("\t}"); - - pw.println("\tpublic " + ft.getReturnType() + " execute() {"); - if (ft.isVoid()) { - pw.println("\t\texecute(null);"); - } else { - pw.println("\t\treturn execute(null);"); - } - pw.println("\t}"); - - pw.println("\tpublic " + ft.getReturnType() + " execute(XToolkit.XErrorHandler errorHandler) {"); - pw.println("\t\tif (__disposed) {"); - pw.println("\t\t throw new IllegalStateException(\"Disposed\");"); - pw.println("\t\t}"); - pw.println("\t\tXToolkit.awtLock();"); - pw.println("\t\ttry {"); - pw.println("\t\t\tif (__executed) {"); - pw.println("\t\t\t throw new IllegalStateException(\"Already executed\");"); - pw.println("\t\t\t}"); - pw.println("\t\t\t__executed = true;"); - pw.println("\t\t\tif (errorHandler != null) {"); - pw.println("\t\t\t XErrorHandlerUtil.WITH_XERROR_HANDLER(errorHandler);"); - pw.println("\t\t\t}"); - iter = ft.getArguments().iterator(); - while (iter.hasNext()) { - AtomicType at = (AtomicType)iter.next(); - if (!at.isIn() && at.isAutoFree()) { - pw.println("\t\t\tNative.put" + at.getTypeUpperCase() + "(" +at.getName() + "_ptr, 0);"); - } - } - if (!ft.isVoid()) { - pw.println("\t\t\t" + ft.getReturnType() + " status = "); - } - pw.println("\t\t\tXlibWrapper." + ft.getName() + "(XToolkit.getDisplay(), "); - iter = ft.getArguments().iterator(); - first = true; - while (iter.hasNext()) { - AtomicType at = (AtomicType)iter.next(); - if (!first) { - pw.println(","); - } - first = false; - if (at.isIn()) { - pw.print("\t\t\t\tget_" + at.getName() + "()"); - } else { - pw.print("\t\t\t\t" + at.getName() + "_ptr"); - } - } - pw.println("\t\t\t);"); - pw.println("\t\t\tif (errorHandler != null) {"); - pw.println("\t\t\t XErrorHandlerUtil.RESTORE_XERROR_HANDLER();"); - pw.println("\t\t\t}"); - if (!ft.isVoid()) { - pw.println("\t\t\treturn status;"); - } - pw.println("\t\t} finally {"); - pw.println("\t\t XToolkit.awtUnlock();"); - pw.println("\t\t}"); - pw.println("\t}"); - - pw.println("\tpublic boolean isExecuted() {"); - pw.println("\t return __executed;"); - pw.println("\t}"); - pw.println("\t"); - pw.println("\tpublic boolean isDisposed() {"); - pw.println("\t return __disposed;"); - pw.println("\t}"); - pw.println("\tpublic void finalize() {"); - pw.println("\t dispose();"); - pw.println("\t}"); - - pw.println("\tpublic void dispose() {"); - pw.println("\t\tXToolkit.awtLock();"); - pw.println("\t\ttry {"); - pw.println("\t\tif (__disposed || !__executed) {"); - pw.println("\t\t return;"); - pw.println("\t\t} finally {"); - pw.println("\t\t XToolkit.awtUnlock();"); - pw.println("\t\t}"); - pw.println("\t\t}"); - - iter = ft.getArguments().iterator(); - while (iter.hasNext()) { - AtomicType at = (AtomicType)iter.next(); - if (!at.isIn()) { - if (at.isAutoFree()) { - pw.println("\t\tif (__executed && get_" + at.getName() + "()!= 0) {"); - pw.println("\t\t\tXlibWrapper.XFree(get_" + at.getName() + "());"); - pw.println("\t\t}"); - } - pw.println("\t\tunsafe.freeMemory(" + at.getName() + "_ptr);"); - } - } - pw.println("\t\t__disposed = true;"); - pw.println("\t\t}"); - pw.println("\t}"); - - iter = ft.getArguments().iterator(); - while (iter.hasNext()) { - AtomicType at = (AtomicType)iter.next(); - pw.println("\tpublic " + at.getJavaType() + " get_" + at.getName() + "() {"); - - pw.println("\t\tif (__disposed) {"); - pw.println("\t\t throw new IllegalStateException(\"Disposed\");"); - pw.println("\t\t}"); - pw.println("\t\tif (!__executed) {"); - pw.println("\t\t throw new IllegalStateException(\"Not executed\");"); - pw.println("\t\t}"); - - if (at.isIn()) { - pw.println("\t\treturn _" + at.getName() + ";"); - } else { - pw.println("\t\treturn Native.get" + at.getTypeUpperCase() + "(" + at.getName() + "_ptr);"); - } - pw.println("\t}"); - - pw.println("\tpublic void set_" + at.getName() + "(" + at.getJavaType() + " data) {"); - if (at.isIn()) { - pw.println("\t\t_" + at.getName() + " = data;"); - } else { - pw.println("\t\tNative.put" + at.getTypeUpperCase() + "(" + at.getName() + "_ptr, data);"); - } - pw.println("\t}"); - } - pw.println("}"); - pw.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - public void writeJavaWrapperClass(String outputDir) { - try { - for (Enumeration e = symbolTable.elements() ; e.hasMoreElements() ;) { - BaseType tp = e.nextElement(); - if (tp instanceof StructType) { - StructType st = (StructType) tp; - writeWrapper(outputDir, st); - } else if (tp instanceof FunctionType) { - writeFunctionCallWrapper(outputDir, (FunctionType)tp); - } - } - } - catch (Exception e) { - e.printStackTrace(); - } - } - - public void writeNativeSizer(String file) - { - int type; - int i=0; - int j=0; - BaseType tp; - StructType stp; - Enumeration eo; - - try { - - FileOutputStream fs = new FileOutputStream(file); - PrintWriter pw = new PrintWriter(fs); - - pw.println("/* This file is an automatically generated file, please do not edit this file, modify the XlibParser.java file instead !*/\n" ); - pw.println("#include \n#include \n#include \n#include \n#include \n"); - pw.println("#include "); - pw.println("#include "); - pw.println("#include \"awt_p.h\""); - pw.println("#include \"color.h\""); - pw.println("#include \"colordata.h\""); - pw.println("\ntypedef struct\n"); - pw.println("{\n"); - pw.println(" unsigned long flags;\n"); - pw.println(" unsigned long functions;\n"); - pw.println(" unsigned long decorations;\n"); - pw.println(" long inputMode;\n"); - pw.println(" unsigned long status;\n"); - pw.println("} PropMwmHints;\n"); - - pw.println("\n\nint main(){"); - j=0; - for ( eo = symbolTable.elements() ; eo.hasMoreElements() ;) { - tp = eo.nextElement(); - if (tp instanceof StructType) - { - stp = (StructType) tp; - if (!stp.getIsInterface()) { - pw.println(stp.getName()+" temp"+ j + ";\n"); - j++; - } - } - } - j=0; - - pw.println("printf(\"long\t%d\\n\",(int)sizeof(long));"); - pw.println("printf(\"int\t%d\\n\",(int)sizeof(int));"); - pw.println("printf(\"short\t%d\\n\",(int)sizeof(short));"); - pw.println("printf(\"ptr\t%d\\n\",(int)sizeof(void *));"); - pw.println("printf(\"Bool\t%d\\n\",(int)sizeof(Bool));"); - pw.println("printf(\"Atom\t%d\\n\",(int)sizeof(Atom));"); - pw.println("printf(\"Window\t%d\\n\",(int)sizeof(Window));"); - - for (eo = symbolTable.elements() ; eo.hasMoreElements() ;) { - - - tp = eo.nextElement(); - if (tp instanceof StructType) - { - stp = (StructType) tp; - if (stp.getIsInterface()) { - continue; - } - for (Enumeration e = stp.getMembers() ; e.hasMoreElements() ;) { - AtomicType atp = (AtomicType) e.nextElement(); - if (atp.isAlias()) continue; - pw.println("printf(\""+ stp.getName() + "." + atp.getName() + "\t%d\\n\""+ - ",(int)((unsigned long ) &temp"+j+"."+atp.getName()+"- (unsigned long ) &temp" + j + ") );"); - - i++; - - - } - pw.println("printf(\""+ stp.getName() + "\t%d\\n\"" + ",(int)sizeof(temp"+j+"));"); - - j++; - } - - } - pw.println("return 0;"); - pw.println("}"); - pw.close(); - - } - catch (Exception e) - { - e.printStackTrace(); - } - } - - private void initTypes() { - symbolTable.put("int", new AtomicType(AtomicType.TYPE_INT, "", "int")); - symbolTable.put("short", new AtomicType(AtomicType.TYPE_SHORT, "", "short")); - symbolTable.put("long", new AtomicType(AtomicType.TYPE_LONG, "", "long")); - symbolTable.put("float", new AtomicType(AtomicType.TYPE_FLOAT, "", "float")); - symbolTable.put("double", new AtomicType(AtomicType.TYPE_DOUBLE, "", "double")); - symbolTable.put("Bool", new AtomicType(AtomicType.TYPE_BOOL, "", "Bool")); - symbolTable.put("char", new AtomicType(AtomicType.TYPE_CHAR, "", "char")); - symbolTable.put("byte", new AtomicType(AtomicType.TYPE_BYTE, "", "byte")); - symbolTable.put("pointer", new AtomicType(AtomicType.TYPE_PTR, "", "pointer")); - symbolTable.put("longlong", new AtomicType(AtomicType.TYPE_LONG_LONG, "", "longlong")); - symbolTable.put("Atom", new AtomicType(AtomicType.TYPE_ATOM, "", "Atom")); - symbolTable.put("ulong", new AtomicType(AtomicType.TYPE_ULONG, "", "ulong")); - } - - public WrapperGenerator(String xlibFilename) { - initTypes(); - try { - BufferedReader in = new BufferedReader(new FileReader(xlibFilename)); - String line; - String splits[]; - BaseType curType = null; - while ((line = in.readLine()) != null) - { - int commentStart = line.indexOf("//"); - if (commentStart >= 0) { - // remove comment - line = line.substring(0, commentStart); - } - - if ("".equals(line)) { - // skip empty line - continue; - } - - splits = line.split("\\p{Space}+"); - if (splits.length >= 2) - { - String struct_name = curType.getName(); - String field_name = splits[1]; - String s_type = splits[2]; - BaseType bt = curType; - int type = AtomicType.getTypeForString(s_type); - AtomicType atp = null; - if (bt != null && type != -1) { - atp = new AtomicType(type,field_name,s_type); - if (splits.length > 3) { - atp.setAttributes(splits); - } - if (bt instanceof StructType) { - StructType stp = (StructType) bt; - stp.addMember(atp); - } else if (bt instanceof FunctionType) { - ((FunctionType)bt).addArgument(atp); - } - } - else if (bt == null) { - System.out.println("Cannot find " + struct_name); - } - - } - else if (line != null) { - BaseType bt = symbolTable.get(line); - if (bt == null) { - if (line.startsWith("!")) { - FunctionType ft = new FunctionType(line); - ft.setName(line); - symbolTable.put(ft.getName(),ft); - curType = ft; - } else { - StructType stp = new StructType(line); - stp.setName(line); - curType = stp; - symbolTable.put(stp.getName(),stp); - } - } - } - - } - in.close(); - } - catch (Exception e) { - e.printStackTrace(); - } - } - - private void makeSizer(String sizerFileName) { - File fp = new File(sizerFileName); - writeNativeSizer(fp.getAbsolutePath()); - } - - private boolean readFileSizeInfo(String filename, boolean wide) { - try { - boolean res = true; - FileInputStream fis = new FileInputStream(filename); - res = readSizeInfo(fis, wide); - fis.close(); - return res; - } catch (Exception e) { - e.printStackTrace(); - return false; - } - } - - private void startGeneration(String outputDir, String filename, boolean wide) { - if (readFileSizeInfo(filename, wide)) - { - writeJavaWrapperClass(outputDir); - } - else { - System.out.println("Error calculating offsets"); - } - } - - public static void main(String[] args) { - if (args.length < 4) { - System.out.println("Usage:\nWrapperGenerator gen_java "); - System.out.println(" or"); - System.out.println("WrapperGenerator gen_c_source "); - System.out.println("Where : 32, 64"); - - System.exit(1); - } - - WrapperGenerator xparser = new WrapperGenerator(args[2]); - if (args[0].equals("gen_c_source")) { - xparser.wide = args[3].equals("64"); - xparser.makeSizer(args[1]); - } else if (args[0].equals("gen_java")) { - boolean wide = args[4].equals("64"); - xparser.startGeneration(args[1], args[3], wide); - } - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/java.desktop/share/tools/org/openjdk/buildtools/x11wrappergen/WrapperGenerator.java 2020-03-23 19:57:32.963962286 +0100 @@ -0,0 +1,1351 @@ +/* + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.x11wrappergen; + +import java.util.*; +import java.io.*; +import java.nio.charset.*; +import java.text.MessageFormat; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class WrapperGenerator { + /* XLibParser converts Xlib.h to a Java Object that encapsulates the + * X11 API and data structures */ + // Charset and decoder for ISO-8859-15 + private final static Logger log = Logger.getLogger("WrapperGenerator"); + boolean generateLog = true; + boolean wide; + private static Charset charset = Charset.forName("ISO-8859-15"); + + String package_name = "sun.awt.X11"; + String package_path = "sun/awt/X11"; + String sizerFileName = "sizer.c"; + String defaultBaseClass = "XWrapperBase"; + + String compile_options = "-lX11"; + static Hashtable symbolTable = new Hashtable<>(); + static Hashtable sizeTable32bit = new Hashtable<>(); + static Hashtable sizeTable64bit = new Hashtable<>(); + static Hashtable knownSizes32 = new Hashtable<>(); + static Hashtable knownSizes64 = new Hashtable<>(); + static { +/* + knownSizes64.put("", Integer.valueOf()); + knownSizes32.put("", Integer.valueOf()); +*/ + knownSizes64.put("XComposeStatus", Integer.valueOf(16)); + knownSizes64.put("XTimeCoord", Integer.valueOf(16)); + knownSizes64.put("XExtData", Integer.valueOf(32)); + knownSizes64.put("XWindowChanges", Integer.valueOf(40)); + knownSizes64.put("XOMCharSetList", Integer.valueOf(16)); + knownSizes64.put("XModifierKeymap", Integer.valueOf(16)); + knownSizes32.put("XIMValuesList", Integer.valueOf(8)); + knownSizes32.put("XGCValues", Integer.valueOf(92)); +// knownSizes32.put("XIMStringConversionCallbackStruct", Integer.valueOf(16)); + } + + private static abstract class BaseType { + + String real_type; + String name; + + + public String getName() { + return name; + } + public String getRealType() { + return real_type; + } + + public String toString() { + return name; + } + } + + private static class AtomicType extends BaseType { + + private boolean alias; + private String aliasName; + + static final int TYPE_INT=0; + static final int TYPE_CHAR=1; + static final int TYPE_LONG=2; + static final int TYPE_LONG_LONG=3; + static final int TYPE_DOUBLE=4; + static final int TYPE_FLOAT=5; + static final int TYPE_PTR=6; + static final int TYPE_SHORT=7; + static final int TYPE_BOOL = 8; + static final int TYPE_STRUCT = 9; + static final int TYPE_ARRAY = 10; + static final int TYPE_BYTE=11; + static final int TYPE_ATOM = 12; + static final int TYPE_ULONG = 13; + static int getTypeForString(String str) { + int type=-1; + if (str.equals("int")) + type = AtomicType.TYPE_INT; + else if (str.equals("long")) + type = AtomicType.TYPE_LONG; + else if (str.equals("byte")) + type = AtomicType.TYPE_BYTE; + else if (str.equals("char")) + type = AtomicType.TYPE_CHAR; + else if (str.equals("long long")) + type = AtomicType.TYPE_LONG_LONG; + else if (str.equals("double")) + type = AtomicType.TYPE_DOUBLE; + else if (str.equals("float")) + type = AtomicType.TYPE_FLOAT; + else if (str.equals("pointer")) + type = AtomicType.TYPE_PTR; + else if (str.equals("short")) + type = AtomicType.TYPE_SHORT; + else if (str.equals("Bool")) + type = AtomicType.TYPE_BOOL; + else if (str.equals("struct")) + type = AtomicType.TYPE_STRUCT; + else if (str.equals("Atom")) + type = AtomicType.TYPE_ATOM; + else if (str.equals("array")) + type = TYPE_ARRAY; + else if (str.equals("ulong")) + type = TYPE_ULONG; + else throw new IllegalArgumentException("Uknown type string: " + str); + + return type; + } + String getJavaType() { + if (referencedType != null) { + if (referencedType instanceof AtomicType) { + return ((AtomicType)referencedType).getJavaType(); + } else { + return referencedType.getName(); + } + } else { + return getJavaTypeForType(type); + } + } + static String getJavaTypeForType(int type) { + switch (type) { + case TYPE_INT: + return "int"; + case TYPE_CHAR: + return "char"; + case TYPE_BYTE: + return "byte"; + case TYPE_LONG: + case TYPE_LONG_LONG: + case TYPE_PTR: + case TYPE_ULONG: + return "long"; + case TYPE_DOUBLE: + return "double"; + case TYPE_FLOAT: + return "float"; + case TYPE_SHORT: + return "short"; + case TYPE_BOOL: + return "boolean"; + case TYPE_ATOM: + return "long"; + default: + throw new IllegalArgumentException("Unknown type: " + type); + } + } + String getItemSize() { + if (referencedType != null) { + if (referencedType instanceof StructType) { + return ((StructType)referencedType).getSize(); + } else { + return ((AtomicType)referencedType).getItemSize(); + } + } else { + int i32 = getNativeSizeForAccess(getJavaAccess(false)); + int i64 = getNativeSizeForAccess(getJavaAccess(true)); + if (i32 != i64) { + return "Native.get" + getNativeAccess() + "Size()"; + } else { + return Integer.toString(i32); + } + } + } + + String getJavaResult(String offset, String base) { + String res = null; + switch (type) { + case TYPE_STRUCT: + res = "pData + " + offset; + break; + case TYPE_PTR: + if (referencedType == null || referencedType instanceof StructType) { + res = base + "+" + offset; + } else if (referencedType instanceof AtomicType) { + res = MessageFormat.format("Native.get{0}({1})", + new Object[] {getNativeAccessForType(((AtomicType)referencedType).type), + base + "+" + offset}); + } + break; + case TYPE_ARRAY: + if (referencedType instanceof StructType) { + res = "pData + " + offset; + } else if (referencedType instanceof AtomicType) { + res = MessageFormat.format("Native.get{0}(pData + {1})", + new Object[] {getNativeAccessForType(((AtomicType)referencedType).type), + offset}); + } + break; + default: + res = MessageFormat.format("(Native.get{0}(pData+{1}))", + new Object[] {getNativeAccess(), offset}); + } + return getJavaResultConversion(res, base); + } + String getJavaResultConversion(String value, String base) { + if (referencedType != null) { + if (referencedType instanceof StructType) { + if (type == TYPE_PTR) { + return MessageFormat.format("({2} != 0)?(new {0}({1})):(null)", new Object[] {referencedType.getName(),value, base}); + } else { + return MessageFormat.format("new {0}({1})", new Object[] {referencedType.getName(),value}); + } + } else { + return value; + } + } else { + return getJavaResultConversionForType(type, value); + } + } + static String getJavaResultConversionForType(int type, String value) { + return value; + } + String getNativeAccess() { + return getNativeAccessForType(type); + } + String getJavaAccess(boolean wide) { + return getJavaAccessForType(type, wide); + } + static String getJavaAccessForType(int type, boolean wide) { + switch (type) { + case TYPE_INT: + return "Int"; + case TYPE_CHAR: + return "Char"; + case TYPE_BYTE: + return "Byte"; + case TYPE_LONG: + case TYPE_PTR: + case TYPE_ARRAY: + case TYPE_STRUCT: + case TYPE_ATOM: + return (wide?"Long":"Int"); + case TYPE_LONG_LONG: + return "Long"; + case TYPE_ULONG: + return (wide?"ULong":"UInt"); + case TYPE_DOUBLE: + return "Double"; + case TYPE_FLOAT: + return "Float"; + case TYPE_SHORT: + return "Short"; + case TYPE_BOOL: + return "Int"; + default: + throw new IllegalArgumentException("Unknown type: " + type); + } + } + static String getNativeAccessForType(int type) { + switch (type) { + case TYPE_INT: + return "Int"; + case TYPE_CHAR: + return "Char"; + case TYPE_BYTE: + return "Byte"; + case TYPE_LONG: + case TYPE_PTR: + case TYPE_ARRAY: + case TYPE_STRUCT: + return "Long"; + case TYPE_LONG_LONG: + return "Long"; + case TYPE_ULONG: + return "ULong"; + case TYPE_DOUBLE: + return "Double"; + case TYPE_FLOAT: + return "Float"; + case TYPE_SHORT: + return "Short"; + case TYPE_BOOL: + return "Bool"; + case TYPE_ATOM: + return "Long"; + default: + throw new IllegalArgumentException("Unknown type: " + type); + } + } + + static int getNativeSizeForAccess(String access) { + if (access.equals("Int")) return 4; + else if (access.equals("Byte")) return 1; + else if (access.equals("Long")) return 8; + else if (access.equals("Double")) return 8; + else if (access.equals("Float")) return 4; + else if (access.equals("Char")) return 2; + else if (access.equals("Short")) return 2; + else if (access.equals("ULong")) return 8; + else if (access.equals("UInt")) return 4; + else throw new IllegalArgumentException("Unknow access type: " + access); + } + + String getJavaConversion(String offset, String value) { + if (referencedType != null) { + if (referencedType instanceof StructType) { + return getJavaConversionForType(TYPE_PTR, offset, value + ".pData"); + } else { + if (type == TYPE_ARRAY) { + return getJavaConversionForType(((AtomicType)referencedType).type, offset, value); + } else { // TYPE_PTR + return getJavaConversionForType(TYPE_PTR, offset, value); + } + } + } else { + return getJavaConversionForType(type, offset, value); + } + } + static String getJavaConversionForType(int type, String offset, String value) { + return MessageFormat.format("Native.put{0}({2}, {1})", new Object[] {getNativeAccessForType(type), value, offset}); + } + + + int type; + int offset; + int direction; + BaseType referencedType; + int arrayLength = -1; + boolean autoFree = false; + public AtomicType(int _type,String _name, String _real_type) { + name = _name.replaceAll("[* \t]",""); + if ((name.indexOf("[") != -1) || (name.indexOf("]") != -1)) + { + name = name.replaceAll("\\[.*\\]",""); + } + type = _type; + real_type = _real_type; + if (real_type == null) + { + System.out.println(" real type is null"); + + } + } + public boolean isIn() { + return direction == 0; + } + public boolean isOut() { + return direction == 1; + } + public boolean isInOut() { + return direction == 2; + } + public boolean isAutoFree() { + return autoFree; + } + public void setAttributes(String[] attributes) { + String mod = attributes[3]; + if ("in".equals(mod)) { + direction = 0; + } else if ("out".equals(mod)) { + direction = 1; + if (attributes.length > 4 && "free".equals(attributes[4])) { + autoFree = true; + } + } else if ("inout".equals(mod)) { + direction = 2; + } else if ("alias".equals(mod)) { + alias = true; + aliasName = attributes[4]; + } else if (type == TYPE_ARRAY || type == TYPE_PTR || type == TYPE_STRUCT) { + referencedType = symbolTable.get(mod); + if (referencedType == null) { + log.warning("Can't find type for name " + mod); + } + if (attributes.length > 4) { // array length + try { + arrayLength = Integer.parseInt(attributes[4]); + } catch (Exception e) { + } + } + } + } + public BaseType getReferencedType() { + return referencedType; + } + public int getArrayLength() { + return arrayLength; + } + public void setOffset(int o) + { + offset = o; + } + public int getType() { + return type; + } + public String getTypeUpperCase() { + switch (type) { + case TYPE_INT: + return "Int"; + case TYPE_CHAR: + return "Char"; + case TYPE_BYTE: + return "Byte"; + case TYPE_LONG: + case TYPE_LONG_LONG: + case TYPE_PTR: + return "Long"; + case TYPE_DOUBLE: + return "Double"; + case TYPE_FLOAT: + return "Float"; + case TYPE_SHORT: + return "Short"; + case TYPE_BOOL: + return "Int"; + case TYPE_ATOM: + return "Long"; + case TYPE_ULONG: + return "ULong"; + default: throw new IllegalArgumentException("Uknown type"); + } + } + public int getOffset() + { + return offset; + } + public boolean isAlias() { + return alias; + } + public String getAliasName() { + return aliasName; + } + } + + private static class StructType extends BaseType { + + Vector members; + String description; + boolean packed; + int size; + String baseClass, interfaces; + boolean isInterface; + String javaClassName; + + /** + * Construct new structured type. + * Description is used for name and type definition and has the following format: + * structName [ '[' base classe ']' ] [ '{' interfaces '}' ] [ '|' javaClassName ] + */ + public StructType(String _desc) + { + members = new Vector<>(); + parseDescription(_desc); + } + public int getNumFields() + { + return members.size(); + } + public void setName(String _name) + { + _name = _name.replaceAll("[* \t]",""); + parseDescription(_name); + } + + public void setSize(int i) + { + size = i; + } + + public String getDescription() + { + return description; + } + + public Enumeration getMembers() + { + return members.elements(); + } + + public void addMember(BaseType tp) + { + members.add(tp); + } + public String getBaseClass() { + return baseClass; + } + public String getInterfaces() { + return interfaces; + } + public boolean getIsInterface() { + return isInterface; + } + public String getJavaClassName() { + return javaClassName; + } + void parseDescription(String _desc) { + if (_desc.indexOf('[') != -1) { // Has base class + baseClass = _desc.substring(_desc.indexOf('[')+1, _desc.indexOf(']')); + _desc = _desc.substring(0, _desc.indexOf('[')) + _desc.substring(_desc.indexOf(']')+1); + } + if (_desc.indexOf('{') != -1) { // Has base class + interfaces = _desc.substring(_desc.indexOf('{')+1, _desc.indexOf('}')); + _desc = _desc.substring(0, _desc.indexOf('{')) + _desc.substring(_desc.indexOf('}')+1); + } + if (_desc.startsWith("-")) { // Interface + isInterface = true; + _desc = _desc.substring(1, _desc.length()); + } + if (_desc.indexOf("|") != -1) { + javaClassName = _desc.substring(_desc.indexOf('|')+1, _desc.length()); + _desc = _desc.substring(0, _desc.indexOf('|')); + } + name = _desc; + if (javaClassName == null) { + javaClassName = name; + } + description = _desc; +// System.out.println("Struct " + name + " extends " + baseClass + " implements " + interfaces); + } + + /** + * Returns String containing Java code calculating size of the structure depending on the data model + */ + public String getSize() { + String s32 = WrapperGenerator.sizeTable32bit.get(getName()); + String s64 = WrapperGenerator.sizeTable64bit.get(getName()); + if (s32 == null || s64 == null) { + return (s32 == null)?(s64):(s32); + } + if (s32.equals(s64)) { + return s32; + } else { + return MessageFormat.format("((XlibWrapper.dataModel == 32)?({0}):({1}))", new Object[] {s32, s64}); + } + } + public String getOffset(AtomicType atp) { + String key = getName()+"."+(atp.isAlias() ? atp.getAliasName() : atp.getName()); + String s64 = WrapperGenerator.sizeTable64bit.get(key); + String s32 = WrapperGenerator.sizeTable32bit.get(key); + if (s32 == null || s64 == null) { + return (s32 == null)?(s64):(s32); + } + if (s32.equals(s64)) { + return s32; + } else { + return MessageFormat.format("((XlibWrapper.dataModel == 32)?({0}):({1}))", new Object[]{s32, s64}); + } + } + } + + private static class FunctionType extends BaseType { + + Vector args; + String description; + boolean packed; + String returnType; + + int alignment; + + public FunctionType(String _desc) + { + args = new Vector<>(); + description = _desc; + setName(_desc); + } + boolean isVoid() { + return (returnType == null); + } + String getReturnType() { + if (returnType == null) { + return "void"; + } else { + return returnType; + } + } + + public int getNumArgs() + { + return args.size(); + } + public void setName(String _name) + { + if (_name.startsWith("!")) { + _name = _name.substring(1, _name.length()); + } + if (_name.indexOf("|") != -1) { + returnType = _name.substring(_name.indexOf("|")+1, _name.length()); + _name = _name.substring(0, _name.indexOf("|")); + } + name = _name.replaceAll("[* \t]",""); + } + + public String getDescription() + { + return description; + } + + public Collection getArguments() + { + return args; + } + public void addArgument(BaseType tp) + { + args.add(tp); + } + } + + public String makeComment(String str) + { + StringTokenizer st = new StringTokenizer(str,"\r\n"); + String ret=""; + + while (st.hasMoreTokens()) + { + ret = ret + "//" + st.nextToken() + "\n"; + } + + return ret; + } + + public String getJavaTypeForSize(int size) { + switch(size) { + case 1: return "byte"; + case 2: return "short"; + case 4: return "int"; + case 8: return "long"; + default: throw new RuntimeException("Unsupported size: " + size); + } + } + public String getOffsets(StructType stp,AtomicType atp, boolean wide) + { + String key = stp.getName()+"."+atp.getName(); + return wide == true ? sizeTable64bit.get(key) : sizeTable32bit.get(key); + } + + public String getStructSize(StructType stp, boolean wide) + { + return wide == true ? sizeTable64bit.get(stp.getName()) : sizeTable32bit.get(stp.getName()); + } + + public int getLongSize(boolean wide) + { + return Integer.parseInt(wide == true ? sizeTable64bit.get("long") : sizeTable32bit.get("long")); + } + + public int getPtrSize(boolean wide) + { + return Integer.parseInt(wide == true ? sizeTable64bit.get("ptr") : sizeTable32bit.get("ptr")); + } + public int getBoolSize(boolean wide) { + return getOrdinalSize("Bool", wide); + } + public int getOrdinalSize(String ordinal, boolean wide) { + return Integer.parseInt(wide == true ? sizeTable64bit.get(ordinal) : sizeTable32bit.get(ordinal)); + } + + public void writeToString(StructType stp, PrintWriter pw) { + int type; + pw.println("\n\n\tString getName() {\n\t\treturn \"" + stp.getName()+ "\"; \n\t}"); + pw.println("\n\n\tString getFieldsAsString() {\n\t\tStringBuilder ret = new StringBuilder(" + stp.getNumFields() * 40 + ");\n"); + + for (Enumeration e = stp.getMembers() ; e.hasMoreElements() ;) { + AtomicType tp = (AtomicType) e.nextElement(); + + type = tp.getType(); + String name = tp.getName().replace('.', '_'); + if ((name != null) && (name.length() > 0)) + { + if (type == AtomicType.TYPE_ATOM) { + pw.println("\t\tret.append(\"" + name + " = \" ).append( XAtom.get(get_" + name + "()) ).append(\", \");"); + } else if (name.equals("type")) { + pw.println("\t\tret.append(\"type = \").append( XlibWrapper.eventToString[get_type()] ).append(\", \");"); + } else if (name.equals("window")){ + pw.println("\t\tret.append(\"window = \" ).append( getWindow(get_window()) ).append(\", \");"); + } else if (type == AtomicType.TYPE_ARRAY) { + pw.print("\t\tret.append(\"{\")"); + for (int i = 0; i < tp.getArrayLength(); i++) { + pw.print("\n\t\t.append( get_" + name + "(" + i + ") ).append(\" \")"); + } + pw.println(".append( \"}\");"); + } else { + pw.println("\t\tret.append(\"" + name +" = \").append( get_"+ name+"() ).append(\", \");"); + } + } + + } + pw.println("\t\treturn ret.toString();\n\t}\n\n"); + } + + public void writeStubs(StructType stp, PrintWriter pw) { + int type; + String prefix = ""; + if (!stp.getIsInterface()) { + prefix = "\t\tabstract "; + } else { + prefix = "\t"; + } + for (Enumeration e = stp.getMembers() ; e.hasMoreElements() ;) { + AtomicType tp = (AtomicType) e.nextElement(); + + type = tp.getType(); + String name = tp.getName().replace('.','_'); + if ((name != null) && (name.length() > 0)) + { + if (type == AtomicType.TYPE_ARRAY) { + // Returns pointer to the start of the array + pw.println(prefix + "long get_" +name +"();"); + + pw.println(prefix + tp.getJavaType() + " get_" +name +"(int index);"); + pw.println(prefix + "void set_" +name +"(int index, " + tp.getJavaType() + " v);"); + } else { + pw.println(prefix + tp.getJavaType() + " get_" +name +"();"); + if (type != AtomicType.TYPE_STRUCT) pw.println(prefix + "void set_" +name +"(" + tp.getJavaType() + " v);"); + } + } + } + } + + private int padSize(int size, int wordLength) { + int bytesPerWord = wordLength / 8; + // Make size dividable by bytesPerWord + return (size + bytesPerWord / 2) / bytesPerWord * bytesPerWord; + } + + public void writeAccessorImpls(StructType stp, PrintWriter pw) { + int type; + int i=0; + String s_size_32 = getStructSize(stp, false); + String s_size_64 = getStructSize(stp, true); + int acc_size_32 = 0; + int acc_size_64 = 0; + String s_log = (generateLog?"log.finest(\"\");":""); + for (Enumeration e = stp.getMembers() ; e.hasMoreElements() ;) { + AtomicType tp = (AtomicType) e.nextElement(); + + type = tp.getType(); + String name = tp.getName().replace('.','_'); + String pref = "\tpublic " ; + if ((name != null) && (name.length() > 0)) + { + String jt = tp.getJavaType(); + String ja_32 = tp.getJavaAccess(false); + String ja_64 = tp.getJavaAccess(true); + String ja = ja_32; + int elemSize_32 = AtomicType.getNativeSizeForAccess(ja_32); + int elemSize_64 = AtomicType.getNativeSizeForAccess(ja_64); + String elemSize = tp.getItemSize(); + if (type == AtomicType.TYPE_ARRAY) { + acc_size_32 += elemSize_32 * tp.getArrayLength(); + acc_size_64 += elemSize_64 * tp.getArrayLength(); + pw.println(pref + tp.getJavaType() + " get_" +name + "(int index) { " +s_log+"return " + + tp.getJavaResult(stp.getOffset(tp) + "+index*" + elemSize, null) + "; }"); + if (tp.getReferencedType() instanceof AtomicType) { // Set for StructType is forbidden + pw.println(MessageFormat.format(pref + "void set_{0}(int index, {1} v) '{' {3} {2}; '}'", + new Object[] { + name, jt, + tp.getJavaConversion("pData+"+stp.getOffset(tp)+" + index*" + elemSize, "v"), + s_log})); + } + // Returns pointer to the start of the array + pw.println(pref + "long get_" +name+ "() { "+s_log+"return pData+"+stp.getOffset(tp)+"; }"); + } else if (type == AtomicType.TYPE_PTR) { + pw.println(MessageFormat.format(pref + "{0} get_{1}(int index) '{' {3} return {2}; '}'", + new Object[] { + jt, name, + tp.getJavaResult("index*" + elemSize, "Native.getLong(pData+"+stp.getOffset(tp)+")"), + s_log + })); + pw.println(pref + "long get_" +name+ "() { "+s_log+"return Native.getLong(pData+"+stp.getOffset(tp)+"); }"); + pw.println(MessageFormat.format(pref + "void set_{0}({1} v) '{' {3} {2}; '}'", + new Object[] {name, "long", "Native.putLong(pData + " + stp.getOffset(tp) + ", v)", s_log})); + acc_size_32 += elemSize_32; + acc_size_64 += elemSize_64; + } else { + acc_size_32 += elemSize_32; + acc_size_64 += elemSize_64; + pw.println(pref + tp.getJavaType() + " get_" +name + + "() { "+s_log+"return " + tp.getJavaResult(stp.getOffset(tp), null) + "; }"); + if (type != AtomicType.TYPE_STRUCT) { + pw.println(MessageFormat.format(pref + "void set_{0}({1} v) '{' {3} {2}; '}'", + new Object[] {name, jt, tp.getJavaConversion("pData+"+stp.getOffset(tp), "v"), s_log})); + } + } + i++; + } + } + if (s_size_32 != null && !s_size_32.equals(Integer.toString(acc_size_32))) { + if (log.isLoggable(Level.FINE)) { + log.fine("32 bits: The size of the structure " + stp.getName() + " " + s_size_32 + + " is not equal to the accumulated size " +acc_size_32 + " of the fields"); + } + } else if (s_size_64 != null && !s_size_64.equals(Integer.toString(acc_size_64))) { + if (log.isLoggable(Level.FINE)) { + log.fine("64 bits: The size of the structure " + stp.getName() + " " +s_size_64+ + " is not equal to the accumulated size " +acc_size_64+" of the fields"); + } + } + } + + public void writeWrapperSubclass(StructType stp, PrintWriter pw, boolean wide) { + + + pw.println("class " + stp.getJavaClassName() + "AccessorImpl" + " extends " + stp.getJavaClassName() + "Accessor {"); + pw.println("/*\nThis class serves as a Wrapper for the following X Struct \nsThe offsets here are calculated based on actual compiler.\n\n" +stp.getDescription() + "\n\n */"); + + writeAccessorImpls(stp, pw); + + pw.println("\n\n } \n\n"); + } + + public void writeWrapper(String outputDir, StructType stp) + { + if (stp.getNumFields() > 0) { + + try { + FileOutputStream fs = new FileOutputStream(outputDir + "/"+stp.getJavaClassName()+".java"); + PrintWriter pw = new PrintWriter(fs); + pw.println("// This file is an automatically generated file, please do not edit this file, modify the WrapperGenerator.java file instead !\n" ); + + pw.println("package "+package_name+";\n"); + pw.println("import jdk.internal.misc.Unsafe;\n"); + pw.println("import sun.util.logging.PlatformLogger;"); + String baseClass = stp.getBaseClass(); + if (baseClass == null) { + baseClass = defaultBaseClass; + } + if (stp.getIsInterface()) { + pw.print("public interface "); + pw.print(stp.getJavaClassName()); + } else { + pw.print("public class "); + pw.print(stp.getJavaClassName() + " extends " + baseClass); + } + if (stp.getInterfaces() != null) { + pw.print(" implements " + stp.getInterfaces()); + } + pw.println(" { "); + if (!stp.getIsInterface()) { + pw.println("\tprivate Unsafe unsafe = XlibWrapper.unsafe; "); + pw.println("\tprivate final boolean should_free_memory;"); + pw.println("\tpublic static int getSize() { return " + stp.getSize() + "; }"); + pw.println("\tpublic int getDataSize() { return getSize(); }"); + pw.println("\n\tlong pData;"); + pw.println("\n\tpublic long getPData() { return pData; }"); + + pw.println("\n\n\tpublic " + stp.getJavaClassName() + "(long addr) {"); + if (generateLog) { + pw.println("\t\tlog.finest(\"Creating\");"); + } + pw.println("\t\tpData=addr;"); + pw.println("\t\tshould_free_memory = false;"); + pw.println("\t}"); + pw.println("\n\n\tpublic " + stp.getJavaClassName() + "() {"); + if (generateLog) { + pw.println("\t\tlog.finest(\"Creating\");"); + } + pw.println("\t\tpData = unsafe.allocateMemory(getSize());"); + pw.println("\t\tshould_free_memory = true;"); + pw.println("\t}"); + + pw.println("\n\n\tpublic void dispose() {"); + if (generateLog) { + pw.println("\t\tlog.finest(\"Disposing\");"); + } + pw.println("\t\tif (should_free_memory) {"); + if (generateLog) { + pw.println("\t\t\tlog.finest(\"freeing memory\");"); + } + pw.println("\t\t\tunsafe.freeMemory(pData); \n\t}"); + pw.println("\t\t}"); + writeAccessorImpls(stp, pw); + writeToString(stp,pw); + } else { + pw.println("\n\n\tvoid dispose();"); + pw.println("\n\tlong getPData();"); + writeStubs(stp,pw); + } + + + pw.println("}\n\n\n"); + pw.close(); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + } + + private boolean readSizeInfo(InputStream is, boolean wide) { + String line; + String splits[]; + BufferedReader in = new BufferedReader(new InputStreamReader(is)); + try { + while ((line = in.readLine()) != null) + { + splits = line.split("\\p{Space}"); + if (splits.length == 2) + { + if (wide) { + sizeTable64bit.put(splits[0],splits[1]); + } else { + sizeTable32bit.put(splits[0],splits[1]); + } + } + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + public void writeFunctionCallWrapper(String outputDir, FunctionType ft) { + try { + FileOutputStream fs = new FileOutputStream(outputDir + "/" + ft.getName()+".java"); + PrintWriter pw = new PrintWriter(fs); + pw.println("// This file is an automatically generated file, please do not edit this file, modify the WrapperGenerator.java file instead !\n" ); + + pw.println("package "+package_name+";\n"); + pw.println("import jdk.internal.misc.Unsafe;\n"); + pw.println("class " + ft.getName() + " {"); + pw.println("\tprivate static Unsafe unsafe = XlibWrapper.unsafe;"); + pw.println("\tprivate boolean __executed = false;"); + pw.println("\tprivate boolean __disposed = false;"); + Iterator iter = ft.getArguments().iterator(); + while (iter.hasNext()) { + AtomicType at = (AtomicType)iter.next(); + if (at.isIn()) { + pw.println("\t" + at.getJavaType() + " _" + at.getName() + ";"); + } else { + pw.println("\tlong " + at.getName() + "_ptr = unsafe.allocateMemory(Native.get" + at.getTypeUpperCase() + "Size());"); + } + } + pw.println("\tpublic " + ft.getName() + "("); + iter = ft.getArguments().iterator(); + boolean first = true; + while (iter.hasNext()) { + AtomicType at = (AtomicType)iter.next(); + if (at.isIn() || at.isInOut()) { + if (!first) { + pw.println(","); + } + first = false; + pw.print("\t\t" + at.getJavaType() + " " + at.getName()); + } + } + pw.println("\t)"); + pw.println("\t{"); + iter = ft.getArguments().iterator(); + while (iter.hasNext()) { + AtomicType at = (AtomicType)iter.next(); + if (at.isIn() || at.isInOut()) { + pw.println("\t\tset_" + at.getName() + "(" + at.getName() + ");"); + } + } + pw.println("\t}"); + + pw.println("\tpublic " + ft.getReturnType() + " execute() {"); + if (ft.isVoid()) { + pw.println("\t\texecute(null);"); + } else { + pw.println("\t\treturn execute(null);"); + } + pw.println("\t}"); + + pw.println("\tpublic " + ft.getReturnType() + " execute(XToolkit.XErrorHandler errorHandler) {"); + pw.println("\t\tif (__disposed) {"); + pw.println("\t\t throw new IllegalStateException(\"Disposed\");"); + pw.println("\t\t}"); + pw.println("\t\tXToolkit.awtLock();"); + pw.println("\t\ttry {"); + pw.println("\t\t\tif (__executed) {"); + pw.println("\t\t\t throw new IllegalStateException(\"Already executed\");"); + pw.println("\t\t\t}"); + pw.println("\t\t\t__executed = true;"); + pw.println("\t\t\tif (errorHandler != null) {"); + pw.println("\t\t\t XErrorHandlerUtil.WITH_XERROR_HANDLER(errorHandler);"); + pw.println("\t\t\t}"); + iter = ft.getArguments().iterator(); + while (iter.hasNext()) { + AtomicType at = (AtomicType)iter.next(); + if (!at.isIn() && at.isAutoFree()) { + pw.println("\t\t\tNative.put" + at.getTypeUpperCase() + "(" +at.getName() + "_ptr, 0);"); + } + } + if (!ft.isVoid()) { + pw.println("\t\t\t" + ft.getReturnType() + " status = "); + } + pw.println("\t\t\tXlibWrapper." + ft.getName() + "(XToolkit.getDisplay(), "); + iter = ft.getArguments().iterator(); + first = true; + while (iter.hasNext()) { + AtomicType at = (AtomicType)iter.next(); + if (!first) { + pw.println(","); + } + first = false; + if (at.isIn()) { + pw.print("\t\t\t\tget_" + at.getName() + "()"); + } else { + pw.print("\t\t\t\t" + at.getName() + "_ptr"); + } + } + pw.println("\t\t\t);"); + pw.println("\t\t\tif (errorHandler != null) {"); + pw.println("\t\t\t XErrorHandlerUtil.RESTORE_XERROR_HANDLER();"); + pw.println("\t\t\t}"); + if (!ft.isVoid()) { + pw.println("\t\t\treturn status;"); + } + pw.println("\t\t} finally {"); + pw.println("\t\t XToolkit.awtUnlock();"); + pw.println("\t\t}"); + pw.println("\t}"); + + pw.println("\tpublic boolean isExecuted() {"); + pw.println("\t return __executed;"); + pw.println("\t}"); + pw.println("\t"); + pw.println("\tpublic boolean isDisposed() {"); + pw.println("\t return __disposed;"); + pw.println("\t}"); + pw.println("\tpublic void finalize() {"); + pw.println("\t dispose();"); + pw.println("\t}"); + + pw.println("\tpublic void dispose() {"); + pw.println("\t\tXToolkit.awtLock();"); + pw.println("\t\ttry {"); + pw.println("\t\tif (__disposed || !__executed) {"); + pw.println("\t\t return;"); + pw.println("\t\t} finally {"); + pw.println("\t\t XToolkit.awtUnlock();"); + pw.println("\t\t}"); + pw.println("\t\t}"); + + iter = ft.getArguments().iterator(); + while (iter.hasNext()) { + AtomicType at = (AtomicType)iter.next(); + if (!at.isIn()) { + if (at.isAutoFree()) { + pw.println("\t\tif (__executed && get_" + at.getName() + "()!= 0) {"); + pw.println("\t\t\tXlibWrapper.XFree(get_" + at.getName() + "());"); + pw.println("\t\t}"); + } + pw.println("\t\tunsafe.freeMemory(" + at.getName() + "_ptr);"); + } + } + pw.println("\t\t__disposed = true;"); + pw.println("\t\t}"); + pw.println("\t}"); + + iter = ft.getArguments().iterator(); + while (iter.hasNext()) { + AtomicType at = (AtomicType)iter.next(); + pw.println("\tpublic " + at.getJavaType() + " get_" + at.getName() + "() {"); + + pw.println("\t\tif (__disposed) {"); + pw.println("\t\t throw new IllegalStateException(\"Disposed\");"); + pw.println("\t\t}"); + pw.println("\t\tif (!__executed) {"); + pw.println("\t\t throw new IllegalStateException(\"Not executed\");"); + pw.println("\t\t}"); + + if (at.isIn()) { + pw.println("\t\treturn _" + at.getName() + ";"); + } else { + pw.println("\t\treturn Native.get" + at.getTypeUpperCase() + "(" + at.getName() + "_ptr);"); + } + pw.println("\t}"); + + pw.println("\tpublic void set_" + at.getName() + "(" + at.getJavaType() + " data) {"); + if (at.isIn()) { + pw.println("\t\t_" + at.getName() + " = data;"); + } else { + pw.println("\t\tNative.put" + at.getTypeUpperCase() + "(" + at.getName() + "_ptr, data);"); + } + pw.println("\t}"); + } + pw.println("}"); + pw.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void writeJavaWrapperClass(String outputDir) { + try { + for (Enumeration e = symbolTable.elements() ; e.hasMoreElements() ;) { + BaseType tp = e.nextElement(); + if (tp instanceof StructType) { + StructType st = (StructType) tp; + writeWrapper(outputDir, st); + } else if (tp instanceof FunctionType) { + writeFunctionCallWrapper(outputDir, (FunctionType)tp); + } + } + } + catch (Exception e) { + e.printStackTrace(); + } + } + + public void writeNativeSizer(String file) + { + int type; + int i=0; + int j=0; + BaseType tp; + StructType stp; + Enumeration eo; + + try { + + FileOutputStream fs = new FileOutputStream(file); + PrintWriter pw = new PrintWriter(fs); + + pw.println("/* This file is an automatically generated file, please do not edit this file, modify the XlibParser.java file instead !*/\n" ); + pw.println("#include \n#include \n#include \n#include \n#include \n"); + pw.println("#include "); + pw.println("#include "); + pw.println("#include \"awt_p.h\""); + pw.println("#include \"color.h\""); + pw.println("#include \"colordata.h\""); + pw.println("\ntypedef struct\n"); + pw.println("{\n"); + pw.println(" unsigned long flags;\n"); + pw.println(" unsigned long functions;\n"); + pw.println(" unsigned long decorations;\n"); + pw.println(" long inputMode;\n"); + pw.println(" unsigned long status;\n"); + pw.println("} PropMwmHints;\n"); + + pw.println("\n\nint main(){"); + j=0; + for ( eo = symbolTable.elements() ; eo.hasMoreElements() ;) { + tp = eo.nextElement(); + if (tp instanceof StructType) + { + stp = (StructType) tp; + if (!stp.getIsInterface()) { + pw.println(stp.getName()+" temp"+ j + ";\n"); + j++; + } + } + } + j=0; + + pw.println("printf(\"long\t%d\\n\",(int)sizeof(long));"); + pw.println("printf(\"int\t%d\\n\",(int)sizeof(int));"); + pw.println("printf(\"short\t%d\\n\",(int)sizeof(short));"); + pw.println("printf(\"ptr\t%d\\n\",(int)sizeof(void *));"); + pw.println("printf(\"Bool\t%d\\n\",(int)sizeof(Bool));"); + pw.println("printf(\"Atom\t%d\\n\",(int)sizeof(Atom));"); + pw.println("printf(\"Window\t%d\\n\",(int)sizeof(Window));"); + + for (eo = symbolTable.elements() ; eo.hasMoreElements() ;) { + + + tp = eo.nextElement(); + if (tp instanceof StructType) + { + stp = (StructType) tp; + if (stp.getIsInterface()) { + continue; + } + for (Enumeration e = stp.getMembers() ; e.hasMoreElements() ;) { + AtomicType atp = (AtomicType) e.nextElement(); + if (atp.isAlias()) continue; + pw.println("printf(\""+ stp.getName() + "." + atp.getName() + "\t%d\\n\""+ + ",(int)((unsigned long ) &temp"+j+"."+atp.getName()+"- (unsigned long ) &temp" + j + ") );"); + + i++; + + + } + pw.println("printf(\""+ stp.getName() + "\t%d\\n\"" + ",(int)sizeof(temp"+j+"));"); + + j++; + } + + } + pw.println("return 0;"); + pw.println("}"); + pw.close(); + + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + private void initTypes() { + symbolTable.put("int", new AtomicType(AtomicType.TYPE_INT, "", "int")); + symbolTable.put("short", new AtomicType(AtomicType.TYPE_SHORT, "", "short")); + symbolTable.put("long", new AtomicType(AtomicType.TYPE_LONG, "", "long")); + symbolTable.put("float", new AtomicType(AtomicType.TYPE_FLOAT, "", "float")); + symbolTable.put("double", new AtomicType(AtomicType.TYPE_DOUBLE, "", "double")); + symbolTable.put("Bool", new AtomicType(AtomicType.TYPE_BOOL, "", "Bool")); + symbolTable.put("char", new AtomicType(AtomicType.TYPE_CHAR, "", "char")); + symbolTable.put("byte", new AtomicType(AtomicType.TYPE_BYTE, "", "byte")); + symbolTable.put("pointer", new AtomicType(AtomicType.TYPE_PTR, "", "pointer")); + symbolTable.put("longlong", new AtomicType(AtomicType.TYPE_LONG_LONG, "", "longlong")); + symbolTable.put("Atom", new AtomicType(AtomicType.TYPE_ATOM, "", "Atom")); + symbolTable.put("ulong", new AtomicType(AtomicType.TYPE_ULONG, "", "ulong")); + } + + public WrapperGenerator(String xlibFilename) { + initTypes(); + try { + BufferedReader in = new BufferedReader(new FileReader(xlibFilename)); + String line; + String splits[]; + BaseType curType = null; + while ((line = in.readLine()) != null) + { + int commentStart = line.indexOf("//"); + if (commentStart >= 0) { + // remove comment + line = line.substring(0, commentStart); + } + + if ("".equals(line)) { + // skip empty line + continue; + } + + splits = line.split("\\p{Space}+"); + if (splits.length >= 2) + { + String struct_name = curType.getName(); + String field_name = splits[1]; + String s_type = splits[2]; + BaseType bt = curType; + int type = AtomicType.getTypeForString(s_type); + AtomicType atp = null; + if (bt != null && type != -1) { + atp = new AtomicType(type,field_name,s_type); + if (splits.length > 3) { + atp.setAttributes(splits); + } + if (bt instanceof StructType) { + StructType stp = (StructType) bt; + stp.addMember(atp); + } else if (bt instanceof FunctionType) { + ((FunctionType)bt).addArgument(atp); + } + } + else if (bt == null) { + System.out.println("Cannot find " + struct_name); + } + + } + else if (line != null) { + BaseType bt = symbolTable.get(line); + if (bt == null) { + if (line.startsWith("!")) { + FunctionType ft = new FunctionType(line); + ft.setName(line); + symbolTable.put(ft.getName(),ft); + curType = ft; + } else { + StructType stp = new StructType(line); + stp.setName(line); + curType = stp; + symbolTable.put(stp.getName(),stp); + } + } + } + + } + in.close(); + } + catch (Exception e) { + e.printStackTrace(); + } + } + + private void makeSizer(String sizerFileName) { + File fp = new File(sizerFileName); + writeNativeSizer(fp.getAbsolutePath()); + } + + private boolean readFileSizeInfo(String filename, boolean wide) { + try { + boolean res = true; + FileInputStream fis = new FileInputStream(filename); + res = readSizeInfo(fis, wide); + fis.close(); + return res; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + private void startGeneration(String outputDir, String filename, boolean wide) { + if (readFileSizeInfo(filename, wide)) + { + writeJavaWrapperClass(outputDir); + } + else { + System.out.println("Error calculating offsets"); + } + } + + public static void main(String[] args) { + if (args.length < 4) { + System.out.println("Usage:\nWrapperGenerator gen_java "); + System.out.println(" or"); + System.out.println("WrapperGenerator gen_c_source "); + System.out.println("Where : 32, 64"); + + System.exit(1); + } + + WrapperGenerator xparser = new WrapperGenerator(args[2]); + if (args[0].equals("gen_c_source")) { + xparser.wide = args[3].equals("64"); + xparser.makeSizer(args[1]); + } else if (args[0].equals("gen_java")) { + boolean wide = args[4].equals("64"); + xparser.startGeneration(args[1], args[3], wide); + } + } +} --- old/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java 2020-03-23 19:57:34.179962277 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,3751 +0,0 @@ -/* - * Copyright (c) 2006, 2018, 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.symbolgenerator; - -import build.tools.symbolgenerator.CreateSymbols - .ModuleHeaderDescription - .ProvidesDescription; -import build.tools.symbolgenerator.CreateSymbols - .ModuleHeaderDescription - .RequiresDescription; -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.StringWriter; -import java.io.Writer; -import java.nio.file.Files; -import java.nio.file.FileVisitResult; -import java.nio.file.FileVisitor; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.stream.Stream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Collection; -import java.util.Collections; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; -import java.util.Set; -import java.util.TimeZone; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import javax.tools.JavaFileManager; -import javax.tools.JavaFileManager.Location; -import javax.tools.JavaFileObject; -import javax.tools.JavaFileObject.Kind; -import javax.tools.StandardLocation; - -import com.sun.source.util.JavacTask; -import com.sun.tools.classfile.AccessFlags; -import com.sun.tools.classfile.Annotation; -import com.sun.tools.classfile.Annotation.Annotation_element_value; -import com.sun.tools.classfile.Annotation.Array_element_value; -import com.sun.tools.classfile.Annotation.Class_element_value; -import com.sun.tools.classfile.Annotation.Enum_element_value; -import com.sun.tools.classfile.Annotation.Primitive_element_value; -import com.sun.tools.classfile.Annotation.element_value; -import com.sun.tools.classfile.Annotation.element_value_pair; -import com.sun.tools.classfile.AnnotationDefault_attribute; -import com.sun.tools.classfile.Attribute; -import com.sun.tools.classfile.Attributes; -import com.sun.tools.classfile.ClassFile; -import com.sun.tools.classfile.ClassWriter; -import com.sun.tools.classfile.ConstantPool; -import com.sun.tools.classfile.ConstantPool.CONSTANT_Class_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_Double_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_Float_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_Integer_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_Long_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_Module_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_Package_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_String_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_Utf8_info; -import com.sun.tools.classfile.ConstantPool.CPInfo; -import com.sun.tools.classfile.ConstantPool.InvalidIndex; -import com.sun.tools.classfile.ConstantPoolException; -import com.sun.tools.classfile.ConstantValue_attribute; -import com.sun.tools.classfile.Deprecated_attribute; -import com.sun.tools.classfile.Descriptor; -import com.sun.tools.classfile.Exceptions_attribute; -import com.sun.tools.classfile.Field; -import com.sun.tools.classfile.InnerClasses_attribute; -import com.sun.tools.classfile.InnerClasses_attribute.Info; -import com.sun.tools.classfile.Method; -import com.sun.tools.classfile.ModuleResolution_attribute; -import com.sun.tools.classfile.ModuleTarget_attribute; -import com.sun.tools.classfile.Module_attribute; -import com.sun.tools.classfile.Module_attribute.ExportsEntry; -import com.sun.tools.classfile.Module_attribute.OpensEntry; -import com.sun.tools.classfile.Module_attribute.ProvidesEntry; -import com.sun.tools.classfile.Module_attribute.RequiresEntry; -import com.sun.tools.classfile.NestHost_attribute; -import com.sun.tools.classfile.NestMembers_attribute; -import com.sun.tools.classfile.RuntimeAnnotations_attribute; -import com.sun.tools.classfile.RuntimeInvisibleAnnotations_attribute; -import com.sun.tools.classfile.RuntimeInvisibleParameterAnnotations_attribute; -import com.sun.tools.classfile.RuntimeParameterAnnotations_attribute; -import com.sun.tools.classfile.RuntimeVisibleAnnotations_attribute; -import com.sun.tools.classfile.RuntimeVisibleParameterAnnotations_attribute; -import com.sun.tools.classfile.Signature_attribute; -import com.sun.tools.javac.api.JavacTool; -import com.sun.tools.javac.jvm.Target; -import com.sun.tools.javac.util.Assert; -import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.Pair; - -/** - * A tool for processing the .sym.txt files. - * - * To add historical data for JDK N, N >= 11, do the following: - * * cd /make/data/symbols - * * /bin/java --add-exports jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED \ - * --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ - * --add-exports jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED \ - * --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \ - * --add-modules jdk.jdeps \ - * ../../../make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java \ - * build-description-incremental symbols include.list - * * sanity-check the new and updates files in make/data/symbols and commit them - * - * The tools allows to: - * * convert the .sym.txt into class/sig files for ct.sym - * * in cooperation with the adjacent history Probe, construct .sym.txt files for previous platforms - * * enhance existing .sym.txt files with a a new set .sym.txt for the current platform - * - * To convert the .sym.txt files to class/sig files from ct.sym, run: - * java build.tool.symbolgenerator.CreateSymbols build-ctsym - * - * The is a file of this format: - * generate platforms - * platform version files <.sym.txt files containing history data for given platform, separate with ':'> - * platform version base files <.sym.txt files containing history data for given platform, separate with ':'> - * - * The content of platform "" is also automatically added to the content of - * platform "", unless explicitly excluded in ""'s .sym.txt files. - * - * To create the .sym.txt files, first run the history Probe for all the previous platforms: - * /bin/java build.tools.symbolgenerator.Probe - * - * Where is a name of a file into which the classes from the bootclasspath of - * will be written. - * - * Then create the file and the .sym.txt files like this: - * java build.tools.symbolgenerator.CreateSymbols build-description - * "" - * - * - * ... - * - * The is a file that specifies classes that should be included/excluded. - * Lines that start with '+' represent class or package that should be included, '-' class or package - * that should be excluded. '/' should be used as package name delimiter, packages should end with '/'. - * Several include list files may be specified, separated by File.pathSeparator. - * - * When is specified, the .sym.txt files for platform N will only contain - * differences between platform N and the specified platform. The first platform (denoted F further) - * that is specified should use literal value "", to have all the APIs of the platform written to - * the .sym.txt files. If there is an existing platform with full .sym.txt files in the repository, - * that platform should be used as the first platform to avoid unnecessary changes to the .sym.txt - * files. The for platform N should be determined as follows: if N < F, then - * should be N + 1. If F < N, then should be N - 1. - * If N is a custom/specialized sub-version of another platform N', then should be N'. - * - * To generate the .sym.txt files for OpenJDK 7 and 8: - * /bin/java build.tools.symbolgenerator.Probe OpenJDK7.classes - * /bin/java build.tools.symbolgenerator.Probe OpenJDK8.classes - * java build.tools.symbolgenerator.CreateSymbols build-description make/data/symbols $TOPDIR make/data/symbols/include.list - * 8 OpenJDK8.classes '' - * 7 OpenJDK7.classes 8 - * - * Note: the versions are expected to be a single character. - * - */ -public class CreateSymbols { - - // - /**Create sig files for ct.sym reading the classes description from the directory that contains - * {@code ctDescriptionFile}, using the file as a recipe to create the sigfiles. - */ - @SuppressWarnings("unchecked") - public void createSymbols(String ctDescriptionFileExtra, String ctDescriptionFile, String ctSymLocation) throws IOException { - LoadDescriptions data = load(ctDescriptionFileExtra != null ? Paths.get(ctDescriptionFileExtra) - : null, - Paths.get(ctDescriptionFile), null); - - splitHeaders(data.classes); - - Map> package2Version2Module = new HashMap<>(); - - for (ModuleDescription md : data.modules.values()) { - for (ModuleHeaderDescription mhd : md.header) { - List versionsList = - Collections.singletonList(mhd.versions); - writeModulesForVersions(ctSymLocation, - md, - mhd, - versionsList); - mhd.exports.stream().forEach(pkg -> { - for (char v : mhd.versions.toCharArray()) { - package2Version2Module.computeIfAbsent(pkg, dummy -> new HashMap<>()).put(v, md.name); - } - }); - } - } - - for (ClassDescription classDescription : data.classes) { - Map version2Module = package2Version2Module.getOrDefault(classDescription.packge().replace('.', '/'), Collections.emptyMap()); - for (ClassHeaderDescription header : classDescription.header) { - Set jointVersions = new HashSet<>(); - jointVersions.add(header.versions); - limitJointVersion(jointVersions, classDescription.fields); - limitJointVersion(jointVersions, classDescription.methods); - Map module2Versions = new HashMap<>(); - for (char v : header.versions.toCharArray()) { - String module = version2Module.get(v); - if (module == null) { - if (v >= '9') { - throw new AssertionError("No module for " + classDescription.name + - " and version " + v); - } - module = version2Module.get('9'); - if (module == null) { - module = "java.base"; - } - } - module2Versions.computeIfAbsent(module, dummy -> new StringBuilder()).append(v); - } - for (Entry e : module2Versions.entrySet()) { - Set currentVersions = new HashSet<>(jointVersions); - limitJointVersion(currentVersions, e.getValue().toString()); - currentVersions = currentVersions.stream().filter(vers -> !disjoint(vers, e.getValue().toString())).collect(Collectors.toSet()); - writeClassesForVersions(ctSymLocation, classDescription, header, e.getKey(), currentVersions); - } - } - } - } - - public static String EXTENSION = ".sig"; - - LoadDescriptions load(Path ctDescriptionWithExtraContent, Path ctDescriptionOpen, String deletePlatform) throws IOException { - Map platforms = new LinkedHashMap<>(); - - if (ctDescriptionWithExtraContent != null && Files.isRegularFile(ctDescriptionWithExtraContent)) { - try (LineBasedReader reader = new LineBasedReader(ctDescriptionWithExtraContent)) { - while (reader.hasNext()) { - switch (reader.lineKey) { - case "generate": - //ignore - reader.moveNext(); - break; - case "platform": - PlatformInput platform = PlatformInput.load(ctDescriptionWithExtraContent, - reader); - if (!platform.version.equals(deletePlatform)) - platforms.put(platform.version, platform); - reader.moveNext(); - break; - default: - throw new IllegalStateException("Unknown key: " + reader.lineKey); - } - } - } - } - - Set generatePlatforms = null; - - try (LineBasedReader reader = new LineBasedReader(ctDescriptionOpen)) { - while (reader.hasNext()) { - switch (reader.lineKey) { - case "generate": - String[] platformsAttr = reader.attributes.get("platforms").split(":"); - generatePlatforms = new HashSet<>(List.of(platformsAttr)); - generatePlatforms.remove(deletePlatform); - reader.moveNext(); - break; - case "platform": - PlatformInput platform = PlatformInput.load(ctDescriptionOpen, reader); - if (!platform.version.equals(deletePlatform) && - !platforms.containsKey(platform.version)) - platforms.put(platform.version, platform); - reader.moveNext(); - break; - default: - throw new IllegalStateException("Unknown key: " + reader.lineKey); - } - } - } - - Map classes = new LinkedHashMap<>(); - Map modules = new LinkedHashMap<>(); - - for (PlatformInput platform : platforms.values()) { - for (ClassDescription cd : classes.values()) { - addNewVersion(cd.header, platform.basePlatform, platform.version); - addNewVersion(cd.fields, platform.basePlatform, platform.version); - addNewVersion(cd.methods, platform.basePlatform, platform.version); - } - for (ModuleDescription md : modules.values()) { - addNewVersion(md.header, platform.basePlatform, platform.version); - } - for (String input : platform.files) { - Path inputFile = platform.ctDescription.getParent().resolve(input); - try (LineBasedReader reader = new LineBasedReader(inputFile)) { - while (reader.hasNext()) { - String nameAttr = reader.attributes.get("name"); - switch (reader.lineKey) { - case "class": case "-class": - ClassDescription cd = - classes.computeIfAbsent(nameAttr, - n -> new ClassDescription()); - if ("-class".equals(reader.lineKey)) { - removeVersion(cd.header, h -> true, - platform.version); - reader.moveNext(); - continue; - } - cd.read(reader, platform.basePlatform, - platform.version); - break; - case "module": { - ModuleDescription md = - modules.computeIfAbsent(nameAttr, - n -> new ModuleDescription()); - md.read(reader, platform.basePlatform, - platform.version); - break; - } - case "-module": { - ModuleDescription md = - modules.computeIfAbsent(nameAttr, - n -> new ModuleDescription()); - removeVersion(md.header, h -> true, - platform.version); - reader.moveNext(); - break; - } - } - } - } - } - } - - ClassList result = new ClassList(); - - for (ClassDescription desc : classes.values()) { - Iterator chdIt = desc.header.iterator(); - - while (chdIt.hasNext()) { - ClassHeaderDescription chd = chdIt.next(); - - chd.versions = reduce(chd.versions, generatePlatforms); - if (chd.versions.isEmpty()) - chdIt.remove(); - } - - if (desc.header.isEmpty()) { - continue; - } - - Iterator methodIt = desc.methods.iterator(); - - while (methodIt.hasNext()) { - MethodDescription method = methodIt.next(); - - method.versions = reduce(method.versions, generatePlatforms); - if (method.versions.isEmpty()) - methodIt.remove(); - } - - Iterator fieldIt = desc.fields.iterator(); - - while (fieldIt.hasNext()) { - FieldDescription field = fieldIt.next(); - - field.versions = reduce(field.versions, generatePlatforms); - if (field.versions.isEmpty()) - fieldIt.remove(); - } - - result.add(desc); - } - - Map moduleList = new HashMap<>(); - - for (ModuleDescription desc : modules.values()) { - Iterator mhdIt = desc.header.iterator(); - - while (mhdIt.hasNext()) { - ModuleHeaderDescription mhd = mhdIt.next(); - - mhd.versions = reduce(mhd.versions, generatePlatforms); - if (mhd.versions.isEmpty()) - mhdIt.remove(); - } - - if (desc.header.isEmpty()) { - continue; - } - - moduleList.put(desc.name, desc); - } - - return new LoadDescriptions(result, moduleList, new ArrayList<>(platforms.values())); - } - - static final class LoadDescriptions { - public final ClassList classes; - public final Map modules; - public final List versions; - - public LoadDescriptions(ClassList classes, - Map modules, - List versions) { - this.classes = classes; - this.modules = modules; - this.versions = versions; - } - - } - - static final class LineBasedReader implements AutoCloseable { - private final BufferedReader input; - public String lineKey; - public Map attributes = new HashMap<>(); - - public LineBasedReader(Path input) throws IOException { - this.input = Files.newBufferedReader(input); - moveNext(); - } - - public void moveNext() throws IOException { - String line = input.readLine(); - - if (line == null) { - lineKey = null; - return ; - } - - if (line.trim().isEmpty() || line.startsWith("#")) { - moveNext(); - return ; - } - - String[] parts = line.split(" "); - - lineKey = parts[0]; - attributes.clear(); - - for (int i = 1; i < parts.length; i += 2) { - attributes.put(parts[i], unquote(parts[i + 1])); - } - } - - public boolean hasNext() { - return lineKey != null; - } - - @Override - public void close() throws IOException { - input.close(); - } - } - - private static String reduce(String original, String other) { - Set otherSet = new HashSet<>(); - - for (char v : other.toCharArray()) { - otherSet.add("" + v); - } - - return reduce(original, otherSet); - } - - private static String reduce(String original, Set generate) { - StringBuilder sb = new StringBuilder(); - - for (char v : original.toCharArray()) { - if (generate.contains("" + v)) { - sb.append(v); - } - } - return sb.toString(); - } - - private static class PlatformInput { - public final String version; - public final String basePlatform; - public final List files; - public final Path ctDescription; - public PlatformInput(Path ctDescription, String version, String basePlatform, List files) { - this.ctDescription = ctDescription; - this.version = version; - this.basePlatform = basePlatform; - this.files = files; - } - - public static PlatformInput load(Path ctDescription, LineBasedReader in) throws IOException { - return new PlatformInput(ctDescription, - in.attributes.get("version"), - in.attributes.get("base"), - List.of(in.attributes.get("files").split(":"))); - } - } - - static void addNewVersion(Collection features, - String baselineVersion, - String version) { - features.stream() - .filter(f -> f.versions.contains(baselineVersion)) - .forEach(f -> f.versions += version); - } - - static void removeVersion(Collection features, - Predicate shouldRemove, - String version) { - for (T existing : features) { - if (shouldRemove.test(existing) && existing.versions.endsWith(version)) { - existing.versions = existing.versions.replace(version, ""); - return; - } - } - } - - /**Changes to class header of an outer class (like adding a new type parameter) may affect - * its innerclasses. So if the outer class's header is different for versions A and B, need to - * split its innerclasses headers to also be different for versions A and B. - */ - static void splitHeaders(ClassList classes) { - Set ctVersions = new HashSet<>(); - - for (ClassDescription cd : classes) { - for (ClassHeaderDescription header : cd.header) { - for (char c : header.versions.toCharArray()) { - ctVersions.add("" + c); - } - } - } - - classes.sort(); - - for (ClassDescription cd : classes) { - Map outerSignatures2Version = new HashMap<>(); - - for (String version : ctVersions) { //XXX - ClassDescription outer = cd; - String outerSignatures = ""; - - while ((outer = classes.enclosingClass(outer)) != null) { - for (ClassHeaderDescription outerHeader : outer.header) { - if (outerHeader.versions.contains(version)) { - outerSignatures += outerHeader.signature; - } - } - } - - outerSignatures2Version.compute(outerSignatures, - (key, value) -> value != null ? value + version : version); - } - - List newHeaders = new ArrayList<>(); - - HEADER_LOOP: for (ClassHeaderDescription header : cd.header) { - for (String versions : outerSignatures2Version.values()) { - if (containsAll(versions, header.versions)) { - newHeaders.add(header); - continue HEADER_LOOP; - } - if (disjoint(versions, header.versions)) { - continue; - } - ClassHeaderDescription newHeader = new ClassHeaderDescription(); - newHeader.classAnnotations = header.classAnnotations; - newHeader.deprecated = header.deprecated; - newHeader.extendsAttr = header.extendsAttr; - newHeader.flags = header.flags; - newHeader.implementsAttr = header.implementsAttr; - newHeader.innerClasses = header.innerClasses; - newHeader.runtimeAnnotations = header.runtimeAnnotations; - newHeader.signature = header.signature; - newHeader.versions = reduce(header.versions, versions); - - newHeaders.add(newHeader); - } - } - - cd.header = newHeaders; - } - } - - void limitJointVersion(Set jointVersions, List features) { - for (FeatureDescription feature : features) { - limitJointVersion(jointVersions, feature.versions); - } - } - - void limitJointVersion(Set jointVersions, String versions) { - for (String version : jointVersions) { - if (!containsAll(versions, version) && - !disjoint(versions, version)) { - StringBuilder featurePart = new StringBuilder(); - StringBuilder otherPart = new StringBuilder(); - for (char v : version.toCharArray()) { - if (versions.indexOf(v) != (-1)) { - featurePart.append(v); - } else { - otherPart.append(v); - } - } - jointVersions.remove(version); - if (featurePart.length() == 0 || otherPart.length() == 0) { - throw new AssertionError(); - } - jointVersions.add(featurePart.toString()); - jointVersions.add(otherPart.toString()); - break; - } - } - } - - private static boolean containsAll(String versions, String subVersions) { - for (char c : subVersions.toCharArray()) { - if (versions.indexOf(c) == (-1)) - return false; - } - return true; - } - - private static boolean disjoint(String version1, String version2) { - for (char c : version2.toCharArray()) { - if (version1.indexOf(c) != (-1)) - return false; - } - return true; - } - - void writeClassesForVersions(String ctSymLocation, - ClassDescription classDescription, - ClassHeaderDescription header, - String module, - Iterable versions) - throws IOException { - for (String ver : versions) { - writeClass(ctSymLocation, classDescription, header, module, ver); - } - } - - void writeModulesForVersions(String ctSymLocation, - ModuleDescription moduleDescription, - ModuleHeaderDescription header, - Iterable versions) - throws IOException { - for (String ver : versions) { - writeModule(ctSymLocation, moduleDescription, header, ver); - } - } - - // - void writeModule(String ctSymLocation, - ModuleDescription moduleDescription, - ModuleHeaderDescription header, - String version) throws IOException { - List constantPool = new ArrayList<>(); - constantPool.add(null); - int currentClass = addClass(constantPool, "module-info"); - int superclass = 0; - int[] interfaces = new int[0]; - AccessFlags flags = new AccessFlags(header.flags); - Map attributesMap = new HashMap<>(); - addAttributes(moduleDescription, header, constantPool, attributesMap); - Attributes attributes = new Attributes(attributesMap); - CPInfo[] cpData = constantPool.toArray(new CPInfo[constantPool.size()]); - ConstantPool cp = new ConstantPool(cpData); - ClassFile classFile = new ClassFile(0xCAFEBABE, - Target.DEFAULT.minorVersion, - Target.DEFAULT.majorVersion, - cp, - flags, - currentClass, - superclass, - interfaces, - new Field[0], - new Method[0], - attributes); - - Path outputClassFile = Paths.get(ctSymLocation, - version, - moduleDescription.name, - "module-info" + EXTENSION); - - Files.createDirectories(outputClassFile.getParent()); - - try (OutputStream out = Files.newOutputStream(outputClassFile)) { - ClassWriter w = new ClassWriter(); - - w.write(classFile, out); - } - } - - void writeClass(String ctSymLocation, - ClassDescription classDescription, - ClassHeaderDescription header, - String module, - String version) throws IOException { - List constantPool = new ArrayList<>(); - constantPool.add(null); - List methods = new ArrayList<>(); - for (MethodDescription methDesc : classDescription.methods) { - if (disjoint(methDesc.versions, version)) - continue; - Descriptor descriptor = new Descriptor(addString(constantPool, methDesc.descriptor)); - //TODO: LinkedHashMap to avoid param annotations vs. Signature problem in javac's ClassReader: - Map attributesMap = new LinkedHashMap<>(); - addAttributes(methDesc, constantPool, attributesMap); - Attributes attributes = new Attributes(attributesMap); - AccessFlags flags = new AccessFlags(methDesc.flags); - int nameString = addString(constantPool, methDesc.name); - methods.add(new Method(flags, nameString, descriptor, attributes)); - } - List fields = new ArrayList<>(); - for (FieldDescription fieldDesc : classDescription.fields) { - if (disjoint(fieldDesc.versions, version)) - continue; - Descriptor descriptor = new Descriptor(addString(constantPool, fieldDesc.descriptor)); - Map attributesMap = new HashMap<>(); - addAttributes(fieldDesc, constantPool, attributesMap); - Attributes attributes = new Attributes(attributesMap); - AccessFlags flags = new AccessFlags(fieldDesc.flags); - int nameString = addString(constantPool, fieldDesc.name); - fields.add(new Field(flags, nameString, descriptor, attributes)); - } - int currentClass = addClass(constantPool, classDescription.name); - int superclass = header.extendsAttr != null ? addClass(constantPool, header.extendsAttr) : 0; - int[] interfaces = new int[header.implementsAttr.size()]; - int i = 0; - for (String intf : header.implementsAttr) { - interfaces[i++] = addClass(constantPool, intf); - } - AccessFlags flags = new AccessFlags(header.flags); - Map attributesMap = new HashMap<>(); - addAttributes(header, constantPool, attributesMap); - Attributes attributes = new Attributes(attributesMap); - ConstantPool cp = new ConstantPool(constantPool.toArray(new CPInfo[constantPool.size()])); - ClassFile classFile = new ClassFile(0xCAFEBABE, - Target.DEFAULT.minorVersion, - Target.DEFAULT.majorVersion, - cp, - flags, - currentClass, - superclass, - interfaces, - fields.toArray(new Field[0]), - methods.toArray(new Method[0]), - attributes); - - Path outputClassFile = Paths.get(ctSymLocation, version); - - if (module != null) { - outputClassFile = outputClassFile.resolve(module); - } - - outputClassFile = outputClassFile.resolve(classDescription.name + EXTENSION); - - Files.createDirectories(outputClassFile.getParent()); - - try (OutputStream out = Files.newOutputStream(outputClassFile)) { - ClassWriter w = new ClassWriter(); - - w.write(classFile, out); - } - } - - private void addAttributes(ModuleDescription md, - ModuleHeaderDescription header, - List cp, - Map attributes) { - addGenericAttributes(header, cp, attributes); - if (header.moduleResolution != null) { - int attrIdx = addString(cp, Attribute.ModuleResolution); - final ModuleResolution_attribute resIdx = - new ModuleResolution_attribute(attrIdx, - header.moduleResolution); - attributes.put(Attribute.ModuleResolution, resIdx); - } - if (header.moduleTarget != null) { - int attrIdx = addString(cp, Attribute.ModuleTarget); - int targetIdx = addString(cp, header.moduleTarget); - attributes.put(Attribute.ModuleTarget, - new ModuleTarget_attribute(attrIdx, targetIdx)); - } - int attrIdx = addString(cp, Attribute.Module); - attributes.put(Attribute.Module, - new Module_attribute(attrIdx, - addModuleName(cp, md.name), - 0, - 0, - header.requires - .stream() - .map(r -> createRequiresEntry(cp, r)) - .collect(Collectors.toList()) - .toArray(new RequiresEntry[0]), - header.exports - .stream() - .map(e -> createExportsEntry(cp, e)) - .collect(Collectors.toList()) - .toArray(new ExportsEntry[0]), - header.opens - .stream() - .map(e -> createOpensEntry(cp, e)) - .collect(Collectors.toList()) - .toArray(new OpensEntry[0]), - header.uses - .stream() - .mapToInt(u -> addClassName(cp, u)) - .toArray(), - header.provides - .stream() - .map(p -> createProvidesEntry(cp, p)) - .collect(Collectors.toList()) - .toArray(new ProvidesEntry[0]))); - addInnerClassesAttribute(header, cp, attributes); - } - - private static RequiresEntry createRequiresEntry(List cp, - RequiresDescription r) { - final int idx = addModuleName(cp, r.moduleName); - return new RequiresEntry(idx, - r.flags, - r.version != null - ? addInt(cp, r.version) - : 0); - } - - private static ExportsEntry createExportsEntry(List cp, - String e) { - return new ExportsEntry(addPackageName(cp, e), 0, new int[0]); - } - - private static OpensEntry createOpensEntry(List cp, String e) { - return new OpensEntry(addPackageName(cp, e), 0, new int[0]); - } - - private static ProvidesEntry createProvidesEntry(List cp, - ModuleHeaderDescription.ProvidesDescription p) { - final int idx = addClassName(cp, p.interfaceName); - return new ProvidesEntry(idx, p.implNames - .stream() - .mapToInt(i -> addClassName(cp, i)) - .toArray()); - } - - private void addAttributes(ClassHeaderDescription header, - List constantPool, Map attributes) { - addGenericAttributes(header, constantPool, attributes); - if (header.nestHost != null) { - int attributeString = addString(constantPool, Attribute.NestHost); - int nestHost = addClass(constantPool, header.nestHost); - attributes.put(Attribute.NestHost, - new NestHost_attribute(attributeString, nestHost)); - } - if (header.nestMembers != null && !header.nestMembers.isEmpty()) { - int attributeString = addString(constantPool, Attribute.NestMembers); - int[] nestMembers = new int[header.nestMembers.size()]; - int i = 0; - for (String intf : header.nestMembers) { - nestMembers[i++] = addClass(constantPool, intf); - } - attributes.put(Attribute.NestMembers, - new NestMembers_attribute(attributeString, nestMembers)); - } - addInnerClassesAttribute(header, constantPool, attributes); - } - - private void addInnerClassesAttribute(HeaderDescription header, - List constantPool, Map attributes) { - if (header.innerClasses != null && !header.innerClasses.isEmpty()) { - Info[] innerClasses = new Info[header.innerClasses.size()]; - int i = 0; - for (InnerClassInfo info : header.innerClasses) { - innerClasses[i++] = - new Info(info.innerClass == null ? 0 : addClass(constantPool, info.innerClass), - info.outerClass == null ? 0 : addClass(constantPool, info.outerClass), - info.innerClassName == null ? 0 : addString(constantPool, info.innerClassName), - new AccessFlags(info.innerClassFlags)); - } - int attributeString = addString(constantPool, Attribute.InnerClasses); - attributes.put(Attribute.InnerClasses, - new InnerClasses_attribute(attributeString, innerClasses)); - } - } - - private void addAttributes(MethodDescription desc, List constantPool, Map attributes) { - addGenericAttributes(desc, constantPool, attributes); - if (desc.thrownTypes != null) { - int[] exceptions = new int[desc.thrownTypes.size()]; - int i = 0; - for (String exc : desc.thrownTypes) { - exceptions[i++] = addClass(constantPool, exc); - } - int attributeString = addString(constantPool, Attribute.Exceptions); - attributes.put(Attribute.Exceptions, - new Exceptions_attribute(attributeString, exceptions)); - } - if (desc.annotationDefaultValue != null) { - int attributeString = addString(constantPool, Attribute.AnnotationDefault); - element_value attributeValue = createAttributeValue(constantPool, - desc.annotationDefaultValue); - attributes.put(Attribute.AnnotationDefault, - new AnnotationDefault_attribute(attributeString, attributeValue)); - } - if (desc.classParameterAnnotations != null && !desc.classParameterAnnotations.isEmpty()) { - int attributeString = - addString(constantPool, Attribute.RuntimeInvisibleParameterAnnotations); - Annotation[][] annotations = - createParameterAnnotations(constantPool, desc.classParameterAnnotations); - attributes.put(Attribute.RuntimeInvisibleParameterAnnotations, - new RuntimeInvisibleParameterAnnotations_attribute(attributeString, - annotations)); - } - if (desc.runtimeParameterAnnotations != null && !desc.runtimeParameterAnnotations.isEmpty()) { - int attributeString = - addString(constantPool, Attribute.RuntimeVisibleParameterAnnotations); - Annotation[][] annotations = - createParameterAnnotations(constantPool, desc.runtimeParameterAnnotations); - attributes.put(Attribute.RuntimeVisibleParameterAnnotations, - new RuntimeVisibleParameterAnnotations_attribute(attributeString, - annotations)); - } - } - - private void addAttributes(FieldDescription desc, List constantPool, Map attributes) { - addGenericAttributes(desc, constantPool, attributes); - if (desc.constantValue != null) { - Pair constantPoolEntry = - addConstant(constantPool, desc.constantValue, false); - Assert.checkNonNull(constantPoolEntry); - int constantValueString = addString(constantPool, Attribute.ConstantValue); - attributes.put(Attribute.ConstantValue, - new ConstantValue_attribute(constantValueString, constantPoolEntry.fst)); - } - } - - private void addGenericAttributes(FeatureDescription desc, List constantPool, Map attributes) { - if (desc.deprecated) { - int attributeString = addString(constantPool, Attribute.Deprecated); - attributes.put(Attribute.Deprecated, - new Deprecated_attribute(attributeString)); - } - if (desc.signature != null) { - int attributeString = addString(constantPool, Attribute.Signature); - int signatureString = addString(constantPool, desc.signature); - attributes.put(Attribute.Signature, - new Signature_attribute(attributeString, signatureString)); - } - if (desc.classAnnotations != null && !desc.classAnnotations.isEmpty()) { - int attributeString = addString(constantPool, Attribute.RuntimeInvisibleAnnotations); - Annotation[] annotations = createAnnotations(constantPool, desc.classAnnotations); - attributes.put(Attribute.RuntimeInvisibleAnnotations, - new RuntimeInvisibleAnnotations_attribute(attributeString, annotations)); - } - if (desc.runtimeAnnotations != null && !desc.runtimeAnnotations.isEmpty()) { - int attributeString = addString(constantPool, Attribute.RuntimeVisibleAnnotations); - Annotation[] annotations = createAnnotations(constantPool, desc.runtimeAnnotations); - attributes.put(Attribute.RuntimeVisibleAnnotations, - new RuntimeVisibleAnnotations_attribute(attributeString, annotations)); - } - } - - private Annotation[] createAnnotations(List constantPool, List desc) { - Annotation[] result = new Annotation[desc.size()]; - int i = 0; - - for (AnnotationDescription ad : desc) { - result[i++] = createAnnotation(constantPool, ad); - } - - return result; - } - - private Annotation[][] createParameterAnnotations(List constantPool, List> desc) { - Annotation[][] result = new Annotation[desc.size()][]; - int i = 0; - - for (List paramAnnos : desc) { - result[i++] = createAnnotations(constantPool, paramAnnos); - } - - return result; - } - - private Annotation createAnnotation(List constantPool, AnnotationDescription desc) { - return new Annotation(null, - addString(constantPool, desc.annotationType), - createElementPairs(constantPool, desc.values)); - } - - private element_value_pair[] createElementPairs(List constantPool, Map annotationAttributes) { - element_value_pair[] pairs = new element_value_pair[annotationAttributes.size()]; - int i = 0; - - for (Entry e : annotationAttributes.entrySet()) { - int elementNameString = addString(constantPool, e.getKey()); - element_value value = createAttributeValue(constantPool, e.getValue()); - pairs[i++] = new element_value_pair(elementNameString, value); - } - - return pairs; - } - - private element_value createAttributeValue(List constantPool, Object value) { - Pair constantPoolEntry = addConstant(constantPool, value, true); - if (constantPoolEntry != null) { - return new Primitive_element_value(constantPoolEntry.fst, constantPoolEntry.snd); - } else if (value instanceof EnumConstant) { - EnumConstant ec = (EnumConstant) value; - return new Enum_element_value(addString(constantPool, ec.type), - addString(constantPool, ec.constant), - 'e'); - } else if (value instanceof ClassConstant) { - ClassConstant cc = (ClassConstant) value; - return new Class_element_value(addString(constantPool, cc.type), 'c'); - } else if (value instanceof AnnotationDescription) { - Annotation annotation = createAnnotation(constantPool, ((AnnotationDescription) value)); - return new Annotation_element_value(annotation, '@'); - } else if (value instanceof Collection) { - @SuppressWarnings("unchecked") - Collection array = (Collection) value; - element_value[] values = new element_value[array.size()]; - int i = 0; - - for (Object elem : array) { - values[i++] = createAttributeValue(constantPool, elem); - } - - return new Array_element_value(values, '['); - } - throw new IllegalStateException(value.getClass().getName()); - } - - private static Pair addConstant(List constantPool, Object value, boolean annotation) { - if (value instanceof Boolean) { - return Pair.of(addToCP(constantPool, new CONSTANT_Integer_info(((Boolean) value) ? 1 : 0)), 'Z'); - } else if (value instanceof Byte) { - return Pair.of(addToCP(constantPool, new CONSTANT_Integer_info((byte) value)), 'B'); - } else if (value instanceof Character) { - return Pair.of(addToCP(constantPool, new CONSTANT_Integer_info((char) value)), 'C'); - } else if (value instanceof Short) { - return Pair.of(addToCP(constantPool, new CONSTANT_Integer_info((short) value)), 'S'); - } else if (value instanceof Integer) { - return Pair.of(addToCP(constantPool, new CONSTANT_Integer_info((int) value)), 'I'); - } else if (value instanceof Long) { - return Pair.of(addToCP(constantPool, new CONSTANT_Long_info((long) value)), 'J'); - } else if (value instanceof Float) { - return Pair.of(addToCP(constantPool, new CONSTANT_Float_info((float) value)), 'F'); - } else if (value instanceof Double) { - return Pair.of(addToCP(constantPool, new CONSTANT_Double_info((double) value)), 'D'); - } else if (value instanceof String) { - int stringIndex = addString(constantPool, (String) value); - if (annotation) { - return Pair.of(stringIndex, 's'); - } else { - return Pair.of(addToCP(constantPool, new CONSTANT_String_info(null, stringIndex)), 's'); - } - } - - return null; - } - - private static int addString(List constantPool, String string) { - Assert.checkNonNull(string); - - int i = 0; - for (CPInfo info : constantPool) { - if (info instanceof CONSTANT_Utf8_info) { - if (((CONSTANT_Utf8_info) info).value.equals(string)) { - return i; - } - } - i++; - } - - return addToCP(constantPool, new CONSTANT_Utf8_info(string)); - } - - private static int addInt(List constantPool, int value) { - int i = 0; - for (CPInfo info : constantPool) { - if (info instanceof CONSTANT_Integer_info) { - if (((CONSTANT_Integer_info) info).value == value) { - return i; - } - } - i++; - } - - return addToCP(constantPool, new CONSTANT_Integer_info(value)); - } - - private static int addModuleName(List constantPool, String moduleName) { - int nameIdx = addString(constantPool, moduleName); - int i = 0; - for (CPInfo info : constantPool) { - if (info instanceof CONSTANT_Module_info) { - if (((CONSTANT_Module_info) info).name_index == nameIdx) { - return i; - } - } - i++; - } - - return addToCP(constantPool, new CONSTANT_Module_info(null, nameIdx)); - } - - private static int addPackageName(List constantPool, String packageName) { - int nameIdx = addString(constantPool, packageName); - int i = 0; - for (CPInfo info : constantPool) { - if (info instanceof CONSTANT_Package_info) { - if (((CONSTANT_Package_info) info).name_index == nameIdx) { - return i; - } - } - i++; - } - - return addToCP(constantPool, new CONSTANT_Package_info(null, nameIdx)); - } - - private static int addClassName(List constantPool, String className) { - int nameIdx = addString(constantPool, className); - int i = 0; - for (CPInfo info : constantPool) { - if (info instanceof CONSTANT_Class_info) { - if (((CONSTANT_Class_info) info).name_index == nameIdx) { - return i; - } - } - i++; - } - - return addToCP(constantPool, new CONSTANT_Class_info(null, nameIdx)); - } - - private static int addToCP(List constantPool, CPInfo entry) { - int result = constantPool.size(); - - constantPool.add(entry); - - if (entry.size() > 1) { - constantPool.add(null); - } - - return result; - } - - private static int addClass(List constantPool, String className) { - int classNameIndex = addString(constantPool, className); - - int i = 0; - for (CPInfo info : constantPool) { - if (info instanceof CONSTANT_Class_info) { - if (((CONSTANT_Class_info) info).name_index == classNameIndex) { - return i; - } - } - i++; - } - - return addToCP(constantPool, new CONSTANT_Class_info(null, classNameIndex)); - } - // - // - - // - public void createBaseLine(List versions, - ExcludeIncludeList excludesIncludes, - Path descDest, - String[] args) throws IOException { - ClassList classes = new ClassList(); - Map modules = new HashMap<>(); - - for (VersionDescription desc : versions) { - List classFileData = new ArrayList<>(); - - try (BufferedReader descIn = - Files.newBufferedReader(Paths.get(desc.classes))) { - String line; - while ((line = descIn.readLine()) != null) { - ByteArrayOutputStream data = new ByteArrayOutputStream(); - for (int i = 0; i < line.length(); i += 2) { - String hex = line.substring(i, i + 2); - data.write(Integer.parseInt(hex, 16)); - } - classFileData.add(data.toByteArray()); - } - } catch (IOException ex) { - throw new IllegalStateException(ex); - } - - loadVersionClasses(classes, modules, classFileData, excludesIncludes, desc.version); - } - - List platforms = - versions.stream() - .map(desc -> new PlatformInput(null, - desc.version, - desc.primaryBaseline, - null)) - .collect(Collectors.toList()); - - dumpDescriptions(classes, modules, platforms, descDest.resolve("symbols"), args); - } - //where: - private static final String DO_NO_MODIFY = - "#\n" + - "# Copyright (c) {YEAR}, Oracle and/or its affiliates. All rights reserved.\n" + - "# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n" + - "#\n" + - "# This code is free software; you can redistribute it and/or modify it\n" + - "# under the terms of the GNU General Public License version 2 only, as\n" + - "# published by the Free Software Foundation. Oracle designates this\n" + - "# particular file as subject to the \"Classpath\" exception as provided\n" + - "# by Oracle in the LICENSE file that accompanied this code.\n" + - "#\n" + - "# This code is distributed in the hope that it will be useful, but WITHOUT\n" + - "# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n" + - "# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\n" + - "# version 2 for more details (a copy is included in the LICENSE file that\n" + - "# accompanied this code).\n" + - "#\n" + - "# You should have received a copy of the GNU General Public License version\n" + - "# 2 along with this work; if not, write to the Free Software Foundation,\n" + - "# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n" + - "#\n" + - "# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n" + - "# or visit www.oracle.com if you need additional information or have any\n" + - "# questions.\n" + - "#\n" + - "# ##########################################################\n" + - "# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ###\n" + - "# ##########################################################\n" + - "#\n"; - - private void loadVersionClasses(ClassList classes, - Map modules, - Iterable classData, - ExcludeIncludeList excludesIncludes, - String version) { - Map currentVersionModules = - new HashMap<>(); - - for (byte[] classFileData : classData) { - try (InputStream in = new ByteArrayInputStream(classFileData)) { - inspectModuleInfoClassFile(in, - currentVersionModules, version); - } catch (IOException | ConstantPoolException ex) { - throw new IllegalStateException(ex); - } - } - - ExcludeIncludeList currentEIList = excludesIncludes; - - if (!currentVersionModules.isEmpty()) { - Set includes = new HashSet<>(); - - for (ModuleDescription md : currentVersionModules.values()) { - md.header.get(0).exports.stream().map(e -> e + '/') - .forEach(includes::add); - } - - currentEIList = new ExcludeIncludeList(includes, - Collections.emptySet()); - } - - ClassList currentVersionClasses = new ClassList(); - - for (byte[] classFileData : classData) { - try (InputStream in = new ByteArrayInputStream(classFileData)) { - inspectClassFile(in, currentVersionClasses, - currentEIList, version); - } catch (IOException | ConstantPoolException ex) { - throw new IllegalStateException(ex); - } - } - - ModuleDescription unsupported = - currentVersionModules.get("jdk.unsupported"); - - if (unsupported != null) { - for (ClassDescription cd : currentVersionClasses.classes) { - if (unsupported.header - .get(0) - .exports - .contains(cd.packge().replace('.', '/'))) { - ClassHeaderDescription ch = cd.header.get(0); - if (ch.classAnnotations == null) { - ch.classAnnotations = new ArrayList<>(); - } - AnnotationDescription ad; - ad = new AnnotationDescription(PROPERITARY_ANNOTATION, - Collections.emptyMap()); - ch.classAnnotations.add(ad); - } - } - } - - Set includedClasses = new HashSet<>(); - boolean modified; - - do { - modified = false; - - for (ClassDescription clazz : currentVersionClasses) { - ClassHeaderDescription header = clazz.header.get(0); - - if (includeEffectiveAccess(currentVersionClasses, clazz)) { - modified |= include(includedClasses, currentVersionClasses, clazz.name); - } - - if (includedClasses.contains(clazz.name)) { - modified |= include(includedClasses, currentVersionClasses, header.extendsAttr); - for (String i : header.implementsAttr) { - modified |= include(includedClasses, currentVersionClasses, i); - } - - modified |= includeOutputType(Collections.singleton(header), - h -> "", - includedClasses, - currentVersionClasses); - modified |= includeOutputType(clazz.fields, - f -> f.descriptor, - includedClasses, - currentVersionClasses); - modified |= includeOutputType(clazz.methods, - m -> m.descriptor, - includedClasses, - currentVersionClasses); - } - } - } while (modified); - - for (ClassDescription clazz : currentVersionClasses) { - if (!includedClasses.contains(clazz.name)) { - continue; - } - - ClassHeaderDescription header = clazz.header.get(0); - - if (header.nestMembers != null) { - Iterator nestMemberIt = header.nestMembers.iterator(); - - while(nestMemberIt.hasNext()) { - String member = nestMemberIt.next(); - if (!includedClasses.contains(member)) - nestMemberIt.remove(); - } - } - - if (header.innerClasses != null) { - Iterator innerClassIt = header.innerClasses.iterator(); - - while(innerClassIt.hasNext()) { - InnerClassInfo ici = innerClassIt.next(); - if (!includedClasses.contains(ici.innerClass)) - innerClassIt.remove(); - } - } - - ClassDescription existing = classes.find(clazz.name, true); - - if (existing != null) { - addClassHeader(existing, header, version); - for (MethodDescription currentMethod : clazz.methods) { - addMethod(existing, currentMethod, version); - } - for (FieldDescription currentField : clazz.fields) { - addField(existing, currentField, version); - } - } else { - classes.add(clazz); - } - } - - for (ModuleDescription module : currentVersionModules.values()) { - ModuleHeaderDescription header = module.header.get(0); - - if (header.innerClasses != null) { - Iterator innerClassIt = - header.innerClasses.iterator(); - - while(innerClassIt.hasNext()) { - InnerClassInfo ici = innerClassIt.next(); - if (!includedClasses.contains(ici.innerClass)) - innerClassIt.remove(); - } - } - - ModuleDescription existing = modules.get(module.name); - - if (existing != null) { - addModuleHeader(existing, header, version); - } else { - modules.put(module.name, module); - } - } - } - //where: - private static final String PROPERITARY_ANNOTATION = - "Lsun/Proprietary+Annotation;"; - - private void dumpDescriptions(ClassList classes, - Map modules, - List versions, - Path ctDescriptionFile, - String[] args) throws IOException { - classes.sort(); - - Map package2Modules = new HashMap<>(); - - versions.stream() - .filter(v -> "9".compareTo(v.version) <= 0) - .sorted((v1, v2) -> v1.version.compareTo(v2.version)) - .forEach(v -> { - for (ModuleDescription md : modules.values()) { - md.header - .stream() - .filter(h -> h.versions.contains(v.version)) - .flatMap(h -> h.exports.stream()) - .map(p -> p.replace('/', '.')) - .forEach(p -> package2Modules.putIfAbsent(p, md.name)); - } - }); - - package2Modules.put("java.awt.dnd.peer", "java.desktop"); - package2Modules.put("java.awt.peer", "java.desktop"); - package2Modules.put("jdk", "java.base"); - - Map> module2Classes = new HashMap<>(); - - for (ClassDescription clazz : classes) { - String pack = clazz.packge(); - String module = package2Modules.get(pack); - - if (module == null) { - module = "java.base"; - - OUTER: while (!pack.isEmpty()) { - for (Entry p2M : package2Modules.entrySet()) { - if (p2M.getKey().startsWith(pack)) { - module = p2M.getValue(); - break OUTER; - } - } - int dot = pack.lastIndexOf('.'); - if (dot == (-1)) - break; - pack = pack.substring(0, dot); - } - } - module2Classes.computeIfAbsent(module, m -> new ArrayList<>()) - .add(clazz); - } - - modules.keySet() - .stream() - .filter(m -> !module2Classes.containsKey(m)) - .forEach(m -> module2Classes.put(m, Collections.emptyList())); - - Files.createDirectories(ctDescriptionFile.getParent()); - - int year = Calendar.getInstance(TimeZone.getTimeZone("UTF"), Locale.ROOT) - .get(Calendar.YEAR); - - try (Writer symbolsOut = Files.newBufferedWriter(ctDescriptionFile)) { - Map> outputFiles = new LinkedHashMap<>(); - - for (PlatformInput desc : versions) { - List files = desc.files; - - if (files == null) { - files = new ArrayList<>(); - for (Entry> e : module2Classes.entrySet()) { - StringWriter data = new StringWriter(); - ModuleDescription module = modules.get(e.getKey()); - - module.write(data, desc.basePlatform, desc.version); - - for (ClassDescription clazz : e.getValue()) { - clazz.write(data, desc.basePlatform, desc.version); - } - - String fileName = e.getKey() + "-" + desc.version + ".sym.txt"; - Path f = ctDescriptionFile.getParent().resolve(fileName); - - String dataString = data.toString(); - - if (!dataString.isEmpty()) { - try (Writer out = Files.newBufferedWriter(f)) { - out.append(DO_NO_MODIFY.replace("{YEAR}", String.valueOf(year))); - out.write(dataString); - } - files.add(f.getFileName().toString()); - } - } - } - - outputFiles.put(desc, files); - } - symbolsOut.append(DO_NO_MODIFY.replace("{YEAR}", "2015, " + year)); - symbolsOut.append("#command used to generate this file:\n"); - symbolsOut.append("#") - .append(CreateSymbols.class.getName()) - .append(" ") - .append(Arrays.stream(args) - .collect(Collectors.joining(" "))) - .append("\n"); - symbolsOut.append("#\n"); - symbolsOut.append("generate platforms ") - .append(versions.stream() - .map(v -> v.version) - .sorted() - .collect(Collectors.joining(":"))) - .append("\n"); - for (Entry> versionFileEntry : outputFiles.entrySet()) { - symbolsOut.append("platform version ") - .append(versionFileEntry.getKey().version); - if (versionFileEntry.getKey().basePlatform != null) { - symbolsOut.append(" base ") - .append(versionFileEntry.getKey().basePlatform); - } - symbolsOut.append(" files ") - .append(versionFileEntry.getValue() - .stream() - .map(p -> p) - .sorted() - .collect(Collectors.joining(":"))) - .append("\n"); - } - } - } - - public void createIncrementalBaseLine(String ctDescriptionFile, - String excludeFile, - String[] args) throws IOException { - String specVersion = System.getProperty("java.specification.version"); - String currentVersion = - Integer.toString(Integer.parseInt(specVersion), Character.MAX_RADIX); - currentVersion = currentVersion.toUpperCase(Locale.ROOT); - Path ctDescriptionPath = Paths.get(ctDescriptionFile).toAbsolutePath(); - LoadDescriptions data = load(null, ctDescriptionPath, currentVersion); - - ClassList classes = data.classes; - Map modules = data.modules; - List versions = data.versions; - - ExcludeIncludeList excludeList = - ExcludeIncludeList.create(excludeFile); - - Iterable classBytes = dumpCurrentClasses(); - loadVersionClasses(classes, modules, classBytes, excludeList, currentVersion); - - String baseline; - - if (versions.isEmpty()) { - baseline = null; - } else { - baseline = versions.stream() - .sorted((v1, v2) -> v2.version.compareTo(v1.version)) - .findFirst() - .get() - .version; - } - - versions.add(new PlatformInput(null, currentVersion, baseline, null)); - dumpDescriptions(classes, modules, versions, ctDescriptionPath, args); - } - - private List dumpCurrentClasses() throws IOException { - JavacTool tool = JavacTool.create(); - Context ctx = new Context(); - String version = System.getProperty("java.specification.version"); - JavacTask task = tool.getTask(null, null, null, - List.of("--release", version), - null, null, ctx); - task.getElements().getTypeElement("java.lang.Object"); - JavaFileManager fm = ctx.get(JavaFileManager.class); - - List data = new ArrayList<>(); - for (Location modLoc : LOCATIONS) { - for (Set module : - fm.listLocationsForModules(modLoc)) { - for (JavaFileManager.Location loc : module) { - Iterable files = - fm.list(loc, - "", - EnumSet.of(Kind.CLASS), - true); - - for (JavaFileObject jfo : files) { - try (InputStream is = jfo.openInputStream(); - InputStream in = - new BufferedInputStream(is)) { - ByteArrayOutputStream baos = - new ByteArrayOutputStream(); - - in.transferTo(baos); - data.add(baos.toByteArray()); - } - } - } - } - } - - return data; - } - //where: - private static final List LOCATIONS = - List.of(StandardLocation.SYSTEM_MODULES, - StandardLocation.UPGRADE_MODULE_PATH); - - // - //non-final for tests: - public static String PROFILE_ANNOTATION = "Ljdk/Profile+Annotation;"; - public static boolean ALLOW_NON_EXISTING_CLASSES = false; - - private void inspectClassFile(InputStream in, ClassList classes, ExcludeIncludeList excludesIncludes, String version) throws IOException, ConstantPoolException { - ClassFile cf = ClassFile.read(in); - - if (cf.access_flags.is(AccessFlags.ACC_MODULE)) { - return ; - } - - if (!excludesIncludes.accepts(cf.getName())) { - return ; - } - - ClassHeaderDescription headerDesc = new ClassHeaderDescription(); - - headerDesc.flags = cf.access_flags.flags; - - if (cf.super_class != 0) { - headerDesc.extendsAttr = cf.getSuperclassName(); - } - List interfaces = new ArrayList<>(); - for (int i = 0; i < cf.interfaces.length; i++) { - interfaces.add(cf.getInterfaceName(i)); - } - headerDesc.implementsAttr = interfaces; - for (Attribute attr : cf.attributes) { - if (!readAttribute(cf, headerDesc, attr)) - return ; - } - - ClassDescription clazzDesc = null; - - for (ClassDescription cd : classes) { - if (cd.name.equals(cf.getName())) { - clazzDesc = cd; - break; - } - } - - if (clazzDesc == null) { - clazzDesc = new ClassDescription(); - clazzDesc.name = cf.getName(); - classes.add(clazzDesc); - } - - addClassHeader(clazzDesc, headerDesc, version); - - for (Method m : cf.methods) { - if (!include(m.access_flags.flags)) - continue; - MethodDescription methDesc = new MethodDescription(); - methDesc.flags = m.access_flags.flags; - methDesc.name = m.getName(cf.constant_pool); - methDesc.descriptor = m.descriptor.getValue(cf.constant_pool); - for (Attribute attr : m.attributes) { - readAttribute(cf, methDesc, attr); - } - addMethod(clazzDesc, methDesc, version); - } - for (Field f : cf.fields) { - if (!include(f.access_flags.flags)) - continue; - FieldDescription fieldDesc = new FieldDescription(); - fieldDesc.flags = f.access_flags.flags; - fieldDesc.name = f.getName(cf.constant_pool); - fieldDesc.descriptor = f.descriptor.getValue(cf.constant_pool); - for (Attribute attr : f.attributes) { - readAttribute(cf, fieldDesc, attr); - } - addField(clazzDesc, fieldDesc, version); - } - } - - private void inspectModuleInfoClassFile(InputStream in, - Map modules, - String version) throws IOException, ConstantPoolException { - ClassFile cf = ClassFile.read(in); - - if (!cf.access_flags.is(AccessFlags.ACC_MODULE)) { - return ; - } - - ModuleHeaderDescription headerDesc = new ModuleHeaderDescription(); - - headerDesc.versions = version; - headerDesc.flags = cf.access_flags.flags; - - for (Attribute attr : cf.attributes) { - if (!readAttribute(cf, headerDesc, attr)) - return ; - } - - String name = headerDesc.name; - - ModuleDescription moduleDesc = modules.get(name); - - if (moduleDesc == null) { - moduleDesc = new ModuleDescription(); - moduleDesc.name = name; - modules.put(moduleDesc.name, moduleDesc); - } - - addModuleHeader(moduleDesc, headerDesc, version); - } - - private void addModuleHeader(ModuleDescription moduleDesc, - ModuleHeaderDescription headerDesc, - String version) { - //normalize: - boolean existed = false; - for (ModuleHeaderDescription existing : moduleDesc.header) { - if (existing.equals(headerDesc)) { - headerDesc = existing; - existed = true; - } - } - - headerDesc.versions += version; - - if (!existed) { - moduleDesc.header.add(headerDesc); - } - } - - private boolean include(int accessFlags) { - return (accessFlags & (AccessFlags.ACC_PUBLIC | AccessFlags.ACC_PROTECTED)) != 0; - } - - private void addClassHeader(ClassDescription clazzDesc, ClassHeaderDescription headerDesc, String version) { - //normalize: - boolean existed = false; - for (ClassHeaderDescription existing : clazzDesc.header) { - if (existing.equals(headerDesc)) { - headerDesc = existing; - existed = true; - } - } - - if (!existed) { - //check if the only difference between the 7 and 8 version is the Profile annotation - //if so, copy it to the pre-8 version, so save space - for (ClassHeaderDescription existing : clazzDesc.header) { - List annots = existing.classAnnotations; - - if (annots != null) { - for (AnnotationDescription ad : annots) { - if (PROFILE_ANNOTATION.equals(ad.annotationType)) { - existing.classAnnotations = new ArrayList<>(annots); - existing.classAnnotations.remove(ad); - if (existing.equals(headerDesc)) { - headerDesc = existing; - existed = true; - } - existing.classAnnotations = annots; - break; - } - } - } - } - } - - headerDesc.versions += version; - - if (!existed) { - clazzDesc.header.add(headerDesc); - } - } - - private void addMethod(ClassDescription clazzDesc, MethodDescription methDesc, String version) { - //normalize: - boolean methodExisted = false; - for (MethodDescription existing : clazzDesc.methods) { - if (existing.equals(methDesc)) { - methodExisted = true; - methDesc = existing; - break; - } - } - methDesc.versions += version; - if (!methodExisted) { - clazzDesc.methods.add(methDesc); - } - } - - private void addField(ClassDescription clazzDesc, FieldDescription fieldDesc, String version) { - boolean fieldExisted = false; - for (FieldDescription existing : clazzDesc.fields) { - if (existing.equals(fieldDesc)) { - fieldExisted = true; - fieldDesc = existing; - break; - } - } - fieldDesc.versions += version; - if (!fieldExisted) { - clazzDesc.fields.add(fieldDesc); - } - } - - private boolean readAttribute(ClassFile cf, FeatureDescription feature, Attribute attr) throws ConstantPoolException { - String attrName = attr.getName(cf.constant_pool); - switch (attrName) { - case Attribute.AnnotationDefault: - assert feature instanceof MethodDescription; - element_value defaultValue = ((AnnotationDefault_attribute) attr).default_value; - ((MethodDescription) feature).annotationDefaultValue = - convertElementValue(cf.constant_pool, defaultValue); - break; - case "Deprecated": - feature.deprecated = true; - break; - case "Exceptions": - assert feature instanceof MethodDescription; - List thrownTypes = new ArrayList<>(); - Exceptions_attribute exceptionAttr = (Exceptions_attribute) attr; - for (int i = 0; i < exceptionAttr.exception_index_table.length; i++) { - thrownTypes.add(exceptionAttr.getException(i, cf.constant_pool)); - } - ((MethodDescription) feature).thrownTypes = thrownTypes; - break; - case Attribute.InnerClasses: - if (feature instanceof ModuleHeaderDescription) - break; //XXX - assert feature instanceof ClassHeaderDescription; - List innerClasses = new ArrayList<>(); - InnerClasses_attribute innerClassesAttr = (InnerClasses_attribute) attr; - for (int i = 0; i < innerClassesAttr.number_of_classes; i++) { - CONSTANT_Class_info outerClassInfo = - innerClassesAttr.classes[i].getOuterClassInfo(cf.constant_pool); - InnerClassInfo info = new InnerClassInfo(); - CONSTANT_Class_info innerClassInfo = - innerClassesAttr.classes[i].getInnerClassInfo(cf.constant_pool); - info.innerClass = innerClassInfo != null ? innerClassInfo.getName() : null; - info.outerClass = outerClassInfo != null ? outerClassInfo.getName() : null; - info.innerClassName = innerClassesAttr.classes[i].getInnerName(cf.constant_pool); - info.innerClassFlags = innerClassesAttr.classes[i].inner_class_access_flags.flags; - innerClasses.add(info); - } - ((ClassHeaderDescription) feature).innerClasses = innerClasses; - break; - case "RuntimeInvisibleAnnotations": - feature.classAnnotations = annotations2Description(cf.constant_pool, attr); - break; - case "RuntimeVisibleAnnotations": - feature.runtimeAnnotations = annotations2Description(cf.constant_pool, attr); - break; - case "Signature": - feature.signature = ((Signature_attribute) attr).getSignature(cf.constant_pool); - break; - case "ConstantValue": - assert feature instanceof FieldDescription; - Object value = convertConstantValue(cf.constant_pool.get(((ConstantValue_attribute) attr).constantvalue_index), ((FieldDescription) feature).descriptor); - if (((FieldDescription) feature).descriptor.equals("C")) { - value = (char) (int) value; - } - ((FieldDescription) feature).constantValue = value; - break; - case "SourceFile": - //ignore, not needed - break; - case "BootstrapMethods": - //ignore, not needed - break; - case "Code": - //ignore, not needed - break; - case "EnclosingMethod": - return false; - case "Synthetic": - break; - case "RuntimeVisibleParameterAnnotations": - assert feature instanceof MethodDescription; - ((MethodDescription) feature).runtimeParameterAnnotations = - parameterAnnotations2Description(cf.constant_pool, attr); - break; - case "RuntimeInvisibleParameterAnnotations": - assert feature instanceof MethodDescription; - ((MethodDescription) feature).classParameterAnnotations = - parameterAnnotations2Description(cf.constant_pool, attr); - break; - case Attribute.Module: { - assert feature instanceof ModuleHeaderDescription; - ModuleHeaderDescription header = - (ModuleHeaderDescription) feature; - Module_attribute mod = (Module_attribute) attr; - - header.name = cf.constant_pool - .getModuleInfo(mod.module_name) - .getName(); - - header.exports = - Arrays.stream(mod.exports) - .filter(ee -> ee.exports_to_count == 0) - .map(ee -> getPackageName(cf, ee.exports_index)) - .collect(Collectors.toList()); - header.requires = - Arrays.stream(mod.requires) - .map(r -> RequiresDescription.create(cf, r)) - .collect(Collectors.toList()); - header.uses = Arrays.stream(mod.uses_index) - .mapToObj(use -> getClassName(cf, use)) - .collect(Collectors.toList()); - header.provides = - Arrays.stream(mod.provides) - .map(p -> ProvidesDescription.create(cf, p)) - .collect(Collectors.toList()); - break; - } - case Attribute.ModuleTarget: { - assert feature instanceof ModuleHeaderDescription; - ModuleHeaderDescription header = - (ModuleHeaderDescription) feature; - ModuleTarget_attribute mod = (ModuleTarget_attribute) attr; - if (mod.target_platform_index != 0) { - header.moduleTarget = - cf.constant_pool - .getUTF8Value(mod.target_platform_index); - } - break; - } - case Attribute.ModuleResolution: { - assert feature instanceof ModuleHeaderDescription; - ModuleHeaderDescription header = - (ModuleHeaderDescription) feature; - ModuleResolution_attribute mod = - (ModuleResolution_attribute) attr; - header.moduleResolution = mod.resolution_flags; - break; - } - case Attribute.ModulePackages: - case Attribute.ModuleHashes: - break; - case Attribute.NestHost: { - assert feature instanceof ClassHeaderDescription; - NestHost_attribute nestHost = (NestHost_attribute) attr; - ClassHeaderDescription chd = (ClassHeaderDescription) feature; - chd.nestHost = nestHost.getNestTop(cf.constant_pool).getName(); - break; - } - case Attribute.NestMembers: { - assert feature instanceof ClassHeaderDescription; - NestMembers_attribute nestMembers = (NestMembers_attribute) attr; - ClassHeaderDescription chd = (ClassHeaderDescription) feature; - chd.nestMembers = Arrays.stream(nestMembers.members_indexes) - .mapToObj(i -> getClassName(cf, i)) - .collect(Collectors.toList()); - break; - } - default: - throw new IllegalStateException("Unhandled attribute: " + - attrName); - } - - return true; - } - - private static String getClassName(ClassFile cf, int idx) { - try { - return cf.constant_pool.getClassInfo(idx).getName(); - } catch (InvalidIndex ex) { - throw new IllegalStateException(ex); - } catch (ConstantPool.UnexpectedEntry ex) { - throw new IllegalStateException(ex); - } catch (ConstantPoolException ex) { - throw new IllegalStateException(ex); - } - } - - private static String getPackageName(ClassFile cf, int idx) { - try { - return cf.constant_pool.getPackageInfo(idx).getName(); - } catch (InvalidIndex ex) { - throw new IllegalStateException(ex); - } catch (ConstantPool.UnexpectedEntry ex) { - throw new IllegalStateException(ex); - } catch (ConstantPoolException ex) { - throw new IllegalStateException(ex); - } - } - - private static String getModuleName(ClassFile cf, int idx) { - try { - return cf.constant_pool.getModuleInfo(idx).getName(); - } catch (InvalidIndex ex) { - throw new IllegalStateException(ex); - } catch (ConstantPool.UnexpectedEntry ex) { - throw new IllegalStateException(ex); - } catch (ConstantPoolException ex) { - throw new IllegalStateException(ex); - } - } - - private static Integer getVersion(ClassFile cf, int idx) { - if (idx == 0) - return null; - try { - return ((CONSTANT_Integer_info) cf.constant_pool.get(idx)).value; - } catch (InvalidIndex ex) { - throw new IllegalStateException(ex); - } - } - - Object convertConstantValue(CPInfo info, String descriptor) throws ConstantPoolException { - if (info instanceof CONSTANT_Integer_info) { - if ("Z".equals(descriptor)) - return ((CONSTANT_Integer_info) info).value == 1; - else - return ((CONSTANT_Integer_info) info).value; - } else if (info instanceof CONSTANT_Long_info) { - return ((CONSTANT_Long_info) info).value; - } else if (info instanceof CONSTANT_Float_info) { - return ((CONSTANT_Float_info) info).value; - } else if (info instanceof CONSTANT_Double_info) { - return ((CONSTANT_Double_info) info).value; - } else if (info instanceof CONSTANT_String_info) { - return ((CONSTANT_String_info) info).getString(); - } - throw new IllegalStateException(info.getClass().getName()); - } - - Object convertElementValue(ConstantPool cp, element_value val) throws InvalidIndex, ConstantPoolException { - switch (val.tag) { - case 'Z': - return ((CONSTANT_Integer_info) cp.get(((Primitive_element_value) val).const_value_index)).value != 0; - case 'B': - return (byte) ((CONSTANT_Integer_info) cp.get(((Primitive_element_value) val).const_value_index)).value; - case 'C': - return (char) ((CONSTANT_Integer_info) cp.get(((Primitive_element_value) val).const_value_index)).value; - case 'S': - return (short) ((CONSTANT_Integer_info) cp.get(((Primitive_element_value) val).const_value_index)).value; - case 'I': - return ((CONSTANT_Integer_info) cp.get(((Primitive_element_value) val).const_value_index)).value; - case 'J': - return ((CONSTANT_Long_info) cp.get(((Primitive_element_value) val).const_value_index)).value; - case 'F': - return ((CONSTANT_Float_info) cp.get(((Primitive_element_value) val).const_value_index)).value; - case 'D': - return ((CONSTANT_Double_info) cp.get(((Primitive_element_value) val).const_value_index)).value; - case 's': - return ((CONSTANT_Utf8_info) cp.get(((Primitive_element_value) val).const_value_index)).value; - - case 'e': - return new EnumConstant(cp.getUTF8Value(((Enum_element_value) val).type_name_index), - cp.getUTF8Value(((Enum_element_value) val).const_name_index)); - case 'c': - return new ClassConstant(cp.getUTF8Value(((Class_element_value) val).class_info_index)); - - case '@': - return annotation2Description(cp, ((Annotation_element_value) val).annotation_value); - - case '[': - List values = new ArrayList<>(); - for (element_value elem : ((Array_element_value) val).values) { - values.add(convertElementValue(cp, elem)); - } - return values; - default: - throw new IllegalStateException("Currently unhandled tag: " + val.tag); - } - } - - private List annotations2Description(ConstantPool cp, Attribute attr) throws ConstantPoolException { - RuntimeAnnotations_attribute annotationsAttr = (RuntimeAnnotations_attribute) attr; - List descs = new ArrayList<>(); - for (Annotation a : annotationsAttr.annotations) { - descs.add(annotation2Description(cp, a)); - } - return descs; - } - - private List> parameterAnnotations2Description(ConstantPool cp, Attribute attr) throws ConstantPoolException { - RuntimeParameterAnnotations_attribute annotationsAttr = - (RuntimeParameterAnnotations_attribute) attr; - List> descs = new ArrayList<>(); - for (Annotation[] attrAnnos : annotationsAttr.parameter_annotations) { - List paramDescs = new ArrayList<>(); - for (Annotation ann : attrAnnos) { - paramDescs.add(annotation2Description(cp, ann)); - } - descs.add(paramDescs); - } - return descs; - } - - private AnnotationDescription annotation2Description(ConstantPool cp, Annotation a) throws ConstantPoolException { - String annotationType = cp.getUTF8Value(a.type_index); - Map values = new HashMap<>(); - - for (element_value_pair e : a.element_value_pairs) { - values.put(cp.getUTF8Value(e.element_name_index), convertElementValue(cp, e.value)); - } - - return new AnnotationDescription(annotationType, values); - } - // - - protected boolean includeEffectiveAccess(ClassList classes, ClassDescription clazz) { - if (!include(clazz.header.get(0).flags)) - return false; - for (ClassDescription outer : classes.enclosingClasses(clazz)) { - if (!include(outer.header.get(0).flags)) - return false; - } - return true; - } - - boolean include(Set includedClasses, ClassList classes, String clazzName) { - if (clazzName == null) - return false; - - boolean modified = includedClasses.add(clazzName); - - for (ClassDescription outer : classes.enclosingClasses(classes.find(clazzName, true))) { - modified |= includedClasses.add(outer.name); - } - - return modified; - } - - boolean includeOutputType(Iterable features, - Function feature2Descriptor, - Set includedClasses, - ClassList classes) { - boolean modified = false; - - for (T feature : features) { - CharSequence sig = - feature.signature != null ? feature.signature : feature2Descriptor.apply(feature); - Matcher m = OUTPUT_TYPE_PATTERN.matcher(sig); - while (m.find()) { - modified |= include(includedClasses, classes, m.group(1)); - } - } - - return modified; - } - - static final Pattern OUTPUT_TYPE_PATTERN = Pattern.compile("L([^;<]+)(;|<)"); - - public static class VersionDescription { - public final String classes; - public final String version; - public final String primaryBaseline; - - public VersionDescription(String classes, String version, String primaryBaseline) { - this.classes = classes; - this.version = version; - this.primaryBaseline = "".equals(primaryBaseline) ? null : primaryBaseline; - } - - } - - public static class ExcludeIncludeList { - public final Set includeList; - public final Set excludeList; - - protected ExcludeIncludeList(Set includeList, Set excludeList) { - this.includeList = includeList; - this.excludeList = excludeList; - } - - public static ExcludeIncludeList create(String files) throws IOException { - Set includeList = new HashSet<>(); - Set excludeList = new HashSet<>(); - for (String file : files.split(File.pathSeparator)) { - try (Stream lines = Files.lines(Paths.get(file))) { - lines.map(l -> l.substring(0, l.indexOf('#') != (-1) ? l.indexOf('#') : l.length())) - .filter(l -> !l.trim().isEmpty()) - .forEach(l -> { - Set target = l.startsWith("+") ? includeList : excludeList; - target.add(l.substring(1)); - }); - } - } - return new ExcludeIncludeList(includeList, excludeList); - } - - public boolean accepts(String className) { - return matches(includeList, className) && !matches(excludeList, className); - } - - private static boolean matches(Set list, String className) { - if (list.contains(className)) - return true; - String pack = className.substring(0, className.lastIndexOf('/') + 1); - return list.contains(pack); - } - } - // - - // - static boolean checkChange(String versions, String version, - String baselineVersion) { - return versions.contains(version) ^ - (baselineVersion != null && - versions.contains(baselineVersion)); - } - - static abstract class FeatureDescription { - int flags; - boolean deprecated; - String signature; - String versions = ""; - List classAnnotations; - List runtimeAnnotations; - - protected void writeAttributes(Appendable output) throws IOException { - if (flags != 0) - output.append(" flags " + Integer.toHexString(flags)); - if (deprecated) { - output.append(" deprecated true"); - } - if (signature != null) { - output.append(" signature " + quote(signature, false)); - } - if (classAnnotations != null && !classAnnotations.isEmpty()) { - output.append(" classAnnotations "); - for (AnnotationDescription a : classAnnotations) { - output.append(quote(a.toString(), false)); - } - } - if (runtimeAnnotations != null && !runtimeAnnotations.isEmpty()) { - output.append(" runtimeAnnotations "); - for (AnnotationDescription a : runtimeAnnotations) { - output.append(quote(a.toString(), false)); - } - } - } - - protected boolean shouldIgnore(String baselineVersion, String version) { - return (!versions.contains(version) && - (baselineVersion == null || !versions.contains(baselineVersion))) || - (baselineVersion != null && - versions.contains(baselineVersion) && versions.contains(version)); - } - - public abstract void write(Appendable output, String baselineVersion, String version) throws IOException; - - protected void readAttributes(LineBasedReader reader) { - String inFlags = reader.attributes.get("flags"); - if (inFlags != null && !inFlags.isEmpty()) { - flags = Integer.parseInt(inFlags, 16); - } - String inDeprecated = reader.attributes.get("deprecated"); - if ("true".equals(inDeprecated)) { - deprecated = true; - } - signature = reader.attributes.get("signature"); - String inClassAnnotations = reader.attributes.get("classAnnotations"); - if (inClassAnnotations != null) { - classAnnotations = parseAnnotations(inClassAnnotations, new int[1]); - } - String inRuntimeAnnotations = reader.attributes.get("runtimeAnnotations"); - if (inRuntimeAnnotations != null) { - runtimeAnnotations = parseAnnotations(inRuntimeAnnotations, new int[1]); - } - } - - public abstract boolean read(LineBasedReader reader) throws IOException; - - @Override - public int hashCode() { - int hash = 3; - hash = 89 * hash + this.flags; - hash = 89 * hash + (this.deprecated ? 1 : 0); - hash = 89 * hash + Objects.hashCode(this.signature); - hash = 89 * hash + listHashCode(this.classAnnotations); - hash = 89 * hash + listHashCode(this.runtimeAnnotations); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final FeatureDescription other = (FeatureDescription) obj; - if (this.flags != other.flags) { - return false; - } - if (this.deprecated != other.deprecated) { - return false; - } - if (!Objects.equals(this.signature, other.signature)) { - return false; - } - if (!listEquals(this.classAnnotations, other.classAnnotations)) { - return false; - } - if (!listEquals(this.runtimeAnnotations, other.runtimeAnnotations)) { - return false; - } - return true; - } - - } - - public static class ModuleDescription { - String name; - List header = new ArrayList<>(); - - public void write(Appendable output, String baselineVersion, - String version) throws IOException { - boolean inBaseline = false; - boolean inVersion = false; - for (ModuleHeaderDescription mhd : header) { - if (baselineVersion != null && - mhd.versions.contains(baselineVersion)) { - inBaseline = true; - } - if (mhd.versions.contains(version)) { - inVersion = true; - } - } - if (!inVersion && !inBaseline) - return ; - if (!inVersion) { - output.append("-module name " + name + "\n\n"); - return; - } - boolean hasChange = hasChange(header, version, baselineVersion); - if (!hasChange) - return; - - output.append("module name " + name + "\n"); - for (ModuleHeaderDescription header : header) { - header.write(output, baselineVersion, version); - } - output.append("\n"); - } - - boolean hasChange(List hasChange, - String version, String baseline) { - return hasChange.stream() - .map(fd -> fd.versions) - .anyMatch(versions -> checkChange(versions, - version, - baseline)); - } - - public void read(LineBasedReader reader, String baselineVersion, - String version) throws IOException { - if (!"module".equals(reader.lineKey)) - return ; - - name = reader.attributes.get("name"); - - reader.moveNext(); - - OUTER: while (reader.hasNext()) { - switch (reader.lineKey) { - case "header": - removeVersion(header, h -> true, version); - ModuleHeaderDescription mhd = - new ModuleHeaderDescription(); - mhd.read(reader); - mhd.name = name; - mhd.versions = version; - header.add(mhd); - break; - case "class": - case "-class": - case "module": - case "-module": - break OUTER; - default: - throw new IllegalStateException(reader.lineKey); - } - } - } - } - - static class ModuleHeaderDescription extends HeaderDescription { - String name; - List exports = new ArrayList<>(); - List opens = new ArrayList<>(); - List requires = new ArrayList<>(); - List uses = new ArrayList<>(); - List provides = new ArrayList<>(); - Integer moduleResolution; - String moduleTarget; - - @Override - public int hashCode() { - int hash = super.hashCode(); - hash = 83 * hash + Objects.hashCode(this.name); - hash = 83 * hash + Objects.hashCode(this.exports); - hash = 83 * hash + Objects.hashCode(this.opens); - hash = 83 * hash + Objects.hashCode(this.requires); - hash = 83 * hash + Objects.hashCode(this.uses); - hash = 83 * hash + Objects.hashCode(this.provides); - hash = 83 * hash + Objects.hashCode(this.moduleResolution); - hash = 83 * hash + Objects.hashCode(this.moduleTarget); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - final ModuleHeaderDescription other = - (ModuleHeaderDescription) obj; - if (!Objects.equals(this.name, other.name)) { - return false; - } - if (!listEquals(this.exports, other.exports)) { - return false; - } - if (!listEquals(this.opens, other.opens)) { - return false; - } - if (!listEquals(this.requires, other.requires)) { - return false; - } - if (!listEquals(this.uses, other.uses)) { - return false; - } - if (!listEquals(this.provides, other.provides)) { - return false; - } - if (!Objects.equals(this.moduleTarget, other.moduleTarget)) { - return false; - } - if (!Objects.equals(this.moduleResolution, - other.moduleResolution)) { - return false; - } - return true; - } - - @Override - public void write(Appendable output, String baselineVersion, - String version) throws IOException { - if (!versions.contains(version) || - (baselineVersion != null && versions.contains(baselineVersion) - && versions.contains(version))) - return ; - output.append("header"); - if (exports != null && !exports.isEmpty()) - output.append(" exports " + serializeList(exports)); - if (opens != null && !opens.isEmpty()) - output.append(" opens " + serializeList(opens)); - if (requires != null && !requires.isEmpty()) { - List requiresList = - requires.stream() - .map(req -> req.serialize()) - .collect(Collectors.toList()); - output.append(" requires " + serializeList(requiresList)); - } - if (uses != null && !uses.isEmpty()) - output.append(" uses " + serializeList(uses)); - if (provides != null && !provides.isEmpty()) { - List providesList = - provides.stream() - .map(p -> p.serialize()) - .collect(Collectors.toList()); - output.append(" provides " + serializeList(providesList)); - } - if (moduleTarget != null) - output.append(" target " + quote(moduleTarget, true)); - if (moduleResolution != null) - output.append(" resolution " + - quote(Integer.toHexString(moduleResolution), - true)); - writeAttributes(output); - output.append("\n"); - writeInnerClasses(output, baselineVersion, version); - } - - private static Map splitAttributes(String data) { - String[] parts = data.split(" "); - - Map attributes = new HashMap<>(); - - for (int i = 0; i < parts.length; i += 2) { - attributes.put(parts[i], unquote(parts[i + 1])); - } - - return attributes; - } - - @Override - public boolean read(LineBasedReader reader) throws IOException { - if (!"header".equals(reader.lineKey)) - return false; - - exports = deserializeList(reader.attributes.get("exports")); - opens = deserializeList(reader.attributes.get("opens")); - List requiresList = - deserializeList(reader.attributes.get("requires")); - requires = requiresList.stream() - .map(RequiresDescription::deserialize) - .collect(Collectors.toList()); - uses = deserializeList(reader.attributes.get("uses")); - List providesList = - deserializeList(reader.attributes.get("provides"), false); - provides = providesList.stream() - .map(ProvidesDescription::deserialize) - .collect(Collectors.toList()); - - moduleTarget = reader.attributes.get("target"); - - if (reader.attributes.containsKey("resolution")) { - final String resolutionFlags = - reader.attributes.get("resolution"); - moduleResolution = Integer.parseInt(resolutionFlags, 16); - } - - readAttributes(reader); - reader.moveNext(); - readInnerClasses(reader); - - return true; - } - - static class RequiresDescription { - final String moduleName; - final int flags; - final Integer version; - - public RequiresDescription(String moduleName, int flags, - Integer version) { - this.moduleName = moduleName; - this.flags = flags; - this.version = version; - } - - public String serialize() { - String versionKeyValue = version != null - ? " version " + quote(String.valueOf(version), true) - : ""; - return "name " + quote(moduleName, true) + - " flags " + quote(Integer.toHexString(flags), true) + - versionKeyValue; - } - - public static RequiresDescription deserialize(String data) { - Map attributes = splitAttributes(data); - - Integer ver = attributes.containsKey("version") - ? Integer.parseInt(attributes.get("version")) - : null; - int flags = Integer.parseInt(attributes.get("flags"), 16); - return new RequiresDescription(attributes.get("name"), - flags, - ver); - } - - public static RequiresDescription create(ClassFile cf, - RequiresEntry req) { - String mod = getModuleName(cf, req.requires_index); - Integer ver = getVersion(cf, req.requires_version_index); - return new RequiresDescription(mod, - req.requires_flags, - ver); - } - - @Override - public int hashCode() { - int hash = 7; - hash = 53 * hash + Objects.hashCode(this.moduleName); - hash = 53 * hash + this.flags; - hash = 53 * hash + Objects.hashCode(this.version); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final RequiresDescription other = (RequiresDescription) obj; - if (this.flags != other.flags) { - return false; - } - if (!Objects.equals(this.moduleName, other.moduleName)) { - return false; - } - if (!Objects.equals(this.version, other.version)) { - return false; - } - return true; - } - - } - - static class ProvidesDescription { - final String interfaceName; - final List implNames; - - public ProvidesDescription(String interfaceName, - List implNames) { - this.interfaceName = interfaceName; - this.implNames = implNames; - } - - public String serialize() { - return "interface " + quote(interfaceName, true) + - " impls " + quote(serializeList(implNames), true, true); - } - - public static ProvidesDescription deserialize(String data) { - Map attributes = splitAttributes(data); - List implsList = - deserializeList(attributes.get("impls"), - false); - return new ProvidesDescription(attributes.get("interface"), - implsList); - } - - public static ProvidesDescription create(ClassFile cf, - ProvidesEntry prov) { - String api = getClassName(cf, prov.provides_index); - List impls = - Arrays.stream(prov.with_index) - .mapToObj(wi -> getClassName(cf, wi)) - .collect(Collectors.toList()); - return new ProvidesDescription(api, impls); - } - - @Override - public int hashCode() { - int hash = 5; - hash = 53 * hash + Objects.hashCode(this.interfaceName); - hash = 53 * hash + Objects.hashCode(this.implNames); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final ProvidesDescription other = (ProvidesDescription) obj; - if (!Objects.equals(this.interfaceName, other.interfaceName)) { - return false; - } - if (!Objects.equals(this.implNames, other.implNames)) { - return false; - } - return true; - } - } - } - - public static class ClassDescription { - String name; - List header = new ArrayList<>(); - List methods = new ArrayList<>(); - List fields = new ArrayList<>(); - - public void write(Appendable output, String baselineVersion, - String version) throws IOException { - boolean inBaseline = false; - boolean inVersion = false; - for (ClassHeaderDescription chd : header) { - if (baselineVersion != null && - chd.versions.contains(baselineVersion)) { - inBaseline = true; - } - if (chd.versions.contains(version)) { - inVersion = true; - } - } - if (!inVersion && !inBaseline) - return ; - if (!inVersion) { - output.append("-class name " + name + "\n\n"); - return; - } - boolean hasChange = hasChange(header, version, baselineVersion) || - hasChange(fields, version, baselineVersion) || - hasChange(methods, version, baselineVersion); - if (!hasChange) - return; - - output.append("class name " + name + "\n"); - for (ClassHeaderDescription header : header) { - header.write(output, baselineVersion, version); - } - for (FieldDescription field : fields) { - field.write(output, baselineVersion, version); - } - for (MethodDescription method : methods) { - method.write(output, baselineVersion, version); - } - output.append("\n"); - } - - boolean hasChange(List hasChange, - String version, - String baseline) { - return hasChange.stream() - .map(fd -> fd.versions) - .anyMatch(versions -> checkChange(versions, - version, - baseline)); - } - - public void read(LineBasedReader reader, String baselineVersion, - String version) throws IOException { - if (!"class".equals(reader.lineKey)) - return ; - - name = reader.attributes.get("name"); - - reader.moveNext(); - - OUTER: while (reader.hasNext()) { - switch (reader.lineKey) { - case "header": - removeVersion(header, h -> true, version); - ClassHeaderDescription chd = new ClassHeaderDescription(); - chd.read(reader); - chd.versions = version; - header.add(chd); - break; - case "field": - FieldDescription field = new FieldDescription(); - field.read(reader); - field.versions += version; - fields.add(field); - break; - case "-field": { - removeVersion(fields, - f -> Objects.equals(f.name, reader.attributes.get("name")) && - Objects.equals(f.descriptor, reader.attributes.get("descriptor")), - version); - reader.moveNext(); - break; - } - case "method": - MethodDescription method = new MethodDescription(); - method.read(reader); - method.versions += version; - methods.add(method); - break; - case "-method": { - removeVersion(methods, - m -> Objects.equals(m.name, reader.attributes.get("name")) && - Objects.equals(m.descriptor, reader.attributes.get("descriptor")), - version); - reader.moveNext(); - break; - } - case "class": - case "-class": - case "module": - case "-module": - break OUTER; - default: - throw new IllegalStateException(reader.lineKey); - } - } - } - - public String packge() { - String pack; - int lastSlash = name.lastIndexOf('/'); - if (lastSlash != (-1)) { - pack = name.substring(0, lastSlash).replace('/', '.'); - } else { - pack = ""; - } - - return pack; - } - } - - static class ClassHeaderDescription extends HeaderDescription { - String extendsAttr; - List implementsAttr; - String nestHost; - List nestMembers; - - @Override - public int hashCode() { - int hash = super.hashCode(); - hash = 17 * hash + Objects.hashCode(this.extendsAttr); - hash = 17 * hash + Objects.hashCode(this.implementsAttr); - hash = 17 * hash + Objects.hashCode(this.nestHost); - hash = 17 * hash + Objects.hashCode(this.nestMembers); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (!super.equals(obj)) { - return false; - } - final ClassHeaderDescription other = (ClassHeaderDescription) obj; - if (!Objects.equals(this.extendsAttr, other.extendsAttr)) { - return false; - } - if (!Objects.equals(this.implementsAttr, other.implementsAttr)) { - return false; - } - if (!Objects.equals(this.nestHost, other.nestHost)) { - return false; - } - if (!listEquals(this.nestMembers, other.nestMembers)) { - return false; - } - return true; - } - - @Override - public void write(Appendable output, String baselineVersion, String version) throws IOException { - if (!versions.contains(version) || - (baselineVersion != null && versions.contains(baselineVersion) && versions.contains(version))) - return ; - output.append("header"); - if (extendsAttr != null) - output.append(" extends " + extendsAttr); - if (implementsAttr != null && !implementsAttr.isEmpty()) - output.append(" implements " + serializeList(implementsAttr)); - if (nestHost != null) - output.append(" nestHost " + nestHost); - if (nestMembers != null && !nestMembers.isEmpty()) - output.append(" nestMembers " + serializeList(nestMembers)); - writeAttributes(output); - output.append("\n"); - writeInnerClasses(output, baselineVersion, version); - } - - @Override - public boolean read(LineBasedReader reader) throws IOException { - if (!"header".equals(reader.lineKey)) - return false; - - extendsAttr = reader.attributes.get("extends"); - String elementsList = reader.attributes.get("implements"); - implementsAttr = deserializeList(elementsList); - - nestHost = reader.attributes.get("nestHost"); - String nestMembersList = reader.attributes.get("nestMembers"); - nestMembers = deserializeList(nestMembersList); - - readAttributes(reader); - reader.moveNext(); - readInnerClasses(reader); - - return true; - } - - } - - static abstract class HeaderDescription extends FeatureDescription { - List innerClasses; - - @Override - public int hashCode() { - int hash = super.hashCode(); - hash = 19 * hash + Objects.hashCode(this.innerClasses); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (!super.equals(obj)) { - return false; - } - final HeaderDescription other = (HeaderDescription) obj; - if (!listEquals(this.innerClasses, other.innerClasses)) { - return false; - } - return true; - } - - protected void writeInnerClasses(Appendable output, - String baselineVersion, - String version) throws IOException { - if (innerClasses != null && !innerClasses.isEmpty()) { - for (InnerClassInfo ici : innerClasses) { - output.append("innerclass"); - output.append(" innerClass " + ici.innerClass); - output.append(" outerClass " + ici.outerClass); - output.append(" innerClassName " + ici.innerClassName); - output.append(" flags " + Integer.toHexString(ici.innerClassFlags)); - output.append("\n"); - } - } - } - - protected void readInnerClasses(LineBasedReader reader) throws IOException { - innerClasses = new ArrayList<>(); - - while ("innerclass".equals(reader.lineKey)) { - InnerClassInfo info = new InnerClassInfo(); - - info.innerClass = reader.attributes.get("innerClass"); - info.outerClass = reader.attributes.get("outerClass"); - info.innerClassName = reader.attributes.get("innerClassName"); - - String inFlags = reader.attributes.get("flags"); - if (inFlags != null && !inFlags.isEmpty()) - info.innerClassFlags = Integer.parseInt(inFlags, 16); - - innerClasses.add(info); - - reader.moveNext(); - } - } - - } - - static class MethodDescription extends FeatureDescription { - String name; - String descriptor; - List thrownTypes; - Object annotationDefaultValue; - List> classParameterAnnotations; - List> runtimeParameterAnnotations; - - @Override - public int hashCode() { - int hash = super.hashCode(); - hash = 59 * hash + Objects.hashCode(this.name); - hash = 59 * hash + Objects.hashCode(this.descriptor); - hash = 59 * hash + Objects.hashCode(this.thrownTypes); - hash = 59 * hash + Objects.hashCode(this.annotationDefaultValue); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (!super.equals(obj)) { - return false; - } - final MethodDescription other = (MethodDescription) obj; - if (!Objects.equals(this.name, other.name)) { - return false; - } - if (!Objects.equals(this.descriptor, other.descriptor)) { - return false; - } - if (!Objects.equals(this.thrownTypes, other.thrownTypes)) { - return false; - } - if (!Objects.equals(this.annotationDefaultValue, other.annotationDefaultValue)) { - return false; - } - return true; - } - - @Override - public void write(Appendable output, String baselineVersion, String version) throws IOException { - if (shouldIgnore(baselineVersion, version)) - return ; - if (!versions.contains(version)) { - output.append("-method"); - output.append(" name " + quote(name, false)); - output.append(" descriptor " + quote(descriptor, false)); - output.append("\n"); - return ; - } - output.append("method"); - output.append(" name " + quote(name, false)); - output.append(" descriptor " + quote(descriptor, false)); - if (thrownTypes != null) - output.append(" thrownTypes " + serializeList(thrownTypes)); - if (annotationDefaultValue != null) - output.append(" annotationDefaultValue " + quote(AnnotationDescription.dumpAnnotationValue(annotationDefaultValue), false)); - writeAttributes(output); - if (classParameterAnnotations != null && !classParameterAnnotations.isEmpty()) { - output.append(" classParameterAnnotations "); - for (List pa : classParameterAnnotations) { - for (AnnotationDescription a : pa) { - output.append(quote(a.toString(), false)); - } - output.append(";"); - } - } - if (runtimeParameterAnnotations != null && !runtimeParameterAnnotations.isEmpty()) { - output.append(" runtimeParameterAnnotations "); - for (List pa : runtimeParameterAnnotations) { - for (AnnotationDescription a : pa) { - output.append(quote(a.toString(), false)); - } - output.append(";"); - } - } - output.append("\n"); - } - - @Override - public boolean read(LineBasedReader reader) throws IOException { - if (!"method".equals(reader.lineKey)) - return false; - - name = reader.attributes.get("name"); - descriptor = reader.attributes.get("descriptor"); - - String thrownTypesValue = reader.attributes.get("thrownTypes"); - - if (thrownTypesValue != null) { - thrownTypes = deserializeList(thrownTypesValue); - } - - String inAnnotationDefaultValue = reader.attributes.get("annotationDefaultValue"); - - if (inAnnotationDefaultValue != null) { - annotationDefaultValue = parseAnnotationValue(inAnnotationDefaultValue, new int[1]); - } - - readAttributes(reader); - - String inClassParamAnnotations = reader.attributes.get("classParameterAnnotations"); - if (inClassParamAnnotations != null) { - List> annos = new ArrayList<>(); - int[] pointer = new int[1]; - do { - annos.add(parseAnnotations(inClassParamAnnotations, pointer)); - assert pointer[0] == inClassParamAnnotations.length() || inClassParamAnnotations.charAt(pointer[0]) == ';'; - } while (++pointer[0] < inClassParamAnnotations.length()); - classParameterAnnotations = annos; - } - - String inRuntimeParamAnnotations = reader.attributes.get("runtimeParameterAnnotations"); - if (inRuntimeParamAnnotations != null) { - List> annos = new ArrayList<>(); - int[] pointer = new int[1]; - do { - annos.add(parseAnnotations(inRuntimeParamAnnotations, pointer)); - assert pointer[0] == inRuntimeParamAnnotations.length() || inRuntimeParamAnnotations.charAt(pointer[0]) == ';'; - } while (++pointer[0] < inRuntimeParamAnnotations.length()); - runtimeParameterAnnotations = annos; - } - - reader.moveNext(); - - return true; - } - - } - - static class FieldDescription extends FeatureDescription { - String name; - String descriptor; - Object constantValue; - - @Override - public int hashCode() { - int hash = super.hashCode(); - hash = 59 * hash + Objects.hashCode(this.name); - hash = 59 * hash + Objects.hashCode(this.descriptor); - hash = 59 * hash + Objects.hashCode(this.constantValue); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (!super.equals(obj)) { - return false; - } - final FieldDescription other = (FieldDescription) obj; - if (!Objects.equals(this.name, other.name)) { - return false; - } - if (!Objects.equals(this.descriptor, other.descriptor)) { - return false; - } - if (!Objects.equals(this.constantValue, other.constantValue)) { - return false; - } - return true; - } - - @Override - public void write(Appendable output, String baselineVersion, String version) throws IOException { - if (shouldIgnore(baselineVersion, version)) - return ; - if (!versions.contains(version)) { - output.append("-field"); - output.append(" name " + quote(name, false)); - output.append(" descriptor " + quote(descriptor, false)); - output.append("\n"); - return ; - } - output.append("field"); - output.append(" name " + name); - output.append(" descriptor " + descriptor); - if (constantValue != null) { - output.append(" constantValue " + quote(constantValue.toString(), false)); - } - writeAttributes(output); - output.append("\n"); - } - - @Override - public boolean read(LineBasedReader reader) throws IOException { - if (!"field".equals(reader.lineKey)) - return false; - - name = reader.attributes.get("name"); - descriptor = reader.attributes.get("descriptor"); - - String inConstantValue = reader.attributes.get("constantValue"); - - if (inConstantValue != null) { - switch (descriptor) { - case "Z": constantValue = "true".equals(inConstantValue); break; - case "B": constantValue = Integer.parseInt(inConstantValue); break; - case "C": constantValue = inConstantValue.charAt(0); break; - case "S": constantValue = Integer.parseInt(inConstantValue); break; - case "I": constantValue = Integer.parseInt(inConstantValue); break; - case "J": constantValue = Long.parseLong(inConstantValue); break; - case "F": constantValue = Float.parseFloat(inConstantValue); break; - case "D": constantValue = Double.parseDouble(inConstantValue); break; - case "Ljava/lang/String;": constantValue = inConstantValue; break; - default: - throw new IllegalStateException("Unrecognized field type: " + descriptor); - } - } - - readAttributes(reader); - - reader.moveNext(); - - return true; - } - - } - - static final class AnnotationDescription { - String annotationType; - Map values; - - public AnnotationDescription(String annotationType, Map values) { - this.annotationType = annotationType; - this.values = values; - } - - @Override - public int hashCode() { - int hash = 7; - hash = 47 * hash + Objects.hashCode(this.annotationType); - hash = 47 * hash + Objects.hashCode(this.values); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final AnnotationDescription other = (AnnotationDescription) obj; - if (!Objects.equals(this.annotationType, other.annotationType)) { - return false; - } - if (!Objects.equals(this.values, other.values)) { - return false; - } - return true; - } - - @Override - public String toString() { - StringBuilder result = new StringBuilder(); - result.append("@" + annotationType); - if (!values.isEmpty()) { - result.append("("); - boolean first = true; - for (Entry e : values.entrySet()) { - if (!first) { - result.append(","); - } - first = false; - result.append(e.getKey()); - result.append("="); - result.append(dumpAnnotationValue(e.getValue())); - result.append(""); - } - result.append(")"); - } - return result.toString(); - } - - private static String dumpAnnotationValue(Object value) { - if (value instanceof List) { - StringBuilder result = new StringBuilder(); - - result.append("{"); - - for (Object element : ((List) value)) { - result.append(dumpAnnotationValue(element)); - } - - result.append("}"); - - return result.toString(); - } - - if (value instanceof String) { - return "\"" + quote((String) value, true) + "\""; - } else if (value instanceof Boolean) { - return "Z" + value; - } else if (value instanceof Byte) { - return "B" + value; - } if (value instanceof Character) { - return "C" + value; - } if (value instanceof Short) { - return "S" + value; - } if (value instanceof Integer) { - return "I" + value; - } if (value instanceof Long) { - return "J" + value; - } if (value instanceof Float) { - return "F" + value; - } if (value instanceof Double) { - return "D" + value; - } else { - return value.toString(); - } - } - } - - static final class EnumConstant { - String type; - String constant; - - public EnumConstant(String type, String constant) { - this.type = type; - this.constant = constant; - } - - @Override - public String toString() { - return "e" + type + constant + ";"; - } - - @Override - public int hashCode() { - int hash = 7; - hash = 19 * hash + Objects.hashCode(this.type); - hash = 19 * hash + Objects.hashCode(this.constant); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final EnumConstant other = (EnumConstant) obj; - if (!Objects.equals(this.type, other.type)) { - return false; - } - if (!Objects.equals(this.constant, other.constant)) { - return false; - } - return true; - } - - } - - static final class ClassConstant { - String type; - - public ClassConstant(String type) { - this.type = type; - } - - @Override - public String toString() { - return "c" + type; - } - - @Override - public int hashCode() { - int hash = 3; - hash = 53 * hash + Objects.hashCode(this.type); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final ClassConstant other = (ClassConstant) obj; - if (!Objects.equals(this.type, other.type)) { - return false; - } - return true; - } - - } - - static final class InnerClassInfo { - String innerClass; - String outerClass; - String innerClassName; - int innerClassFlags; - - @Override - public int hashCode() { - int hash = 3; - hash = 11 * hash + Objects.hashCode(this.innerClass); - hash = 11 * hash + Objects.hashCode(this.outerClass); - hash = 11 * hash + Objects.hashCode(this.innerClassName); - hash = 11 * hash + Objects.hashCode(this.innerClassFlags); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final InnerClassInfo other = (InnerClassInfo) obj; - if (!Objects.equals(this.innerClass, other.innerClass)) { - return false; - } - if (!Objects.equals(this.outerClass, other.outerClass)) { - return false; - } - if (!Objects.equals(this.innerClassName, other.innerClassName)) { - return false; - } - if (!Objects.equals(this.innerClassFlags, other.innerClassFlags)) { - return false; - } - return true; - } - - } - - public static final class ClassList implements Iterable { - private final List classes = new ArrayList<>(); - private final Map name2Class = new HashMap<>(); - private final Map inner2Outter = new HashMap<>(); - - @Override - public Iterator iterator() { - return classes.iterator(); - } - - public void add(ClassDescription desc) { - classes.add(desc); - name2Class.put(desc.name, desc); - } - - public ClassDescription find(String name) { - return find(name, ALLOW_NON_EXISTING_CLASSES); - } - - public ClassDescription find(String name, boolean allowNull) { - ClassDescription desc = name2Class.get(name); - - if (desc != null || allowNull) - return desc; - - throw new IllegalStateException("Cannot find: " + name); - } - - private static final ClassDescription NONE = new ClassDescription(); - - public ClassDescription enclosingClass(ClassDescription clazz) { - if (clazz == null) - return null; - ClassDescription desc = inner2Outter.computeIfAbsent(clazz, c -> { - ClassHeaderDescription header = clazz.header.get(0); - - if (header.innerClasses != null) { - for (InnerClassInfo ici : header.innerClasses) { - if (ici.innerClass.equals(clazz.name)) { - return find(ici.outerClass); - } - } - } - - return NONE; - }); - - return desc != NONE ? desc : null; - } - - public Iterable enclosingClasses(ClassDescription clazz) { - List result = new ArrayList<>(); - ClassDescription outer = enclosingClass(clazz); - - while (outer != null) { - result.add(outer); - outer = enclosingClass(outer); - } - - return result; - } - - public void sort() { - Collections.sort(classes, (cd1, cd2) -> cd1.name.compareTo(cd2.name)); - } - } - - private static int listHashCode(Collection c) { - return c == null || c.isEmpty() ? 0 : c.hashCode(); - } - - private static boolean listEquals(Collection c1, Collection c2) { - if (c1 == c2) return true; - if (c1 == null && c2.isEmpty()) return true; - if (c2 == null && c1.isEmpty()) return true; - return Objects.equals(c1, c2); - } - - private static String serializeList(List list) { - StringBuilder result = new StringBuilder(); - String sep = ""; - - for (Object o : list) { - result.append(sep); - result.append(o); - sep = ","; - } - - return quote(result.toString(), false); - } - - private static List deserializeList(String serialized) { - return deserializeList(serialized, true); - } - - private static List deserializeList(String serialized, - boolean unquote) { - serialized = unquote ? unquote(serialized) : serialized; - if (serialized == null) - return new ArrayList<>(); - return new ArrayList<>(List.of(serialized.split(","))); - } - - private static String quote(String value, boolean quoteQuotes) { - return quote(value, quoteQuotes, false); - } - - private static String quote(String value, boolean quoteQuotes, - boolean quoteCommas) { - StringBuilder result = new StringBuilder(); - - for (char c : value.toCharArray()) { - if (c <= 32 || c >= 127 || c == '\\' || - (quoteQuotes && c == '"') || (quoteCommas && c == ',')) { - result.append("\\u" + String.format("%04X", (int) c) + ";"); - } else { - result.append(c); - } - } - - return result.toString(); - } - - private static final Pattern unicodePattern = - Pattern.compile("\\\\u([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])"); - - private static String unquote(String value) { - if (value == null) - return null; - - StringBuilder result = new StringBuilder(); - Matcher m = unicodePattern.matcher(value); - int lastStart = 0; - - while (m.find(lastStart)) { - result.append(value.substring(lastStart, m.start())); - result.append((char) Integer.parseInt(m.group(1), 16)); - lastStart = m.end() + 1; - } - - result.append(value.substring(lastStart, value.length())); - - return result.toString(); - } - - private static String readDigits(String value, int[] valuePointer) { - int start = valuePointer[0]; - - if (value.charAt(valuePointer[0]) == '-') - valuePointer[0]++; - - while (valuePointer[0] < value.length() && Character.isDigit(value.charAt(valuePointer[0]))) - valuePointer[0]++; - - return value.substring(start, valuePointer[0]); - } - - private static String className(String value, int[] valuePointer) { - int start = valuePointer[0]; - while (value.charAt(valuePointer[0]++) != ';') - ; - return value.substring(start, valuePointer[0]); - } - - private static Object parseAnnotationValue(String value, int[] valuePointer) { - switch (value.charAt(valuePointer[0]++)) { - case 'Z': - if ("true".equals(value.substring(valuePointer[0], valuePointer[0] + 4))) { - valuePointer[0] += 4; - return true; - } else if ("false".equals(value.substring(valuePointer[0], valuePointer[0] + 5))) { - valuePointer[0] += 5; - return false; - } else { - throw new IllegalStateException("Unrecognized boolean structure: " + value); - } - case 'B': return Byte.parseByte(readDigits(value, valuePointer)); - case 'C': return value.charAt(valuePointer[0]++); - case 'S': return Short.parseShort(readDigits(value, valuePointer)); - case 'I': return Integer.parseInt(readDigits(value, valuePointer)); - case 'J': return Long.parseLong(readDigits(value, valuePointer)); - case 'F': return Float.parseFloat(readDigits(value, valuePointer)); - case 'D': return Double.parseDouble(readDigits(value, valuePointer)); - case 'c': - return new ClassConstant(className(value, valuePointer)); - case 'e': - return new EnumConstant(className(value, valuePointer), className(value, valuePointer).replaceFirst(";$", "")); - case '{': - List elements = new ArrayList<>(); //TODO: a good test for this would be highly desirable - while (value.charAt(valuePointer[0]) != '}') { - elements.add(parseAnnotationValue(value, valuePointer)); - } - valuePointer[0]++; - return elements; - case '"': - int start = valuePointer[0]; - while (value.charAt(valuePointer[0]) != '"') - valuePointer[0]++; - return unquote(value.substring(start, valuePointer[0]++)); - case '@': - return parseAnnotation(value, valuePointer); - default: - throw new IllegalStateException("Unrecognized signature type: " + value.charAt(valuePointer[0] - 1) + "; value=" + value); - } - } - - public static List parseAnnotations(String encoded, int[] pointer) { - ArrayList result = new ArrayList<>(); - - while (pointer[0] < encoded.length() && encoded.charAt(pointer[0]) == '@') { - pointer[0]++; - result.add(parseAnnotation(encoded, pointer)); - } - - return result; - } - - private static AnnotationDescription parseAnnotation(String value, int[] valuePointer) { - String className = className(value, valuePointer); - Map attribute2Value = new HashMap<>(); - - if (valuePointer[0] < value.length() && value.charAt(valuePointer[0]) == '(') { - while (value.charAt(valuePointer[0]) != ')') { - int nameStart = ++valuePointer[0]; - - while (value.charAt(valuePointer[0]++) != '='); - - String name = value.substring(nameStart, valuePointer[0] - 1); - - attribute2Value.put(name, parseAnnotationValue(value, valuePointer)); - } - - valuePointer[0]++; - } - - return new AnnotationDescription(className, attribute2Value); - } - // - - private static void help() { - System.err.println("Help..."); - } - - public static void main(String... args) throws IOException { - if (args.length < 1) { - help(); - return ; - } - - switch (args[0]) { - case "build-description": { - if (args.length < 3) { - help(); - return ; - } - - Path descDest = Paths.get(args[1]); - List versions = new ArrayList<>(); - - for (int i = 3; i + 2 < args.length; i += 3) { - versions.add(new VersionDescription(args[i + 1], args[i], args[i + 2])); - } - - Files.walkFileTree(descDest, new FileVisitor() { - @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { - return FileVisitResult.CONTINUE; - } - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - Files.delete(file); - return FileVisitResult.CONTINUE; - } - @Override - public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { - return FileVisitResult.CONTINUE; - } - @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { - Files.delete(dir); - return FileVisitResult.CONTINUE; - } - }); - - ExcludeIncludeList excludeList = - ExcludeIncludeList.create(args[2]); - - new CreateSymbols().createBaseLine(versions, - excludeList, - descDest, - args); - break; - } - case "build-description-incremental": { - if (args.length != 3) { - help(); - return ; - } - - new CreateSymbols().createIncrementalBaseLine(args[1], args[2], args); - break; - } - case "build-ctsym": - String ctDescriptionFileExtra; - String ctDescriptionFile; - String ctSymLocation; - - if (args.length == 3) { - ctDescriptionFileExtra = null; - ctDescriptionFile = args[1]; - ctSymLocation = args[2]; - } else if (args.length == 4) { - ctDescriptionFileExtra = args[1]; - ctDescriptionFile = args[2]; - ctSymLocation = args[3]; - } else { - help(); - return ; - } - - new CreateSymbols().createSymbols(ctDescriptionFileExtra, - ctDescriptionFile, - ctSymLocation); - break; - } - } - -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.compiler/share/tools/org/openjdk/buildtools/symbolgenerator/CreateSymbols.java 2020-03-23 19:57:33.767962280 +0100 @@ -0,0 +1,3751 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.symbolgenerator; + +import org.openjdk.buildtools.symbolgenerator.CreateSymbols + .ModuleHeaderDescription + .ProvidesDescription; +import org.openjdk.buildtools.symbolgenerator.CreateSymbols + .ModuleHeaderDescription + .RequiresDescription; +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.StringWriter; +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.FileVisitResult; +import java.nio.file.FileVisitor; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.stream.Stream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; +import java.util.TimeZone; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import javax.tools.JavaFileManager; +import javax.tools.JavaFileManager.Location; +import javax.tools.JavaFileObject; +import javax.tools.JavaFileObject.Kind; +import javax.tools.StandardLocation; + +import com.sun.source.util.JavacTask; +import com.sun.tools.classfile.AccessFlags; +import com.sun.tools.classfile.Annotation; +import com.sun.tools.classfile.Annotation.Annotation_element_value; +import com.sun.tools.classfile.Annotation.Array_element_value; +import com.sun.tools.classfile.Annotation.Class_element_value; +import com.sun.tools.classfile.Annotation.Enum_element_value; +import com.sun.tools.classfile.Annotation.Primitive_element_value; +import com.sun.tools.classfile.Annotation.element_value; +import com.sun.tools.classfile.Annotation.element_value_pair; +import com.sun.tools.classfile.AnnotationDefault_attribute; +import com.sun.tools.classfile.Attribute; +import com.sun.tools.classfile.Attributes; +import com.sun.tools.classfile.ClassFile; +import com.sun.tools.classfile.ClassWriter; +import com.sun.tools.classfile.ConstantPool; +import com.sun.tools.classfile.ConstantPool.CONSTANT_Class_info; +import com.sun.tools.classfile.ConstantPool.CONSTANT_Double_info; +import com.sun.tools.classfile.ConstantPool.CONSTANT_Float_info; +import com.sun.tools.classfile.ConstantPool.CONSTANT_Integer_info; +import com.sun.tools.classfile.ConstantPool.CONSTANT_Long_info; +import com.sun.tools.classfile.ConstantPool.CONSTANT_Module_info; +import com.sun.tools.classfile.ConstantPool.CONSTANT_Package_info; +import com.sun.tools.classfile.ConstantPool.CONSTANT_String_info; +import com.sun.tools.classfile.ConstantPool.CONSTANT_Utf8_info; +import com.sun.tools.classfile.ConstantPool.CPInfo; +import com.sun.tools.classfile.ConstantPool.InvalidIndex; +import com.sun.tools.classfile.ConstantPoolException; +import com.sun.tools.classfile.ConstantValue_attribute; +import com.sun.tools.classfile.Deprecated_attribute; +import com.sun.tools.classfile.Descriptor; +import com.sun.tools.classfile.Exceptions_attribute; +import com.sun.tools.classfile.Field; +import com.sun.tools.classfile.InnerClasses_attribute; +import com.sun.tools.classfile.InnerClasses_attribute.Info; +import com.sun.tools.classfile.Method; +import com.sun.tools.classfile.ModuleResolution_attribute; +import com.sun.tools.classfile.ModuleTarget_attribute; +import com.sun.tools.classfile.Module_attribute; +import com.sun.tools.classfile.Module_attribute.ExportsEntry; +import com.sun.tools.classfile.Module_attribute.OpensEntry; +import com.sun.tools.classfile.Module_attribute.ProvidesEntry; +import com.sun.tools.classfile.Module_attribute.RequiresEntry; +import com.sun.tools.classfile.NestHost_attribute; +import com.sun.tools.classfile.NestMembers_attribute; +import com.sun.tools.classfile.RuntimeAnnotations_attribute; +import com.sun.tools.classfile.RuntimeInvisibleAnnotations_attribute; +import com.sun.tools.classfile.RuntimeInvisibleParameterAnnotations_attribute; +import com.sun.tools.classfile.RuntimeParameterAnnotations_attribute; +import com.sun.tools.classfile.RuntimeVisibleAnnotations_attribute; +import com.sun.tools.classfile.RuntimeVisibleParameterAnnotations_attribute; +import com.sun.tools.classfile.Signature_attribute; +import com.sun.tools.javac.api.JavacTool; +import com.sun.tools.javac.jvm.Target; +import com.sun.tools.javac.util.Assert; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.Pair; + +/** + * A tool for processing the .sym.txt files. + * + * To add historical data for JDK N, N >= 11, do the following: + * * cd /make/data/symbols + * * /bin/java --add-exports jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED \ + * --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ + * --add-exports jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED \ + * --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \ + * --add-modules jdk.jdeps \ + * ../../../make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java \ + * build-description-incremental symbols include.list + * * sanity-check the new and updates files in make/data/symbols and commit them + * + * The tools allows to: + * * convert the .sym.txt into class/sig files for ct.sym + * * in cooperation with the adjacent history Probe, construct .sym.txt files for previous platforms + * * enhance existing .sym.txt files with a a new set .sym.txt for the current platform + * + * To convert the .sym.txt files to class/sig files from ct.sym, run: + * java build.tool.symbolgenerator.CreateSymbols build-ctsym + * + * The is a file of this format: + * generate platforms + * platform version files <.sym.txt files containing history data for given platform, separate with ':'> + * platform version base files <.sym.txt files containing history data for given platform, separate with ':'> + * + * The content of platform "" is also automatically added to the content of + * platform "", unless explicitly excluded in ""'s .sym.txt files. + * + * To create the .sym.txt files, first run the history Probe for all the previous platforms: + * /bin/java org.openjdk.buildtools.symbolgenerator.Probe + * + * Where is a name of a file into which the classes from the bootclasspath of + * will be written. + * + * Then create the file and the .sym.txt files like this: + * java org.openjdk.buildtools.symbolgenerator.CreateSymbols build-description + * "" + * + * + * ... + * + * The is a file that specifies classes that should be included/excluded. + * Lines that start with '+' represent class or package that should be included, '-' class or package + * that should be excluded. '/' should be used as package name delimiter, packages should end with '/'. + * Several include list files may be specified, separated by File.pathSeparator. + * + * When is specified, the .sym.txt files for platform N will only contain + * differences between platform N and the specified platform. The first platform (denoted F further) + * that is specified should use literal value "", to have all the APIs of the platform written to + * the .sym.txt files. If there is an existing platform with full .sym.txt files in the repository, + * that platform should be used as the first platform to avoid unnecessary changes to the .sym.txt + * files. The for platform N should be determined as follows: if N < F, then + * should be N + 1. If F < N, then should be N - 1. + * If N is a custom/specialized sub-version of another platform N', then should be N'. + * + * To generate the .sym.txt files for OpenJDK 7 and 8: + * /bin/java org.openjdk.buildtools.symbolgenerator.Probe OpenJDK7.classes + * /bin/java org.openjdk.buildtools.symbolgenerator.Probe OpenJDK8.classes + * java org.openjdk.buildtools.symbolgenerator.CreateSymbols build-description make/data/symbols $TOPDIR make/data/symbols/include.list + * 8 OpenJDK8.classes '' + * 7 OpenJDK7.classes 8 + * + * Note: the versions are expected to be a single character. + * + */ +public class CreateSymbols { + + // + /**Create sig files for ct.sym reading the classes description from the directory that contains + * {@code ctDescriptionFile}, using the file as a recipe to create the sigfiles. + */ + @SuppressWarnings("unchecked") + public void createSymbols(String ctDescriptionFileExtra, String ctDescriptionFile, String ctSymLocation) throws IOException { + LoadDescriptions data = load(ctDescriptionFileExtra != null ? Paths.get(ctDescriptionFileExtra) + : null, + Paths.get(ctDescriptionFile), null); + + splitHeaders(data.classes); + + Map> package2Version2Module = new HashMap<>(); + + for (ModuleDescription md : data.modules.values()) { + for (ModuleHeaderDescription mhd : md.header) { + List versionsList = + Collections.singletonList(mhd.versions); + writeModulesForVersions(ctSymLocation, + md, + mhd, + versionsList); + mhd.exports.stream().forEach(pkg -> { + for (char v : mhd.versions.toCharArray()) { + package2Version2Module.computeIfAbsent(pkg, dummy -> new HashMap<>()).put(v, md.name); + } + }); + } + } + + for (ClassDescription classDescription : data.classes) { + Map version2Module = package2Version2Module.getOrDefault(classDescription.packge().replace('.', '/'), Collections.emptyMap()); + for (ClassHeaderDescription header : classDescription.header) { + Set jointVersions = new HashSet<>(); + jointVersions.add(header.versions); + limitJointVersion(jointVersions, classDescription.fields); + limitJointVersion(jointVersions, classDescription.methods); + Map module2Versions = new HashMap<>(); + for (char v : header.versions.toCharArray()) { + String module = version2Module.get(v); + if (module == null) { + if (v >= '9') { + throw new AssertionError("No module for " + classDescription.name + + " and version " + v); + } + module = version2Module.get('9'); + if (module == null) { + module = "java.base"; + } + } + module2Versions.computeIfAbsent(module, dummy -> new StringBuilder()).append(v); + } + for (Entry e : module2Versions.entrySet()) { + Set currentVersions = new HashSet<>(jointVersions); + limitJointVersion(currentVersions, e.getValue().toString()); + currentVersions = currentVersions.stream().filter(vers -> !disjoint(vers, e.getValue().toString())).collect(Collectors.toSet()); + writeClassesForVersions(ctSymLocation, classDescription, header, e.getKey(), currentVersions); + } + } + } + } + + public static String EXTENSION = ".sig"; + + LoadDescriptions load(Path ctDescriptionWithExtraContent, Path ctDescriptionOpen, String deletePlatform) throws IOException { + Map platforms = new LinkedHashMap<>(); + + if (ctDescriptionWithExtraContent != null && Files.isRegularFile(ctDescriptionWithExtraContent)) { + try (LineBasedReader reader = new LineBasedReader(ctDescriptionWithExtraContent)) { + while (reader.hasNext()) { + switch (reader.lineKey) { + case "generate": + //ignore + reader.moveNext(); + break; + case "platform": + PlatformInput platform = PlatformInput.load(ctDescriptionWithExtraContent, + reader); + if (!platform.version.equals(deletePlatform)) + platforms.put(platform.version, platform); + reader.moveNext(); + break; + default: + throw new IllegalStateException("Unknown key: " + reader.lineKey); + } + } + } + } + + Set generatePlatforms = null; + + try (LineBasedReader reader = new LineBasedReader(ctDescriptionOpen)) { + while (reader.hasNext()) { + switch (reader.lineKey) { + case "generate": + String[] platformsAttr = reader.attributes.get("platforms").split(":"); + generatePlatforms = new HashSet<>(List.of(platformsAttr)); + generatePlatforms.remove(deletePlatform); + reader.moveNext(); + break; + case "platform": + PlatformInput platform = PlatformInput.load(ctDescriptionOpen, reader); + if (!platform.version.equals(deletePlatform) && + !platforms.containsKey(platform.version)) + platforms.put(platform.version, platform); + reader.moveNext(); + break; + default: + throw new IllegalStateException("Unknown key: " + reader.lineKey); + } + } + } + + Map classes = new LinkedHashMap<>(); + Map modules = new LinkedHashMap<>(); + + for (PlatformInput platform : platforms.values()) { + for (ClassDescription cd : classes.values()) { + addNewVersion(cd.header, platform.basePlatform, platform.version); + addNewVersion(cd.fields, platform.basePlatform, platform.version); + addNewVersion(cd.methods, platform.basePlatform, platform.version); + } + for (ModuleDescription md : modules.values()) { + addNewVersion(md.header, platform.basePlatform, platform.version); + } + for (String input : platform.files) { + Path inputFile = platform.ctDescription.getParent().resolve(input); + try (LineBasedReader reader = new LineBasedReader(inputFile)) { + while (reader.hasNext()) { + String nameAttr = reader.attributes.get("name"); + switch (reader.lineKey) { + case "class": case "-class": + ClassDescription cd = + classes.computeIfAbsent(nameAttr, + n -> new ClassDescription()); + if ("-class".equals(reader.lineKey)) { + removeVersion(cd.header, h -> true, + platform.version); + reader.moveNext(); + continue; + } + cd.read(reader, platform.basePlatform, + platform.version); + break; + case "module": { + ModuleDescription md = + modules.computeIfAbsent(nameAttr, + n -> new ModuleDescription()); + md.read(reader, platform.basePlatform, + platform.version); + break; + } + case "-module": { + ModuleDescription md = + modules.computeIfAbsent(nameAttr, + n -> new ModuleDescription()); + removeVersion(md.header, h -> true, + platform.version); + reader.moveNext(); + break; + } + } + } + } + } + } + + ClassList result = new ClassList(); + + for (ClassDescription desc : classes.values()) { + Iterator chdIt = desc.header.iterator(); + + while (chdIt.hasNext()) { + ClassHeaderDescription chd = chdIt.next(); + + chd.versions = reduce(chd.versions, generatePlatforms); + if (chd.versions.isEmpty()) + chdIt.remove(); + } + + if (desc.header.isEmpty()) { + continue; + } + + Iterator methodIt = desc.methods.iterator(); + + while (methodIt.hasNext()) { + MethodDescription method = methodIt.next(); + + method.versions = reduce(method.versions, generatePlatforms); + if (method.versions.isEmpty()) + methodIt.remove(); + } + + Iterator fieldIt = desc.fields.iterator(); + + while (fieldIt.hasNext()) { + FieldDescription field = fieldIt.next(); + + field.versions = reduce(field.versions, generatePlatforms); + if (field.versions.isEmpty()) + fieldIt.remove(); + } + + result.add(desc); + } + + Map moduleList = new HashMap<>(); + + for (ModuleDescription desc : modules.values()) { + Iterator mhdIt = desc.header.iterator(); + + while (mhdIt.hasNext()) { + ModuleHeaderDescription mhd = mhdIt.next(); + + mhd.versions = reduce(mhd.versions, generatePlatforms); + if (mhd.versions.isEmpty()) + mhdIt.remove(); + } + + if (desc.header.isEmpty()) { + continue; + } + + moduleList.put(desc.name, desc); + } + + return new LoadDescriptions(result, moduleList, new ArrayList<>(platforms.values())); + } + + static final class LoadDescriptions { + public final ClassList classes; + public final Map modules; + public final List versions; + + public LoadDescriptions(ClassList classes, + Map modules, + List versions) { + this.classes = classes; + this.modules = modules; + this.versions = versions; + } + + } + + static final class LineBasedReader implements AutoCloseable { + private final BufferedReader input; + public String lineKey; + public Map attributes = new HashMap<>(); + + public LineBasedReader(Path input) throws IOException { + this.input = Files.newBufferedReader(input); + moveNext(); + } + + public void moveNext() throws IOException { + String line = input.readLine(); + + if (line == null) { + lineKey = null; + return ; + } + + if (line.trim().isEmpty() || line.startsWith("#")) { + moveNext(); + return ; + } + + String[] parts = line.split(" "); + + lineKey = parts[0]; + attributes.clear(); + + for (int i = 1; i < parts.length; i += 2) { + attributes.put(parts[i], unquote(parts[i + 1])); + } + } + + public boolean hasNext() { + return lineKey != null; + } + + @Override + public void close() throws IOException { + input.close(); + } + } + + private static String reduce(String original, String other) { + Set otherSet = new HashSet<>(); + + for (char v : other.toCharArray()) { + otherSet.add("" + v); + } + + return reduce(original, otherSet); + } + + private static String reduce(String original, Set generate) { + StringBuilder sb = new StringBuilder(); + + for (char v : original.toCharArray()) { + if (generate.contains("" + v)) { + sb.append(v); + } + } + return sb.toString(); + } + + private static class PlatformInput { + public final String version; + public final String basePlatform; + public final List files; + public final Path ctDescription; + public PlatformInput(Path ctDescription, String version, String basePlatform, List files) { + this.ctDescription = ctDescription; + this.version = version; + this.basePlatform = basePlatform; + this.files = files; + } + + public static PlatformInput load(Path ctDescription, LineBasedReader in) throws IOException { + return new PlatformInput(ctDescription, + in.attributes.get("version"), + in.attributes.get("base"), + List.of(in.attributes.get("files").split(":"))); + } + } + + static void addNewVersion(Collection features, + String baselineVersion, + String version) { + features.stream() + .filter(f -> f.versions.contains(baselineVersion)) + .forEach(f -> f.versions += version); + } + + static void removeVersion(Collection features, + Predicate shouldRemove, + String version) { + for (T existing : features) { + if (shouldRemove.test(existing) && existing.versions.endsWith(version)) { + existing.versions = existing.versions.replace(version, ""); + return; + } + } + } + + /**Changes to class header of an outer class (like adding a new type parameter) may affect + * its innerclasses. So if the outer class's header is different for versions A and B, need to + * split its innerclasses headers to also be different for versions A and B. + */ + static void splitHeaders(ClassList classes) { + Set ctVersions = new HashSet<>(); + + for (ClassDescription cd : classes) { + for (ClassHeaderDescription header : cd.header) { + for (char c : header.versions.toCharArray()) { + ctVersions.add("" + c); + } + } + } + + classes.sort(); + + for (ClassDescription cd : classes) { + Map outerSignatures2Version = new HashMap<>(); + + for (String version : ctVersions) { //XXX + ClassDescription outer = cd; + String outerSignatures = ""; + + while ((outer = classes.enclosingClass(outer)) != null) { + for (ClassHeaderDescription outerHeader : outer.header) { + if (outerHeader.versions.contains(version)) { + outerSignatures += outerHeader.signature; + } + } + } + + outerSignatures2Version.compute(outerSignatures, + (key, value) -> value != null ? value + version : version); + } + + List newHeaders = new ArrayList<>(); + + HEADER_LOOP: for (ClassHeaderDescription header : cd.header) { + for (String versions : outerSignatures2Version.values()) { + if (containsAll(versions, header.versions)) { + newHeaders.add(header); + continue HEADER_LOOP; + } + if (disjoint(versions, header.versions)) { + continue; + } + ClassHeaderDescription newHeader = new ClassHeaderDescription(); + newHeader.classAnnotations = header.classAnnotations; + newHeader.deprecated = header.deprecated; + newHeader.extendsAttr = header.extendsAttr; + newHeader.flags = header.flags; + newHeader.implementsAttr = header.implementsAttr; + newHeader.innerClasses = header.innerClasses; + newHeader.runtimeAnnotations = header.runtimeAnnotations; + newHeader.signature = header.signature; + newHeader.versions = reduce(header.versions, versions); + + newHeaders.add(newHeader); + } + } + + cd.header = newHeaders; + } + } + + void limitJointVersion(Set jointVersions, List features) { + for (FeatureDescription feature : features) { + limitJointVersion(jointVersions, feature.versions); + } + } + + void limitJointVersion(Set jointVersions, String versions) { + for (String version : jointVersions) { + if (!containsAll(versions, version) && + !disjoint(versions, version)) { + StringBuilder featurePart = new StringBuilder(); + StringBuilder otherPart = new StringBuilder(); + for (char v : version.toCharArray()) { + if (versions.indexOf(v) != (-1)) { + featurePart.append(v); + } else { + otherPart.append(v); + } + } + jointVersions.remove(version); + if (featurePart.length() == 0 || otherPart.length() == 0) { + throw new AssertionError(); + } + jointVersions.add(featurePart.toString()); + jointVersions.add(otherPart.toString()); + break; + } + } + } + + private static boolean containsAll(String versions, String subVersions) { + for (char c : subVersions.toCharArray()) { + if (versions.indexOf(c) == (-1)) + return false; + } + return true; + } + + private static boolean disjoint(String version1, String version2) { + for (char c : version2.toCharArray()) { + if (version1.indexOf(c) != (-1)) + return false; + } + return true; + } + + void writeClassesForVersions(String ctSymLocation, + ClassDescription classDescription, + ClassHeaderDescription header, + String module, + Iterable versions) + throws IOException { + for (String ver : versions) { + writeClass(ctSymLocation, classDescription, header, module, ver); + } + } + + void writeModulesForVersions(String ctSymLocation, + ModuleDescription moduleDescription, + ModuleHeaderDescription header, + Iterable versions) + throws IOException { + for (String ver : versions) { + writeModule(ctSymLocation, moduleDescription, header, ver); + } + } + + // + void writeModule(String ctSymLocation, + ModuleDescription moduleDescription, + ModuleHeaderDescription header, + String version) throws IOException { + List constantPool = new ArrayList<>(); + constantPool.add(null); + int currentClass = addClass(constantPool, "module-info"); + int superclass = 0; + int[] interfaces = new int[0]; + AccessFlags flags = new AccessFlags(header.flags); + Map attributesMap = new HashMap<>(); + addAttributes(moduleDescription, header, constantPool, attributesMap); + Attributes attributes = new Attributes(attributesMap); + CPInfo[] cpData = constantPool.toArray(new CPInfo[constantPool.size()]); + ConstantPool cp = new ConstantPool(cpData); + ClassFile classFile = new ClassFile(0xCAFEBABE, + Target.DEFAULT.minorVersion, + Target.DEFAULT.majorVersion, + cp, + flags, + currentClass, + superclass, + interfaces, + new Field[0], + new Method[0], + attributes); + + Path outputClassFile = Paths.get(ctSymLocation, + version, + moduleDescription.name, + "module-info" + EXTENSION); + + Files.createDirectories(outputClassFile.getParent()); + + try (OutputStream out = Files.newOutputStream(outputClassFile)) { + ClassWriter w = new ClassWriter(); + + w.write(classFile, out); + } + } + + void writeClass(String ctSymLocation, + ClassDescription classDescription, + ClassHeaderDescription header, + String module, + String version) throws IOException { + List constantPool = new ArrayList<>(); + constantPool.add(null); + List methods = new ArrayList<>(); + for (MethodDescription methDesc : classDescription.methods) { + if (disjoint(methDesc.versions, version)) + continue; + Descriptor descriptor = new Descriptor(addString(constantPool, methDesc.descriptor)); + //TODO: LinkedHashMap to avoid param annotations vs. Signature problem in javac's ClassReader: + Map attributesMap = new LinkedHashMap<>(); + addAttributes(methDesc, constantPool, attributesMap); + Attributes attributes = new Attributes(attributesMap); + AccessFlags flags = new AccessFlags(methDesc.flags); + int nameString = addString(constantPool, methDesc.name); + methods.add(new Method(flags, nameString, descriptor, attributes)); + } + List fields = new ArrayList<>(); + for (FieldDescription fieldDesc : classDescription.fields) { + if (disjoint(fieldDesc.versions, version)) + continue; + Descriptor descriptor = new Descriptor(addString(constantPool, fieldDesc.descriptor)); + Map attributesMap = new HashMap<>(); + addAttributes(fieldDesc, constantPool, attributesMap); + Attributes attributes = new Attributes(attributesMap); + AccessFlags flags = new AccessFlags(fieldDesc.flags); + int nameString = addString(constantPool, fieldDesc.name); + fields.add(new Field(flags, nameString, descriptor, attributes)); + } + int currentClass = addClass(constantPool, classDescription.name); + int superclass = header.extendsAttr != null ? addClass(constantPool, header.extendsAttr) : 0; + int[] interfaces = new int[header.implementsAttr.size()]; + int i = 0; + for (String intf : header.implementsAttr) { + interfaces[i++] = addClass(constantPool, intf); + } + AccessFlags flags = new AccessFlags(header.flags); + Map attributesMap = new HashMap<>(); + addAttributes(header, constantPool, attributesMap); + Attributes attributes = new Attributes(attributesMap); + ConstantPool cp = new ConstantPool(constantPool.toArray(new CPInfo[constantPool.size()])); + ClassFile classFile = new ClassFile(0xCAFEBABE, + Target.DEFAULT.minorVersion, + Target.DEFAULT.majorVersion, + cp, + flags, + currentClass, + superclass, + interfaces, + fields.toArray(new Field[0]), + methods.toArray(new Method[0]), + attributes); + + Path outputClassFile = Paths.get(ctSymLocation, version); + + if (module != null) { + outputClassFile = outputClassFile.resolve(module); + } + + outputClassFile = outputClassFile.resolve(classDescription.name + EXTENSION); + + Files.createDirectories(outputClassFile.getParent()); + + try (OutputStream out = Files.newOutputStream(outputClassFile)) { + ClassWriter w = new ClassWriter(); + + w.write(classFile, out); + } + } + + private void addAttributes(ModuleDescription md, + ModuleHeaderDescription header, + List cp, + Map attributes) { + addGenericAttributes(header, cp, attributes); + if (header.moduleResolution != null) { + int attrIdx = addString(cp, Attribute.ModuleResolution); + final ModuleResolution_attribute resIdx = + new ModuleResolution_attribute(attrIdx, + header.moduleResolution); + attributes.put(Attribute.ModuleResolution, resIdx); + } + if (header.moduleTarget != null) { + int attrIdx = addString(cp, Attribute.ModuleTarget); + int targetIdx = addString(cp, header.moduleTarget); + attributes.put(Attribute.ModuleTarget, + new ModuleTarget_attribute(attrIdx, targetIdx)); + } + int attrIdx = addString(cp, Attribute.Module); + attributes.put(Attribute.Module, + new Module_attribute(attrIdx, + addModuleName(cp, md.name), + 0, + 0, + header.requires + .stream() + .map(r -> createRequiresEntry(cp, r)) + .collect(Collectors.toList()) + .toArray(new RequiresEntry[0]), + header.exports + .stream() + .map(e -> createExportsEntry(cp, e)) + .collect(Collectors.toList()) + .toArray(new ExportsEntry[0]), + header.opens + .stream() + .map(e -> createOpensEntry(cp, e)) + .collect(Collectors.toList()) + .toArray(new OpensEntry[0]), + header.uses + .stream() + .mapToInt(u -> addClassName(cp, u)) + .toArray(), + header.provides + .stream() + .map(p -> createProvidesEntry(cp, p)) + .collect(Collectors.toList()) + .toArray(new ProvidesEntry[0]))); + addInnerClassesAttribute(header, cp, attributes); + } + + private static RequiresEntry createRequiresEntry(List cp, + RequiresDescription r) { + final int idx = addModuleName(cp, r.moduleName); + return new RequiresEntry(idx, + r.flags, + r.version != null + ? addInt(cp, r.version) + : 0); + } + + private static ExportsEntry createExportsEntry(List cp, + String e) { + return new ExportsEntry(addPackageName(cp, e), 0, new int[0]); + } + + private static OpensEntry createOpensEntry(List cp, String e) { + return new OpensEntry(addPackageName(cp, e), 0, new int[0]); + } + + private static ProvidesEntry createProvidesEntry(List cp, + ModuleHeaderDescription.ProvidesDescription p) { + final int idx = addClassName(cp, p.interfaceName); + return new ProvidesEntry(idx, p.implNames + .stream() + .mapToInt(i -> addClassName(cp, i)) + .toArray()); + } + + private void addAttributes(ClassHeaderDescription header, + List constantPool, Map attributes) { + addGenericAttributes(header, constantPool, attributes); + if (header.nestHost != null) { + int attributeString = addString(constantPool, Attribute.NestHost); + int nestHost = addClass(constantPool, header.nestHost); + attributes.put(Attribute.NestHost, + new NestHost_attribute(attributeString, nestHost)); + } + if (header.nestMembers != null && !header.nestMembers.isEmpty()) { + int attributeString = addString(constantPool, Attribute.NestMembers); + int[] nestMembers = new int[header.nestMembers.size()]; + int i = 0; + for (String intf : header.nestMembers) { + nestMembers[i++] = addClass(constantPool, intf); + } + attributes.put(Attribute.NestMembers, + new NestMembers_attribute(attributeString, nestMembers)); + } + addInnerClassesAttribute(header, constantPool, attributes); + } + + private void addInnerClassesAttribute(HeaderDescription header, + List constantPool, Map attributes) { + if (header.innerClasses != null && !header.innerClasses.isEmpty()) { + Info[] innerClasses = new Info[header.innerClasses.size()]; + int i = 0; + for (InnerClassInfo info : header.innerClasses) { + innerClasses[i++] = + new Info(info.innerClass == null ? 0 : addClass(constantPool, info.innerClass), + info.outerClass == null ? 0 : addClass(constantPool, info.outerClass), + info.innerClassName == null ? 0 : addString(constantPool, info.innerClassName), + new AccessFlags(info.innerClassFlags)); + } + int attributeString = addString(constantPool, Attribute.InnerClasses); + attributes.put(Attribute.InnerClasses, + new InnerClasses_attribute(attributeString, innerClasses)); + } + } + + private void addAttributes(MethodDescription desc, List constantPool, Map attributes) { + addGenericAttributes(desc, constantPool, attributes); + if (desc.thrownTypes != null) { + int[] exceptions = new int[desc.thrownTypes.size()]; + int i = 0; + for (String exc : desc.thrownTypes) { + exceptions[i++] = addClass(constantPool, exc); + } + int attributeString = addString(constantPool, Attribute.Exceptions); + attributes.put(Attribute.Exceptions, + new Exceptions_attribute(attributeString, exceptions)); + } + if (desc.annotationDefaultValue != null) { + int attributeString = addString(constantPool, Attribute.AnnotationDefault); + element_value attributeValue = createAttributeValue(constantPool, + desc.annotationDefaultValue); + attributes.put(Attribute.AnnotationDefault, + new AnnotationDefault_attribute(attributeString, attributeValue)); + } + if (desc.classParameterAnnotations != null && !desc.classParameterAnnotations.isEmpty()) { + int attributeString = + addString(constantPool, Attribute.RuntimeInvisibleParameterAnnotations); + Annotation[][] annotations = + createParameterAnnotations(constantPool, desc.classParameterAnnotations); + attributes.put(Attribute.RuntimeInvisibleParameterAnnotations, + new RuntimeInvisibleParameterAnnotations_attribute(attributeString, + annotations)); + } + if (desc.runtimeParameterAnnotations != null && !desc.runtimeParameterAnnotations.isEmpty()) { + int attributeString = + addString(constantPool, Attribute.RuntimeVisibleParameterAnnotations); + Annotation[][] annotations = + createParameterAnnotations(constantPool, desc.runtimeParameterAnnotations); + attributes.put(Attribute.RuntimeVisibleParameterAnnotations, + new RuntimeVisibleParameterAnnotations_attribute(attributeString, + annotations)); + } + } + + private void addAttributes(FieldDescription desc, List constantPool, Map attributes) { + addGenericAttributes(desc, constantPool, attributes); + if (desc.constantValue != null) { + Pair constantPoolEntry = + addConstant(constantPool, desc.constantValue, false); + Assert.checkNonNull(constantPoolEntry); + int constantValueString = addString(constantPool, Attribute.ConstantValue); + attributes.put(Attribute.ConstantValue, + new ConstantValue_attribute(constantValueString, constantPoolEntry.fst)); + } + } + + private void addGenericAttributes(FeatureDescription desc, List constantPool, Map attributes) { + if (desc.deprecated) { + int attributeString = addString(constantPool, Attribute.Deprecated); + attributes.put(Attribute.Deprecated, + new Deprecated_attribute(attributeString)); + } + if (desc.signature != null) { + int attributeString = addString(constantPool, Attribute.Signature); + int signatureString = addString(constantPool, desc.signature); + attributes.put(Attribute.Signature, + new Signature_attribute(attributeString, signatureString)); + } + if (desc.classAnnotations != null && !desc.classAnnotations.isEmpty()) { + int attributeString = addString(constantPool, Attribute.RuntimeInvisibleAnnotations); + Annotation[] annotations = createAnnotations(constantPool, desc.classAnnotations); + attributes.put(Attribute.RuntimeInvisibleAnnotations, + new RuntimeInvisibleAnnotations_attribute(attributeString, annotations)); + } + if (desc.runtimeAnnotations != null && !desc.runtimeAnnotations.isEmpty()) { + int attributeString = addString(constantPool, Attribute.RuntimeVisibleAnnotations); + Annotation[] annotations = createAnnotations(constantPool, desc.runtimeAnnotations); + attributes.put(Attribute.RuntimeVisibleAnnotations, + new RuntimeVisibleAnnotations_attribute(attributeString, annotations)); + } + } + + private Annotation[] createAnnotations(List constantPool, List desc) { + Annotation[] result = new Annotation[desc.size()]; + int i = 0; + + for (AnnotationDescription ad : desc) { + result[i++] = createAnnotation(constantPool, ad); + } + + return result; + } + + private Annotation[][] createParameterAnnotations(List constantPool, List> desc) { + Annotation[][] result = new Annotation[desc.size()][]; + int i = 0; + + for (List paramAnnos : desc) { + result[i++] = createAnnotations(constantPool, paramAnnos); + } + + return result; + } + + private Annotation createAnnotation(List constantPool, AnnotationDescription desc) { + return new Annotation(null, + addString(constantPool, desc.annotationType), + createElementPairs(constantPool, desc.values)); + } + + private element_value_pair[] createElementPairs(List constantPool, Map annotationAttributes) { + element_value_pair[] pairs = new element_value_pair[annotationAttributes.size()]; + int i = 0; + + for (Entry e : annotationAttributes.entrySet()) { + int elementNameString = addString(constantPool, e.getKey()); + element_value value = createAttributeValue(constantPool, e.getValue()); + pairs[i++] = new element_value_pair(elementNameString, value); + } + + return pairs; + } + + private element_value createAttributeValue(List constantPool, Object value) { + Pair constantPoolEntry = addConstant(constantPool, value, true); + if (constantPoolEntry != null) { + return new Primitive_element_value(constantPoolEntry.fst, constantPoolEntry.snd); + } else if (value instanceof EnumConstant) { + EnumConstant ec = (EnumConstant) value; + return new Enum_element_value(addString(constantPool, ec.type), + addString(constantPool, ec.constant), + 'e'); + } else if (value instanceof ClassConstant) { + ClassConstant cc = (ClassConstant) value; + return new Class_element_value(addString(constantPool, cc.type), 'c'); + } else if (value instanceof AnnotationDescription) { + Annotation annotation = createAnnotation(constantPool, ((AnnotationDescription) value)); + return new Annotation_element_value(annotation, '@'); + } else if (value instanceof Collection) { + @SuppressWarnings("unchecked") + Collection array = (Collection) value; + element_value[] values = new element_value[array.size()]; + int i = 0; + + for (Object elem : array) { + values[i++] = createAttributeValue(constantPool, elem); + } + + return new Array_element_value(values, '['); + } + throw new IllegalStateException(value.getClass().getName()); + } + + private static Pair addConstant(List constantPool, Object value, boolean annotation) { + if (value instanceof Boolean) { + return Pair.of(addToCP(constantPool, new CONSTANT_Integer_info(((Boolean) value) ? 1 : 0)), 'Z'); + } else if (value instanceof Byte) { + return Pair.of(addToCP(constantPool, new CONSTANT_Integer_info((byte) value)), 'B'); + } else if (value instanceof Character) { + return Pair.of(addToCP(constantPool, new CONSTANT_Integer_info((char) value)), 'C'); + } else if (value instanceof Short) { + return Pair.of(addToCP(constantPool, new CONSTANT_Integer_info((short) value)), 'S'); + } else if (value instanceof Integer) { + return Pair.of(addToCP(constantPool, new CONSTANT_Integer_info((int) value)), 'I'); + } else if (value instanceof Long) { + return Pair.of(addToCP(constantPool, new CONSTANT_Long_info((long) value)), 'J'); + } else if (value instanceof Float) { + return Pair.of(addToCP(constantPool, new CONSTANT_Float_info((float) value)), 'F'); + } else if (value instanceof Double) { + return Pair.of(addToCP(constantPool, new CONSTANT_Double_info((double) value)), 'D'); + } else if (value instanceof String) { + int stringIndex = addString(constantPool, (String) value); + if (annotation) { + return Pair.of(stringIndex, 's'); + } else { + return Pair.of(addToCP(constantPool, new CONSTANT_String_info(null, stringIndex)), 's'); + } + } + + return null; + } + + private static int addString(List constantPool, String string) { + Assert.checkNonNull(string); + + int i = 0; + for (CPInfo info : constantPool) { + if (info instanceof CONSTANT_Utf8_info) { + if (((CONSTANT_Utf8_info) info).value.equals(string)) { + return i; + } + } + i++; + } + + return addToCP(constantPool, new CONSTANT_Utf8_info(string)); + } + + private static int addInt(List constantPool, int value) { + int i = 0; + for (CPInfo info : constantPool) { + if (info instanceof CONSTANT_Integer_info) { + if (((CONSTANT_Integer_info) info).value == value) { + return i; + } + } + i++; + } + + return addToCP(constantPool, new CONSTANT_Integer_info(value)); + } + + private static int addModuleName(List constantPool, String moduleName) { + int nameIdx = addString(constantPool, moduleName); + int i = 0; + for (CPInfo info : constantPool) { + if (info instanceof CONSTANT_Module_info) { + if (((CONSTANT_Module_info) info).name_index == nameIdx) { + return i; + } + } + i++; + } + + return addToCP(constantPool, new CONSTANT_Module_info(null, nameIdx)); + } + + private static int addPackageName(List constantPool, String packageName) { + int nameIdx = addString(constantPool, packageName); + int i = 0; + for (CPInfo info : constantPool) { + if (info instanceof CONSTANT_Package_info) { + if (((CONSTANT_Package_info) info).name_index == nameIdx) { + return i; + } + } + i++; + } + + return addToCP(constantPool, new CONSTANT_Package_info(null, nameIdx)); + } + + private static int addClassName(List constantPool, String className) { + int nameIdx = addString(constantPool, className); + int i = 0; + for (CPInfo info : constantPool) { + if (info instanceof CONSTANT_Class_info) { + if (((CONSTANT_Class_info) info).name_index == nameIdx) { + return i; + } + } + i++; + } + + return addToCP(constantPool, new CONSTANT_Class_info(null, nameIdx)); + } + + private static int addToCP(List constantPool, CPInfo entry) { + int result = constantPool.size(); + + constantPool.add(entry); + + if (entry.size() > 1) { + constantPool.add(null); + } + + return result; + } + + private static int addClass(List constantPool, String className) { + int classNameIndex = addString(constantPool, className); + + int i = 0; + for (CPInfo info : constantPool) { + if (info instanceof CONSTANT_Class_info) { + if (((CONSTANT_Class_info) info).name_index == classNameIndex) { + return i; + } + } + i++; + } + + return addToCP(constantPool, new CONSTANT_Class_info(null, classNameIndex)); + } + // + // + + // + public void createBaseLine(List versions, + ExcludeIncludeList excludesIncludes, + Path descDest, + String[] args) throws IOException { + ClassList classes = new ClassList(); + Map modules = new HashMap<>(); + + for (VersionDescription desc : versions) { + List classFileData = new ArrayList<>(); + + try (BufferedReader descIn = + Files.newBufferedReader(Paths.get(desc.classes))) { + String line; + while ((line = descIn.readLine()) != null) { + ByteArrayOutputStream data = new ByteArrayOutputStream(); + for (int i = 0; i < line.length(); i += 2) { + String hex = line.substring(i, i + 2); + data.write(Integer.parseInt(hex, 16)); + } + classFileData.add(data.toByteArray()); + } + } catch (IOException ex) { + throw new IllegalStateException(ex); + } + + loadVersionClasses(classes, modules, classFileData, excludesIncludes, desc.version); + } + + List platforms = + versions.stream() + .map(desc -> new PlatformInput(null, + desc.version, + desc.primaryBaseline, + null)) + .collect(Collectors.toList()); + + dumpDescriptions(classes, modules, platforms, descDest.resolve("symbols"), args); + } + //where: + private static final String DO_NO_MODIFY = + "#\n" + + "# Copyright (c) {YEAR}, Oracle and/or its affiliates. All rights reserved.\n" + + "# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n" + + "#\n" + + "# This code is free software; you can redistribute it and/or modify it\n" + + "# under the terms of the GNU General Public License version 2 only, as\n" + + "# published by the Free Software Foundation. Oracle designates this\n" + + "# particular file as subject to the \"Classpath\" exception as provided\n" + + "# by Oracle in the LICENSE file that accompanied this code.\n" + + "#\n" + + "# This code is distributed in the hope that it will be useful, but WITHOUT\n" + + "# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n" + + "# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\n" + + "# version 2 for more details (a copy is included in the LICENSE file that\n" + + "# accompanied this code).\n" + + "#\n" + + "# You should have received a copy of the GNU General Public License version\n" + + "# 2 along with this work; if not, write to the Free Software Foundation,\n" + + "# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n" + + "#\n" + + "# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n" + + "# or visit www.oracle.com if you need additional information or have any\n" + + "# questions.\n" + + "#\n" + + "# ##########################################################\n" + + "# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ###\n" + + "# ##########################################################\n" + + "#\n"; + + private void loadVersionClasses(ClassList classes, + Map modules, + Iterable classData, + ExcludeIncludeList excludesIncludes, + String version) { + Map currentVersionModules = + new HashMap<>(); + + for (byte[] classFileData : classData) { + try (InputStream in = new ByteArrayInputStream(classFileData)) { + inspectModuleInfoClassFile(in, + currentVersionModules, version); + } catch (IOException | ConstantPoolException ex) { + throw new IllegalStateException(ex); + } + } + + ExcludeIncludeList currentEIList = excludesIncludes; + + if (!currentVersionModules.isEmpty()) { + Set includes = new HashSet<>(); + + for (ModuleDescription md : currentVersionModules.values()) { + md.header.get(0).exports.stream().map(e -> e + '/') + .forEach(includes::add); + } + + currentEIList = new ExcludeIncludeList(includes, + Collections.emptySet()); + } + + ClassList currentVersionClasses = new ClassList(); + + for (byte[] classFileData : classData) { + try (InputStream in = new ByteArrayInputStream(classFileData)) { + inspectClassFile(in, currentVersionClasses, + currentEIList, version); + } catch (IOException | ConstantPoolException ex) { + throw new IllegalStateException(ex); + } + } + + ModuleDescription unsupported = + currentVersionModules.get("jdk.unsupported"); + + if (unsupported != null) { + for (ClassDescription cd : currentVersionClasses.classes) { + if (unsupported.header + .get(0) + .exports + .contains(cd.packge().replace('.', '/'))) { + ClassHeaderDescription ch = cd.header.get(0); + if (ch.classAnnotations == null) { + ch.classAnnotations = new ArrayList<>(); + } + AnnotationDescription ad; + ad = new AnnotationDescription(PROPERITARY_ANNOTATION, + Collections.emptyMap()); + ch.classAnnotations.add(ad); + } + } + } + + Set includedClasses = new HashSet<>(); + boolean modified; + + do { + modified = false; + + for (ClassDescription clazz : currentVersionClasses) { + ClassHeaderDescription header = clazz.header.get(0); + + if (includeEffectiveAccess(currentVersionClasses, clazz)) { + modified |= include(includedClasses, currentVersionClasses, clazz.name); + } + + if (includedClasses.contains(clazz.name)) { + modified |= include(includedClasses, currentVersionClasses, header.extendsAttr); + for (String i : header.implementsAttr) { + modified |= include(includedClasses, currentVersionClasses, i); + } + + modified |= includeOutputType(Collections.singleton(header), + h -> "", + includedClasses, + currentVersionClasses); + modified |= includeOutputType(clazz.fields, + f -> f.descriptor, + includedClasses, + currentVersionClasses); + modified |= includeOutputType(clazz.methods, + m -> m.descriptor, + includedClasses, + currentVersionClasses); + } + } + } while (modified); + + for (ClassDescription clazz : currentVersionClasses) { + if (!includedClasses.contains(clazz.name)) { + continue; + } + + ClassHeaderDescription header = clazz.header.get(0); + + if (header.nestMembers != null) { + Iterator nestMemberIt = header.nestMembers.iterator(); + + while(nestMemberIt.hasNext()) { + String member = nestMemberIt.next(); + if (!includedClasses.contains(member)) + nestMemberIt.remove(); + } + } + + if (header.innerClasses != null) { + Iterator innerClassIt = header.innerClasses.iterator(); + + while(innerClassIt.hasNext()) { + InnerClassInfo ici = innerClassIt.next(); + if (!includedClasses.contains(ici.innerClass)) + innerClassIt.remove(); + } + } + + ClassDescription existing = classes.find(clazz.name, true); + + if (existing != null) { + addClassHeader(existing, header, version); + for (MethodDescription currentMethod : clazz.methods) { + addMethod(existing, currentMethod, version); + } + for (FieldDescription currentField : clazz.fields) { + addField(existing, currentField, version); + } + } else { + classes.add(clazz); + } + } + + for (ModuleDescription module : currentVersionModules.values()) { + ModuleHeaderDescription header = module.header.get(0); + + if (header.innerClasses != null) { + Iterator innerClassIt = + header.innerClasses.iterator(); + + while(innerClassIt.hasNext()) { + InnerClassInfo ici = innerClassIt.next(); + if (!includedClasses.contains(ici.innerClass)) + innerClassIt.remove(); + } + } + + ModuleDescription existing = modules.get(module.name); + + if (existing != null) { + addModuleHeader(existing, header, version); + } else { + modules.put(module.name, module); + } + } + } + //where: + private static final String PROPERITARY_ANNOTATION = + "Lsun/Proprietary+Annotation;"; + + private void dumpDescriptions(ClassList classes, + Map modules, + List versions, + Path ctDescriptionFile, + String[] args) throws IOException { + classes.sort(); + + Map package2Modules = new HashMap<>(); + + versions.stream() + .filter(v -> "9".compareTo(v.version) <= 0) + .sorted((v1, v2) -> v1.version.compareTo(v2.version)) + .forEach(v -> { + for (ModuleDescription md : modules.values()) { + md.header + .stream() + .filter(h -> h.versions.contains(v.version)) + .flatMap(h -> h.exports.stream()) + .map(p -> p.replace('/', '.')) + .forEach(p -> package2Modules.putIfAbsent(p, md.name)); + } + }); + + package2Modules.put("java.awt.dnd.peer", "java.desktop"); + package2Modules.put("java.awt.peer", "java.desktop"); + package2Modules.put("jdk", "java.base"); + + Map> module2Classes = new HashMap<>(); + + for (ClassDescription clazz : classes) { + String pack = clazz.packge(); + String module = package2Modules.get(pack); + + if (module == null) { + module = "java.base"; + + OUTER: while (!pack.isEmpty()) { + for (Entry p2M : package2Modules.entrySet()) { + if (p2M.getKey().startsWith(pack)) { + module = p2M.getValue(); + break OUTER; + } + } + int dot = pack.lastIndexOf('.'); + if (dot == (-1)) + break; + pack = pack.substring(0, dot); + } + } + module2Classes.computeIfAbsent(module, m -> new ArrayList<>()) + .add(clazz); + } + + modules.keySet() + .stream() + .filter(m -> !module2Classes.containsKey(m)) + .forEach(m -> module2Classes.put(m, Collections.emptyList())); + + Files.createDirectories(ctDescriptionFile.getParent()); + + int year = Calendar.getInstance(TimeZone.getTimeZone("UTF"), Locale.ROOT) + .get(Calendar.YEAR); + + try (Writer symbolsOut = Files.newBufferedWriter(ctDescriptionFile)) { + Map> outputFiles = new LinkedHashMap<>(); + + for (PlatformInput desc : versions) { + List files = desc.files; + + if (files == null) { + files = new ArrayList<>(); + for (Entry> e : module2Classes.entrySet()) { + StringWriter data = new StringWriter(); + ModuleDescription module = modules.get(e.getKey()); + + module.write(data, desc.basePlatform, desc.version); + + for (ClassDescription clazz : e.getValue()) { + clazz.write(data, desc.basePlatform, desc.version); + } + + String fileName = e.getKey() + "-" + desc.version + ".sym.txt"; + Path f = ctDescriptionFile.getParent().resolve(fileName); + + String dataString = data.toString(); + + if (!dataString.isEmpty()) { + try (Writer out = Files.newBufferedWriter(f)) { + out.append(DO_NO_MODIFY.replace("{YEAR}", String.valueOf(year))); + out.write(dataString); + } + files.add(f.getFileName().toString()); + } + } + } + + outputFiles.put(desc, files); + } + symbolsOut.append(DO_NO_MODIFY.replace("{YEAR}", "2015, " + year)); + symbolsOut.append("#command used to generate this file:\n"); + symbolsOut.append("#") + .append(CreateSymbols.class.getName()) + .append(" ") + .append(Arrays.stream(args) + .collect(Collectors.joining(" "))) + .append("\n"); + symbolsOut.append("#\n"); + symbolsOut.append("generate platforms ") + .append(versions.stream() + .map(v -> v.version) + .sorted() + .collect(Collectors.joining(":"))) + .append("\n"); + for (Entry> versionFileEntry : outputFiles.entrySet()) { + symbolsOut.append("platform version ") + .append(versionFileEntry.getKey().version); + if (versionFileEntry.getKey().basePlatform != null) { + symbolsOut.append(" base ") + .append(versionFileEntry.getKey().basePlatform); + } + symbolsOut.append(" files ") + .append(versionFileEntry.getValue() + .stream() + .map(p -> p) + .sorted() + .collect(Collectors.joining(":"))) + .append("\n"); + } + } + } + + public void createIncrementalBaseLine(String ctDescriptionFile, + String excludeFile, + String[] args) throws IOException { + String specVersion = System.getProperty("java.specification.version"); + String currentVersion = + Integer.toString(Integer.parseInt(specVersion), Character.MAX_RADIX); + currentVersion = currentVersion.toUpperCase(Locale.ROOT); + Path ctDescriptionPath = Paths.get(ctDescriptionFile).toAbsolutePath(); + LoadDescriptions data = load(null, ctDescriptionPath, currentVersion); + + ClassList classes = data.classes; + Map modules = data.modules; + List versions = data.versions; + + ExcludeIncludeList excludeList = + ExcludeIncludeList.create(excludeFile); + + Iterable classBytes = dumpCurrentClasses(); + loadVersionClasses(classes, modules, classBytes, excludeList, currentVersion); + + String baseline; + + if (versions.isEmpty()) { + baseline = null; + } else { + baseline = versions.stream() + .sorted((v1, v2) -> v2.version.compareTo(v1.version)) + .findFirst() + .get() + .version; + } + + versions.add(new PlatformInput(null, currentVersion, baseline, null)); + dumpDescriptions(classes, modules, versions, ctDescriptionPath, args); + } + + private List dumpCurrentClasses() throws IOException { + JavacTool tool = JavacTool.create(); + Context ctx = new Context(); + String version = System.getProperty("java.specification.version"); + JavacTask task = tool.getTask(null, null, null, + List.of("--release", version), + null, null, ctx); + task.getElements().getTypeElement("java.lang.Object"); + JavaFileManager fm = ctx.get(JavaFileManager.class); + + List data = new ArrayList<>(); + for (Location modLoc : LOCATIONS) { + for (Set module : + fm.listLocationsForModules(modLoc)) { + for (JavaFileManager.Location loc : module) { + Iterable files = + fm.list(loc, + "", + EnumSet.of(Kind.CLASS), + true); + + for (JavaFileObject jfo : files) { + try (InputStream is = jfo.openInputStream(); + InputStream in = + new BufferedInputStream(is)) { + ByteArrayOutputStream baos = + new ByteArrayOutputStream(); + + in.transferTo(baos); + data.add(baos.toByteArray()); + } + } + } + } + } + + return data; + } + //where: + private static final List LOCATIONS = + List.of(StandardLocation.SYSTEM_MODULES, + StandardLocation.UPGRADE_MODULE_PATH); + + // + //non-final for tests: + public static String PROFILE_ANNOTATION = "Ljdk/Profile+Annotation;"; + public static boolean ALLOW_NON_EXISTING_CLASSES = false; + + private void inspectClassFile(InputStream in, ClassList classes, ExcludeIncludeList excludesIncludes, String version) throws IOException, ConstantPoolException { + ClassFile cf = ClassFile.read(in); + + if (cf.access_flags.is(AccessFlags.ACC_MODULE)) { + return ; + } + + if (!excludesIncludes.accepts(cf.getName())) { + return ; + } + + ClassHeaderDescription headerDesc = new ClassHeaderDescription(); + + headerDesc.flags = cf.access_flags.flags; + + if (cf.super_class != 0) { + headerDesc.extendsAttr = cf.getSuperclassName(); + } + List interfaces = new ArrayList<>(); + for (int i = 0; i < cf.interfaces.length; i++) { + interfaces.add(cf.getInterfaceName(i)); + } + headerDesc.implementsAttr = interfaces; + for (Attribute attr : cf.attributes) { + if (!readAttribute(cf, headerDesc, attr)) + return ; + } + + ClassDescription clazzDesc = null; + + for (ClassDescription cd : classes) { + if (cd.name.equals(cf.getName())) { + clazzDesc = cd; + break; + } + } + + if (clazzDesc == null) { + clazzDesc = new ClassDescription(); + clazzDesc.name = cf.getName(); + classes.add(clazzDesc); + } + + addClassHeader(clazzDesc, headerDesc, version); + + for (Method m : cf.methods) { + if (!include(m.access_flags.flags)) + continue; + MethodDescription methDesc = new MethodDescription(); + methDesc.flags = m.access_flags.flags; + methDesc.name = m.getName(cf.constant_pool); + methDesc.descriptor = m.descriptor.getValue(cf.constant_pool); + for (Attribute attr : m.attributes) { + readAttribute(cf, methDesc, attr); + } + addMethod(clazzDesc, methDesc, version); + } + for (Field f : cf.fields) { + if (!include(f.access_flags.flags)) + continue; + FieldDescription fieldDesc = new FieldDescription(); + fieldDesc.flags = f.access_flags.flags; + fieldDesc.name = f.getName(cf.constant_pool); + fieldDesc.descriptor = f.descriptor.getValue(cf.constant_pool); + for (Attribute attr : f.attributes) { + readAttribute(cf, fieldDesc, attr); + } + addField(clazzDesc, fieldDesc, version); + } + } + + private void inspectModuleInfoClassFile(InputStream in, + Map modules, + String version) throws IOException, ConstantPoolException { + ClassFile cf = ClassFile.read(in); + + if (!cf.access_flags.is(AccessFlags.ACC_MODULE)) { + return ; + } + + ModuleHeaderDescription headerDesc = new ModuleHeaderDescription(); + + headerDesc.versions = version; + headerDesc.flags = cf.access_flags.flags; + + for (Attribute attr : cf.attributes) { + if (!readAttribute(cf, headerDesc, attr)) + return ; + } + + String name = headerDesc.name; + + ModuleDescription moduleDesc = modules.get(name); + + if (moduleDesc == null) { + moduleDesc = new ModuleDescription(); + moduleDesc.name = name; + modules.put(moduleDesc.name, moduleDesc); + } + + addModuleHeader(moduleDesc, headerDesc, version); + } + + private void addModuleHeader(ModuleDescription moduleDesc, + ModuleHeaderDescription headerDesc, + String version) { + //normalize: + boolean existed = false; + for (ModuleHeaderDescription existing : moduleDesc.header) { + if (existing.equals(headerDesc)) { + headerDesc = existing; + existed = true; + } + } + + headerDesc.versions += version; + + if (!existed) { + moduleDesc.header.add(headerDesc); + } + } + + private boolean include(int accessFlags) { + return (accessFlags & (AccessFlags.ACC_PUBLIC | AccessFlags.ACC_PROTECTED)) != 0; + } + + private void addClassHeader(ClassDescription clazzDesc, ClassHeaderDescription headerDesc, String version) { + //normalize: + boolean existed = false; + for (ClassHeaderDescription existing : clazzDesc.header) { + if (existing.equals(headerDesc)) { + headerDesc = existing; + existed = true; + } + } + + if (!existed) { + //check if the only difference between the 7 and 8 version is the Profile annotation + //if so, copy it to the pre-8 version, so save space + for (ClassHeaderDescription existing : clazzDesc.header) { + List annots = existing.classAnnotations; + + if (annots != null) { + for (AnnotationDescription ad : annots) { + if (PROFILE_ANNOTATION.equals(ad.annotationType)) { + existing.classAnnotations = new ArrayList<>(annots); + existing.classAnnotations.remove(ad); + if (existing.equals(headerDesc)) { + headerDesc = existing; + existed = true; + } + existing.classAnnotations = annots; + break; + } + } + } + } + } + + headerDesc.versions += version; + + if (!existed) { + clazzDesc.header.add(headerDesc); + } + } + + private void addMethod(ClassDescription clazzDesc, MethodDescription methDesc, String version) { + //normalize: + boolean methodExisted = false; + for (MethodDescription existing : clazzDesc.methods) { + if (existing.equals(methDesc)) { + methodExisted = true; + methDesc = existing; + break; + } + } + methDesc.versions += version; + if (!methodExisted) { + clazzDesc.methods.add(methDesc); + } + } + + private void addField(ClassDescription clazzDesc, FieldDescription fieldDesc, String version) { + boolean fieldExisted = false; + for (FieldDescription existing : clazzDesc.fields) { + if (existing.equals(fieldDesc)) { + fieldExisted = true; + fieldDesc = existing; + break; + } + } + fieldDesc.versions += version; + if (!fieldExisted) { + clazzDesc.fields.add(fieldDesc); + } + } + + private boolean readAttribute(ClassFile cf, FeatureDescription feature, Attribute attr) throws ConstantPoolException { + String attrName = attr.getName(cf.constant_pool); + switch (attrName) { + case Attribute.AnnotationDefault: + assert feature instanceof MethodDescription; + element_value defaultValue = ((AnnotationDefault_attribute) attr).default_value; + ((MethodDescription) feature).annotationDefaultValue = + convertElementValue(cf.constant_pool, defaultValue); + break; + case "Deprecated": + feature.deprecated = true; + break; + case "Exceptions": + assert feature instanceof MethodDescription; + List thrownTypes = new ArrayList<>(); + Exceptions_attribute exceptionAttr = (Exceptions_attribute) attr; + for (int i = 0; i < exceptionAttr.exception_index_table.length; i++) { + thrownTypes.add(exceptionAttr.getException(i, cf.constant_pool)); + } + ((MethodDescription) feature).thrownTypes = thrownTypes; + break; + case Attribute.InnerClasses: + if (feature instanceof ModuleHeaderDescription) + break; //XXX + assert feature instanceof ClassHeaderDescription; + List innerClasses = new ArrayList<>(); + InnerClasses_attribute innerClassesAttr = (InnerClasses_attribute) attr; + for (int i = 0; i < innerClassesAttr.number_of_classes; i++) { + CONSTANT_Class_info outerClassInfo = + innerClassesAttr.classes[i].getOuterClassInfo(cf.constant_pool); + InnerClassInfo info = new InnerClassInfo(); + CONSTANT_Class_info innerClassInfo = + innerClassesAttr.classes[i].getInnerClassInfo(cf.constant_pool); + info.innerClass = innerClassInfo != null ? innerClassInfo.getName() : null; + info.outerClass = outerClassInfo != null ? outerClassInfo.getName() : null; + info.innerClassName = innerClassesAttr.classes[i].getInnerName(cf.constant_pool); + info.innerClassFlags = innerClassesAttr.classes[i].inner_class_access_flags.flags; + innerClasses.add(info); + } + ((ClassHeaderDescription) feature).innerClasses = innerClasses; + break; + case "RuntimeInvisibleAnnotations": + feature.classAnnotations = annotations2Description(cf.constant_pool, attr); + break; + case "RuntimeVisibleAnnotations": + feature.runtimeAnnotations = annotations2Description(cf.constant_pool, attr); + break; + case "Signature": + feature.signature = ((Signature_attribute) attr).getSignature(cf.constant_pool); + break; + case "ConstantValue": + assert feature instanceof FieldDescription; + Object value = convertConstantValue(cf.constant_pool.get(((ConstantValue_attribute) attr).constantvalue_index), ((FieldDescription) feature).descriptor); + if (((FieldDescription) feature).descriptor.equals("C")) { + value = (char) (int) value; + } + ((FieldDescription) feature).constantValue = value; + break; + case "SourceFile": + //ignore, not needed + break; + case "BootstrapMethods": + //ignore, not needed + break; + case "Code": + //ignore, not needed + break; + case "EnclosingMethod": + return false; + case "Synthetic": + break; + case "RuntimeVisibleParameterAnnotations": + assert feature instanceof MethodDescription; + ((MethodDescription) feature).runtimeParameterAnnotations = + parameterAnnotations2Description(cf.constant_pool, attr); + break; + case "RuntimeInvisibleParameterAnnotations": + assert feature instanceof MethodDescription; + ((MethodDescription) feature).classParameterAnnotations = + parameterAnnotations2Description(cf.constant_pool, attr); + break; + case Attribute.Module: { + assert feature instanceof ModuleHeaderDescription; + ModuleHeaderDescription header = + (ModuleHeaderDescription) feature; + Module_attribute mod = (Module_attribute) attr; + + header.name = cf.constant_pool + .getModuleInfo(mod.module_name) + .getName(); + + header.exports = + Arrays.stream(mod.exports) + .filter(ee -> ee.exports_to_count == 0) + .map(ee -> getPackageName(cf, ee.exports_index)) + .collect(Collectors.toList()); + header.requires = + Arrays.stream(mod.requires) + .map(r -> RequiresDescription.create(cf, r)) + .collect(Collectors.toList()); + header.uses = Arrays.stream(mod.uses_index) + .mapToObj(use -> getClassName(cf, use)) + .collect(Collectors.toList()); + header.provides = + Arrays.stream(mod.provides) + .map(p -> ProvidesDescription.create(cf, p)) + .collect(Collectors.toList()); + break; + } + case Attribute.ModuleTarget: { + assert feature instanceof ModuleHeaderDescription; + ModuleHeaderDescription header = + (ModuleHeaderDescription) feature; + ModuleTarget_attribute mod = (ModuleTarget_attribute) attr; + if (mod.target_platform_index != 0) { + header.moduleTarget = + cf.constant_pool + .getUTF8Value(mod.target_platform_index); + } + break; + } + case Attribute.ModuleResolution: { + assert feature instanceof ModuleHeaderDescription; + ModuleHeaderDescription header = + (ModuleHeaderDescription) feature; + ModuleResolution_attribute mod = + (ModuleResolution_attribute) attr; + header.moduleResolution = mod.resolution_flags; + break; + } + case Attribute.ModulePackages: + case Attribute.ModuleHashes: + break; + case Attribute.NestHost: { + assert feature instanceof ClassHeaderDescription; + NestHost_attribute nestHost = (NestHost_attribute) attr; + ClassHeaderDescription chd = (ClassHeaderDescription) feature; + chd.nestHost = nestHost.getNestTop(cf.constant_pool).getName(); + break; + } + case Attribute.NestMembers: { + assert feature instanceof ClassHeaderDescription; + NestMembers_attribute nestMembers = (NestMembers_attribute) attr; + ClassHeaderDescription chd = (ClassHeaderDescription) feature; + chd.nestMembers = Arrays.stream(nestMembers.members_indexes) + .mapToObj(i -> getClassName(cf, i)) + .collect(Collectors.toList()); + break; + } + default: + throw new IllegalStateException("Unhandled attribute: " + + attrName); + } + + return true; + } + + private static String getClassName(ClassFile cf, int idx) { + try { + return cf.constant_pool.getClassInfo(idx).getName(); + } catch (InvalidIndex ex) { + throw new IllegalStateException(ex); + } catch (ConstantPool.UnexpectedEntry ex) { + throw new IllegalStateException(ex); + } catch (ConstantPoolException ex) { + throw new IllegalStateException(ex); + } + } + + private static String getPackageName(ClassFile cf, int idx) { + try { + return cf.constant_pool.getPackageInfo(idx).getName(); + } catch (InvalidIndex ex) { + throw new IllegalStateException(ex); + } catch (ConstantPool.UnexpectedEntry ex) { + throw new IllegalStateException(ex); + } catch (ConstantPoolException ex) { + throw new IllegalStateException(ex); + } + } + + private static String getModuleName(ClassFile cf, int idx) { + try { + return cf.constant_pool.getModuleInfo(idx).getName(); + } catch (InvalidIndex ex) { + throw new IllegalStateException(ex); + } catch (ConstantPool.UnexpectedEntry ex) { + throw new IllegalStateException(ex); + } catch (ConstantPoolException ex) { + throw new IllegalStateException(ex); + } + } + + private static Integer getVersion(ClassFile cf, int idx) { + if (idx == 0) + return null; + try { + return ((CONSTANT_Integer_info) cf.constant_pool.get(idx)).value; + } catch (InvalidIndex ex) { + throw new IllegalStateException(ex); + } + } + + Object convertConstantValue(CPInfo info, String descriptor) throws ConstantPoolException { + if (info instanceof CONSTANT_Integer_info) { + if ("Z".equals(descriptor)) + return ((CONSTANT_Integer_info) info).value == 1; + else + return ((CONSTANT_Integer_info) info).value; + } else if (info instanceof CONSTANT_Long_info) { + return ((CONSTANT_Long_info) info).value; + } else if (info instanceof CONSTANT_Float_info) { + return ((CONSTANT_Float_info) info).value; + } else if (info instanceof CONSTANT_Double_info) { + return ((CONSTANT_Double_info) info).value; + } else if (info instanceof CONSTANT_String_info) { + return ((CONSTANT_String_info) info).getString(); + } + throw new IllegalStateException(info.getClass().getName()); + } + + Object convertElementValue(ConstantPool cp, element_value val) throws InvalidIndex, ConstantPoolException { + switch (val.tag) { + case 'Z': + return ((CONSTANT_Integer_info) cp.get(((Primitive_element_value) val).const_value_index)).value != 0; + case 'B': + return (byte) ((CONSTANT_Integer_info) cp.get(((Primitive_element_value) val).const_value_index)).value; + case 'C': + return (char) ((CONSTANT_Integer_info) cp.get(((Primitive_element_value) val).const_value_index)).value; + case 'S': + return (short) ((CONSTANT_Integer_info) cp.get(((Primitive_element_value) val).const_value_index)).value; + case 'I': + return ((CONSTANT_Integer_info) cp.get(((Primitive_element_value) val).const_value_index)).value; + case 'J': + return ((CONSTANT_Long_info) cp.get(((Primitive_element_value) val).const_value_index)).value; + case 'F': + return ((CONSTANT_Float_info) cp.get(((Primitive_element_value) val).const_value_index)).value; + case 'D': + return ((CONSTANT_Double_info) cp.get(((Primitive_element_value) val).const_value_index)).value; + case 's': + return ((CONSTANT_Utf8_info) cp.get(((Primitive_element_value) val).const_value_index)).value; + + case 'e': + return new EnumConstant(cp.getUTF8Value(((Enum_element_value) val).type_name_index), + cp.getUTF8Value(((Enum_element_value) val).const_name_index)); + case 'c': + return new ClassConstant(cp.getUTF8Value(((Class_element_value) val).class_info_index)); + + case '@': + return annotation2Description(cp, ((Annotation_element_value) val).annotation_value); + + case '[': + List values = new ArrayList<>(); + for (element_value elem : ((Array_element_value) val).values) { + values.add(convertElementValue(cp, elem)); + } + return values; + default: + throw new IllegalStateException("Currently unhandled tag: " + val.tag); + } + } + + private List annotations2Description(ConstantPool cp, Attribute attr) throws ConstantPoolException { + RuntimeAnnotations_attribute annotationsAttr = (RuntimeAnnotations_attribute) attr; + List descs = new ArrayList<>(); + for (Annotation a : annotationsAttr.annotations) { + descs.add(annotation2Description(cp, a)); + } + return descs; + } + + private List> parameterAnnotations2Description(ConstantPool cp, Attribute attr) throws ConstantPoolException { + RuntimeParameterAnnotations_attribute annotationsAttr = + (RuntimeParameterAnnotations_attribute) attr; + List> descs = new ArrayList<>(); + for (Annotation[] attrAnnos : annotationsAttr.parameter_annotations) { + List paramDescs = new ArrayList<>(); + for (Annotation ann : attrAnnos) { + paramDescs.add(annotation2Description(cp, ann)); + } + descs.add(paramDescs); + } + return descs; + } + + private AnnotationDescription annotation2Description(ConstantPool cp, Annotation a) throws ConstantPoolException { + String annotationType = cp.getUTF8Value(a.type_index); + Map values = new HashMap<>(); + + for (element_value_pair e : a.element_value_pairs) { + values.put(cp.getUTF8Value(e.element_name_index), convertElementValue(cp, e.value)); + } + + return new AnnotationDescription(annotationType, values); + } + // + + protected boolean includeEffectiveAccess(ClassList classes, ClassDescription clazz) { + if (!include(clazz.header.get(0).flags)) + return false; + for (ClassDescription outer : classes.enclosingClasses(clazz)) { + if (!include(outer.header.get(0).flags)) + return false; + } + return true; + } + + boolean include(Set includedClasses, ClassList classes, String clazzName) { + if (clazzName == null) + return false; + + boolean modified = includedClasses.add(clazzName); + + for (ClassDescription outer : classes.enclosingClasses(classes.find(clazzName, true))) { + modified |= includedClasses.add(outer.name); + } + + return modified; + } + + boolean includeOutputType(Iterable features, + Function feature2Descriptor, + Set includedClasses, + ClassList classes) { + boolean modified = false; + + for (T feature : features) { + CharSequence sig = + feature.signature != null ? feature.signature : feature2Descriptor.apply(feature); + Matcher m = OUTPUT_TYPE_PATTERN.matcher(sig); + while (m.find()) { + modified |= include(includedClasses, classes, m.group(1)); + } + } + + return modified; + } + + static final Pattern OUTPUT_TYPE_PATTERN = Pattern.compile("L([^;<]+)(;|<)"); + + public static class VersionDescription { + public final String classes; + public final String version; + public final String primaryBaseline; + + public VersionDescription(String classes, String version, String primaryBaseline) { + this.classes = classes; + this.version = version; + this.primaryBaseline = "".equals(primaryBaseline) ? null : primaryBaseline; + } + + } + + public static class ExcludeIncludeList { + public final Set includeList; + public final Set excludeList; + + protected ExcludeIncludeList(Set includeList, Set excludeList) { + this.includeList = includeList; + this.excludeList = excludeList; + } + + public static ExcludeIncludeList create(String files) throws IOException { + Set includeList = new HashSet<>(); + Set excludeList = new HashSet<>(); + for (String file : files.split(File.pathSeparator)) { + try (Stream lines = Files.lines(Paths.get(file))) { + lines.map(l -> l.substring(0, l.indexOf('#') != (-1) ? l.indexOf('#') : l.length())) + .filter(l -> !l.trim().isEmpty()) + .forEach(l -> { + Set target = l.startsWith("+") ? includeList : excludeList; + target.add(l.substring(1)); + }); + } + } + return new ExcludeIncludeList(includeList, excludeList); + } + + public boolean accepts(String className) { + return matches(includeList, className) && !matches(excludeList, className); + } + + private static boolean matches(Set list, String className) { + if (list.contains(className)) + return true; + String pack = className.substring(0, className.lastIndexOf('/') + 1); + return list.contains(pack); + } + } + // + + // + static boolean checkChange(String versions, String version, + String baselineVersion) { + return versions.contains(version) ^ + (baselineVersion != null && + versions.contains(baselineVersion)); + } + + static abstract class FeatureDescription { + int flags; + boolean deprecated; + String signature; + String versions = ""; + List classAnnotations; + List runtimeAnnotations; + + protected void writeAttributes(Appendable output) throws IOException { + if (flags != 0) + output.append(" flags " + Integer.toHexString(flags)); + if (deprecated) { + output.append(" deprecated true"); + } + if (signature != null) { + output.append(" signature " + quote(signature, false)); + } + if (classAnnotations != null && !classAnnotations.isEmpty()) { + output.append(" classAnnotations "); + for (AnnotationDescription a : classAnnotations) { + output.append(quote(a.toString(), false)); + } + } + if (runtimeAnnotations != null && !runtimeAnnotations.isEmpty()) { + output.append(" runtimeAnnotations "); + for (AnnotationDescription a : runtimeAnnotations) { + output.append(quote(a.toString(), false)); + } + } + } + + protected boolean shouldIgnore(String baselineVersion, String version) { + return (!versions.contains(version) && + (baselineVersion == null || !versions.contains(baselineVersion))) || + (baselineVersion != null && + versions.contains(baselineVersion) && versions.contains(version)); + } + + public abstract void write(Appendable output, String baselineVersion, String version) throws IOException; + + protected void readAttributes(LineBasedReader reader) { + String inFlags = reader.attributes.get("flags"); + if (inFlags != null && !inFlags.isEmpty()) { + flags = Integer.parseInt(inFlags, 16); + } + String inDeprecated = reader.attributes.get("deprecated"); + if ("true".equals(inDeprecated)) { + deprecated = true; + } + signature = reader.attributes.get("signature"); + String inClassAnnotations = reader.attributes.get("classAnnotations"); + if (inClassAnnotations != null) { + classAnnotations = parseAnnotations(inClassAnnotations, new int[1]); + } + String inRuntimeAnnotations = reader.attributes.get("runtimeAnnotations"); + if (inRuntimeAnnotations != null) { + runtimeAnnotations = parseAnnotations(inRuntimeAnnotations, new int[1]); + } + } + + public abstract boolean read(LineBasedReader reader) throws IOException; + + @Override + public int hashCode() { + int hash = 3; + hash = 89 * hash + this.flags; + hash = 89 * hash + (this.deprecated ? 1 : 0); + hash = 89 * hash + Objects.hashCode(this.signature); + hash = 89 * hash + listHashCode(this.classAnnotations); + hash = 89 * hash + listHashCode(this.runtimeAnnotations); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final FeatureDescription other = (FeatureDescription) obj; + if (this.flags != other.flags) { + return false; + } + if (this.deprecated != other.deprecated) { + return false; + } + if (!Objects.equals(this.signature, other.signature)) { + return false; + } + if (!listEquals(this.classAnnotations, other.classAnnotations)) { + return false; + } + if (!listEquals(this.runtimeAnnotations, other.runtimeAnnotations)) { + return false; + } + return true; + } + + } + + public static class ModuleDescription { + String name; + List header = new ArrayList<>(); + + public void write(Appendable output, String baselineVersion, + String version) throws IOException { + boolean inBaseline = false; + boolean inVersion = false; + for (ModuleHeaderDescription mhd : header) { + if (baselineVersion != null && + mhd.versions.contains(baselineVersion)) { + inBaseline = true; + } + if (mhd.versions.contains(version)) { + inVersion = true; + } + } + if (!inVersion && !inBaseline) + return ; + if (!inVersion) { + output.append("-module name " + name + "\n\n"); + return; + } + boolean hasChange = hasChange(header, version, baselineVersion); + if (!hasChange) + return; + + output.append("module name " + name + "\n"); + for (ModuleHeaderDescription header : header) { + header.write(output, baselineVersion, version); + } + output.append("\n"); + } + + boolean hasChange(List hasChange, + String version, String baseline) { + return hasChange.stream() + .map(fd -> fd.versions) + .anyMatch(versions -> checkChange(versions, + version, + baseline)); + } + + public void read(LineBasedReader reader, String baselineVersion, + String version) throws IOException { + if (!"module".equals(reader.lineKey)) + return ; + + name = reader.attributes.get("name"); + + reader.moveNext(); + + OUTER: while (reader.hasNext()) { + switch (reader.lineKey) { + case "header": + removeVersion(header, h -> true, version); + ModuleHeaderDescription mhd = + new ModuleHeaderDescription(); + mhd.read(reader); + mhd.name = name; + mhd.versions = version; + header.add(mhd); + break; + case "class": + case "-class": + case "module": + case "-module": + break OUTER; + default: + throw new IllegalStateException(reader.lineKey); + } + } + } + } + + static class ModuleHeaderDescription extends HeaderDescription { + String name; + List exports = new ArrayList<>(); + List opens = new ArrayList<>(); + List requires = new ArrayList<>(); + List uses = new ArrayList<>(); + List provides = new ArrayList<>(); + Integer moduleResolution; + String moduleTarget; + + @Override + public int hashCode() { + int hash = super.hashCode(); + hash = 83 * hash + Objects.hashCode(this.name); + hash = 83 * hash + Objects.hashCode(this.exports); + hash = 83 * hash + Objects.hashCode(this.opens); + hash = 83 * hash + Objects.hashCode(this.requires); + hash = 83 * hash + Objects.hashCode(this.uses); + hash = 83 * hash + Objects.hashCode(this.provides); + hash = 83 * hash + Objects.hashCode(this.moduleResolution); + hash = 83 * hash + Objects.hashCode(this.moduleTarget); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + final ModuleHeaderDescription other = + (ModuleHeaderDescription) obj; + if (!Objects.equals(this.name, other.name)) { + return false; + } + if (!listEquals(this.exports, other.exports)) { + return false; + } + if (!listEquals(this.opens, other.opens)) { + return false; + } + if (!listEquals(this.requires, other.requires)) { + return false; + } + if (!listEquals(this.uses, other.uses)) { + return false; + } + if (!listEquals(this.provides, other.provides)) { + return false; + } + if (!Objects.equals(this.moduleTarget, other.moduleTarget)) { + return false; + } + if (!Objects.equals(this.moduleResolution, + other.moduleResolution)) { + return false; + } + return true; + } + + @Override + public void write(Appendable output, String baselineVersion, + String version) throws IOException { + if (!versions.contains(version) || + (baselineVersion != null && versions.contains(baselineVersion) + && versions.contains(version))) + return ; + output.append("header"); + if (exports != null && !exports.isEmpty()) + output.append(" exports " + serializeList(exports)); + if (opens != null && !opens.isEmpty()) + output.append(" opens " + serializeList(opens)); + if (requires != null && !requires.isEmpty()) { + List requiresList = + requires.stream() + .map(req -> req.serialize()) + .collect(Collectors.toList()); + output.append(" requires " + serializeList(requiresList)); + } + if (uses != null && !uses.isEmpty()) + output.append(" uses " + serializeList(uses)); + if (provides != null && !provides.isEmpty()) { + List providesList = + provides.stream() + .map(p -> p.serialize()) + .collect(Collectors.toList()); + output.append(" provides " + serializeList(providesList)); + } + if (moduleTarget != null) + output.append(" target " + quote(moduleTarget, true)); + if (moduleResolution != null) + output.append(" resolution " + + quote(Integer.toHexString(moduleResolution), + true)); + writeAttributes(output); + output.append("\n"); + writeInnerClasses(output, baselineVersion, version); + } + + private static Map splitAttributes(String data) { + String[] parts = data.split(" "); + + Map attributes = new HashMap<>(); + + for (int i = 0; i < parts.length; i += 2) { + attributes.put(parts[i], unquote(parts[i + 1])); + } + + return attributes; + } + + @Override + public boolean read(LineBasedReader reader) throws IOException { + if (!"header".equals(reader.lineKey)) + return false; + + exports = deserializeList(reader.attributes.get("exports")); + opens = deserializeList(reader.attributes.get("opens")); + List requiresList = + deserializeList(reader.attributes.get("requires")); + requires = requiresList.stream() + .map(RequiresDescription::deserialize) + .collect(Collectors.toList()); + uses = deserializeList(reader.attributes.get("uses")); + List providesList = + deserializeList(reader.attributes.get("provides"), false); + provides = providesList.stream() + .map(ProvidesDescription::deserialize) + .collect(Collectors.toList()); + + moduleTarget = reader.attributes.get("target"); + + if (reader.attributes.containsKey("resolution")) { + final String resolutionFlags = + reader.attributes.get("resolution"); + moduleResolution = Integer.parseInt(resolutionFlags, 16); + } + + readAttributes(reader); + reader.moveNext(); + readInnerClasses(reader); + + return true; + } + + static class RequiresDescription { + final String moduleName; + final int flags; + final Integer version; + + public RequiresDescription(String moduleName, int flags, + Integer version) { + this.moduleName = moduleName; + this.flags = flags; + this.version = version; + } + + public String serialize() { + String versionKeyValue = version != null + ? " version " + quote(String.valueOf(version), true) + : ""; + return "name " + quote(moduleName, true) + + " flags " + quote(Integer.toHexString(flags), true) + + versionKeyValue; + } + + public static RequiresDescription deserialize(String data) { + Map attributes = splitAttributes(data); + + Integer ver = attributes.containsKey("version") + ? Integer.parseInt(attributes.get("version")) + : null; + int flags = Integer.parseInt(attributes.get("flags"), 16); + return new RequiresDescription(attributes.get("name"), + flags, + ver); + } + + public static RequiresDescription create(ClassFile cf, + RequiresEntry req) { + String mod = getModuleName(cf, req.requires_index); + Integer ver = getVersion(cf, req.requires_version_index); + return new RequiresDescription(mod, + req.requires_flags, + ver); + } + + @Override + public int hashCode() { + int hash = 7; + hash = 53 * hash + Objects.hashCode(this.moduleName); + hash = 53 * hash + this.flags; + hash = 53 * hash + Objects.hashCode(this.version); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final RequiresDescription other = (RequiresDescription) obj; + if (this.flags != other.flags) { + return false; + } + if (!Objects.equals(this.moduleName, other.moduleName)) { + return false; + } + if (!Objects.equals(this.version, other.version)) { + return false; + } + return true; + } + + } + + static class ProvidesDescription { + final String interfaceName; + final List implNames; + + public ProvidesDescription(String interfaceName, + List implNames) { + this.interfaceName = interfaceName; + this.implNames = implNames; + } + + public String serialize() { + return "interface " + quote(interfaceName, true) + + " impls " + quote(serializeList(implNames), true, true); + } + + public static ProvidesDescription deserialize(String data) { + Map attributes = splitAttributes(data); + List implsList = + deserializeList(attributes.get("impls"), + false); + return new ProvidesDescription(attributes.get("interface"), + implsList); + } + + public static ProvidesDescription create(ClassFile cf, + ProvidesEntry prov) { + String api = getClassName(cf, prov.provides_index); + List impls = + Arrays.stream(prov.with_index) + .mapToObj(wi -> getClassName(cf, wi)) + .collect(Collectors.toList()); + return new ProvidesDescription(api, impls); + } + + @Override + public int hashCode() { + int hash = 5; + hash = 53 * hash + Objects.hashCode(this.interfaceName); + hash = 53 * hash + Objects.hashCode(this.implNames); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final ProvidesDescription other = (ProvidesDescription) obj; + if (!Objects.equals(this.interfaceName, other.interfaceName)) { + return false; + } + if (!Objects.equals(this.implNames, other.implNames)) { + return false; + } + return true; + } + } + } + + public static class ClassDescription { + String name; + List header = new ArrayList<>(); + List methods = new ArrayList<>(); + List fields = new ArrayList<>(); + + public void write(Appendable output, String baselineVersion, + String version) throws IOException { + boolean inBaseline = false; + boolean inVersion = false; + for (ClassHeaderDescription chd : header) { + if (baselineVersion != null && + chd.versions.contains(baselineVersion)) { + inBaseline = true; + } + if (chd.versions.contains(version)) { + inVersion = true; + } + } + if (!inVersion && !inBaseline) + return ; + if (!inVersion) { + output.append("-class name " + name + "\n\n"); + return; + } + boolean hasChange = hasChange(header, version, baselineVersion) || + hasChange(fields, version, baselineVersion) || + hasChange(methods, version, baselineVersion); + if (!hasChange) + return; + + output.append("class name " + name + "\n"); + for (ClassHeaderDescription header : header) { + header.write(output, baselineVersion, version); + } + for (FieldDescription field : fields) { + field.write(output, baselineVersion, version); + } + for (MethodDescription method : methods) { + method.write(output, baselineVersion, version); + } + output.append("\n"); + } + + boolean hasChange(List hasChange, + String version, + String baseline) { + return hasChange.stream() + .map(fd -> fd.versions) + .anyMatch(versions -> checkChange(versions, + version, + baseline)); + } + + public void read(LineBasedReader reader, String baselineVersion, + String version) throws IOException { + if (!"class".equals(reader.lineKey)) + return ; + + name = reader.attributes.get("name"); + + reader.moveNext(); + + OUTER: while (reader.hasNext()) { + switch (reader.lineKey) { + case "header": + removeVersion(header, h -> true, version); + ClassHeaderDescription chd = new ClassHeaderDescription(); + chd.read(reader); + chd.versions = version; + header.add(chd); + break; + case "field": + FieldDescription field = new FieldDescription(); + field.read(reader); + field.versions += version; + fields.add(field); + break; + case "-field": { + removeVersion(fields, + f -> Objects.equals(f.name, reader.attributes.get("name")) && + Objects.equals(f.descriptor, reader.attributes.get("descriptor")), + version); + reader.moveNext(); + break; + } + case "method": + MethodDescription method = new MethodDescription(); + method.read(reader); + method.versions += version; + methods.add(method); + break; + case "-method": { + removeVersion(methods, + m -> Objects.equals(m.name, reader.attributes.get("name")) && + Objects.equals(m.descriptor, reader.attributes.get("descriptor")), + version); + reader.moveNext(); + break; + } + case "class": + case "-class": + case "module": + case "-module": + break OUTER; + default: + throw new IllegalStateException(reader.lineKey); + } + } + } + + public String packge() { + String pack; + int lastSlash = name.lastIndexOf('/'); + if (lastSlash != (-1)) { + pack = name.substring(0, lastSlash).replace('/', '.'); + } else { + pack = ""; + } + + return pack; + } + } + + static class ClassHeaderDescription extends HeaderDescription { + String extendsAttr; + List implementsAttr; + String nestHost; + List nestMembers; + + @Override + public int hashCode() { + int hash = super.hashCode(); + hash = 17 * hash + Objects.hashCode(this.extendsAttr); + hash = 17 * hash + Objects.hashCode(this.implementsAttr); + hash = 17 * hash + Objects.hashCode(this.nestHost); + hash = 17 * hash + Objects.hashCode(this.nestMembers); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (!super.equals(obj)) { + return false; + } + final ClassHeaderDescription other = (ClassHeaderDescription) obj; + if (!Objects.equals(this.extendsAttr, other.extendsAttr)) { + return false; + } + if (!Objects.equals(this.implementsAttr, other.implementsAttr)) { + return false; + } + if (!Objects.equals(this.nestHost, other.nestHost)) { + return false; + } + if (!listEquals(this.nestMembers, other.nestMembers)) { + return false; + } + return true; + } + + @Override + public void write(Appendable output, String baselineVersion, String version) throws IOException { + if (!versions.contains(version) || + (baselineVersion != null && versions.contains(baselineVersion) && versions.contains(version))) + return ; + output.append("header"); + if (extendsAttr != null) + output.append(" extends " + extendsAttr); + if (implementsAttr != null && !implementsAttr.isEmpty()) + output.append(" implements " + serializeList(implementsAttr)); + if (nestHost != null) + output.append(" nestHost " + nestHost); + if (nestMembers != null && !nestMembers.isEmpty()) + output.append(" nestMembers " + serializeList(nestMembers)); + writeAttributes(output); + output.append("\n"); + writeInnerClasses(output, baselineVersion, version); + } + + @Override + public boolean read(LineBasedReader reader) throws IOException { + if (!"header".equals(reader.lineKey)) + return false; + + extendsAttr = reader.attributes.get("extends"); + String elementsList = reader.attributes.get("implements"); + implementsAttr = deserializeList(elementsList); + + nestHost = reader.attributes.get("nestHost"); + String nestMembersList = reader.attributes.get("nestMembers"); + nestMembers = deserializeList(nestMembersList); + + readAttributes(reader); + reader.moveNext(); + readInnerClasses(reader); + + return true; + } + + } + + static abstract class HeaderDescription extends FeatureDescription { + List innerClasses; + + @Override + public int hashCode() { + int hash = super.hashCode(); + hash = 19 * hash + Objects.hashCode(this.innerClasses); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (!super.equals(obj)) { + return false; + } + final HeaderDescription other = (HeaderDescription) obj; + if (!listEquals(this.innerClasses, other.innerClasses)) { + return false; + } + return true; + } + + protected void writeInnerClasses(Appendable output, + String baselineVersion, + String version) throws IOException { + if (innerClasses != null && !innerClasses.isEmpty()) { + for (InnerClassInfo ici : innerClasses) { + output.append("innerclass"); + output.append(" innerClass " + ici.innerClass); + output.append(" outerClass " + ici.outerClass); + output.append(" innerClassName " + ici.innerClassName); + output.append(" flags " + Integer.toHexString(ici.innerClassFlags)); + output.append("\n"); + } + } + } + + protected void readInnerClasses(LineBasedReader reader) throws IOException { + innerClasses = new ArrayList<>(); + + while ("innerclass".equals(reader.lineKey)) { + InnerClassInfo info = new InnerClassInfo(); + + info.innerClass = reader.attributes.get("innerClass"); + info.outerClass = reader.attributes.get("outerClass"); + info.innerClassName = reader.attributes.get("innerClassName"); + + String inFlags = reader.attributes.get("flags"); + if (inFlags != null && !inFlags.isEmpty()) + info.innerClassFlags = Integer.parseInt(inFlags, 16); + + innerClasses.add(info); + + reader.moveNext(); + } + } + + } + + static class MethodDescription extends FeatureDescription { + String name; + String descriptor; + List thrownTypes; + Object annotationDefaultValue; + List> classParameterAnnotations; + List> runtimeParameterAnnotations; + + @Override + public int hashCode() { + int hash = super.hashCode(); + hash = 59 * hash + Objects.hashCode(this.name); + hash = 59 * hash + Objects.hashCode(this.descriptor); + hash = 59 * hash + Objects.hashCode(this.thrownTypes); + hash = 59 * hash + Objects.hashCode(this.annotationDefaultValue); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (!super.equals(obj)) { + return false; + } + final MethodDescription other = (MethodDescription) obj; + if (!Objects.equals(this.name, other.name)) { + return false; + } + if (!Objects.equals(this.descriptor, other.descriptor)) { + return false; + } + if (!Objects.equals(this.thrownTypes, other.thrownTypes)) { + return false; + } + if (!Objects.equals(this.annotationDefaultValue, other.annotationDefaultValue)) { + return false; + } + return true; + } + + @Override + public void write(Appendable output, String baselineVersion, String version) throws IOException { + if (shouldIgnore(baselineVersion, version)) + return ; + if (!versions.contains(version)) { + output.append("-method"); + output.append(" name " + quote(name, false)); + output.append(" descriptor " + quote(descriptor, false)); + output.append("\n"); + return ; + } + output.append("method"); + output.append(" name " + quote(name, false)); + output.append(" descriptor " + quote(descriptor, false)); + if (thrownTypes != null) + output.append(" thrownTypes " + serializeList(thrownTypes)); + if (annotationDefaultValue != null) + output.append(" annotationDefaultValue " + quote(AnnotationDescription.dumpAnnotationValue(annotationDefaultValue), false)); + writeAttributes(output); + if (classParameterAnnotations != null && !classParameterAnnotations.isEmpty()) { + output.append(" classParameterAnnotations "); + for (List pa : classParameterAnnotations) { + for (AnnotationDescription a : pa) { + output.append(quote(a.toString(), false)); + } + output.append(";"); + } + } + if (runtimeParameterAnnotations != null && !runtimeParameterAnnotations.isEmpty()) { + output.append(" runtimeParameterAnnotations "); + for (List pa : runtimeParameterAnnotations) { + for (AnnotationDescription a : pa) { + output.append(quote(a.toString(), false)); + } + output.append(";"); + } + } + output.append("\n"); + } + + @Override + public boolean read(LineBasedReader reader) throws IOException { + if (!"method".equals(reader.lineKey)) + return false; + + name = reader.attributes.get("name"); + descriptor = reader.attributes.get("descriptor"); + + String thrownTypesValue = reader.attributes.get("thrownTypes"); + + if (thrownTypesValue != null) { + thrownTypes = deserializeList(thrownTypesValue); + } + + String inAnnotationDefaultValue = reader.attributes.get("annotationDefaultValue"); + + if (inAnnotationDefaultValue != null) { + annotationDefaultValue = parseAnnotationValue(inAnnotationDefaultValue, new int[1]); + } + + readAttributes(reader); + + String inClassParamAnnotations = reader.attributes.get("classParameterAnnotations"); + if (inClassParamAnnotations != null) { + List> annos = new ArrayList<>(); + int[] pointer = new int[1]; + do { + annos.add(parseAnnotations(inClassParamAnnotations, pointer)); + assert pointer[0] == inClassParamAnnotations.length() || inClassParamAnnotations.charAt(pointer[0]) == ';'; + } while (++pointer[0] < inClassParamAnnotations.length()); + classParameterAnnotations = annos; + } + + String inRuntimeParamAnnotations = reader.attributes.get("runtimeParameterAnnotations"); + if (inRuntimeParamAnnotations != null) { + List> annos = new ArrayList<>(); + int[] pointer = new int[1]; + do { + annos.add(parseAnnotations(inRuntimeParamAnnotations, pointer)); + assert pointer[0] == inRuntimeParamAnnotations.length() || inRuntimeParamAnnotations.charAt(pointer[0]) == ';'; + } while (++pointer[0] < inRuntimeParamAnnotations.length()); + runtimeParameterAnnotations = annos; + } + + reader.moveNext(); + + return true; + } + + } + + static class FieldDescription extends FeatureDescription { + String name; + String descriptor; + Object constantValue; + + @Override + public int hashCode() { + int hash = super.hashCode(); + hash = 59 * hash + Objects.hashCode(this.name); + hash = 59 * hash + Objects.hashCode(this.descriptor); + hash = 59 * hash + Objects.hashCode(this.constantValue); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (!super.equals(obj)) { + return false; + } + final FieldDescription other = (FieldDescription) obj; + if (!Objects.equals(this.name, other.name)) { + return false; + } + if (!Objects.equals(this.descriptor, other.descriptor)) { + return false; + } + if (!Objects.equals(this.constantValue, other.constantValue)) { + return false; + } + return true; + } + + @Override + public void write(Appendable output, String baselineVersion, String version) throws IOException { + if (shouldIgnore(baselineVersion, version)) + return ; + if (!versions.contains(version)) { + output.append("-field"); + output.append(" name " + quote(name, false)); + output.append(" descriptor " + quote(descriptor, false)); + output.append("\n"); + return ; + } + output.append("field"); + output.append(" name " + name); + output.append(" descriptor " + descriptor); + if (constantValue != null) { + output.append(" constantValue " + quote(constantValue.toString(), false)); + } + writeAttributes(output); + output.append("\n"); + } + + @Override + public boolean read(LineBasedReader reader) throws IOException { + if (!"field".equals(reader.lineKey)) + return false; + + name = reader.attributes.get("name"); + descriptor = reader.attributes.get("descriptor"); + + String inConstantValue = reader.attributes.get("constantValue"); + + if (inConstantValue != null) { + switch (descriptor) { + case "Z": constantValue = "true".equals(inConstantValue); break; + case "B": constantValue = Integer.parseInt(inConstantValue); break; + case "C": constantValue = inConstantValue.charAt(0); break; + case "S": constantValue = Integer.parseInt(inConstantValue); break; + case "I": constantValue = Integer.parseInt(inConstantValue); break; + case "J": constantValue = Long.parseLong(inConstantValue); break; + case "F": constantValue = Float.parseFloat(inConstantValue); break; + case "D": constantValue = Double.parseDouble(inConstantValue); break; + case "Ljava/lang/String;": constantValue = inConstantValue; break; + default: + throw new IllegalStateException("Unrecognized field type: " + descriptor); + } + } + + readAttributes(reader); + + reader.moveNext(); + + return true; + } + + } + + static final class AnnotationDescription { + String annotationType; + Map values; + + public AnnotationDescription(String annotationType, Map values) { + this.annotationType = annotationType; + this.values = values; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 47 * hash + Objects.hashCode(this.annotationType); + hash = 47 * hash + Objects.hashCode(this.values); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final AnnotationDescription other = (AnnotationDescription) obj; + if (!Objects.equals(this.annotationType, other.annotationType)) { + return false; + } + if (!Objects.equals(this.values, other.values)) { + return false; + } + return true; + } + + @Override + public String toString() { + StringBuilder result = new StringBuilder(); + result.append("@" + annotationType); + if (!values.isEmpty()) { + result.append("("); + boolean first = true; + for (Entry e : values.entrySet()) { + if (!first) { + result.append(","); + } + first = false; + result.append(e.getKey()); + result.append("="); + result.append(dumpAnnotationValue(e.getValue())); + result.append(""); + } + result.append(")"); + } + return result.toString(); + } + + private static String dumpAnnotationValue(Object value) { + if (value instanceof List) { + StringBuilder result = new StringBuilder(); + + result.append("{"); + + for (Object element : ((List) value)) { + result.append(dumpAnnotationValue(element)); + } + + result.append("}"); + + return result.toString(); + } + + if (value instanceof String) { + return "\"" + quote((String) value, true) + "\""; + } else if (value instanceof Boolean) { + return "Z" + value; + } else if (value instanceof Byte) { + return "B" + value; + } if (value instanceof Character) { + return "C" + value; + } if (value instanceof Short) { + return "S" + value; + } if (value instanceof Integer) { + return "I" + value; + } if (value instanceof Long) { + return "J" + value; + } if (value instanceof Float) { + return "F" + value; + } if (value instanceof Double) { + return "D" + value; + } else { + return value.toString(); + } + } + } + + static final class EnumConstant { + String type; + String constant; + + public EnumConstant(String type, String constant) { + this.type = type; + this.constant = constant; + } + + @Override + public String toString() { + return "e" + type + constant + ";"; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 19 * hash + Objects.hashCode(this.type); + hash = 19 * hash + Objects.hashCode(this.constant); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final EnumConstant other = (EnumConstant) obj; + if (!Objects.equals(this.type, other.type)) { + return false; + } + if (!Objects.equals(this.constant, other.constant)) { + return false; + } + return true; + } + + } + + static final class ClassConstant { + String type; + + public ClassConstant(String type) { + this.type = type; + } + + @Override + public String toString() { + return "c" + type; + } + + @Override + public int hashCode() { + int hash = 3; + hash = 53 * hash + Objects.hashCode(this.type); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final ClassConstant other = (ClassConstant) obj; + if (!Objects.equals(this.type, other.type)) { + return false; + } + return true; + } + + } + + static final class InnerClassInfo { + String innerClass; + String outerClass; + String innerClassName; + int innerClassFlags; + + @Override + public int hashCode() { + int hash = 3; + hash = 11 * hash + Objects.hashCode(this.innerClass); + hash = 11 * hash + Objects.hashCode(this.outerClass); + hash = 11 * hash + Objects.hashCode(this.innerClassName); + hash = 11 * hash + Objects.hashCode(this.innerClassFlags); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final InnerClassInfo other = (InnerClassInfo) obj; + if (!Objects.equals(this.innerClass, other.innerClass)) { + return false; + } + if (!Objects.equals(this.outerClass, other.outerClass)) { + return false; + } + if (!Objects.equals(this.innerClassName, other.innerClassName)) { + return false; + } + if (!Objects.equals(this.innerClassFlags, other.innerClassFlags)) { + return false; + } + return true; + } + + } + + public static final class ClassList implements Iterable { + private final List classes = new ArrayList<>(); + private final Map name2Class = new HashMap<>(); + private final Map inner2Outter = new HashMap<>(); + + @Override + public Iterator iterator() { + return classes.iterator(); + } + + public void add(ClassDescription desc) { + classes.add(desc); + name2Class.put(desc.name, desc); + } + + public ClassDescription find(String name) { + return find(name, ALLOW_NON_EXISTING_CLASSES); + } + + public ClassDescription find(String name, boolean allowNull) { + ClassDescription desc = name2Class.get(name); + + if (desc != null || allowNull) + return desc; + + throw new IllegalStateException("Cannot find: " + name); + } + + private static final ClassDescription NONE = new ClassDescription(); + + public ClassDescription enclosingClass(ClassDescription clazz) { + if (clazz == null) + return null; + ClassDescription desc = inner2Outter.computeIfAbsent(clazz, c -> { + ClassHeaderDescription header = clazz.header.get(0); + + if (header.innerClasses != null) { + for (InnerClassInfo ici : header.innerClasses) { + if (ici.innerClass.equals(clazz.name)) { + return find(ici.outerClass); + } + } + } + + return NONE; + }); + + return desc != NONE ? desc : null; + } + + public Iterable enclosingClasses(ClassDescription clazz) { + List result = new ArrayList<>(); + ClassDescription outer = enclosingClass(clazz); + + while (outer != null) { + result.add(outer); + outer = enclosingClass(outer); + } + + return result; + } + + public void sort() { + Collections.sort(classes, (cd1, cd2) -> cd1.name.compareTo(cd2.name)); + } + } + + private static int listHashCode(Collection c) { + return c == null || c.isEmpty() ? 0 : c.hashCode(); + } + + private static boolean listEquals(Collection c1, Collection c2) { + if (c1 == c2) return true; + if (c1 == null && c2.isEmpty()) return true; + if (c2 == null && c1.isEmpty()) return true; + return Objects.equals(c1, c2); + } + + private static String serializeList(List list) { + StringBuilder result = new StringBuilder(); + String sep = ""; + + for (Object o : list) { + result.append(sep); + result.append(o); + sep = ","; + } + + return quote(result.toString(), false); + } + + private static List deserializeList(String serialized) { + return deserializeList(serialized, true); + } + + private static List deserializeList(String serialized, + boolean unquote) { + serialized = unquote ? unquote(serialized) : serialized; + if (serialized == null) + return new ArrayList<>(); + return new ArrayList<>(List.of(serialized.split(","))); + } + + private static String quote(String value, boolean quoteQuotes) { + return quote(value, quoteQuotes, false); + } + + private static String quote(String value, boolean quoteQuotes, + boolean quoteCommas) { + StringBuilder result = new StringBuilder(); + + for (char c : value.toCharArray()) { + if (c <= 32 || c >= 127 || c == '\\' || + (quoteQuotes && c == '"') || (quoteCommas && c == ',')) { + result.append("\\u" + String.format("%04X", (int) c) + ";"); + } else { + result.append(c); + } + } + + return result.toString(); + } + + private static final Pattern unicodePattern = + Pattern.compile("\\\\u([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])"); + + private static String unquote(String value) { + if (value == null) + return null; + + StringBuilder result = new StringBuilder(); + Matcher m = unicodePattern.matcher(value); + int lastStart = 0; + + while (m.find(lastStart)) { + result.append(value.substring(lastStart, m.start())); + result.append((char) Integer.parseInt(m.group(1), 16)); + lastStart = m.end() + 1; + } + + result.append(value.substring(lastStart, value.length())); + + return result.toString(); + } + + private static String readDigits(String value, int[] valuePointer) { + int start = valuePointer[0]; + + if (value.charAt(valuePointer[0]) == '-') + valuePointer[0]++; + + while (valuePointer[0] < value.length() && Character.isDigit(value.charAt(valuePointer[0]))) + valuePointer[0]++; + + return value.substring(start, valuePointer[0]); + } + + private static String className(String value, int[] valuePointer) { + int start = valuePointer[0]; + while (value.charAt(valuePointer[0]++) != ';') + ; + return value.substring(start, valuePointer[0]); + } + + private static Object parseAnnotationValue(String value, int[] valuePointer) { + switch (value.charAt(valuePointer[0]++)) { + case 'Z': + if ("true".equals(value.substring(valuePointer[0], valuePointer[0] + 4))) { + valuePointer[0] += 4; + return true; + } else if ("false".equals(value.substring(valuePointer[0], valuePointer[0] + 5))) { + valuePointer[0] += 5; + return false; + } else { + throw new IllegalStateException("Unrecognized boolean structure: " + value); + } + case 'B': return Byte.parseByte(readDigits(value, valuePointer)); + case 'C': return value.charAt(valuePointer[0]++); + case 'S': return Short.parseShort(readDigits(value, valuePointer)); + case 'I': return Integer.parseInt(readDigits(value, valuePointer)); + case 'J': return Long.parseLong(readDigits(value, valuePointer)); + case 'F': return Float.parseFloat(readDigits(value, valuePointer)); + case 'D': return Double.parseDouble(readDigits(value, valuePointer)); + case 'c': + return new ClassConstant(className(value, valuePointer)); + case 'e': + return new EnumConstant(className(value, valuePointer), className(value, valuePointer).replaceFirst(";$", "")); + case '{': + List elements = new ArrayList<>(); //TODO: a good test for this would be highly desirable + while (value.charAt(valuePointer[0]) != '}') { + elements.add(parseAnnotationValue(value, valuePointer)); + } + valuePointer[0]++; + return elements; + case '"': + int start = valuePointer[0]; + while (value.charAt(valuePointer[0]) != '"') + valuePointer[0]++; + return unquote(value.substring(start, valuePointer[0]++)); + case '@': + return parseAnnotation(value, valuePointer); + default: + throw new IllegalStateException("Unrecognized signature type: " + value.charAt(valuePointer[0] - 1) + "; value=" + value); + } + } + + public static List parseAnnotations(String encoded, int[] pointer) { + ArrayList result = new ArrayList<>(); + + while (pointer[0] < encoded.length() && encoded.charAt(pointer[0]) == '@') { + pointer[0]++; + result.add(parseAnnotation(encoded, pointer)); + } + + return result; + } + + private static AnnotationDescription parseAnnotation(String value, int[] valuePointer) { + String className = className(value, valuePointer); + Map attribute2Value = new HashMap<>(); + + if (valuePointer[0] < value.length() && value.charAt(valuePointer[0]) == '(') { + while (value.charAt(valuePointer[0]) != ')') { + int nameStart = ++valuePointer[0]; + + while (value.charAt(valuePointer[0]++) != '='); + + String name = value.substring(nameStart, valuePointer[0] - 1); + + attribute2Value.put(name, parseAnnotationValue(value, valuePointer)); + } + + valuePointer[0]++; + } + + return new AnnotationDescription(className, attribute2Value); + } + // + + private static void help() { + System.err.println("Help..."); + } + + public static void main(String... args) throws IOException { + if (args.length < 1) { + help(); + return ; + } + + switch (args[0]) { + case "build-description": { + if (args.length < 3) { + help(); + return ; + } + + Path descDest = Paths.get(args[1]); + List versions = new ArrayList<>(); + + for (int i = 3; i + 2 < args.length; i += 3) { + versions.add(new VersionDescription(args[i + 1], args[i], args[i + 2])); + } + + Files.walkFileTree(descDest, new FileVisitor() { + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { + return FileVisitResult.CONTINUE; + } + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Files.delete(file); + return FileVisitResult.CONTINUE; + } + @Override + public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { + return FileVisitResult.CONTINUE; + } + @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + Files.delete(dir); + return FileVisitResult.CONTINUE; + } + }); + + ExcludeIncludeList excludeList = + ExcludeIncludeList.create(args[2]); + + new CreateSymbols().createBaseLine(versions, + excludeList, + descDest, + args); + break; + } + case "build-description-incremental": { + if (args.length != 3) { + help(); + return ; + } + + new CreateSymbols().createIncrementalBaseLine(args[1], args[2], args); + break; + } + case "build-ctsym": + String ctDescriptionFileExtra; + String ctDescriptionFile; + String ctSymLocation; + + if (args.length == 3) { + ctDescriptionFileExtra = null; + ctDescriptionFile = args[1]; + ctSymLocation = args[2]; + } else if (args.length == 4) { + ctDescriptionFileExtra = args[1]; + ctDescriptionFile = args[2]; + ctSymLocation = args[3]; + } else { + help(); + return ; + } + + new CreateSymbols().createSymbols(ctDescriptionFileExtra, + ctDescriptionFile, + ctSymLocation); + break; + } + } + +} --- old/make/langtools/src/classes/build/tools/symbolgenerator/Probe.java 2020-03-23 19:57:35.103962270 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.symbolgenerator; - -import java.io.BufferedInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.charset.Charset; -import java.util.EnumSet; - -import javax.tools.JavaCompiler; -import javax.tools.JavaFileObject; -import javax.tools.JavaFileObject.Kind; -import javax.tools.StandardJavaFileManager; -import javax.tools.StandardLocation; -import javax.tools.ToolProvider; - -/**A tool to dump the content of the default javac's bootclasspath. This tool should not use any - * features not available on the oldest supported target JDK, which is currently JDK 6. - * - * For more information on use of this site, please see CreateSymbols. - */ -public class Probe { - - public static void main(String... args) throws IOException { - if (args.length != 1) { - System.err.println("Not enough arguments."); - System.err.println("Usage:"); - System.err.println(" java " + Probe.class.getName() + " "); - return ; - } - - File outFile = new File(args[0]); - Charset cs = Charset.forName("UTF-8"); - JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); - StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null); - OutputStream out = new FileOutputStream(outFile); - - try { - Iterable bcpFiles = - fm.list(StandardLocation.PLATFORM_CLASS_PATH, "", EnumSet.of(Kind.CLASS), true); - - for (JavaFileObject jfo : bcpFiles) { - InputStream in = new BufferedInputStream(jfo.openInputStream()); - try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - StringBuilder textual = new StringBuilder(); - int read; - - while ((read = in.read()) != (-1)) { - baos.write(read); - textual.append(String.format("%02x", read)); - } - - textual.append("\n"); - out.write(textual.toString().getBytes(cs)); - } finally { - in.close(); - } - } - } finally { - out.close(); - } - } - -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.compiler/share/tools/org/openjdk/buildtools/symbolgenerator/Probe.java 2020-03-23 19:57:34.671962273 +0100 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.symbolgenerator; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.Charset; +import java.util.EnumSet; + +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.JavaFileObject.Kind; +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; +import javax.tools.ToolProvider; + +/**A tool to dump the content of the default javac's bootclasspath. This tool should not use any + * features not available on the oldest supported target JDK, which is currently JDK 6. + * + * For more information on use of this site, please see CreateSymbols. + */ +public class Probe { + + public static void main(String... args) throws IOException { + if (args.length != 1) { + System.err.println("Not enough arguments."); + System.err.println("Usage:"); + System.err.println(" java " + Probe.class.getName() + " "); + return ; + } + + File outFile = new File(args[0]); + Charset cs = Charset.forName("UTF-8"); + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null); + OutputStream out = new FileOutputStream(outFile); + + try { + Iterable bcpFiles = + fm.list(StandardLocation.PLATFORM_CLASS_PATH, "", EnumSet.of(Kind.CLASS), true); + + for (JavaFileObject jfo : bcpFiles) { + InputStream in = new BufferedInputStream(jfo.openInputStream()); + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + StringBuilder textual = new StringBuilder(); + int read; + + while ((read = in.read()) != (-1)) { + baos.write(read); + textual.append(String.format("%02x", read)); + } + + textual.append("\n"); + out.write(textual.toString().getBytes(cs)); + } finally { + in.close(); + } + } + } finally { + out.close(); + } + } + +} --- old/make/langtools/src/classes/build/tools/symbolgenerator/ProbeModular.java 2020-03-23 19:57:35.959962264 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.symbolgenerator; - -import com.sun.source.util.JavacTask; -import com.sun.tools.javac.api.JavacTool; -import com.sun.tools.javac.util.Context; -import java.io.BufferedInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.charset.Charset; -import java.util.Arrays; -import java.util.EnumSet; -import java.util.List; -import java.util.Set; - -import javax.tools.JavaFileManager; -import javax.tools.JavaFileManager.Location; -import javax.tools.JavaFileObject; -import javax.tools.JavaFileObject.Kind; -import javax.tools.StandardLocation; - -/**A tool to dump the content of the default javac's bootclasspath. This tool should not use any - * features not available on the oldest supported target JDK, or not available in the boot JDK. - * - * For more information on use of this site, please see CreateSymbols. - */ -public class ProbeModular { - - public static void main(String... args) throws IOException { - if (args.length != 1) { - System.err.println("Not enough arguments."); - System.err.println("Usage:"); - System.err.println(" java " + - ProbeModular.class.getName() + - " "); - return ; - } - - File outFile = new File(args[0]); - Charset cs = Charset.forName("UTF-8"); - JavacTool tool = JavacTool.create(); - Context ctx = new Context(); - String version = System.getProperty("java.specification.version"); - JavacTask task = tool.getTask(null, null, null, - Arrays.asList("--release", version), - null, null, ctx); - task.getElements().getTypeElement("java.lang.Object"); - JavaFileManager fm = ctx.get(JavaFileManager.class); - - try (OutputStream out = new FileOutputStream(outFile)) { - for (Location modLoc : LOCATIONS) { - for (Set module : - fm.listLocationsForModules(modLoc)) { - for (JavaFileManager.Location loc : module) { - Iterable files = - fm.list(loc, - "", - EnumSet.of(Kind.CLASS), - true); - - for (JavaFileObject jfo : files) { - try (InputStream is = jfo.openInputStream(); - InputStream in = - new BufferedInputStream(is)) { - ByteArrayOutputStream baos = - new ByteArrayOutputStream(); - StringBuilder textual = new StringBuilder(); - int read; - - while ((read = in.read()) != (-1)) { - baos.write(read); - String hex = String.format("%02x", read); - textual.append(hex); - } - - textual.append("\n"); - out.write(textual.toString().getBytes(cs)); - } - } - } - } - } - } - } - //where: - private static final List LOCATIONS = - Arrays.asList(StandardLocation.SYSTEM_MODULES, - StandardLocation.UPGRADE_MODULE_PATH); - -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.compiler/share/tools/org/openjdk/buildtools/symbolgenerator/ProbeModular.java 2020-03-23 19:57:35.519962267 +0100 @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.symbolgenerator; + +import com.sun.source.util.JavacTask; +import com.sun.tools.javac.api.JavacTool; +import com.sun.tools.javac.util.Context; +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.List; +import java.util.Set; + +import javax.tools.JavaFileManager; +import javax.tools.JavaFileManager.Location; +import javax.tools.JavaFileObject; +import javax.tools.JavaFileObject.Kind; +import javax.tools.StandardLocation; + +/**A tool to dump the content of the default javac's bootclasspath. This tool should not use any + * features not available on the oldest supported target JDK, or not available in the boot JDK. + * + * For more information on use of this site, please see CreateSymbols. + */ +public class ProbeModular { + + public static void main(String... args) throws IOException { + if (args.length != 1) { + System.err.println("Not enough arguments."); + System.err.println("Usage:"); + System.err.println(" java " + + ProbeModular.class.getName() + + " "); + return ; + } + + File outFile = new File(args[0]); + Charset cs = Charset.forName("UTF-8"); + JavacTool tool = JavacTool.create(); + Context ctx = new Context(); + String version = System.getProperty("java.specification.version"); + JavacTask task = tool.getTask(null, null, null, + Arrays.asList("--release", version), + null, null, ctx); + task.getElements().getTypeElement("java.lang.Object"); + JavaFileManager fm = ctx.get(JavaFileManager.class); + + try (OutputStream out = new FileOutputStream(outFile)) { + for (Location modLoc : LOCATIONS) { + for (Set module : + fm.listLocationsForModules(modLoc)) { + for (JavaFileManager.Location loc : module) { + Iterable files = + fm.list(loc, + "", + EnumSet.of(Kind.CLASS), + true); + + for (JavaFileObject jfo : files) { + try (InputStream is = jfo.openInputStream(); + InputStream in = + new BufferedInputStream(is)) { + ByteArrayOutputStream baos = + new ByteArrayOutputStream(); + StringBuilder textual = new StringBuilder(); + int read; + + while ((read = in.read()) != (-1)) { + baos.write(read); + String hex = String.format("%02x", read); + textual.append(hex); + } + + textual.append("\n"); + out.write(textual.toString().getBytes(cs)); + } + } + } + } + } + } + } + //where: + private static final List LOCATIONS = + Arrays.asList(StandardLocation.SYSTEM_MODULES, + StandardLocation.UPGRADE_MODULE_PATH); + +} --- old/make/langtools/src/classes/build/tools/symbolgenerator/TransitiveDependencies.java 2020-03-23 19:57:36.843962257 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2017, 2018, 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.symbolgenerator; - -import java.io.IOException; -import java.io.PrintWriter; -import java.io.Writer; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayDeque; -import java.util.Arrays; -import java.util.Deque; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.Set; -import java.util.stream.Collectors; - -import javax.lang.model.element.ModuleElement.RequiresDirective; -import javax.lang.model.util.Elements; -import javax.tools.JavaCompiler; - -import com.sun.tools.javac.api.JavacTaskImpl; -import com.sun.tools.javac.api.JavacTool; -import com.sun.tools.javac.code.Source; -import com.sun.tools.javac.code.Symbol.ModuleSymbol; -import com.sun.tools.javac.jvm.Target; - -/** - * Write reflexive transitive closure of the given modules along their requires transitive edges into - * file /system-modules in the specified directory. - */ -public class TransitiveDependencies { - - private static void help() { - System.err.println("java TransitiveDependencies "); - } - - public static void main(String... args) throws IOException { - if (args.length < 2) { - help(); - return ; - } - - JavaCompiler compiler = JavacTool.create(); - List options = List.of("-source", Source.DEFAULT.name, - "-target", Target.DEFAULT.name, - "-proc:only", - "--system", "none", - "--module-source-path", args[1], - "--add-modules", Arrays.stream(args) - .skip(2) - .collect(Collectors.joining(","))); - List jlObjectList = List.of("java.lang.Object"); - JavacTaskImpl task = (JavacTaskImpl) compiler.getTask(null, null, null, options, jlObjectList, null); - task.enter(); - Elements elements = task.getElements(); - Deque todo = new ArrayDeque<>(); - Arrays.stream(args).skip(2).forEach(todo::add); - Set allModules = new HashSet<>(); - - while (!todo.isEmpty()) { - String current = todo.removeFirst(); - - if (!allModules.add(current)) - continue; - - ModuleSymbol mod = (ModuleSymbol) elements.getModuleElement(current); - - if (mod == null) { - throw new IllegalStateException("Missing: " + current); - } - - //use the internal structure to avoid unnecesarily completing the symbol using the UsesProvidesVisitor: - for (RequiresDirective rd : mod.requires) { - if (rd.isTransitive()) { - todo.offerLast(rd.getDependency().getQualifiedName().toString()); - } - } - } - - allModules.add("java.base"); - allModules.add("jdk.unsupported"); - - String version = - Integer.toString(Integer.parseInt(Source.DEFAULT.name), Character.MAX_RADIX); - version = version.toUpperCase(Locale.ROOT); - - Path targetFile = Paths.get(args[0]).resolve(version).resolve("system-modules"); - - Files.createDirectories(targetFile.getParent()); - - try (Writer w = Files.newBufferedWriter(targetFile); - PrintWriter out = new PrintWriter(w)) { - allModules.stream() - .sorted() - .forEach(out::println); - } - } - -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.compiler/share/tools/org/openjdk/buildtools/symbolgenerator/TransitiveDependencies.java 2020-03-23 19:57:36.403962261 +0100 @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.symbolgenerator; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.Writer; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.Deque; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.lang.model.element.ModuleElement.RequiresDirective; +import javax.lang.model.util.Elements; +import javax.tools.JavaCompiler; + +import com.sun.tools.javac.api.JavacTaskImpl; +import com.sun.tools.javac.api.JavacTool; +import com.sun.tools.javac.code.Source; +import com.sun.tools.javac.code.Symbol.ModuleSymbol; +import com.sun.tools.javac.jvm.Target; + +/** + * Write reflexive transitive closure of the given modules along their requires transitive edges into + * file /system-modules in the specified directory. + */ +public class TransitiveDependencies { + + private static void help() { + System.err.println("java TransitiveDependencies "); + } + + public static void main(String... args) throws IOException { + if (args.length < 2) { + help(); + return ; + } + + JavaCompiler compiler = JavacTool.create(); + List options = List.of("-source", Source.DEFAULT.name, + "-target", Target.DEFAULT.name, + "-proc:only", + "--system", "none", + "--module-source-path", args[1], + "--add-modules", Arrays.stream(args) + .skip(2) + .collect(Collectors.joining(","))); + List jlObjectList = List.of("java.lang.Object"); + JavacTaskImpl task = (JavacTaskImpl) compiler.getTask(null, null, null, options, jlObjectList, null); + task.enter(); + Elements elements = task.getElements(); + Deque todo = new ArrayDeque<>(); + Arrays.stream(args).skip(2).forEach(todo::add); + Set allModules = new HashSet<>(); + + while (!todo.isEmpty()) { + String current = todo.removeFirst(); + + if (!allModules.add(current)) + continue; + + ModuleSymbol mod = (ModuleSymbol) elements.getModuleElement(current); + + if (mod == null) { + throw new IllegalStateException("Missing: " + current); + } + + //use the internal structure to avoid unnecesarily completing the symbol using the UsesProvidesVisitor: + for (RequiresDirective rd : mod.requires) { + if (rd.isTransitive()) { + todo.offerLast(rd.getDependency().getQualifiedName().toString()); + } + } + } + + allModules.add("java.base"); + allModules.add("jdk.unsupported"); + + String version = + Integer.toString(Integer.parseInt(Source.DEFAULT.name), Character.MAX_RADIX); + version = version.toUpperCase(Locale.ROOT); + + Path targetFile = Paths.get(args[0]).resolve(version).resolve("system-modules"); + + Files.createDirectories(targetFile.getParent()); + + try (Writer w = Files.newBufferedWriter(targetFile); + PrintWriter out = new PrintWriter(w)) { + allModules.stream() + .sorted() + .forEach(out::println); + } + } + +} --- old/make/jdk/src/classes/build/tools/jdwpgen/AbstractCommandNode.java 2020-03-23 19:57:37.695962251 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,47 +0,0 @@ -/* - * Copyright (c) 1998, 2019, 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.jdwpgen; - -import java.io.*; - -class AbstractCommandNode extends AbstractNamedNode { - - void document(PrintWriter writer) { - writer.println("

    " + name + - " Command (" + nameNode.value() + ")

    "); - writer.println(comment()); - writer.println("
    "); - for (Node node : components) { - node.document(writer); - } - writer.println("
    "); - } - - void documentIndex(PrintWriter writer) { - writer.print("
  • "); - writer.println(name() + " (" + nameNode.value() + ")"); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/AbstractCommandNode.java 2020-03-23 19:57:37.287962254 +0100 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.jdwpgen; + +import java.io.*; + +class AbstractCommandNode extends AbstractNamedNode { + + void document(PrintWriter writer) { + writer.println("

    " + name + + " Command (" + nameNode.value() + ")

    "); + writer.println(comment()); + writer.println("
    "); + for (Node node : components) { + node.document(writer); + } + writer.println("
    "); + } + + void documentIndex(PrintWriter writer) { + writer.print("
  • "); + writer.println(name() + " (" + nameNode.value() + ")"); + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/AbstractGroupNode.java 2020-03-23 19:57:38.555962245 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,112 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.io.*; - -abstract class AbstractGroupNode extends AbstractTypeListNode { - - void document(PrintWriter writer) { - for (Node node : components) { - node.document(writer); - } - } - - String javaType() { - return name(); - } - - void genJava(PrintWriter writer, int depth) { - genJavaClass(writer, depth); - } - - void genJavaWriteMethod(PrintWriter writer, int depth) { - genJavaWriteMethod(writer, depth, "private "); - } - - void genJavaWriteMethod(PrintWriter writer, int depth, String modifier) { - writer.println(); - indent(writer, depth); - writer.print(modifier); - writer.println("void write(PacketStream ps) {"); - genJavaWrites(writer, depth+1); - indent(writer, depth); - writer.println("}"); - } - - void genJavaClassSpecifics(PrintWriter writer, int depth) { - switch (context.state) { - case Context.readingReply: - genJavaReadingClassBody(writer, depth, name()); - break; - - case Context.writingCommand: - genJavaWritingClassBody(writer, depth, name()); - genJavaWriteMethod(writer, depth); - break; - - default: - error("Group in outer"); - break; - } - } - - public void genJavaDeclaration(PrintWriter writer, int depth) { - writer.println(); - genJavaComment(writer, depth); - indent(writer, depth); - writer.print("final "); - writer.print(name()); - writer.print(" a" + name()); - writer.println(";"); - } - - public String javaParam() { - return name() + " a" + name(); - } - - public void genJavaWrite(PrintWriter writer, int depth, - String writeLabel) { - genJavaDebugWrite(writer, depth, writeLabel, "\"\""); - indent(writer, depth); - writer.println(writeLabel + ".write(ps);"); - } - - String javaRead() { - error("Internal - Should not call AbstractGroupNode.javaRead()"); - return ""; - } - - public void genJavaRead(PrintWriter writer, int depth, - String readLabel) { - genJavaDebugRead(writer, depth, readLabel, "\"\""); - indent(writer, depth); - writer.print(readLabel); - writer.print(" = new "); - writer.print(name()); - writer.println("(vm, ps);"); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/AbstractGroupNode.java 2020-03-23 19:57:38.139962248 +0100 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.io.*; + +abstract class AbstractGroupNode extends AbstractTypeListNode { + + void document(PrintWriter writer) { + for (Node node : components) { + node.document(writer); + } + } + + String javaType() { + return name(); + } + + void genJava(PrintWriter writer, int depth) { + genJavaClass(writer, depth); + } + + void genJavaWriteMethod(PrintWriter writer, int depth) { + genJavaWriteMethod(writer, depth, "private "); + } + + void genJavaWriteMethod(PrintWriter writer, int depth, String modifier) { + writer.println(); + indent(writer, depth); + writer.print(modifier); + writer.println("void write(PacketStream ps) {"); + genJavaWrites(writer, depth+1); + indent(writer, depth); + writer.println("}"); + } + + void genJavaClassSpecifics(PrintWriter writer, int depth) { + switch (context.state) { + case Context.readingReply: + genJavaReadingClassBody(writer, depth, name()); + break; + + case Context.writingCommand: + genJavaWritingClassBody(writer, depth, name()); + genJavaWriteMethod(writer, depth); + break; + + default: + error("Group in outer"); + break; + } + } + + public void genJavaDeclaration(PrintWriter writer, int depth) { + writer.println(); + genJavaComment(writer, depth); + indent(writer, depth); + writer.print("final "); + writer.print(name()); + writer.print(" a" + name()); + writer.println(";"); + } + + public String javaParam() { + return name() + " a" + name(); + } + + public void genJavaWrite(PrintWriter writer, int depth, + String writeLabel) { + genJavaDebugWrite(writer, depth, writeLabel, "\"\""); + indent(writer, depth); + writer.println(writeLabel + ".write(ps);"); + } + + String javaRead() { + error("Internal - Should not call AbstractGroupNode.javaRead()"); + return ""; + } + + public void genJavaRead(PrintWriter writer, int depth, + String readLabel) { + genJavaDebugRead(writer, depth, readLabel, "\"\""); + indent(writer, depth); + writer.print(readLabel); + writer.print(" = new "); + writer.print(name()); + writer.println("(vm, ps);"); + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/AbstractNamedNode.java 2020-03-23 19:57:39.387962239 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,107 +0,0 @@ -/* - * Copyright (c) 1998, 2019, 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.jdwpgen; - -import java.util.*; -import java.io.*; - -abstract class AbstractNamedNode extends Node { - - NameNode nameNode = null; - String name; - - public String name() { - return name; - } - - void prune() { - Iterator it = components.iterator(); - - if (it.hasNext()) { - Node nameNode = it.next(); - - if (nameNode instanceof NameNode) { - this.nameNode = (NameNode)nameNode; - this.name = this.nameNode.text(); - it.remove(); - } else { - error("Bad name: " + name); - } - } else { - error("empty"); - } - super.prune(); - } - - void constrain(Context ctx) { - nameNode.constrain(ctx); - super.constrain(ctx.subcontext(name)); - } - - void document(PrintWriter writer) { - writer.println("

    " + name + - " Command Set

    "); - for (Node node : components) { - node.document(writer); - } - } - - String javaClassName() { - return name(); - } - - void genJavaClassSpecifics(PrintWriter writer, int depth) { - } - - String javaClassImplements() { - return ""; // does not implement anything, by default - } - - void genJavaClass(PrintWriter writer, int depth) { - writer.println(); - genJavaComment(writer, depth); - indent(writer, depth); - if (depth != 0) { - writer.print("static "); - } - writer.print("class " + javaClassName()); - writer.println(javaClassImplements() + " {"); - genJavaClassSpecifics(writer, depth+1); - for (Node node : components) { - node.genJava(writer, depth+1); - } - indent(writer, depth); - writer.println("}"); - } - - void genCInclude(PrintWriter writer) { - if (nameNode instanceof NameValueNode) { - writer.println("#define " + context.whereC + - " " + nameNode.value()); - } - super.genCInclude(writer); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/AbstractNamedNode.java 2020-03-23 19:57:38.991962242 +0100 @@ -0,0 +1,107 @@ +/* + * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +abstract class AbstractNamedNode extends Node { + + NameNode nameNode = null; + String name; + + public String name() { + return name; + } + + void prune() { + Iterator it = components.iterator(); + + if (it.hasNext()) { + Node nameNode = it.next(); + + if (nameNode instanceof NameNode) { + this.nameNode = (NameNode)nameNode; + this.name = this.nameNode.text(); + it.remove(); + } else { + error("Bad name: " + name); + } + } else { + error("empty"); + } + super.prune(); + } + + void constrain(Context ctx) { + nameNode.constrain(ctx); + super.constrain(ctx.subcontext(name)); + } + + void document(PrintWriter writer) { + writer.println("

    " + name + + " Command Set

    "); + for (Node node : components) { + node.document(writer); + } + } + + String javaClassName() { + return name(); + } + + void genJavaClassSpecifics(PrintWriter writer, int depth) { + } + + String javaClassImplements() { + return ""; // does not implement anything, by default + } + + void genJavaClass(PrintWriter writer, int depth) { + writer.println(); + genJavaComment(writer, depth); + indent(writer, depth); + if (depth != 0) { + writer.print("static "); + } + writer.print("class " + javaClassName()); + writer.println(javaClassImplements() + " {"); + genJavaClassSpecifics(writer, depth+1); + for (Node node : components) { + node.genJava(writer, depth+1); + } + indent(writer, depth); + writer.println("}"); + } + + void genCInclude(PrintWriter writer) { + if (nameNode instanceof NameValueNode) { + writer.println("#define " + context.whereC + + " " + nameNode.value()); + } + super.genCInclude(writer); + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/AbstractSimpleNode.java 2020-03-23 19:57:40.203962233 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,41 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -abstract class AbstractSimpleNode extends Node { - - AbstractSimpleNode() { - kind = "-simple-"; - components = new ArrayList(); - } - - void document(PrintWriter writer) { - writer.print(toString()); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/AbstractSimpleNode.java 2020-03-23 19:57:39.803962236 +0100 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +abstract class AbstractSimpleNode extends Node { + + AbstractSimpleNode() { + kind = "-simple-"; + components = new ArrayList(); + } + + void document(PrintWriter writer) { + writer.print(toString()); + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/AbstractSimpleTypeNode.java 2020-03-23 19:57:41.015962227 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,39 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; - -abstract class AbstractSimpleTypeNode extends AbstractTypeNode { - - void constrain(Context ctx) { - context = ctx; - nameNode.constrain(ctx); - if (components.size() != 0) { - error("Extraneous content: " + components.get(0)); - } - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/AbstractSimpleTypeNode.java 2020-03-23 19:57:40.619962230 +0100 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; + +abstract class AbstractSimpleTypeNode extends AbstractTypeNode { + + void constrain(Context ctx) { + context = ctx; + nameNode.constrain(ctx); + if (components.size() != 0) { + error("Extraneous content: " + components.get(0)); + } + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/AbstractTypeListNode.java 2020-03-23 19:57:41.863962220 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,123 +0,0 @@ -/* - * Copyright (c) 1998, 2018, 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.jdwpgen; - -import java.util.*; -import java.io.*; - -abstract class AbstractTypeListNode extends AbstractNamedNode { - - void constrainComponent(Context ctx, Node node) { - if (node instanceof TypeNode) { - node.constrain(ctx); - } else { - error("Expected type descriptor item, got: " + node); - } - } - - void document(PrintWriter writer) { - writer.println("
    " + name() + " Data"); - writer.println("
    "); - if (components.isEmpty()) { - writer.println("(None)"); - } else { - writer.println(""); - writer.println(""); - for (Node node : components) { - node.document(writer); - } - writer.println("
    Type"); - writer.println("Name"); - writer.println("Description"); - writer.println("
    "); - } - writer.println("
    "); - } - - void genJavaClassBodyComponents(PrintWriter writer, int depth) { - for (Node node : components) { - TypeNode tn = (TypeNode)node; - - tn.genJavaDeclaration(writer, depth); - } - } - - void genJavaReads(PrintWriter writer, int depth) { - for (Node node : components) { - TypeNode tn = (TypeNode)node; - tn.genJavaRead(writer, depth, tn.name()); - } - } - - void genJavaReadingClassBody(PrintWriter writer, int depth, - String className) { - genJavaClassBodyComponents(writer, depth); - writer.println(); - indent(writer, depth); - if (!context.inEvent()) { - writer.print("private "); - } - writer.println(className + - "(VirtualMachineImpl vm, PacketStream ps) {"); - genJavaReads(writer, depth+1); - indent(writer, depth); - writer.println("}"); - } - - String javaParams() { - StringBuffer sb = new StringBuffer(); - for (Iterator it = components.iterator(); it.hasNext();) { - TypeNode tn = (TypeNode)it.next(); - sb.append(tn.javaParam()); - if (it.hasNext()) { - sb.append(", "); - } - } - return sb.toString(); - } - - void genJavaWrites(PrintWriter writer, int depth) { - for (Node node : components) { - TypeNode tn = (TypeNode)node; - tn.genJavaWrite(writer, depth, tn.name()); - } - } - - void genJavaWritingClassBody(PrintWriter writer, int depth, - String className) { - genJavaClassBodyComponents(writer, depth); - writer.println(); - indent(writer, depth); - writer.println(className + "(" + javaParams() + ") {"); - for (Node node : components) { - TypeNode tn = (TypeNode)node; - indent(writer, depth+1); - writer.println("this." + tn.name() + " = " + tn.name() + ";"); - } - indent(writer, depth); - writer.println("}"); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/AbstractTypeListNode.java 2020-03-23 19:57:41.427962224 +0100 @@ -0,0 +1,123 @@ +/* + * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +abstract class AbstractTypeListNode extends AbstractNamedNode { + + void constrainComponent(Context ctx, Node node) { + if (node instanceof TypeNode) { + node.constrain(ctx); + } else { + error("Expected type descriptor item, got: " + node); + } + } + + void document(PrintWriter writer) { + writer.println("
    " + name() + " Data"); + writer.println("
    "); + if (components.isEmpty()) { + writer.println("(None)"); + } else { + writer.println(""); + writer.println(""); + for (Node node : components) { + node.document(writer); + } + writer.println("
    Type"); + writer.println("Name"); + writer.println("Description"); + writer.println("
    "); + } + writer.println("
    "); + } + + void genJavaClassBodyComponents(PrintWriter writer, int depth) { + for (Node node : components) { + TypeNode tn = (TypeNode)node; + + tn.genJavaDeclaration(writer, depth); + } + } + + void genJavaReads(PrintWriter writer, int depth) { + for (Node node : components) { + TypeNode tn = (TypeNode)node; + tn.genJavaRead(writer, depth, tn.name()); + } + } + + void genJavaReadingClassBody(PrintWriter writer, int depth, + String className) { + genJavaClassBodyComponents(writer, depth); + writer.println(); + indent(writer, depth); + if (!context.inEvent()) { + writer.print("private "); + } + writer.println(className + + "(VirtualMachineImpl vm, PacketStream ps) {"); + genJavaReads(writer, depth+1); + indent(writer, depth); + writer.println("}"); + } + + String javaParams() { + StringBuffer sb = new StringBuffer(); + for (Iterator it = components.iterator(); it.hasNext();) { + TypeNode tn = (TypeNode)it.next(); + sb.append(tn.javaParam()); + if (it.hasNext()) { + sb.append(", "); + } + } + return sb.toString(); + } + + void genJavaWrites(PrintWriter writer, int depth) { + for (Node node : components) { + TypeNode tn = (TypeNode)node; + tn.genJavaWrite(writer, depth, tn.name()); + } + } + + void genJavaWritingClassBody(PrintWriter writer, int depth, + String className) { + genJavaClassBodyComponents(writer, depth); + writer.println(); + indent(writer, depth); + writer.println(className + "(" + javaParams() + ") {"); + for (Node node : components) { + TypeNode tn = (TypeNode)node; + indent(writer, depth+1); + writer.println("this." + tn.name() + " = " + tn.name() + ";"); + } + indent(writer, depth); + writer.println("}"); + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/AbstractTypeNode.java 2020-03-23 19:57:42.747962214 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,77 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - - -import java.util.*; -import java.io.*; - -abstract class AbstractTypeNode extends AbstractNamedNode - implements TypeNode { - - abstract String docType(); - - public abstract void genJavaWrite(PrintWriter writer, int depth, - String writeLabel); - - abstract String javaRead(); - - void document(PrintWriter writer) { - writer.println(""); - writer.println("" + indentElement(structIndent, docType())); - writer.println("" + name() + ""); - writer.println("" + comment() + " "); - writer.println(""); - } - - String javaType() { - return docType(); // default - } - - public void genJavaRead(PrintWriter writer, int depth, - String readLabel) { - indent(writer, depth); - writer.print(readLabel); - writer.print(" = "); - writer.print(javaRead()); - writer.println(";"); - genJavaDebugRead(writer, depth, readLabel, debugValue(readLabel)); - } - - public void genJavaDeclaration(PrintWriter writer, int depth) { - writer.println(); - genJavaComment(writer, depth); - indent(writer, depth); - writer.print("final "); - writer.print(javaType()); - writer.print(" " + name); - writer.println(";"); - } - - public String javaParam() { - return javaType() + " " + name; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/AbstractTypeNode.java 2020-03-23 19:57:42.311962217 +0100 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + + +import java.util.*; +import java.io.*; + +abstract class AbstractTypeNode extends AbstractNamedNode + implements TypeNode { + + abstract String docType(); + + public abstract void genJavaWrite(PrintWriter writer, int depth, + String writeLabel); + + abstract String javaRead(); + + void document(PrintWriter writer) { + writer.println(""); + writer.println("" + indentElement(structIndent, docType())); + writer.println("" + name() + ""); + writer.println("" + comment() + " "); + writer.println(""); + } + + String javaType() { + return docType(); // default + } + + public void genJavaRead(PrintWriter writer, int depth, + String readLabel) { + indent(writer, depth); + writer.print(readLabel); + writer.print(" = "); + writer.print(javaRead()); + writer.println(";"); + genJavaDebugRead(writer, depth, readLabel, debugValue(readLabel)); + } + + public void genJavaDeclaration(PrintWriter writer, int depth) { + writer.println(); + genJavaComment(writer, depth); + indent(writer, depth); + writer.print("final "); + writer.print(javaType()); + writer.print(" " + name); + writer.println(";"); + } + + public String javaParam() { + return javaType() + " " + name; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/AltNode.java 2020-03-23 19:57:43.603962208 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,117 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class AltNode extends AbstractGroupNode implements TypeNode { - - SelectNode select = null; - - void constrain(Context ctx) { - super.constrain(ctx); - - if (!(nameNode instanceof NameValueNode)) { - error("Alt name must have value: " + nameNode); - } - if (parent instanceof SelectNode) { - select = (SelectNode)parent; - } else { - error("Alt must be in Select"); - } - } - - void document(PrintWriter writer) { - writer.println(""); - writer.println("" - + indentElement(structIndent, - "Case " + nameNode.name - + " - if " + ((SelectNode)parent).typeNode.name + "" + - " is " + nameNode.value() + ":")); - writer.println("" + comment() + " "); - writer.println(""); - - ++structIndent; - super.document(writer); - --structIndent; - } - - String javaClassImplements() { - return " extends " + select.commonBaseClass(); - } - - void genJavaClassSpecifics(PrintWriter writer, int depth) { - indent(writer, depth); - writer.print("static final " + select.typeNode.javaType()); - writer.println(" ALT_ID = " + nameNode.value() + ";"); - if (context.isWritingCommand()) { - genJavaCreateMethod(writer, depth); - } else { - indent(writer, depth); - writer.println(select.typeNode.javaParam() + "() {"); - indent(writer, depth+1); - writer.println("return ALT_ID;"); - indent(writer, depth); - writer.println("}"); - } - super.genJavaClassSpecifics(writer, depth); - } - - void genJavaWriteMethod(PrintWriter writer, int depth) { - genJavaWriteMethod(writer, depth, ""); - } - - void genJavaReadsSelectCase(PrintWriter writer, int depth, String common) { - indent(writer, depth); - writer.println("case " + nameNode.value() + ":"); - indent(writer, depth+1); - writer.println(common + " = new " + name + "(vm, ps);"); - indent(writer, depth+1); - writer.println("break;"); - } - - void genJavaCreateMethod(PrintWriter writer, int depth) { - indent(writer, depth); - writer.print("static " + select.name() + " create("); - writer.print(javaParams()); - writer.println(") {"); - indent(writer, depth+1); - writer.print("return new " + select.name() + "("); - writer.print("ALT_ID, new " + javaClassName() + "("); - for (Iterator it = components.iterator(); it.hasNext();) { - TypeNode tn = (TypeNode)it.next(); - writer.print(tn.name()); - if (it.hasNext()) { - writer.print(", "); - } - } - writer.println("));"); - indent(writer, depth); - writer.println("}"); - } - -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/AltNode.java 2020-03-23 19:57:43.195962211 +0100 @@ -0,0 +1,117 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class AltNode extends AbstractGroupNode implements TypeNode { + + SelectNode select = null; + + void constrain(Context ctx) { + super.constrain(ctx); + + if (!(nameNode instanceof NameValueNode)) { + error("Alt name must have value: " + nameNode); + } + if (parent instanceof SelectNode) { + select = (SelectNode)parent; + } else { + error("Alt must be in Select"); + } + } + + void document(PrintWriter writer) { + writer.println(""); + writer.println("" + + indentElement(structIndent, + "Case " + nameNode.name + + " - if " + ((SelectNode)parent).typeNode.name + "" + + " is " + nameNode.value() + ":")); + writer.println("" + comment() + " "); + writer.println(""); + + ++structIndent; + super.document(writer); + --structIndent; + } + + String javaClassImplements() { + return " extends " + select.commonBaseClass(); + } + + void genJavaClassSpecifics(PrintWriter writer, int depth) { + indent(writer, depth); + writer.print("static final " + select.typeNode.javaType()); + writer.println(" ALT_ID = " + nameNode.value() + ";"); + if (context.isWritingCommand()) { + genJavaCreateMethod(writer, depth); + } else { + indent(writer, depth); + writer.println(select.typeNode.javaParam() + "() {"); + indent(writer, depth+1); + writer.println("return ALT_ID;"); + indent(writer, depth); + writer.println("}"); + } + super.genJavaClassSpecifics(writer, depth); + } + + void genJavaWriteMethod(PrintWriter writer, int depth) { + genJavaWriteMethod(writer, depth, ""); + } + + void genJavaReadsSelectCase(PrintWriter writer, int depth, String common) { + indent(writer, depth); + writer.println("case " + nameNode.value() + ":"); + indent(writer, depth+1); + writer.println(common + " = new " + name + "(vm, ps);"); + indent(writer, depth+1); + writer.println("break;"); + } + + void genJavaCreateMethod(PrintWriter writer, int depth) { + indent(writer, depth); + writer.print("static " + select.name() + " create("); + writer.print(javaParams()); + writer.println(") {"); + indent(writer, depth+1); + writer.print("return new " + select.name() + "("); + writer.print("ALT_ID, new " + javaClassName() + "("); + for (Iterator it = components.iterator(); it.hasNext();) { + TypeNode tn = (TypeNode)it.next(); + writer.print(tn.name()); + if (it.hasNext()) { + writer.print(", "); + } + } + writer.println("));"); + indent(writer, depth); + writer.println("}"); + } + +} --- old/make/jdk/src/classes/build/tools/jdwpgen/ArrayObjectTypeNode.java 2020-03-23 19:57:44.499962201 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,43 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; - -class ArrayObjectTypeNode extends ObjectTypeNode { - - String docType() { - return "arrayID"; - } - - String javaType() { - return "ArrayReferenceImpl"; - } - - String javaRead() { - return "ps.readArrayReference()"; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/ArrayObjectTypeNode.java 2020-03-23 19:57:44.047962204 +0100 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; + +class ArrayObjectTypeNode extends ObjectTypeNode { + + String docType() { + return "arrayID"; + } + + String javaType() { + return "ArrayReferenceImpl"; + } + + String javaRead() { + return "ps.readArrayReference()"; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/ArrayRegionTypeNode.java 2020-03-23 19:57:45.347962195 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,49 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class ArrayRegionTypeNode extends AbstractSimpleTypeNode { - - String docType() { - return "arrayregion"; - } - - String javaType() { - return "List"; - } - - public void genJavaWrite(PrintWriter writer, int depth, - String writeLabel) { - error("Not implemented"); - } - - String javaRead() { - return "ps.readArrayRegion()"; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/ArrayRegionTypeNode.java 2020-03-23 19:57:44.911962198 +0100 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class ArrayRegionTypeNode extends AbstractSimpleTypeNode { + + String docType() { + return "arrayregion"; + } + + String javaType() { + return "List"; + } + + public void genJavaWrite(PrintWriter writer, int depth, + String writeLabel) { + error("Not implemented"); + } + + String javaRead() { + return "ps.readArrayRegion()"; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/ArrayTypeNode.java 2020-03-23 19:57:46.195962188 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,43 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; - -class ArrayTypeNode extends ReferenceTypeNode { - - String docType() { - return "arrayTypeID"; - } - - String javaType() { - return "ArrayTypeImpl"; - } - - String javaRead() { - return "--- should not get generated ---"; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/ArrayTypeNode.java 2020-03-23 19:57:45.759962192 +0100 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; + +class ArrayTypeNode extends ReferenceTypeNode { + + String docType() { + return "arrayTypeID"; + } + + String javaType() { + return "ArrayTypeImpl"; + } + + String javaRead() { + return "--- should not get generated ---"; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/BooleanTypeNode.java 2020-03-23 19:57:47.047962182 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,47 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class BooleanTypeNode extends AbstractSimpleTypeNode { - - String docType() { - return "boolean"; - } - - public void genJavaWrite(PrintWriter writer, int depth, - String writeLabel) { - genJavaDebugWrite(writer, depth, writeLabel); - indent(writer, depth); - writer.println("ps.writeBoolean(" + writeLabel + ");"); - } - - String javaRead() { - return "ps.readBoolean()"; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/BooleanTypeNode.java 2020-03-23 19:57:46.639962185 +0100 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class BooleanTypeNode extends AbstractSimpleTypeNode { + + String docType() { + return "boolean"; + } + + public void genJavaWrite(PrintWriter writer, int depth, + String writeLabel) { + genJavaDebugWrite(writer, depth, writeLabel); + indent(writer, depth); + writer.println("ps.writeBoolean(" + writeLabel + ");"); + } + + String javaRead() { + return "ps.readBoolean()"; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/ByteTypeNode.java 2020-03-23 19:57:47.899962176 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,47 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class ByteTypeNode extends AbstractSimpleTypeNode { - - String docType() { - return "byte"; - } - - public void genJavaWrite(PrintWriter writer, int depth, - String writeLabel) { - genJavaDebugWrite(writer, depth, writeLabel); - indent(writer, depth); - writer.println("ps.writeByte(" + writeLabel + ");"); - } - - String javaRead() { - return "ps.readByte()"; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/ByteTypeNode.java 2020-03-23 19:57:47.491962179 +0100 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class ByteTypeNode extends AbstractSimpleTypeNode { + + String docType() { + return "byte"; + } + + public void genJavaWrite(PrintWriter writer, int depth, + String writeLabel) { + genJavaDebugWrite(writer, depth, writeLabel); + indent(writer, depth); + writer.println("ps.writeByte(" + writeLabel + ");"); + } + + String javaRead() { + return "ps.readByte()"; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/ClassLoaderObjectTypeNode.java 2020-03-23 19:57:48.699962170 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,43 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; - -class ClassLoaderObjectTypeNode extends ObjectTypeNode { - - String docType() { - return "classLoaderID"; - } - - String javaType() { - return "ClassLoaderReferenceImpl"; - } - - String javaRead() { - return "ps.readClassLoaderReference()"; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/ClassLoaderObjectTypeNode.java 2020-03-23 19:57:48.279962173 +0100 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; + +class ClassLoaderObjectTypeNode extends ObjectTypeNode { + + String docType() { + return "classLoaderID"; + } + + String javaType() { + return "ClassLoaderReferenceImpl"; + } + + String javaRead() { + return "ps.readClassLoaderReference()"; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/ClassObjectTypeNode.java 2020-03-23 19:57:49.515962164 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,43 +0,0 @@ -/* - * Copyright (c) 1999, 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 build.tools.jdwpgen; - -import java.util.*; - -class ClassObjectTypeNode extends ObjectTypeNode { - - String docType() { - return "classObjectID"; - } - - String javaType() { - return "ClassObjectReferenceImpl"; - } - - String javaRead() { - return "ps.readClassObjectReference()"; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/ClassObjectTypeNode.java 2020-03-23 19:57:49.119962167 +0100 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 1999, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; + +class ClassObjectTypeNode extends ObjectTypeNode { + + String docType() { + return "classObjectID"; + } + + String javaType() { + return "ClassObjectReferenceImpl"; + } + + String javaRead() { + return "ps.readClassObjectReference()"; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/ClassTypeNode.java 2020-03-23 19:57:50.395962157 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,43 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; - -class ClassTypeNode extends ReferenceTypeNode { - - String docType() { - return "classID"; - } - - String javaType() { - return "ClassTypeImpl"; - } - - String javaRead() { - return "vm.classType(ps.readClassRef())"; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/ClassTypeNode.java 2020-03-23 19:57:49.963962161 +0100 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; + +class ClassTypeNode extends ReferenceTypeNode { + + String docType() { + return "classID"; + } + + String javaType() { + return "ClassTypeImpl"; + } + + String javaRead() { + return "vm.classType(ps.readClassRef())"; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/CommandNode.java 2020-03-23 19:57:51.183962152 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,67 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class CommandNode extends AbstractCommandNode { - - void constrain(Context ctx) { - if (components.size() == 3) { - Node out = components.get(0); - Node reply = components.get(1); - Node error = components.get(2); - if (!(out instanceof OutNode)) { - error("Expected 'Out' item, got: " + out); - } - if (!(reply instanceof ReplyNode)) { - error("Expected 'Reply' item, got: " + reply); - } - if (!(error instanceof ErrorSetNode)) { - error("Expected 'ErrorSet' item, got: " + error); - } - } else if (components.size() == 1) { - Node evt = components.get(0); - if (!(evt instanceof EventNode)) { - error("Expected 'Event' item, got: " + evt); - } - } else { - error("Command must have Out and Reply items or ErrorSet item"); - } - super.constrain(ctx); - } - - void genJavaClassSpecifics(PrintWriter writer, int depth) { - indent(writer, depth); - writer.println("static final int COMMAND = " + - nameNode.value() + ";"); - } - - void genJava(PrintWriter writer, int depth) { - genJavaClass(writer, depth); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/CommandNode.java 2020-03-23 19:57:50.811962154 +0100 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class CommandNode extends AbstractCommandNode { + + void constrain(Context ctx) { + if (components.size() == 3) { + Node out = components.get(0); + Node reply = components.get(1); + Node error = components.get(2); + if (!(out instanceof OutNode)) { + error("Expected 'Out' item, got: " + out); + } + if (!(reply instanceof ReplyNode)) { + error("Expected 'Reply' item, got: " + reply); + } + if (!(error instanceof ErrorSetNode)) { + error("Expected 'ErrorSet' item, got: " + error); + } + } else if (components.size() == 1) { + Node evt = components.get(0); + if (!(evt instanceof EventNode)) { + error("Expected 'Event' item, got: " + evt); + } + } else { + error("Command must have Out and Reply items or ErrorSet item"); + } + super.constrain(ctx); + } + + void genJavaClassSpecifics(PrintWriter writer, int depth) { + indent(writer, depth); + writer.println("static final int COMMAND = " + + nameNode.value() + ";"); + } + + void genJava(PrintWriter writer, int depth) { + genJavaClass(writer, depth); + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/CommandSetNode.java 2020-03-23 19:57:51.967962146 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,74 +0,0 @@ -/* - * Copyright (c) 1998, 2019, 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.jdwpgen; - -import java.io.*; - -class CommandSetNode extends AbstractNamedNode { - - void constrainComponent(Context ctx, Node node) { - if (node instanceof CommandNode) { - node.constrain(ctx); - } else { - error("Expected 'Command' item, got: " + node); - } - } - - void document(PrintWriter writer) { - writer.println("

    " + name + - " Command Set (" + - nameNode.value() + ")

    "); - writer.println(comment()); - for (Node node : components) { - node.document(writer); - } - } - - void documentIndex(PrintWriter writer) { - writer.print("
  • "); - writer.println(name() + " Command Set (" + - nameNode.value() + ")"); - if (components.size() > 0) { - writer.println("
      "); - for (Node node : components) { - node.documentIndex(writer); - } - writer.println("
    "); - } - } - - void genJavaClassSpecifics(PrintWriter writer, int depth) { - indent(writer, depth); - writer.println("static final int COMMAND_SET = " + nameNode.value() + ";"); - indent(writer, depth); - writer.println("private " + name() + "() {} // hide constructor"); - } - - void genJava(PrintWriter writer, int depth) { - genJavaClass(writer, depth); - } - -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/CommandSetNode.java 2020-03-23 19:57:51.599962149 +0100 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.jdwpgen; + +import java.io.*; + +class CommandSetNode extends AbstractNamedNode { + + void constrainComponent(Context ctx, Node node) { + if (node instanceof CommandNode) { + node.constrain(ctx); + } else { + error("Expected 'Command' item, got: " + node); + } + } + + void document(PrintWriter writer) { + writer.println("

    " + name + + " Command Set (" + + nameNode.value() + ")

    "); + writer.println(comment()); + for (Node node : components) { + node.document(writer); + } + } + + void documentIndex(PrintWriter writer) { + writer.print("
  • "); + writer.println(name() + " Command Set (" + + nameNode.value() + ")"); + if (components.size() > 0) { + writer.println("
      "); + for (Node node : components) { + node.documentIndex(writer); + } + writer.println("
    "); + } + } + + void genJavaClassSpecifics(PrintWriter writer, int depth) { + indent(writer, depth); + writer.println("static final int COMMAND_SET = " + nameNode.value() + ";"); + indent(writer, depth); + writer.println("private " + name() + "() {} // hide constructor"); + } + + void genJava(PrintWriter writer, int depth) { + genJavaClass(writer, depth); + } + +} --- old/make/jdk/src/classes/build/tools/jdwpgen/CommentNode.java 2020-03-23 19:57:52.855962139 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,42 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class CommentNode extends AbstractSimpleNode { - - String text; - - CommentNode(String text) { - this.text = text; - } - - String text() { - return text; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/CommentNode.java 2020-03-23 19:57:52.411962143 +0100 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class CommentNode extends AbstractSimpleNode { + + String text; + + CommentNode(String text) { + this.text = text; + } + + String text() { + return text; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/ConstantNode.java 2020-03-23 19:57:53.723962133 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,78 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class ConstantNode extends AbstractCommandNode { - - ConstantNode() { - this(new ArrayList()); - } - - ConstantNode(List components) { - this.kind = "Constant"; - this.components = components; - this.lineno = 0; - } - - void constrain(Context ctx) { - if (components.size() != 0) { - error("Constants have no internal structure"); - } - super.constrain(ctx); - } - - void genJava(PrintWriter writer, int depth) { - indent(writer, depth); - writer.println("static final int " + name + " = " + - nameNode.value() + ";"); - } - - void document(PrintWriter writer) { - //Add anchor to each constant with format _ - if (!(parent instanceof AbstractNamedNode)) { - error("Parent must be ConstantSetNode, but it's " + parent.getClass().getSimpleName()); - } - String tableName = ((AbstractNamedNode)parent).name; - writer.println("" - + "" - + "" - + name - + "" + nameNode.value() - + "" + comment() + " " - + ""); - } - - public String getName(){ - - if (name == null || name.length() == 0) { - prune(); - } - return name; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/ConstantNode.java 2020-03-23 19:57:53.299962136 +0100 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class ConstantNode extends AbstractCommandNode { + + ConstantNode() { + this(new ArrayList()); + } + + ConstantNode(List components) { + this.kind = "Constant"; + this.components = components; + this.lineno = 0; + } + + void constrain(Context ctx) { + if (components.size() != 0) { + error("Constants have no internal structure"); + } + super.constrain(ctx); + } + + void genJava(PrintWriter writer, int depth) { + indent(writer, depth); + writer.println("static final int " + name + " = " + + nameNode.value() + ";"); + } + + void document(PrintWriter writer) { + //Add anchor to each constant with format _ + if (!(parent instanceof AbstractNamedNode)) { + error("Parent must be ConstantSetNode, but it's " + parent.getClass().getSimpleName()); + } + String tableName = ((AbstractNamedNode)parent).name; + writer.println("" + + "" + + "" + + name + + "" + nameNode.value() + + "" + comment() + " " + + ""); + } + + public String getName(){ + + if (name == null || name.length() == 0) { + prune(); + } + return name; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/ConstantSetNode.java 2020-03-23 19:57:54.507962127 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,96 +0,0 @@ -/* - * Copyright (c) 1998, 2019, 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.jdwpgen; - -import java.util.*; -import java.io.*; - -class ConstantSetNode extends AbstractNamedNode { - - /** - * The mapping between a constant and its value. - */ - protected static final Map constantMap = new HashMap<>(); - - void prune() { - List addons = new ArrayList<>(); - - if (!addons.isEmpty()) { - components.addAll(addons); - } - super.prune(); - } - - void constrainComponent(Context ctx, Node node) { - if (node instanceof ConstantNode) { - node.constrain(ctx); - constantMap.put(name + "_" + ((ConstantNode) node).getName(), node.comment()); - } else { - error("Expected 'Constant', got: " + node); - } - } - - void document(PrintWriter writer) { - writer.println("

    " + name + " Constants

    "); - writer.println(comment()); - writer.println(""); - writer.println(""); - for (Node node : components) { - node.document(writer); - } - writer.println("
    Name"); - writer.println("Value"); - writer.println("Description"); - writer.println("
    "); - } - - void documentIndex(PrintWriter writer) { - writer.print("
  • "); - writer.println(name() + " Constants"); -// writer.println("
      "); -// for (Iterator it = components.iterator(); it.hasNext();) { -// ((Node)it.next()).documentIndex(writer); -// } -// writer.println("
    "); - } - - void genJavaClassSpecifics(PrintWriter writer, int depth) { - } - - void genJava(PrintWriter writer, int depth) { - genJavaClass(writer, depth); - } - - public static String getConstant(String key){ - String com = constantMap.get(key); - if(com == null){ - return ""; - } else { - return com; - } - } - -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/ConstantSetNode.java 2020-03-23 19:57:54.135962130 +0100 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class ConstantSetNode extends AbstractNamedNode { + + /** + * The mapping between a constant and its value. + */ + protected static final Map constantMap = new HashMap<>(); + + void prune() { + List addons = new ArrayList<>(); + + if (!addons.isEmpty()) { + components.addAll(addons); + } + super.prune(); + } + + void constrainComponent(Context ctx, Node node) { + if (node instanceof ConstantNode) { + node.constrain(ctx); + constantMap.put(name + "_" + ((ConstantNode) node).getName(), node.comment()); + } else { + error("Expected 'Constant', got: " + node); + } + } + + void document(PrintWriter writer) { + writer.println("

    " + name + " Constants

    "); + writer.println(comment()); + writer.println(""); + writer.println(""); + for (Node node : components) { + node.document(writer); + } + writer.println("
    Name"); + writer.println("Value"); + writer.println("Description"); + writer.println("
    "); + } + + void documentIndex(PrintWriter writer) { + writer.print("
  • "); + writer.println(name() + " Constants"); +// writer.println("
      "); +// for (Iterator it = components.iterator(); it.hasNext();) { +// ((Node)it.next()).documentIndex(writer); +// } +// writer.println("
    "); + } + + void genJavaClassSpecifics(PrintWriter writer, int depth) { + } + + void genJava(PrintWriter writer, int depth) { + genJavaClass(writer, depth); + } + + public static String getConstant(String key){ + String com = constantMap.get(key); + if(com == null){ + return ""; + } else { + return com; + } + } + +} --- old/make/jdk/src/classes/build/tools/jdwpgen/Context.java 2020-03-23 19:57:55.383962121 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,100 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; - -class Context { - - static final int outer = 0; - static final int readingReply = 1; - static final int writingCommand = 2; - - final String whereJava; - final String whereC; - - int state = outer; - private boolean inEvent = false; - - Context() { - whereJava = ""; - whereC = ""; - } - - private Context(String whereJava, String whereC) { - this.whereJava = whereJava; - this.whereC = whereC; - } - - Context subcontext(String level) { - Context ctx; - if (whereC.length() == 0) { - ctx = new Context(level, level); - } else { - ctx = new Context(whereJava + "." + level, whereC + "_" + level); - } - ctx.state = state; - ctx.inEvent = inEvent; - return ctx; - } - - private Context cloneContext() { - Context ctx = new Context(whereJava, whereC); - ctx.state = state; - ctx.inEvent = inEvent; - return ctx; - } - - Context replyReadingSubcontext() { - Context ctx = cloneContext(); - ctx.state = readingReply; - return ctx; - } - - Context commandWritingSubcontext() { - Context ctx = cloneContext(); - ctx.state = writingCommand; - return ctx; - } - - Context inEventSubcontext() { - Context ctx = cloneContext(); - ctx.inEvent = true; - return ctx; - } - - boolean inEvent() { - return inEvent; - } - - boolean isWritingCommand() { - return state == writingCommand; - } - - boolean isReadingReply() { - return state == readingReply; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/Context.java 2020-03-23 19:57:54.955962124 +0100 @@ -0,0 +1,100 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; + +class Context { + + static final int outer = 0; + static final int readingReply = 1; + static final int writingCommand = 2; + + final String whereJava; + final String whereC; + + int state = outer; + private boolean inEvent = false; + + Context() { + whereJava = ""; + whereC = ""; + } + + private Context(String whereJava, String whereC) { + this.whereJava = whereJava; + this.whereC = whereC; + } + + Context subcontext(String level) { + Context ctx; + if (whereC.length() == 0) { + ctx = new Context(level, level); + } else { + ctx = new Context(whereJava + "." + level, whereC + "_" + level); + } + ctx.state = state; + ctx.inEvent = inEvent; + return ctx; + } + + private Context cloneContext() { + Context ctx = new Context(whereJava, whereC); + ctx.state = state; + ctx.inEvent = inEvent; + return ctx; + } + + Context replyReadingSubcontext() { + Context ctx = cloneContext(); + ctx.state = readingReply; + return ctx; + } + + Context commandWritingSubcontext() { + Context ctx = cloneContext(); + ctx.state = writingCommand; + return ctx; + } + + Context inEventSubcontext() { + Context ctx = cloneContext(); + ctx.inEvent = true; + return ctx; + } + + boolean inEvent() { + return inEvent; + } + + boolean isWritingCommand() { + return state == writingCommand; + } + + boolean isReadingReply() { + return state == readingReply; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/ErrorNode.java 2020-03-23 19:57:56.263962114 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2001, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class ErrorNode extends AbstractCommandNode { - - protected static final String NAME_OF_ERROR_TABLE = "Error"; - - ErrorNode() { - this(new ArrayList()); - } - - ErrorNode(List components) { - this.kind = "Error"; - this.components = components; - this.lineno = 0; - } - - void constrain(Context ctx) { - if (components.size() != 0) { - error("Errors have no internal structure"); - } - super.constrain(ctx); - } - - void document(PrintWriter writer) { - - String com = comment(); - if (com == null || com.length() == 0) { - com = ConstantSetNode.getConstant("Error_" + name); - } - writer.println("" - + "" + "" + name + "" - + "" + com + " " - + ""); - } - - void genJavaComment(PrintWriter writer, int depth) {} - - void genJava(PrintWriter writer, int depth) {} - - void genCInclude(PrintWriter writer) {} - - void genJavaDebugWrite(PrintWriter writer, int depth, - String writeLabel) {} - - void genJavaDebugWrite(PrintWriter writer, int depth, - String writeLabel, String displayValue) {} - - public void genJavaRead(PrintWriter writer, int depth, - String readLabel) {} - - void genJavaDebugRead(PrintWriter writer, int depth, - String readLabel, String displayValue) {} - - void genJavaPreDef(PrintWriter writer, int depth) {} -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/ErrorNode.java 2020-03-23 19:57:55.831962117 +0100 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2001, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class ErrorNode extends AbstractCommandNode { + + protected static final String NAME_OF_ERROR_TABLE = "Error"; + + ErrorNode() { + this(new ArrayList()); + } + + ErrorNode(List components) { + this.kind = "Error"; + this.components = components; + this.lineno = 0; + } + + void constrain(Context ctx) { + if (components.size() != 0) { + error("Errors have no internal structure"); + } + super.constrain(ctx); + } + + void document(PrintWriter writer) { + + String com = comment(); + if (com == null || com.length() == 0) { + com = ConstantSetNode.getConstant("Error_" + name); + } + writer.println("" + + "" + "" + name + "" + + "" + com + " " + + ""); + } + + void genJavaComment(PrintWriter writer, int depth) {} + + void genJava(PrintWriter writer, int depth) {} + + void genCInclude(PrintWriter writer) {} + + void genJavaDebugWrite(PrintWriter writer, int depth, + String writeLabel) {} + + void genJavaDebugWrite(PrintWriter writer, int depth, + String writeLabel, String displayValue) {} + + public void genJavaRead(PrintWriter writer, int depth, + String readLabel) {} + + void genJavaDebugRead(PrintWriter writer, int depth, + String readLabel, String displayValue) {} + + void genJavaPreDef(PrintWriter writer, int depth) {} +} --- old/make/jdk/src/classes/build/tools/jdwpgen/ErrorSetNode.java 2020-03-23 19:57:57.055962108 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2001, 2018, 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.jdwpgen; - -import java.io.*; - -class ErrorSetNode extends AbstractSimpleNode { - - void constrainComponent(Context ctx, Node node) { - if (node instanceof ErrorNode) { - node.constrain(ctx); - } else { - error("Expected 'Error' item, got: " + node); - } - } - - void document(PrintWriter writer) { - writer.println("
    Error Data
    "); - writer.print("
    "); - if (components.isEmpty()) { - writer.println("(None)"); - } else { - writer.println(""); - writer.println(""); - for (Node node : components) { - node.document(writer); - } - writer.println("
    Value"); - writer.println("Description"); - writer.println("
    "); - } - writer.print("
    "); - } - - void genJavaComment(PrintWriter writer, int depth) {} - - void genJava(PrintWriter writer, int depth) {} - - void genCInclude(PrintWriter writer) {} - - void genJavaDebugWrite(PrintWriter writer, int depth, - String writeLabel) {} - - void genJavaDebugWrite(PrintWriter writer, int depth, - String writeLabel, String displayValue) {} - - public void genJavaRead(PrintWriter writer, int depth, - String readLabel) {} - - void genJavaDebugRead(PrintWriter writer, int depth, - String readLabel, String displayValue) {} - - void genJavaPreDef(PrintWriter writer, int depth) {} - -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/ErrorSetNode.java 2020-03-23 19:57:56.647962111 +0100 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.jdwpgen; + +import java.io.*; + +class ErrorSetNode extends AbstractSimpleNode { + + void constrainComponent(Context ctx, Node node) { + if (node instanceof ErrorNode) { + node.constrain(ctx); + } else { + error("Expected 'Error' item, got: " + node); + } + } + + void document(PrintWriter writer) { + writer.println("
    Error Data
    "); + writer.print("
    "); + if (components.isEmpty()) { + writer.println("(None)"); + } else { + writer.println(""); + writer.println(""); + for (Node node : components) { + node.document(writer); + } + writer.println("
    Value"); + writer.println("Description"); + writer.println("
    "); + } + writer.print("
    "); + } + + void genJavaComment(PrintWriter writer, int depth) {} + + void genJava(PrintWriter writer, int depth) {} + + void genCInclude(PrintWriter writer) {} + + void genJavaDebugWrite(PrintWriter writer, int depth, + String writeLabel) {} + + void genJavaDebugWrite(PrintWriter writer, int depth, + String writeLabel, String displayValue) {} + + public void genJavaRead(PrintWriter writer, int depth, + String readLabel) {} + + void genJavaDebugRead(PrintWriter writer, int depth, + String readLabel, String displayValue) {} + + void genJavaPreDef(PrintWriter writer, int depth) {} + +} --- old/make/jdk/src/classes/build/tools/jdwpgen/EventNode.java 2020-03-23 19:57:57.843962103 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,36 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class EventNode extends ReplyNode { - - void constrain(Context ctx) { - super.constrain(ctx.inEventSubcontext()); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/EventNode.java 2020-03-23 19:57:57.467962105 +0100 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class EventNode extends ReplyNode { + + void constrain(Context ctx) { + super.constrain(ctx.inEventSubcontext()); + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/FieldTypeNode.java 2020-03-23 19:57:58.623962097 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,51 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class FieldTypeNode extends AbstractSimpleTypeNode { - - String docType() { - return "fieldID"; - } - - String javaType() { - return "long"; - } - - public void genJavaWrite(PrintWriter writer, int depth, - String writeLabel) { - genJavaDebugWrite(writer, depth, writeLabel); - indent(writer, depth); - writer.println("ps.writeFieldRef(" + writeLabel + ");"); - } - - String javaRead() { - return "ps.readFieldRef()"; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/FieldTypeNode.java 2020-03-23 19:57:58.255962099 +0100 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class FieldTypeNode extends AbstractSimpleTypeNode { + + String docType() { + return "fieldID"; + } + + String javaType() { + return "long"; + } + + public void genJavaWrite(PrintWriter writer, int depth, + String writeLabel) { + genJavaDebugWrite(writer, depth, writeLabel); + indent(writer, depth); + writer.println("ps.writeFieldRef(" + writeLabel + ");"); + } + + String javaRead() { + return "ps.readFieldRef()"; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/FrameTypeNode.java 2020-03-23 19:57:59.443962091 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,51 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class FrameTypeNode extends AbstractSimpleTypeNode { - - String docType() { - return "frameID"; - } - - String javaType() { - return "long"; - } - - public void genJavaWrite(PrintWriter writer, int depth, - String writeLabel) { - genJavaDebugWrite(writer, depth, writeLabel); - indent(writer, depth); - writer.println("ps.writeFrameRef(" + writeLabel + ");"); - } - - String javaRead() { - return "ps.readFrameRef()"; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/FrameTypeNode.java 2020-03-23 19:57:59.071962093 +0100 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class FrameTypeNode extends AbstractSimpleTypeNode { + + String docType() { + return "frameID"; + } + + String javaType() { + return "long"; + } + + public void genJavaWrite(PrintWriter writer, int depth, + String writeLabel) { + genJavaDebugWrite(writer, depth, writeLabel); + indent(writer, depth); + writer.println("ps.writeFrameRef(" + writeLabel + ");"); + } + + String javaRead() { + return "ps.readFrameRef()"; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/GroupNode.java 2020-03-23 19:58:00.299962084 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,33 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class GroupNode extends AbstractGroupNode implements TypeNode { - -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/GroupNode.java 2020-03-23 19:57:59.859962088 +0100 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class GroupNode extends AbstractGroupNode implements TypeNode { + +} --- old/make/jdk/src/classes/build/tools/jdwpgen/IntTypeNode.java 2020-03-23 19:58:01.139962078 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,47 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class IntTypeNode extends AbstractSimpleTypeNode { - - String docType() { - return "int"; - } - - public void genJavaWrite(PrintWriter writer, int depth, - String writeLabel) { - genJavaDebugWrite(writer, depth, writeLabel); - indent(writer, depth); - writer.println("ps.writeInt(" + writeLabel + ");"); - } - - String javaRead() { - return "ps.readInt()"; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/IntTypeNode.java 2020-03-23 19:58:00.739962081 +0100 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class IntTypeNode extends AbstractSimpleTypeNode { + + String docType() { + return "int"; + } + + public void genJavaWrite(PrintWriter writer, int depth, + String writeLabel) { + genJavaDebugWrite(writer, depth, writeLabel); + indent(writer, depth); + writer.println("ps.writeInt(" + writeLabel + ");"); + } + + String javaRead() { + return "ps.readInt()"; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/InterfaceTypeNode.java 2020-03-23 19:58:02.015962072 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,43 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; - -class InterfaceTypeNode extends ReferenceTypeNode { - - String docType() { - return "interfaceID"; - } - - String javaType() { - return "InterfaceTypeImpl"; - } - - String javaRead() { - return "vm.interfaceType(ps.readClassRef())"; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/InterfaceTypeNode.java 2020-03-23 19:58:01.579962075 +0100 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; + +class InterfaceTypeNode extends ReferenceTypeNode { + + String docType() { + return "interfaceID"; + } + + String javaType() { + return "InterfaceTypeImpl"; + } + + String javaRead() { + return "vm.interfaceType(ps.readClassRef())"; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/LocationTypeNode.java 2020-03-23 19:58:02.799962066 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,51 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class LocationTypeNode extends AbstractSimpleTypeNode { - - String docType() { - return "location"; - } - - String javaType() { - return "Location"; - } - - public void genJavaWrite(PrintWriter writer, int depth, - String writeLabel) { - genJavaDebugWrite(writer, depth, writeLabel); - indent(writer, depth); - writer.println("ps.writeLocation(" + writeLabel + ");"); - } - - String javaRead() { - return "ps.readLocation()"; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/LocationTypeNode.java 2020-03-23 19:58:02.399962069 +0100 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class LocationTypeNode extends AbstractSimpleTypeNode { + + String docType() { + return "location"; + } + + String javaType() { + return "Location"; + } + + public void genJavaWrite(PrintWriter writer, int depth, + String writeLabel) { + genJavaDebugWrite(writer, depth, writeLabel); + indent(writer, depth); + writer.println("ps.writeLocation(" + writeLabel + ");"); + } + + String javaRead() { + return "ps.readLocation()"; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/LongTypeNode.java 2020-03-23 19:58:03.643962060 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,47 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class LongTypeNode extends AbstractSimpleTypeNode { - - String docType() { - return "long"; - } - - public void genJavaWrite(PrintWriter writer, int depth, - String writeLabel) { - genJavaDebugWrite(writer, depth, writeLabel); - indent(writer, depth); - writer.println("ps.writeLong(" + writeLabel + ");"); - } - - String javaRead() { - return "ps.readLong()"; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/LongTypeNode.java 2020-03-23 19:58:03.239962063 +0100 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class LongTypeNode extends AbstractSimpleTypeNode { + + String docType() { + return "long"; + } + + public void genJavaWrite(PrintWriter writer, int depth, + String writeLabel) { + genJavaDebugWrite(writer, depth, writeLabel); + indent(writer, depth); + writer.println("ps.writeLong(" + writeLabel + ");"); + } + + String javaRead() { + return "ps.readLong()"; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/Main.java 2020-03-23 19:58:04.531962053 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,97 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.io.*; - -class Main { - - static String specSource; - static boolean genDebug = true; - - static void usage() { - System.err.println(); - System.err.println( - "java Main ..."); - System.err.println(); - System.err.println("Options:"); - System.err.println("-doc "); - System.err.println("-jdi "); - System.err.println("-include "); - } - - public static void main(String args[]) throws IOException { - Reader reader = null; - PrintWriter doc = null; - PrintWriter jdi = null; - PrintWriter include = null; - - // Parse arguments - for (int i = 0 ; i < args.length ; ++i) { - String arg = args[i]; - if (arg.startsWith("-")) { - String fn = args[++i]; - if (arg.equals("-doc")) { - doc = new PrintWriter(new FileWriter(fn)); - } else if (arg.equals("-jdi")) { - jdi = new PrintWriter(new FileWriter(fn)); - } else if (arg.equals("-include")) { - include = new PrintWriter(new FileWriter(fn)); - } else { - System.err.println("Invalid option: " + arg); - usage(); - return; - } - } else { - specSource = arg; - reader = new FileReader(specSource); - } - } - if (reader == null) { - System.err.println(" must be specified"); - usage(); - return; - } - - Parse parse = new Parse(reader); - RootNode root = parse.items(); - root.parentAndExtractComments(); - root.prune(); - root.constrain(new Context()); - if (doc != null) { - root.document(doc); - doc.close(); - } - if (jdi != null) { - root.genJava(jdi, 0); - jdi.close(); - } - if (include != null) { - root.genCInclude(include); - include.close(); - } - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/Main.java 2020-03-23 19:58:04.083962056 +0100 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.io.*; + +class Main { + + static String specSource; + static boolean genDebug = true; + + static void usage() { + System.err.println(); + System.err.println( + "java Main ..."); + System.err.println(); + System.err.println("Options:"); + System.err.println("-doc "); + System.err.println("-jdi "); + System.err.println("-include "); + } + + public static void main(String args[]) throws IOException { + Reader reader = null; + PrintWriter doc = null; + PrintWriter jdi = null; + PrintWriter include = null; + + // Parse arguments + for (int i = 0 ; i < args.length ; ++i) { + String arg = args[i]; + if (arg.startsWith("-")) { + String fn = args[++i]; + if (arg.equals("-doc")) { + doc = new PrintWriter(new FileWriter(fn)); + } else if (arg.equals("-jdi")) { + jdi = new PrintWriter(new FileWriter(fn)); + } else if (arg.equals("-include")) { + include = new PrintWriter(new FileWriter(fn)); + } else { + System.err.println("Invalid option: " + arg); + usage(); + return; + } + } else { + specSource = arg; + reader = new FileReader(specSource); + } + } + if (reader == null) { + System.err.println(" must be specified"); + usage(); + return; + } + + Parse parse = new Parse(reader); + RootNode root = parse.items(); + root.parentAndExtractComments(); + root.prune(); + root.constrain(new Context()); + if (doc != null) { + root.document(doc); + doc.close(); + } + if (jdi != null) { + root.genJava(jdi, 0); + jdi.close(); + } + if (include != null) { + root.genCInclude(include); + include.close(); + } + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/MethodTypeNode.java 2020-03-23 19:58:05.359962047 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,51 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class MethodTypeNode extends AbstractSimpleTypeNode { - - String docType() { - return "methodID"; - } - - String javaType() { - return "long"; - } - - public void genJavaWrite(PrintWriter writer, int depth, - String writeLabel) { - genJavaDebugWrite(writer, depth, writeLabel); - indent(writer, depth); - writer.println("ps.writeMethodRef(" + writeLabel + ");"); - } - - String javaRead() { - return "ps.readMethodRef()"; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/MethodTypeNode.java 2020-03-23 19:58:04.911962050 +0100 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class MethodTypeNode extends AbstractSimpleTypeNode { + + String docType() { + return "methodID"; + } + + String javaType() { + return "long"; + } + + public void genJavaWrite(PrintWriter writer, int depth, + String writeLabel) { + genJavaDebugWrite(writer, depth, writeLabel); + indent(writer, depth); + writer.println("ps.writeMethodRef(" + writeLabel + ");"); + } + + String javaRead() { + return "ps.readMethodRef()"; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/ModuleTypeNode.java 2020-03-23 19:58:06.227962041 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class ModuleTypeNode extends AbstractSimpleTypeNode { - - String docType() { - return "moduleID"; - } - - String javaType() { - return "ModuleReferenceImpl"; - } - - String debugValue(String label) { - return "(" + label + "==null?\"NULL\":\"ref=\"+" + label + ".ref())"; - } - - public void genJavaWrite(PrintWriter writer, int depth, - String writeLabel) { - genJavaDebugWrite(writer, depth, writeLabel, - debugValue(writeLabel)); - indent(writer, depth); - writer.println("ps.writeModuleRef(" + writeLabel + ".ref());"); - } - - String javaRead() { - return "ps.readModule()"; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/ModuleTypeNode.java 2020-03-23 19:58:05.799962044 +0100 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class ModuleTypeNode extends AbstractSimpleTypeNode { + + String docType() { + return "moduleID"; + } + + String javaType() { + return "ModuleReferenceImpl"; + } + + String debugValue(String label) { + return "(" + label + "==null?\"NULL\":\"ref=\"+" + label + ".ref())"; + } + + public void genJavaWrite(PrintWriter writer, int depth, + String writeLabel) { + genJavaDebugWrite(writer, depth, writeLabel, + debugValue(writeLabel)); + indent(writer, depth); + writer.println("ps.writeModuleRef(" + writeLabel + ".ref());"); + } + + String javaRead() { + return "ps.readModule()"; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/NameNode.java 2020-03-23 19:58:07.083962034 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,51 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class NameNode extends AbstractSimpleNode { - - String name; - - NameNode(String name) { - this.name = name; - } - - String text() { - return name; - } - - String value() { - error("Valueless Name asked for value"); - return null; - } - - public String toString() { - return name; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/NameNode.java 2020-03-23 19:58:06.643962038 +0100 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class NameNode extends AbstractSimpleNode { + + String name; + + NameNode(String name) { + this.name = name; + } + + String text() { + return name; + } + + String value() { + error("Valueless Name asked for value"); + return null; + } + + public String toString() { + return name; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/NameValueNode.java 2020-03-23 19:58:07.919962028 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,52 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class NameValueNode extends NameNode { - - String val; - - NameValueNode(String name, String val) { - super(name); - this.val = val; - } - - NameValueNode(String name, int ival) { - super(name); - this.val = Integer.toString(ival); - } - - String value() { - return val; - } - - public String toString() { - return name + "=" + val; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/NameValueNode.java 2020-03-23 19:58:07.495962031 +0100 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class NameValueNode extends NameNode { + + String val; + + NameValueNode(String name, String val) { + super(name); + this.val = val; + } + + NameValueNode(String name, int ival) { + super(name); + this.val = Integer.toString(ival); + } + + String value() { + return val; + } + + public String toString() { + return name + "=" + val; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/Node.java 2020-03-23 19:58:08.699962022 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,194 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - - -import java.util.*; -import java.io.*; - -abstract class Node { - - String kind; - List components; - int lineno; - List commentList = new ArrayList<>(); - Node parent = null; - Context context = null; - - static final int maxStructIndent = 5; - static int structIndent = 0; // horrible hack - - abstract void document(PrintWriter writer); - - void set(String kind, List components, int lineno) { - this.kind = kind; - this.components = components; - this.lineno = lineno; - } - - void parentAndExtractComments() { - for (Iterator it = components.iterator(); it.hasNext();) { - Node node = it.next(); - if (node instanceof CommentNode) { - it.remove(); - commentList.add(((CommentNode)node).text()); - } else { - node.parent = this; - node.parentAndExtractComments(); - } - } - } - - void prune() { - for (Node node : components) { - node.prune(); - } - } - - void constrain(Context ctx) { - context = ctx; - for (Node node : components) { - constrainComponent(ctx, node); - } - } - - void constrainComponent(Context ctx, Node node) { - node.constrain(ctx); - } - - void indent(PrintWriter writer, int depth) { - for (int i = 0; i < depth; i++) { - writer.print(" "); - } - } - - void documentIndex(PrintWriter writer) { - } - - String indentElement(int depth, String content) { - return depth > 0 - ? "
    " + content + "
    " - : content; - } - - String comment() { - StringBuffer comment = new StringBuffer(); - for (String st : commentList) { - comment.append(st); - } - return comment.toString(); - } - - void genJavaComment(PrintWriter writer, int depth) { - if (commentList.size() > 0) { - indent(writer, depth); - writer.println("/**"); - for (String comment : commentList) { - indent(writer, depth); - writer.println(" * " + comment); - } - indent(writer, depth); - writer.println(" */"); - } - } - - String javaType() { - return "-- WRONG ---"; - } - - void genJava(PrintWriter writer, int depth) { - for (Node node : components) { - node.genJava(writer, depth); - } - } - - void genCInclude(PrintWriter writer) { - for (Node node : components) { - node.genCInclude(writer); - } - } - - String debugValue(String label) { - return label; - } - - void genJavaDebugWrite(PrintWriter writer, int depth, - String writeLabel) { - genJavaDebugWrite(writer, depth, writeLabel, debugValue(writeLabel)); - } - - void genJavaDebugWrite(PrintWriter writer, int depth, - String writeLabel, String displayValue) { - if (!Main.genDebug) { - return; - } - indent(writer, depth); - writer.println( - "if ((ps.vm.traceFlags & VirtualMachineImpl.TRACE_SENDS) != 0) {"); - indent(writer, depth+1); - writer.print("ps.vm.printTrace(\"Sending: "); - indent(writer, depth); // this is inside the quotes - writer.print(writeLabel + "(" + javaType() + "): \" + "); - writer.println(displayValue + ");"); - indent(writer, depth); - writer.println("}"); - } - - public void genJavaRead(PrintWriter writer, int depth, - String readLabel) { - error("Internal - Should not call Node.genJavaRead()"); - } - - void genJavaDebugRead(PrintWriter writer, int depth, - String readLabel, String displayValue) { - if (!Main.genDebug) { - return; - } - indent(writer, depth); - writer.println( - "if (vm.traceReceives) {"); - indent(writer, depth+1); - writer.print("vm.printReceiveTrace(" + depth + ", \""); - writer.print(readLabel + "(" + javaType() + "): \" + "); - writer.println(displayValue + ");"); - indent(writer, depth); - writer.println("}"); - } - - void genJavaPreDef(PrintWriter writer, int depth) { - for (Node node : components) { - node.genJavaPreDef(writer, depth); - } - } - - void error(String errmsg) { - System.err.println(); - System.err.println(Main.specSource + ":" + lineno + ": " + - kind + " - " + errmsg); - System.err.println(); - throw new RuntimeException("Error: " + errmsg); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/Node.java 2020-03-23 19:58:08.303962025 +0100 @@ -0,0 +1,194 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + + +import java.util.*; +import java.io.*; + +abstract class Node { + + String kind; + List components; + int lineno; + List commentList = new ArrayList<>(); + Node parent = null; + Context context = null; + + static final int maxStructIndent = 5; + static int structIndent = 0; // horrible hack + + abstract void document(PrintWriter writer); + + void set(String kind, List components, int lineno) { + this.kind = kind; + this.components = components; + this.lineno = lineno; + } + + void parentAndExtractComments() { + for (Iterator it = components.iterator(); it.hasNext();) { + Node node = it.next(); + if (node instanceof CommentNode) { + it.remove(); + commentList.add(((CommentNode)node).text()); + } else { + node.parent = this; + node.parentAndExtractComments(); + } + } + } + + void prune() { + for (Node node : components) { + node.prune(); + } + } + + void constrain(Context ctx) { + context = ctx; + for (Node node : components) { + constrainComponent(ctx, node); + } + } + + void constrainComponent(Context ctx, Node node) { + node.constrain(ctx); + } + + void indent(PrintWriter writer, int depth) { + for (int i = 0; i < depth; i++) { + writer.print(" "); + } + } + + void documentIndex(PrintWriter writer) { + } + + String indentElement(int depth, String content) { + return depth > 0 + ? "
    " + content + "
    " + : content; + } + + String comment() { + StringBuffer comment = new StringBuffer(); + for (String st : commentList) { + comment.append(st); + } + return comment.toString(); + } + + void genJavaComment(PrintWriter writer, int depth) { + if (commentList.size() > 0) { + indent(writer, depth); + writer.println("/**"); + for (String comment : commentList) { + indent(writer, depth); + writer.println(" * " + comment); + } + indent(writer, depth); + writer.println(" */"); + } + } + + String javaType() { + return "-- WRONG ---"; + } + + void genJava(PrintWriter writer, int depth) { + for (Node node : components) { + node.genJava(writer, depth); + } + } + + void genCInclude(PrintWriter writer) { + for (Node node : components) { + node.genCInclude(writer); + } + } + + String debugValue(String label) { + return label; + } + + void genJavaDebugWrite(PrintWriter writer, int depth, + String writeLabel) { + genJavaDebugWrite(writer, depth, writeLabel, debugValue(writeLabel)); + } + + void genJavaDebugWrite(PrintWriter writer, int depth, + String writeLabel, String displayValue) { + if (!Main.genDebug) { + return; + } + indent(writer, depth); + writer.println( + "if ((ps.vm.traceFlags & VirtualMachineImpl.TRACE_SENDS) != 0) {"); + indent(writer, depth+1); + writer.print("ps.vm.printTrace(\"Sending: "); + indent(writer, depth); // this is inside the quotes + writer.print(writeLabel + "(" + javaType() + "): \" + "); + writer.println(displayValue + ");"); + indent(writer, depth); + writer.println("}"); + } + + public void genJavaRead(PrintWriter writer, int depth, + String readLabel) { + error("Internal - Should not call Node.genJavaRead()"); + } + + void genJavaDebugRead(PrintWriter writer, int depth, + String readLabel, String displayValue) { + if (!Main.genDebug) { + return; + } + indent(writer, depth); + writer.println( + "if (vm.traceReceives) {"); + indent(writer, depth+1); + writer.print("vm.printReceiveTrace(" + depth + ", \""); + writer.print(readLabel + "(" + javaType() + "): \" + "); + writer.println(displayValue + ");"); + indent(writer, depth); + writer.println("}"); + } + + void genJavaPreDef(PrintWriter writer, int depth) { + for (Node node : components) { + node.genJavaPreDef(writer, depth); + } + } + + void error(String errmsg) { + System.err.println(); + System.err.println(Main.specSource + ":" + lineno + ": " + + kind + " - " + errmsg); + System.err.println(); + throw new RuntimeException("Error: " + errmsg); + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/ObjectTypeNode.java 2020-03-23 19:58:09.547962016 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,55 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class ObjectTypeNode extends AbstractSimpleTypeNode { - - String docType() { - return "objectID"; - } - - String javaType() { - return "ObjectReferenceImpl"; - } - - String debugValue(String label) { - return "(" + label + "==null?\"NULL\":\"ref=\"+" + label + ".ref())"; - } - - public void genJavaWrite(PrintWriter writer, int depth, - String writeLabel) { - genJavaDebugWrite(writer, depth, writeLabel, debugValue(writeLabel)); - indent(writer, depth); - writer.println("ps.writeObjectRef(" + writeLabel + ".ref());"); - } - - String javaRead() { - return "ps.readObjectReference()"; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/ObjectTypeNode.java 2020-03-23 19:58:09.115962019 +0100 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class ObjectTypeNode extends AbstractSimpleTypeNode { + + String docType() { + return "objectID"; + } + + String javaType() { + return "ObjectReferenceImpl"; + } + + String debugValue(String label) { + return "(" + label + "==null?\"NULL\":\"ref=\"+" + label + ".ref())"; + } + + public void genJavaWrite(PrintWriter writer, int depth, + String writeLabel) { + genJavaDebugWrite(writer, depth, writeLabel, debugValue(writeLabel)); + indent(writer, depth); + writer.println("ps.writeObjectRef(" + writeLabel + ".ref());"); + } + + String javaRead() { + return "ps.readObjectReference()"; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/OutNode.java 2020-03-23 19:58:10.383962010 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,134 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class OutNode extends AbstractTypeListNode { - - String cmdName; - - void set(String kind, List components, int lineno) { - super.set(kind, components, lineno); - components.add(0, new NameNode("Out")); - } - - void constrain(Context ctx) { - super.constrain(ctx.commandWritingSubcontext()); - CommandNode cmd = (CommandNode)parent; - cmdName = cmd.name; - } - - void genProcessMethod(PrintWriter writer, int depth) { - writer.println(); - indent(writer, depth); - writer.print( - "static " + cmdName + " process(VirtualMachineImpl vm"); - for (Node node : components) { - TypeNode tn = (TypeNode)node; - writer.println(", "); - indent(writer, depth+5); - writer.print(tn.javaParam()); - } - writer.println(")"); - indent(writer, depth+6); - writer.println("throws JDWPException {"); - indent(writer, depth+1); - writer.print("PacketStream ps = enqueueCommand(vm"); - for (Node node : components) { - TypeNode tn = (TypeNode)node; - writer.print(", "); - writer.print(tn.name()); - } - writer.println(");"); - indent(writer, depth+1); - writer.println("return waitForReply(vm, ps);"); - indent(writer, depth); - writer.println("}"); - } - - void genEnqueueMethod(PrintWriter writer, int depth) { - writer.println(); - indent(writer, depth); - writer.print( - "static PacketStream enqueueCommand(VirtualMachineImpl vm"); - for (Node node : components) { - TypeNode tn = (TypeNode)node; - writer.println(", "); - indent(writer, depth+5); - writer.print(tn.javaParam()); - } - writer.println(") {"); - indent(writer, depth+1); - writer.println( - "PacketStream ps = new PacketStream(vm, COMMAND_SET, COMMAND);"); - if (Main.genDebug) { - indent(writer, depth+1); - writer.println( - "if ((vm.traceFlags & VirtualMachineImpl.TRACE_SENDS) != 0) {"); - indent(writer, depth+2); - writer.print( - "vm.printTrace(\"Sending Command(id=\" + ps.pkt.id + \") "); - writer.print(parent.context.whereJava); - writer.println( - "\"+(ps.pkt.flags!=0?\", FLAGS=\" + ps.pkt.flags:\"\"));"); - indent(writer, depth+1); - writer.println("}"); - } - genJavaWrites(writer, depth+1); - indent(writer, depth+1); - writer.println("ps.send();"); - indent(writer, depth+1); - writer.println("return ps;"); - indent(writer, depth); - writer.println("}"); - } - - void genWaitMethod(PrintWriter writer, int depth) { - writer.println(); - indent(writer, depth); - writer.println( - "static " + cmdName + " waitForReply(VirtualMachineImpl vm, " + - "PacketStream ps)"); - indent(writer, depth+6); - writer.println("throws JDWPException {"); - indent(writer, depth+1); - writer.println("ps.waitForReply();"); - indent(writer, depth+1); - writer.println("return new " + cmdName + "(vm, ps);"); - indent(writer, depth); - writer.println("}"); - } - - void genJava(PrintWriter writer, int depth) { - genJavaPreDef(writer, depth); - super.genJava(writer, depth); - genProcessMethod(writer, depth); - genEnqueueMethod(writer, depth); - genWaitMethod(writer, depth); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/OutNode.java 2020-03-23 19:58:09.963962013 +0100 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class OutNode extends AbstractTypeListNode { + + String cmdName; + + void set(String kind, List components, int lineno) { + super.set(kind, components, lineno); + components.add(0, new NameNode("Out")); + } + + void constrain(Context ctx) { + super.constrain(ctx.commandWritingSubcontext()); + CommandNode cmd = (CommandNode)parent; + cmdName = cmd.name; + } + + void genProcessMethod(PrintWriter writer, int depth) { + writer.println(); + indent(writer, depth); + writer.print( + "static " + cmdName + " process(VirtualMachineImpl vm"); + for (Node node : components) { + TypeNode tn = (TypeNode)node; + writer.println(", "); + indent(writer, depth+5); + writer.print(tn.javaParam()); + } + writer.println(")"); + indent(writer, depth+6); + writer.println("throws JDWPException {"); + indent(writer, depth+1); + writer.print("PacketStream ps = enqueueCommand(vm"); + for (Node node : components) { + TypeNode tn = (TypeNode)node; + writer.print(", "); + writer.print(tn.name()); + } + writer.println(");"); + indent(writer, depth+1); + writer.println("return waitForReply(vm, ps);"); + indent(writer, depth); + writer.println("}"); + } + + void genEnqueueMethod(PrintWriter writer, int depth) { + writer.println(); + indent(writer, depth); + writer.print( + "static PacketStream enqueueCommand(VirtualMachineImpl vm"); + for (Node node : components) { + TypeNode tn = (TypeNode)node; + writer.println(", "); + indent(writer, depth+5); + writer.print(tn.javaParam()); + } + writer.println(") {"); + indent(writer, depth+1); + writer.println( + "PacketStream ps = new PacketStream(vm, COMMAND_SET, COMMAND);"); + if (Main.genDebug) { + indent(writer, depth+1); + writer.println( + "if ((vm.traceFlags & VirtualMachineImpl.TRACE_SENDS) != 0) {"); + indent(writer, depth+2); + writer.print( + "vm.printTrace(\"Sending Command(id=\" + ps.pkt.id + \") "); + writer.print(parent.context.whereJava); + writer.println( + "\"+(ps.pkt.flags!=0?\", FLAGS=\" + ps.pkt.flags:\"\"));"); + indent(writer, depth+1); + writer.println("}"); + } + genJavaWrites(writer, depth+1); + indent(writer, depth+1); + writer.println("ps.send();"); + indent(writer, depth+1); + writer.println("return ps;"); + indent(writer, depth); + writer.println("}"); + } + + void genWaitMethod(PrintWriter writer, int depth) { + writer.println(); + indent(writer, depth); + writer.println( + "static " + cmdName + " waitForReply(VirtualMachineImpl vm, " + + "PacketStream ps)"); + indent(writer, depth+6); + writer.println("throws JDWPException {"); + indent(writer, depth+1); + writer.println("ps.waitForReply();"); + indent(writer, depth+1); + writer.println("return new " + cmdName + "(vm, ps);"); + indent(writer, depth); + writer.println("}"); + } + + void genJava(PrintWriter writer, int depth) { + genJavaPreDef(writer, depth); + super.genJava(writer, depth); + genProcessMethod(writer, depth); + genEnqueueMethod(writer, depth); + genWaitMethod(writer, depth); + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/Parse.java 2020-03-23 19:58:11.171962004 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,183 +0,0 @@ -/* - * Copyright (c) 1998, 2020, 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.jdwpgen; - -import java.util.*; -import java.io.*; -import java.lang.reflect.InvocationTargetException; - -class Parse { - - final StreamTokenizer izer; - final Map kindMap = new HashMap(); - - Parse(Reader reader) { - izer = new StreamTokenizer(new BufferedReader(reader)); - izer.resetSyntax(); - izer.slashStarComments(true); - izer.slashSlashComments(true); - izer.wordChars((int)'a', (int)'z'); - izer.wordChars((int)'A', (int)'Z'); - izer.wordChars((int)'0', (int)'9'); - izer.wordChars((int)'_', (int)'_'); - izer.wordChars((int)'-', (int)'-'); - izer.wordChars((int)'.', (int)'.'); - izer.whitespaceChars(0, 32); - izer.quoteChar('"'); - izer.quoteChar('\''); - - kindMap.put("CommandSet", new CommandSetNode()); - kindMap.put("Command", new CommandNode()); - kindMap.put("Out", new OutNode()); - kindMap.put("Reply", new ReplyNode()); - kindMap.put("ErrorSet", new ErrorSetNode()); - kindMap.put("Error", new ErrorNode()); - kindMap.put("Event", new EventNode()); - kindMap.put("Repeat", new RepeatNode()); - kindMap.put("Group", new GroupNode()); - kindMap.put("Select", new SelectNode()); - kindMap.put("Alt", new AltNode()); - kindMap.put("ConstantSet", new ConstantSetNode()); - kindMap.put("Constant", new ConstantNode()); - kindMap.put("int", new IntTypeNode()); - kindMap.put("long", new LongTypeNode()); - kindMap.put("boolean", new BooleanTypeNode()); - kindMap.put("object", new ObjectTypeNode()); - kindMap.put("threadObject", new ThreadObjectTypeNode()); - kindMap.put("threadGroupObject", new ThreadGroupObjectTypeNode()); - kindMap.put("arrayObject", new ArrayObjectTypeNode()); - kindMap.put("stringObject", new StringObjectTypeNode()); - kindMap.put("classLoaderObject", new ClassLoaderObjectTypeNode()); - kindMap.put("classObject", new ClassObjectTypeNode()); - kindMap.put("referenceType", new ReferenceTypeNode()); - kindMap.put("referenceTypeID", new ReferenceIDTypeNode()); - kindMap.put("classType", new ClassTypeNode()); - kindMap.put("interfaceType", new InterfaceTypeNode()); - kindMap.put("arrayType", new ArrayTypeNode()); - kindMap.put("method", new MethodTypeNode()); - kindMap.put("field", new FieldTypeNode()); - kindMap.put("frame", new FrameTypeNode()); - kindMap.put("string", new StringTypeNode()); - kindMap.put("moduleID", new ModuleTypeNode()); - kindMap.put("value", new ValueTypeNode()); - kindMap.put("byte", new ByteTypeNode()); - kindMap.put("location", new LocationTypeNode()); - kindMap.put("tagged-object", new TaggedObjectTypeNode()); - kindMap.put("referenceTypeID", new ReferenceIDTypeNode()); - kindMap.put("typed-sequence", new ArrayRegionTypeNode()); - kindMap.put("untagged-value", new UntaggedValueTypeNode()); - } - - RootNode items() throws IOException { - List list = new ArrayList(); - - while (izer.nextToken() != StreamTokenizer.TT_EOF) { - izer.pushBack(); - list.add(item()); - } - RootNode node = new RootNode(); - node.set("Root", list, 1); - return node; - } - - Node item() throws IOException { - switch (izer.nextToken()) { - case StreamTokenizer.TT_EOF: - error("Unexpect end-of-file"); - return null; - - case StreamTokenizer.TT_WORD: { - String name = izer.sval; - if (izer.nextToken() == '=') { - int ntok = izer.nextToken(); - if (ntok == StreamTokenizer.TT_WORD) { - return new NameValueNode(name, izer.sval); - } else if (ntok == '\'') { - return new NameValueNode(name, izer.sval.charAt(0)); - } else { - error("Expected value after: " + name + " ="); - return null; - } - } else { - izer.pushBack(); - return new NameNode(name); - } - } - - case '"': - return new CommentNode(izer.sval); - - case '(': { - if (izer.nextToken() == StreamTokenizer.TT_WORD) { - String kind = izer.sval; - List list = new ArrayList(); - - while (izer.nextToken() != ')') { - izer.pushBack(); - list.add(item()); - } - Node proto = kindMap.get(kind); - if (proto == null) { - error("Invalid kind: " + kind); - return null; - } else { - try { - Node node = (Node)proto.getClass().getDeclaredConstructor().newInstance(); - node.set(kind, list, izer.lineno()); - return node; - } catch (InstantiationException exc) { - error(exc.toString()); - return null; - } catch (NoSuchMethodException exc) { - error(exc.toString()); - return null; - } catch (InvocationTargetException exc) { - error(exc.toString()); - return null; - } catch (IllegalAccessException exc) { - error(exc.toString()); - return null; - } - } - } else { - error("Expected kind identifier, got " + izer.ttype + - " : " + izer.sval); - return null; - } - } - - default: - error("Unexpected character: '" + (char)izer.ttype + "'"); - return null; - } - } - - void error(String errmsg) { - System.err.println(Main.specSource + ":" + izer.lineno() + - ": " + errmsg); - throw new RuntimeException("Error: " + errmsg); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/Parse.java 2020-03-23 19:58:10.759962007 +0100 @@ -0,0 +1,183 @@ +/* + * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; +import java.lang.reflect.InvocationTargetException; + +class Parse { + + final StreamTokenizer izer; + final Map kindMap = new HashMap(); + + Parse(Reader reader) { + izer = new StreamTokenizer(new BufferedReader(reader)); + izer.resetSyntax(); + izer.slashStarComments(true); + izer.slashSlashComments(true); + izer.wordChars((int)'a', (int)'z'); + izer.wordChars((int)'A', (int)'Z'); + izer.wordChars((int)'0', (int)'9'); + izer.wordChars((int)'_', (int)'_'); + izer.wordChars((int)'-', (int)'-'); + izer.wordChars((int)'.', (int)'.'); + izer.whitespaceChars(0, 32); + izer.quoteChar('"'); + izer.quoteChar('\''); + + kindMap.put("CommandSet", new CommandSetNode()); + kindMap.put("Command", new CommandNode()); + kindMap.put("Out", new OutNode()); + kindMap.put("Reply", new ReplyNode()); + kindMap.put("ErrorSet", new ErrorSetNode()); + kindMap.put("Error", new ErrorNode()); + kindMap.put("Event", new EventNode()); + kindMap.put("Repeat", new RepeatNode()); + kindMap.put("Group", new GroupNode()); + kindMap.put("Select", new SelectNode()); + kindMap.put("Alt", new AltNode()); + kindMap.put("ConstantSet", new ConstantSetNode()); + kindMap.put("Constant", new ConstantNode()); + kindMap.put("int", new IntTypeNode()); + kindMap.put("long", new LongTypeNode()); + kindMap.put("boolean", new BooleanTypeNode()); + kindMap.put("object", new ObjectTypeNode()); + kindMap.put("threadObject", new ThreadObjectTypeNode()); + kindMap.put("threadGroupObject", new ThreadGroupObjectTypeNode()); + kindMap.put("arrayObject", new ArrayObjectTypeNode()); + kindMap.put("stringObject", new StringObjectTypeNode()); + kindMap.put("classLoaderObject", new ClassLoaderObjectTypeNode()); + kindMap.put("classObject", new ClassObjectTypeNode()); + kindMap.put("referenceType", new ReferenceTypeNode()); + kindMap.put("referenceTypeID", new ReferenceIDTypeNode()); + kindMap.put("classType", new ClassTypeNode()); + kindMap.put("interfaceType", new InterfaceTypeNode()); + kindMap.put("arrayType", new ArrayTypeNode()); + kindMap.put("method", new MethodTypeNode()); + kindMap.put("field", new FieldTypeNode()); + kindMap.put("frame", new FrameTypeNode()); + kindMap.put("string", new StringTypeNode()); + kindMap.put("moduleID", new ModuleTypeNode()); + kindMap.put("value", new ValueTypeNode()); + kindMap.put("byte", new ByteTypeNode()); + kindMap.put("location", new LocationTypeNode()); + kindMap.put("tagged-object", new TaggedObjectTypeNode()); + kindMap.put("referenceTypeID", new ReferenceIDTypeNode()); + kindMap.put("typed-sequence", new ArrayRegionTypeNode()); + kindMap.put("untagged-value", new UntaggedValueTypeNode()); + } + + RootNode items() throws IOException { + List list = new ArrayList(); + + while (izer.nextToken() != StreamTokenizer.TT_EOF) { + izer.pushBack(); + list.add(item()); + } + RootNode node = new RootNode(); + node.set("Root", list, 1); + return node; + } + + Node item() throws IOException { + switch (izer.nextToken()) { + case StreamTokenizer.TT_EOF: + error("Unexpect end-of-file"); + return null; + + case StreamTokenizer.TT_WORD: { + String name = izer.sval; + if (izer.nextToken() == '=') { + int ntok = izer.nextToken(); + if (ntok == StreamTokenizer.TT_WORD) { + return new NameValueNode(name, izer.sval); + } else if (ntok == '\'') { + return new NameValueNode(name, izer.sval.charAt(0)); + } else { + error("Expected value after: " + name + " ="); + return null; + } + } else { + izer.pushBack(); + return new NameNode(name); + } + } + + case '"': + return new CommentNode(izer.sval); + + case '(': { + if (izer.nextToken() == StreamTokenizer.TT_WORD) { + String kind = izer.sval; + List list = new ArrayList(); + + while (izer.nextToken() != ')') { + izer.pushBack(); + list.add(item()); + } + Node proto = kindMap.get(kind); + if (proto == null) { + error("Invalid kind: " + kind); + return null; + } else { + try { + Node node = (Node)proto.getClass().getDeclaredConstructor().newInstance(); + node.set(kind, list, izer.lineno()); + return node; + } catch (InstantiationException exc) { + error(exc.toString()); + return null; + } catch (NoSuchMethodException exc) { + error(exc.toString()); + return null; + } catch (InvocationTargetException exc) { + error(exc.toString()); + return null; + } catch (IllegalAccessException exc) { + error(exc.toString()); + return null; + } + } + } else { + error("Expected kind identifier, got " + izer.ttype + + " : " + izer.sval); + return null; + } + } + + default: + error("Unexpected character: '" + (char)izer.ttype + "'"); + return null; + } + } + + void error(String errmsg) { + System.err.println(Main.specSource + ":" + izer.lineno() + + ": " + errmsg); + throw new RuntimeException("Error: " + errmsg); + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/ReferenceIDTypeNode.java 2020-03-23 19:58:11.959961998 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,51 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class ReferenceIDTypeNode extends ReferenceTypeNode { - - String javaType() { - return "long"; - } - - String debugValue(String label) { - return "\"ref=\"+" + label; - } - - public void genJavaWrite(PrintWriter writer, int depth, - String writeLabel) { - genJavaDebugWrite(writer, depth, writeLabel); - indent(writer, depth); - writer.println("ps.writeClassRef(" + writeLabel + ");"); - } - - String javaRead() { - return "ps.readClassRef()"; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/ReferenceIDTypeNode.java 2020-03-23 19:58:11.587962001 +0100 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class ReferenceIDTypeNode extends ReferenceTypeNode { + + String javaType() { + return "long"; + } + + String debugValue(String label) { + return "\"ref=\"+" + label; + } + + public void genJavaWrite(PrintWriter writer, int depth, + String writeLabel) { + genJavaDebugWrite(writer, depth, writeLabel); + indent(writer, depth); + writer.println("ps.writeClassRef(" + writeLabel + ");"); + } + + String javaRead() { + return "ps.readClassRef()"; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/ReferenceTypeNode.java 2020-03-23 19:58:12.771961992 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,57 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class ReferenceTypeNode extends AbstractSimpleTypeNode { - - String docType() { - return "referenceTypeID"; - } - - String javaType() { - return "ReferenceTypeImpl"; - } - - String debugValue(String label) { - return "(" + label + "==null?\"NULL\":\"ref=\"+" + label + ".ref())"; - } - - public void genJavaWrite(PrintWriter writer, int depth, - String writeLabel) { - genJavaDebugWrite(writer, depth, writeLabel, - debugValue(writeLabel)); - indent(writer, depth); - writer.println("ps.writeClassRef(" + writeLabel + ".ref());"); - } - - String javaRead() { - error("--- should not gen ---"); - return null; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/ReferenceTypeNode.java 2020-03-23 19:58:12.375961995 +0100 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class ReferenceTypeNode extends AbstractSimpleTypeNode { + + String docType() { + return "referenceTypeID"; + } + + String javaType() { + return "ReferenceTypeImpl"; + } + + String debugValue(String label) { + return "(" + label + "==null?\"NULL\":\"ref=\"+" + label + ".ref())"; + } + + public void genJavaWrite(PrintWriter writer, int depth, + String writeLabel) { + genJavaDebugWrite(writer, depth, writeLabel, + debugValue(writeLabel)); + indent(writer, depth); + writer.println("ps.writeClassRef(" + writeLabel + ".ref());"); + } + + String javaRead() { + error("--- should not gen ---"); + return null; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/RepeatNode.java 2020-03-23 19:58:13.667961986 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,103 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class RepeatNode extends AbstractTypeNode { - - Node member = null; - - void constrain(Context ctx) { - super.constrain(ctx); - if (components.size() != 1) { - error("Repeat must have exactly one member, use Group for more"); - } - member = components.get(0); - if (!(member instanceof TypeNode)) { - error("Repeat member must be type specifier"); - } - } - - void document(PrintWriter writer) { - writer.println(""); - writer.println("" + indentElement(structIndent, "int")); - writer.println("" + name() + ""); - writer.println("" + comment() + " "); - writer.println(""); - - writer.println(""); - writer.println("" - + indentElement(structIndent, "Repeated " + name() + " times:")); - writer.println(""); - - ++structIndent; - member.document(writer); - --structIndent; - } - - String docType() { - return "-BOGUS-"; // should never call this - } - - String javaType() { - return member.javaType() + "[]"; - } - - public void genJavaWrite(PrintWriter writer, int depth, - String writeLabel) { - genJavaDebugWrite(writer, depth, writeLabel, "\"\""); - indent(writer, depth); - writer.println("ps.writeInt(" + writeLabel + ".length);"); - indent(writer, depth); - writer.println("for (int i = 0; i < " + writeLabel + ".length; i++) {;"); - ((TypeNode)member).genJavaWrite(writer, depth+1, writeLabel + "[i]"); - indent(writer, depth); - writer.println("}"); - } - - String javaRead() { - error("Internal - Should not call RepeatNode.javaRead()"); - return ""; - } - - public void genJavaRead(PrintWriter writer, int depth, - String readLabel) { - genJavaDebugRead(writer, depth, readLabel, "\"\""); - String cntLbl = readLabel + "Count"; - indent(writer, depth); - writer.println("int " + cntLbl + " = ps.readInt();"); - indent(writer, depth); - writer.println(readLabel + " = new " + member.javaType() + - "[" + cntLbl + "];"); - indent(writer, depth); - writer.println("for (int i = 0; i < " + cntLbl + "; i++) {;"); - member.genJavaRead(writer, depth+1, readLabel + "[i]"); - indent(writer, depth); - writer.println("}"); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/RepeatNode.java 2020-03-23 19:58:13.215961989 +0100 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class RepeatNode extends AbstractTypeNode { + + Node member = null; + + void constrain(Context ctx) { + super.constrain(ctx); + if (components.size() != 1) { + error("Repeat must have exactly one member, use Group for more"); + } + member = components.get(0); + if (!(member instanceof TypeNode)) { + error("Repeat member must be type specifier"); + } + } + + void document(PrintWriter writer) { + writer.println(""); + writer.println("" + indentElement(structIndent, "int")); + writer.println("" + name() + ""); + writer.println("" + comment() + " "); + writer.println(""); + + writer.println(""); + writer.println("" + + indentElement(structIndent, "Repeated " + name() + " times:")); + writer.println(""); + + ++structIndent; + member.document(writer); + --structIndent; + } + + String docType() { + return "-BOGUS-"; // should never call this + } + + String javaType() { + return member.javaType() + "[]"; + } + + public void genJavaWrite(PrintWriter writer, int depth, + String writeLabel) { + genJavaDebugWrite(writer, depth, writeLabel, "\"\""); + indent(writer, depth); + writer.println("ps.writeInt(" + writeLabel + ".length);"); + indent(writer, depth); + writer.println("for (int i = 0; i < " + writeLabel + ".length; i++) {;"); + ((TypeNode)member).genJavaWrite(writer, depth+1, writeLabel + "[i]"); + indent(writer, depth); + writer.println("}"); + } + + String javaRead() { + error("Internal - Should not call RepeatNode.javaRead()"); + return ""; + } + + public void genJavaRead(PrintWriter writer, int depth, + String readLabel) { + genJavaDebugRead(writer, depth, readLabel, "\"\""); + String cntLbl = readLabel + "Count"; + indent(writer, depth); + writer.println("int " + cntLbl + " = ps.readInt();"); + indent(writer, depth); + writer.println(readLabel + " = new " + member.javaType() + + "[" + cntLbl + "];"); + indent(writer, depth); + writer.println("for (int i = 0; i < " + cntLbl + "; i++) {;"); + member.genJavaRead(writer, depth+1, readLabel + "[i]"); + indent(writer, depth); + writer.println("}"); + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/ReplyNode.java 2020-03-23 19:58:14.499961980 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,73 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class ReplyNode extends AbstractTypeListNode { - - String cmdName; - - void set(String kind, List components, int lineno) { - super.set(kind, components, lineno); - components.add(0, new NameNode(kind)); - } - - void constrain(Context ctx) { - super.constrain(ctx.replyReadingSubcontext()); - CommandNode cmd = (CommandNode)parent; - cmdName = cmd.name; - } - - void genJava(PrintWriter writer, int depth) { - genJavaPreDef(writer, depth); - super.genJava(writer, depth); - writer.println(); - genJavaReadingClassBody(writer, depth, cmdName); - } - - void genJavaReads(PrintWriter writer, int depth) { - if (Main.genDebug) { - indent(writer, depth); - writer.println( - "if (vm.traceReceives) {"); - indent(writer, depth+1); - writer.print( - "vm.printTrace(\"Receiving Command(id=\" + ps.pkt.id + \") "); - writer.print(parent.context.whereJava); - writer.print("\""); - writer.print( - "+(ps.pkt.flags!=0?\", FLAGS=\" + ps.pkt.flags:\"\")"); - writer.print( - "+(ps.pkt.errorCode!=0?\", ERROR CODE=\" + ps.pkt.errorCode:\"\")"); - writer.println(");"); - indent(writer, depth); - writer.println("}"); - } - super.genJavaReads(writer, depth); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/ReplyNode.java 2020-03-23 19:58:14.079961983 +0100 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class ReplyNode extends AbstractTypeListNode { + + String cmdName; + + void set(String kind, List components, int lineno) { + super.set(kind, components, lineno); + components.add(0, new NameNode(kind)); + } + + void constrain(Context ctx) { + super.constrain(ctx.replyReadingSubcontext()); + CommandNode cmd = (CommandNode)parent; + cmdName = cmd.name; + } + + void genJava(PrintWriter writer, int depth) { + genJavaPreDef(writer, depth); + super.genJava(writer, depth); + writer.println(); + genJavaReadingClassBody(writer, depth, cmdName); + } + + void genJavaReads(PrintWriter writer, int depth) { + if (Main.genDebug) { + indent(writer, depth); + writer.println( + "if (vm.traceReceives) {"); + indent(writer, depth+1); + writer.print( + "vm.printTrace(\"Receiving Command(id=\" + ps.pkt.id + \") "); + writer.print(parent.context.whereJava); + writer.print("\""); + writer.print( + "+(ps.pkt.flags!=0?\", FLAGS=\" + ps.pkt.flags:\"\")"); + writer.print( + "+(ps.pkt.errorCode!=0?\", ERROR CODE=\" + ps.pkt.errorCode:\"\")"); + writer.println(");"); + indent(writer, depth); + writer.println("}"); + } + super.genJavaReads(writer, depth); + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/RootNode.java 2020-03-23 19:58:15.303961974 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,88 +0,0 @@ -/* - * Copyright (c) 1998, 2019, 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.jdwpgen; - -import java.util.*; -import java.io.*; - -class RootNode extends AbstractNamedNode { - - void constrainComponent(Context ctx, Node node) { - if (node instanceof CommandSetNode || - node instanceof ConstantSetNode) { - node.constrain(ctx); - } else { - error("Expected 'CommandSet' item, got: " + node); - } - } - - void document(PrintWriter writer) { - writer.println(""); - writer.println(""); - writer.println(""); - writer.println(""); - writer.println("" + comment() + ""); - writer.println(""); - writer.println(""); - writer.println(""); - writer.println("
    "); - writer.println("

    Java Debug Wire Protocol Details

    "); - writer.println("
    "); - writer.println(""); - writer.println("
    "); - for (Node node : components) { - node.document(writer); - } - writer.println("
    "); - writer.println(""); - } - - void genJava(PrintWriter writer, int depth) { - writer.println("package com.sun.tools.jdi;"); - writer.println(); - writer.println("import com.sun.jdi.*;"); - writer.println("import java.util.*;"); - writer.println(); - - genJavaClass(writer, depth); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/RootNode.java 2020-03-23 19:58:14.911961977 +0100 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class RootNode extends AbstractNamedNode { + + void constrainComponent(Context ctx, Node node) { + if (node instanceof CommandSetNode || + node instanceof ConstantSetNode) { + node.constrain(ctx); + } else { + error("Expected 'CommandSet' item, got: " + node); + } + } + + void document(PrintWriter writer) { + writer.println(""); + writer.println(""); + writer.println(""); + writer.println(""); + writer.println("" + comment() + ""); + writer.println(""); + writer.println(""); + writer.println(""); + writer.println("
    "); + writer.println("

    Java Debug Wire Protocol Details

    "); + writer.println("
    "); + writer.println(""); + writer.println("
    "); + for (Node node : components) { + node.document(writer); + } + writer.println("
    "); + writer.println(""); + } + + void genJava(PrintWriter writer, int depth) { + writer.println("package com.sun.tools.jdi;"); + writer.println(); + writer.println("import com.sun.jdi.*;"); + writer.println("import java.util.*;"); + writer.println(); + + genJavaClass(writer, depth); + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/SelectNode.java 2020-03-23 19:58:16.179961967 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,150 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class SelectNode extends AbstractGroupNode implements TypeNode { - - AbstractSimpleTypeNode typeNode = null; - - void prune() { - super.prune(); - Iterator it = components.iterator(); - - if (it.hasNext()) { - Node typeNode = it.next(); - - if (typeNode instanceof ByteTypeNode || - typeNode instanceof IntTypeNode) { - this.typeNode = (AbstractSimpleTypeNode)typeNode; - it.remove(); - } else { - error("Select must be based on 'int' or 'byte'"); - } - } else { - error("empty"); - } - } - - void constrain(Context ctx) { - super.constrain(ctx); - if (components.size() < 2) { - error("Select must have at least two options"); - } - } - - void constrainComponent(Context ctx, Node node) { - node.constrain(ctx); - if (!(node instanceof AltNode)) { - error("Select must consist of selector followed by Alt items"); - } - } - - void document(PrintWriter writer) { - typeNode.document(writer); - super.document(writer); - } - - String docType() { - // should never call this - error("Internal - called SelectNode.docType()"); - return null; - } - - String commonBaseClass() { - return name() + "Common"; - } - - private String commonVar() { - return " a" + commonBaseClass(); - } - - void genJavaClassSpecifics(PrintWriter writer, int depth) { - indent(writer, depth); - writer.println("abstract static class " + commonBaseClass() + " {"); - if (context.isWritingCommand()) { - indent(writer, depth+1); - writer.println("abstract void write(PacketStream ps);"); - } else { - indent(writer, depth+1); - writer.println("abstract " + typeNode.javaParam() + "();"); - } - indent(writer, depth); - writer.println("}"); - typeNode.genJavaDeclaration(writer, depth); - indent(writer, depth); - writer.println(commonBaseClass() + commonVar() + ";"); - super.genJavaClassSpecifics(writer, depth); - } - - void genJavaClassBodyComponents(PrintWriter writer, int depth) { - // don't naively include alt components - } - - void genJavaWritingClassBody(PrintWriter writer, int depth, - String className) { - writer.println(); - indent(writer, depth); - writer.print(className + "(" + typeNode.javaParam() + ", "); - writer.print(commonBaseClass() + commonVar()); - writer.println(") {"); - indent(writer, depth+1); - writer.println("this." + typeNode.name() + " = " + typeNode.name() + ";"); - indent(writer, depth+1); - writer.println("this." + commonVar() + " =" + commonVar() + ";"); - indent(writer, depth); - writer.println("}"); - } - - void genJavaWrites(PrintWriter writer, int depth) { - typeNode.genJavaWrite(writer, depth, typeNode.name()); - indent(writer, depth); - writer.println(commonVar() + ".write(ps);"); - } - - void genJavaReads(PrintWriter writer, int depth) { - typeNode.genJavaRead(writer, depth, typeNode.name()); - indent(writer, depth); - writer.println("switch (" + typeNode.name() + ") {"); - for (Node node : components) { - AltNode alt = (AltNode)node; - alt.genJavaReadsSelectCase(writer, depth+1, commonVar()); - } - indent(writer, depth); - writer.println("}"); - } - - public void genJavaDeclaration(PrintWriter writer, int depth) { - typeNode.genJavaDeclaration(writer, depth); - super.genJavaDeclaration(writer, depth); - } - - public String javaParam() { - return typeNode.javaParam() + ", " + name() + " a" + name(); - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/SelectNode.java 2020-03-23 19:58:15.751961970 +0100 @@ -0,0 +1,150 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class SelectNode extends AbstractGroupNode implements TypeNode { + + AbstractSimpleTypeNode typeNode = null; + + void prune() { + super.prune(); + Iterator it = components.iterator(); + + if (it.hasNext()) { + Node typeNode = it.next(); + + if (typeNode instanceof ByteTypeNode || + typeNode instanceof IntTypeNode) { + this.typeNode = (AbstractSimpleTypeNode)typeNode; + it.remove(); + } else { + error("Select must be based on 'int' or 'byte'"); + } + } else { + error("empty"); + } + } + + void constrain(Context ctx) { + super.constrain(ctx); + if (components.size() < 2) { + error("Select must have at least two options"); + } + } + + void constrainComponent(Context ctx, Node node) { + node.constrain(ctx); + if (!(node instanceof AltNode)) { + error("Select must consist of selector followed by Alt items"); + } + } + + void document(PrintWriter writer) { + typeNode.document(writer); + super.document(writer); + } + + String docType() { + // should never call this + error("Internal - called SelectNode.docType()"); + return null; + } + + String commonBaseClass() { + return name() + "Common"; + } + + private String commonVar() { + return " a" + commonBaseClass(); + } + + void genJavaClassSpecifics(PrintWriter writer, int depth) { + indent(writer, depth); + writer.println("abstract static class " + commonBaseClass() + " {"); + if (context.isWritingCommand()) { + indent(writer, depth+1); + writer.println("abstract void write(PacketStream ps);"); + } else { + indent(writer, depth+1); + writer.println("abstract " + typeNode.javaParam() + "();"); + } + indent(writer, depth); + writer.println("}"); + typeNode.genJavaDeclaration(writer, depth); + indent(writer, depth); + writer.println(commonBaseClass() + commonVar() + ";"); + super.genJavaClassSpecifics(writer, depth); + } + + void genJavaClassBodyComponents(PrintWriter writer, int depth) { + // don't naively include alt components + } + + void genJavaWritingClassBody(PrintWriter writer, int depth, + String className) { + writer.println(); + indent(writer, depth); + writer.print(className + "(" + typeNode.javaParam() + ", "); + writer.print(commonBaseClass() + commonVar()); + writer.println(") {"); + indent(writer, depth+1); + writer.println("this." + typeNode.name() + " = " + typeNode.name() + ";"); + indent(writer, depth+1); + writer.println("this." + commonVar() + " =" + commonVar() + ";"); + indent(writer, depth); + writer.println("}"); + } + + void genJavaWrites(PrintWriter writer, int depth) { + typeNode.genJavaWrite(writer, depth, typeNode.name()); + indent(writer, depth); + writer.println(commonVar() + ".write(ps);"); + } + + void genJavaReads(PrintWriter writer, int depth) { + typeNode.genJavaRead(writer, depth, typeNode.name()); + indent(writer, depth); + writer.println("switch (" + typeNode.name() + ") {"); + for (Node node : components) { + AltNode alt = (AltNode)node; + alt.genJavaReadsSelectCase(writer, depth+1, commonVar()); + } + indent(writer, depth); + writer.println("}"); + } + + public void genJavaDeclaration(PrintWriter writer, int depth) { + typeNode.genJavaDeclaration(writer, depth); + super.genJavaDeclaration(writer, depth); + } + + public String javaParam() { + return typeNode.javaParam() + ", " + name() + " a" + name(); + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/StringObjectTypeNode.java 2020-03-23 19:58:17.015961961 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,43 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; - -class StringObjectTypeNode extends ObjectTypeNode { - - String docType() { - return "stringID"; - } - - String javaType() { - return "StringReferenceImpl"; - } - - String javaRead() { - return "ps.readStringReference()"; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/StringObjectTypeNode.java 2020-03-23 19:58:16.595961964 +0100 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; + +class StringObjectTypeNode extends ObjectTypeNode { + + String docType() { + return "stringID"; + } + + String javaType() { + return "StringReferenceImpl"; + } + + String javaRead() { + return "ps.readStringReference()"; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/StringTypeNode.java 2020-03-23 19:58:17.883961955 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,51 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class StringTypeNode extends AbstractSimpleTypeNode { - - String docType() { - return "string"; - } - - String javaType() { - return "String"; - } - - public void genJavaWrite(PrintWriter writer, int depth, - String writeLabel) { - genJavaDebugWrite(writer, depth, writeLabel); - indent(writer, depth); - writer.println("ps.writeString(" + writeLabel + ");"); - } - - String javaRead() { - return "ps.readString()"; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/StringTypeNode.java 2020-03-23 19:58:17.455961958 +0100 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class StringTypeNode extends AbstractSimpleTypeNode { + + String docType() { + return "string"; + } + + String javaType() { + return "String"; + } + + public void genJavaWrite(PrintWriter writer, int depth, + String writeLabel) { + genJavaDebugWrite(writer, depth, writeLabel); + indent(writer, depth); + writer.println("ps.writeString(" + writeLabel + ");"); + } + + String javaRead() { + return "ps.readString()"; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/TaggedObjectTypeNode.java 2020-03-23 19:58:18.727961948 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,45 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class TaggedObjectTypeNode extends ObjectTypeNode { - - String docType() { - return "tagged-objectID"; - } - - public void genJavaWrite(PrintWriter writer, int depth, - String writeLabel) { - error("Why write a tagged-object?"); - } - - String javaRead() { - return "ps.readTaggedObjectReference()"; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/TaggedObjectTypeNode.java 2020-03-23 19:58:18.327961951 +0100 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class TaggedObjectTypeNode extends ObjectTypeNode { + + String docType() { + return "tagged-objectID"; + } + + public void genJavaWrite(PrintWriter writer, int depth, + String writeLabel) { + error("Why write a tagged-object?"); + } + + String javaRead() { + return "ps.readTaggedObjectReference()"; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/ThreadGroupObjectTypeNode.java 2020-03-23 19:58:19.583961942 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,43 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; - -class ThreadGroupObjectTypeNode extends ObjectTypeNode { - - String docType() { - return "threadGroupID"; - } - - String javaType() { - return "ThreadGroupReferenceImpl"; - } - - String javaRead() { - return "ps.readThreadGroupReference()"; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/ThreadGroupObjectTypeNode.java 2020-03-23 19:58:19.143961945 +0100 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; + +class ThreadGroupObjectTypeNode extends ObjectTypeNode { + + String docType() { + return "threadGroupID"; + } + + String javaType() { + return "ThreadGroupReferenceImpl"; + } + + String javaRead() { + return "ps.readThreadGroupReference()"; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/ThreadObjectTypeNode.java 2020-03-23 19:58:20.371961936 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,43 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; - -class ThreadObjectTypeNode extends ObjectTypeNode { - - String docType() { - return "threadID"; - } - - String javaType() { - return "ThreadReferenceImpl"; - } - - String javaRead() { - return "ps.readThreadReference()"; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/ThreadObjectTypeNode.java 2020-03-23 19:58:19.995961939 +0100 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; + +class ThreadObjectTypeNode extends ObjectTypeNode { + + String docType() { + return "threadID"; + } + + String javaType() { + return "ThreadReferenceImpl"; + } + + String javaRead() { + return "ps.readThreadReference()"; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/TypeNode.java 2020-03-23 19:58:21.215961930 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,43 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - - -import java.util.*; -import java.io.*; - -interface TypeNode { - - String name(); - - void genJavaWrite(PrintWriter writer, int depth, String writeLabel); - - void genJavaRead(PrintWriter writer, int depth, String readLabel); - - void genJavaDeclaration(PrintWriter writer, int depth); - - String javaParam(); -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/TypeNode.java 2020-03-23 19:58:20.791961933 +0100 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + + +import java.util.*; +import java.io.*; + +interface TypeNode { + + String name(); + + void genJavaWrite(PrintWriter writer, int depth, String writeLabel); + + void genJavaRead(PrintWriter writer, int depth, String readLabel); + + void genJavaDeclaration(PrintWriter writer, int depth); + + String javaParam(); +} --- old/make/jdk/src/classes/build/tools/jdwpgen/UntaggedValueTypeNode.java 2020-03-23 19:58:22.095961924 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,47 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class UntaggedValueTypeNode extends ValueTypeNode { - - String docType() { - return "untagged-value"; - } - - public void genJavaWrite(PrintWriter writer, int depth, - String writeLabel) { - genJavaDebugWrite(writer, depth, writeLabel); - indent(writer, depth); - writer.println("ps.writeUntaggedValue(" + writeLabel + ");"); - } - - String javaRead() { - return "ps.readUntaggedValue()"; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/UntaggedValueTypeNode.java 2020-03-23 19:58:21.655961927 +0100 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class UntaggedValueTypeNode extends ValueTypeNode { + + String docType() { + return "untagged-value"; + } + + public void genJavaWrite(PrintWriter writer, int depth, + String writeLabel) { + genJavaDebugWrite(writer, depth, writeLabel); + indent(writer, depth); + writer.println("ps.writeUntaggedValue(" + writeLabel + ");"); + } + + String javaRead() { + return "ps.readUntaggedValue()"; + } +} --- old/make/jdk/src/classes/build/tools/jdwpgen/ValueTypeNode.java 2020-03-23 19:58:22.971961917 +0100 +++ /dev/null 2020-02-11 10:29:13.086348146 +0100 @@ -1,51 +0,0 @@ -/* - * Copyright (c) 1998, 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 build.tools.jdwpgen; - -import java.util.*; -import java.io.*; - -class ValueTypeNode extends AbstractSimpleTypeNode { - - String docType() { - return "value"; - } - - String javaType() { - return "ValueImpl"; - } - - public void genJavaWrite(PrintWriter writer, int depth, - String writeLabel) { - genJavaDebugWrite(writer, depth, writeLabel); - indent(writer, depth); - writer.println("ps.writeValue(" + writeLabel + ");"); - } - - String javaRead() { - return "ps.readValue()"; - } -} --- /dev/null 2020-02-11 10:29:13.086348146 +0100 +++ new/src/jdk.jdi/share/tools/org/openjdk/buildtools/jdwpgen/ValueTypeNode.java 2020-03-23 19:58:22.535961920 +0100 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1998, 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 org.openjdk.buildtools.jdwpgen; + +import java.util.*; +import java.io.*; + +class ValueTypeNode extends AbstractSimpleTypeNode { + + String docType() { + return "value"; + } + + String javaType() { + return "ValueImpl"; + } + + public void genJavaWrite(PrintWriter writer, int depth, + String writeLabel) { + genJavaDebugWrite(writer, depth, writeLabel); + indent(writer, depth); + writer.println("ps.writeValue(" + writeLabel + ");"); + } + + String javaRead() { + return "ps.readValue()"; + } +}