This commit is contained in:
Phil Race 2017-12-13 10:25:38 -08:00
commit 4b727d4f18
215 changed files with 11659 additions and 2940 deletions

View File

@ -37,6 +37,7 @@ import java.util.ResourceBundle.Control;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.SAXNotRecognizedException;
@ -52,21 +53,32 @@ public class CLDRConverter {
static final String LDML_DTD_SYSTEM_ID = "http://www.unicode.org/cldr/dtd/2.0/ldml.dtd";
static final String SPPL_LDML_DTD_SYSTEM_ID = "http://www.unicode.org/cldr/dtd/2.0/ldmlSupplemental.dtd";
static final String BCP47_LDML_DTD_SYSTEM_ID = "http://www.unicode.org/cldr/dtd/2.0/ldmlBCP47.dtd";
private static String CLDR_BASE = "../CLDR/21.0.1/";
static String LOCAL_LDML_DTD;
static String LOCAL_SPPL_LDML_DTD;
static String LOCAL_BCP47_LDML_DTD;
private static String SOURCE_FILE_DIR;
private static String SPPL_SOURCE_FILE;
private static String NUMBERING_SOURCE_FILE;
private static String METAZONES_SOURCE_FILE;
private static String LIKELYSUBTAGS_SOURCE_FILE;
private static String TIMEZONE_SOURCE_FILE;
static String DESTINATION_DIR = "build/gensrc";
static final String LOCALE_NAME_PREFIX = "locale.displayname.";
static final String LOCALE_SEPARATOR = LOCALE_NAME_PREFIX + "separator";
static final String LOCALE_KEYTYPE = LOCALE_NAME_PREFIX + "keytype";
static final String LOCALE_KEY_PREFIX = LOCALE_NAME_PREFIX + "key.";
static final String LOCALE_TYPE_PREFIX = LOCALE_NAME_PREFIX + "type.";
static final String LOCALE_TYPE_PREFIX_CA = LOCALE_TYPE_PREFIX + "ca.";
static final String CURRENCY_SYMBOL_PREFIX = "currency.symbol.";
static final String CURRENCY_NAME_PREFIX = "currency.displayname.";
static final String CALENDAR_NAME_PREFIX = "calendarname.";
static final String CALENDAR_FIRSTDAY_PREFIX = "firstDay.";
static final String CALENDAR_MINDAYS_PREFIX = "minDays.";
static final String TIMEZONE_ID_PREFIX = "timezone.id.";
static final String ZONE_NAME_PREFIX = "timezone.displayname.";
static final String METAZONE_ID_PREFIX = "metazone.id.";
@ -76,6 +88,7 @@ public class CLDRConverter {
private static LikelySubtagsParseHandler handlerLikelySubtags;
static NumberingSystemsParseHandler handlerNumbering;
static MetaZonesParseHandler handlerMetaZones;
static TimeZoneParseHandler handlerTimeZone;
private static BundleGenerator bundleGenerator;
// java.base module related
@ -201,11 +214,13 @@ public class CLDRConverter {
// Set up path names
LOCAL_LDML_DTD = CLDR_BASE + "/dtd/ldml.dtd";
LOCAL_SPPL_LDML_DTD = CLDR_BASE + "/dtd/ldmlSupplemental.dtd";
LOCAL_BCP47_LDML_DTD = CLDR_BASE + "/dtd/ldmlBCP47.dtd";
SOURCE_FILE_DIR = CLDR_BASE + "/main";
SPPL_SOURCE_FILE = CLDR_BASE + "/supplemental/supplementalData.xml";
LIKELYSUBTAGS_SOURCE_FILE = CLDR_BASE + "/supplemental/likelySubtags.xml";
NUMBERING_SOURCE_FILE = CLDR_BASE + "/supplemental/numberingSystems.xml";
METAZONES_SOURCE_FILE = CLDR_BASE + "/supplemental/metaZones.xml";
TIMEZONE_SOURCE_FILE = CLDR_BASE + "/bcp47/timezone.xml";
if (BASE_LOCALES.isEmpty()) {
setupBaseLocales("en-US");
@ -215,10 +230,10 @@ public class CLDRConverter {
// Parse data independent of locales
parseSupplemental();
parseBCP47();
List<Bundle> bundles = readBundleList();
convertBundles(bundles);
convertBundles(addedBundles);
}
private static void usage() {
@ -314,34 +329,19 @@ public class CLDRConverter {
}
private static final Map<String, Map<String, Object>> cldrBundles = new HashMap<>();
// this list will contain additional bundles to be generated for Region dependent Data.
private static List<Bundle> addedBundles = new ArrayList<>();
private static Map<String, SortedSet<String>> metaInfo = new HashMap<>();
static {
// For generating information on supported locales.
metaInfo.put("LocaleNames", new TreeSet<>());
metaInfo.put("CurrencyNames", new TreeSet<>());
metaInfo.put("TimeZoneNames", new TreeSet<>());
metaInfo.put("CalendarData", new TreeSet<>());
metaInfo.put("FormatData", new TreeSet<>());
metaInfo.put("AvailableLocales", new TreeSet<>());
}
private static Set<String> calendarDataFields = Set.of("firstDayOfWeek", "minimalDaysInFirstWeek");
static Map<String, Object> getCLDRBundle(String id) throws Exception {
Map<String, Object> bundle = cldrBundles.get(id);
if (bundle != null) {
return bundle;
}
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setValidating(true);
SAXParser parser = factory.newSAXParser();
enableFileAccess(parser);
LDMLParseHandler handler = new LDMLParseHandler(id);
File file = new File(SOURCE_FILE_DIR + File.separator + id + ".xml");
if (!file.exists()) {
// Skip if the file doesn't exist.
@ -349,14 +349,15 @@ public class CLDRConverter {
}
info("..... main directory .....");
info("Reading file " + file);
parser.parse(file, handler);
LDMLParseHandler handler = new LDMLParseHandler(id);
parseLDMLFile(file, handler);
bundle = handler.getData();
cldrBundles.put(id, bundle);
String country = getCountryCode(id);
if (country != null) {
bundle = handlerSuppl.getData(country);
if (id.equals("root")) {
// Calendar data (firstDayOfWeek & minDaysInFirstWeek)
bundle = handlerSuppl.getData("root");
if (bundle != null) {
//merge two maps into one map
Map<String, Object> temp = cldrBundles.remove(id);
@ -379,98 +380,44 @@ public class CLDRConverter {
// SupplementalData file also provides the "parent" locales which
// are othrwise not to be fallen back. Process them here as well.
//
info("..... Parsing supplementalData.xml .....");
SAXParserFactory factorySuppl = SAXParserFactory.newInstance();
factorySuppl.setValidating(true);
SAXParser parserSuppl = factorySuppl.newSAXParser();
enableFileAccess(parserSuppl);
handlerSuppl = new SupplementDataParseHandler();
File fileSupply = new File(SPPL_SOURCE_FILE);
parserSuppl.parse(fileSupply, handlerSuppl);
parseLDMLFile(new File(SPPL_SOURCE_FILE), handlerSuppl);
Map<String, Object> parentData = handlerSuppl.getData("root");
parentData.keySet().forEach(key -> {
parentData.keySet().stream()
.filter(key -> key.startsWith(PARENT_LOCALE_PREFIX))
.forEach(key -> {
parentLocalesMap.put(key, new TreeSet(
Arrays.asList(((String)parentData.get(key)).split(" "))));
});
// Parse numberingSystems to get digit zero character information.
SAXParserFactory numberingParser = SAXParserFactory.newInstance();
numberingParser.setValidating(true);
SAXParser parserNumbering = numberingParser.newSAXParser();
enableFileAccess(parserNumbering);
handlerNumbering = new NumberingSystemsParseHandler();
File fileNumbering = new File(NUMBERING_SOURCE_FILE);
parserNumbering.parse(fileNumbering, handlerNumbering);
parseLDMLFile(new File(NUMBERING_SOURCE_FILE), handlerNumbering);
// Parse metaZones to create mappings between Olson tzids and CLDR meta zone names
info("..... Parsing metaZones.xml .....");
SAXParserFactory metazonesParser = SAXParserFactory.newInstance();
metazonesParser.setValidating(true);
SAXParser parserMetaZones = metazonesParser.newSAXParser();
enableFileAccess(parserMetaZones);
handlerMetaZones = new MetaZonesParseHandler();
File fileMetaZones = new File(METAZONES_SOURCE_FILE);
parserMetaZones.parse(fileMetaZones, handlerMetaZones);
parseLDMLFile(new File(METAZONES_SOURCE_FILE), handlerMetaZones);
// Parse likelySubtags
info("..... Parsing likelySubtags.xml .....");
SAXParserFactory likelySubtagsParser = SAXParserFactory.newInstance();
likelySubtagsParser.setValidating(true);
SAXParser parserLikelySubtags = likelySubtagsParser.newSAXParser();
enableFileAccess(parserLikelySubtags);
handlerLikelySubtags = new LikelySubtagsParseHandler();
File fileLikelySubtags = new File(LIKELYSUBTAGS_SOURCE_FILE);
parserLikelySubtags.parse(fileLikelySubtags, handlerLikelySubtags);
parseLDMLFile(new File(LIKELYSUBTAGS_SOURCE_FILE), handlerLikelySubtags);
}
/**
* This method will check if a new region dependent Bundle needs to be
* generated for this Locale id and targetMap. New Bundle will be generated
* when Locale id has non empty script and country code and targetMap
* contains region dependent data. This method will also remove region
* dependent data from this targetMap after candidate locales check. E.g. It
* will call genRegionDependentBundle() in case of az_Latn_AZ locale and
* remove region dependent data from this targetMap so that az_Latn_AZ
* bundle will not be created. For az_Cyrl_AZ, new Bundle will be generated
* but region dependent data will not be removed from targetMap as its candidate
* locales are [az_Cyrl_AZ, az_Cyrl, root], which does not include az_AZ for
* fallback.
*
*/
private static void checkRegionDependentBundle(Map<String, Object> targetMap, String id) {
if ((CLDRConverter.getScript(id) != "")
&& (CLDRConverter.getCountryCode(id) != "")) {
Map<String, Object> regionDepDataMap = targetMap
.keySet()
.stream()
.filter(calendarDataFields::contains)
.collect(Collectors.toMap(k -> k, targetMap::get));
if (!regionDepDataMap.isEmpty()) {
Locale cldrLoc = new Locale(CLDRConverter.getLanguageCode(id),
CLDRConverter.getCountryCode(id));
genRegionDependentBundle(regionDepDataMap, cldrLoc);
if (checkCandidateLocales(id, cldrLoc)) {
// Remove matchedKeys from this targetMap only if checkCandidateLocales() returns true.
regionDepDataMap.keySet().forEach(targetMap::remove);
}
}
}
// Parsers for data in "bcp47" directory
//
private static void parseBCP47() throws Exception {
// Parse timezone
handlerTimeZone = new TimeZoneParseHandler();
parseLDMLFile(new File(TIMEZONE_SOURCE_FILE), handlerTimeZone);
}
/**
* This method will generate a new Bundle for region dependent data,
* minimalDaysInFirstWeek and firstDayOfWeek. Newly generated Bundle will be added
* to addedBundles list.
*/
private static void genRegionDependentBundle(Map<String, Object> targetMap, Locale cldrLoc) {
String localeId = cldrLoc.toString();
StringBuilder sb = getCandLocales(cldrLoc);
if (sb.indexOf(localeId) == -1) {
sb.append(localeId);
}
Bundle bundle = new Bundle(localeId, sb.toString(), null, null);
cldrBundles.put(localeId, targetMap);
addedBundles.add(bundle);
private static void parseLDMLFile(File srcfile, AbstractLDMLHandler handler) throws Exception {
info("..... Parsing " + srcfile.getName() + " .....");
SAXParserFactory pf = SAXParserFactory.newInstance();
pf.setValidating(true);
SAXParser parser = pf.newSAXParser();
enableFileAccess(parser);
parser.parse(srcfile, handler);
}
private static StringBuilder getCandLocales(Locale cldrLoc) {
@ -491,16 +438,6 @@ public class CLDRConverter {
return candList;
}
/**
* This method will return true, if for a given locale, its language and
* country specific locale will exist in runtime lookup path. E.g. it will
* return true for bs_Latn_BA.
*/
private static boolean checkCandidateLocales(String id, Locale cldrLoc) {
return(getCandidateLocales(Locale.forLanguageTag(id.replaceAll("_", "-")))
.contains(cldrLoc));
}
private static void convertBundles(List<Bundle> bundles) throws Exception {
// parent locales map. The mappings are put in base metaInfo file
// for now.
@ -514,8 +451,6 @@ public class CLDRConverter {
Map<String, Object> targetMap = bundle.getTargetMap();
// check if new region DependentBundle needs to be generated for this Locale.
checkRegionDependentBundle(targetMap, bundle.getID());
EnumSet<Bundle.Type> bundleTypes = bundle.getBundleTypes();
if (bundle.isRoot()) {
@ -528,40 +463,30 @@ public class CLDRConverter {
if (bundleTypes.contains(Bundle.Type.LOCALENAMES)) {
Map<String, Object> localeNamesMap = extractLocaleNames(targetMap, bundle.getID());
if (!localeNamesMap.isEmpty() || bundle.isRoot()) {
metaInfo.get("LocaleNames").add(toLanguageTag(bundle.getID()));
addLikelySubtags(metaInfo, "LocaleNames", bundle.getID());
bundleGenerator.generateBundle("util", "LocaleNames", bundle.getJavaID(), true, localeNamesMap, BundleType.OPEN);
}
}
if (bundleTypes.contains(Bundle.Type.CURRENCYNAMES)) {
Map<String, Object> currencyNamesMap = extractCurrencyNames(targetMap, bundle.getID(), bundle.getCurrencies());
if (!currencyNamesMap.isEmpty() || bundle.isRoot()) {
metaInfo.get("CurrencyNames").add(toLanguageTag(bundle.getID()));
addLikelySubtags(metaInfo, "CurrencyNames", bundle.getID());
bundleGenerator.generateBundle("util", "CurrencyNames", bundle.getJavaID(), true, currencyNamesMap, BundleType.OPEN);
}
}
if (bundleTypes.contains(Bundle.Type.TIMEZONENAMES)) {
Map<String, Object> zoneNamesMap = extractZoneNames(targetMap, bundle.getID());
if (!zoneNamesMap.isEmpty() || bundle.isRoot()) {
metaInfo.get("TimeZoneNames").add(toLanguageTag(bundle.getID()));
addLikelySubtags(metaInfo, "TimeZoneNames", bundle.getID());
bundleGenerator.generateBundle("util", "TimeZoneNames", bundle.getJavaID(), true, zoneNamesMap, BundleType.TIMEZONE);
}
}
if (bundleTypes.contains(Bundle.Type.CALENDARDATA)) {
Map<String, Object> calendarDataMap = extractCalendarData(targetMap, bundle.getID());
if (!calendarDataMap.isEmpty() || bundle.isRoot()) {
metaInfo.get("CalendarData").add(toLanguageTag(bundle.getID()));
addLikelySubtags(metaInfo, "CalendarData", bundle.getID());
bundleGenerator.generateBundle("util", "CalendarData", bundle.getJavaID(), true, calendarDataMap, BundleType.PLAIN);
}
}
if (bundleTypes.contains(Bundle.Type.FORMATDATA)) {
Map<String, Object> formatDataMap = extractFormatData(targetMap, bundle.getID());
if (!formatDataMap.isEmpty() || bundle.isRoot()) {
metaInfo.get("FormatData").add(toLanguageTag(bundle.getID()));
addLikelySubtags(metaInfo, "FormatData", bundle.getID());
bundleGenerator.generateBundle("text", "FormatData", bundle.getJavaID(), true, formatDataMap, BundleType.PLAIN);
}
}
@ -570,43 +495,9 @@ public class CLDRConverter {
metaInfo.get("AvailableLocales").add(toLanguageTag(bundle.getID()));
addLikelySubtags(metaInfo, "AvailableLocales", bundle.getID());
}
addCldrImplicitLocales(metaInfo);
bundleGenerator.generateMetaInfo(metaInfo);
}
/**
* These are the Locales that are implicitly supported by CLDR.
* Adding them explicitly as likelySubtags here, will ensure that
* COMPAT locales do not precede them during ResourceBundle search path.
*/
private static void addCldrImplicitLocales(Map<String, SortedSet<String>> metaInfo) {
metaInfo.get("LocaleNames").add("zh-Hans-CN");
metaInfo.get("LocaleNames").add("zh-Hans-SG");
metaInfo.get("LocaleNames").add("zh-Hant-HK");
metaInfo.get("LocaleNames").add("zh-Hant-MO");
metaInfo.get("LocaleNames").add("zh-Hant-TW");
metaInfo.get("CurrencyNames").add("zh-Hans-CN");
metaInfo.get("CurrencyNames").add("zh-Hans-SG");
metaInfo.get("CurrencyNames").add("zh-Hant-HK");
metaInfo.get("CurrencyNames").add("zh-Hant-MO");
metaInfo.get("CurrencyNames").add("zh-Hant-TW");
metaInfo.get("TimeZoneNames").add("zh-Hans-CN");
metaInfo.get("TimeZoneNames").add("zh-Hans-SG");
metaInfo.get("TimeZoneNames").add("zh-Hant-HK");
metaInfo.get("TimeZoneNames").add("zh-Hant-MO");
metaInfo.get("TimeZoneNames").add("zh-Hant-TW");
metaInfo.get("TimeZoneNames").add("zh-HK");
metaInfo.get("CalendarData").add("zh-Hans-CN");
metaInfo.get("CalendarData").add("zh-Hans-SG");
metaInfo.get("CalendarData").add("zh-Hant-HK");
metaInfo.get("CalendarData").add("zh-Hant-MO");
metaInfo.get("CalendarData").add("zh-Hant-TW");
metaInfo.get("FormatData").add("zh-Hans-CN");
metaInfo.get("FormatData").add("zh-Hans-SG");
metaInfo.get("FormatData").add("zh-Hant-HK");
metaInfo.get("FormatData").add("zh-Hant-MO");
metaInfo.get("FormatData").add("zh-Hant-TW");
}
static final Map<String, String> aliases = new HashMap<>();
/**
@ -656,14 +547,6 @@ public class CLDRConverter {
return Locale.forLanguageTag(id.replaceAll("_", "-")).getCountry();
}
/*
* Returns the script portion of the given id.
* If id is "root", "" is returned.
*/
static String getScript(String id) {
return "root".equals(id) ? "" : Locale.forLanguageTag(id.replaceAll("_", "-")).getScript();
}
private static class KeyComparator implements Comparator<String> {
static KeyComparator INSTANCE = new KeyComparator();
@ -695,9 +578,25 @@ public class CLDRConverter {
Map<String, Object> localeNames = new TreeMap<>(KeyComparator.INSTANCE);
for (String key : map.keySet()) {
if (key.startsWith(LOCALE_NAME_PREFIX)) {
localeNames.put(key.substring(LOCALE_NAME_PREFIX.length()), map.get(key));
switch (key) {
case LOCALE_SEPARATOR:
localeNames.put("ListCompositionPattern", map.get(key));
break;
case LOCALE_KEYTYPE:
localeNames.put("ListKeyTypePattern", map.get(key));
break;
default:
localeNames.put(key.substring(LOCALE_NAME_PREFIX.length()), map.get(key));
break;
}
}
}
if (id.equals("root")) {
// Add display name pattern, which is not in CLDR
localeNames.put("DisplayNamePattern", "{0,choice,0#|1#{1}|2#{1} ({2})}");
}
return localeNames;
}
@ -778,10 +677,30 @@ public class CLDRConverter {
return names;
}
/**
* Extracts the language independent calendar data. Each of the two keys,
* "firstDayOfWeek" and "minimalDaysInFirstWeek" has a string value consists of
* one or multiple occurrences of:
* i: rg1 rg2 ... rgn;
* where "i" is the data for the following regions (delimited by a space) after
* ":", and ends with a ";".
*/
private static Map<String, Object> extractCalendarData(Map<String, Object> map, String id) {
Map<String, Object> calendarData = new LinkedHashMap<>();
copyIfPresent(map, "firstDayOfWeek", calendarData);
copyIfPresent(map, "minimalDaysInFirstWeek", calendarData);
if (id.equals("root")) {
calendarData.put("firstDayOfWeek",
IntStream.range(1, 8)
.mapToObj(String::valueOf)
.filter(d -> map.keySet().contains(CALENDAR_FIRSTDAY_PREFIX + d))
.map(d -> d + ": " + map.get(CALENDAR_FIRSTDAY_PREFIX + d))
.collect(Collectors.joining(";")));
calendarData.put("minimalDaysInFirstWeek",
IntStream.range(0, 7)
.mapToObj(String::valueOf)
.filter(d -> map.keySet().contains(CALENDAR_MINDAYS_PREFIX + d))
.map(d -> d + ": " + map.get(CALENDAR_MINDAYS_PREFIX + d))
.collect(Collectors.joining(";")));
}
return calendarData;
}
@ -844,17 +763,19 @@ public class CLDRConverter {
for (String key : map.keySet()) {
// Copy available calendar names
if (key.startsWith(CLDRConverter.CALENDAR_NAME_PREFIX)) {
String type = key.substring(CLDRConverter.CALENDAR_NAME_PREFIX.length());
if (key.startsWith(CLDRConverter.LOCALE_TYPE_PREFIX_CA)) {
String type = key.substring(CLDRConverter.LOCALE_TYPE_PREFIX_CA.length());
for (CalendarType calendarType : CalendarType.values()) {
if (calendarType == CalendarType.GENERIC) {
continue;
}
if (type.equals(calendarType.lname())) {
Object value = map.get(key);
formatData.put(key, value);
String ukey = CLDRConverter.CALENDAR_NAME_PREFIX + calendarType.uname();
if (!key.equals(ukey)) {
String dataKey = key.replace(LOCALE_TYPE_PREFIX_CA,
CALENDAR_NAME_PREFIX);
formatData.put(dataKey, value);
String ukey = CALENDAR_NAME_PREFIX + calendarType.uname();
if (!dataKey.equals(ukey)) {
formatData.put(ukey, value);
}
}
@ -874,6 +795,18 @@ public class CLDRConverter {
copyIfPresent(map, "NumberElements", formatData);
}
copyIfPresent(map, "NumberPatterns", formatData);
// put extra number elements for available scripts into formatData, if it is "root"
if (id.equals("root")) {
handlerNumbering.keySet().stream()
.filter(k -> !numberingScripts.contains(k))
.forEach(k -> {
String[] ne = (String[])map.get("latn.NumberElements");
String[] neNew = Arrays.copyOf(ne, ne.length);
neNew[4] = handlerNumbering.get(k).substring(0, 1);
formatData.put(k + ".NumberElements", neNew);
});
}
return formatData;
}

View File

@ -76,12 +76,16 @@ class LDMLParseHandler extends AbstractLDMLHandler<Object> {
// ignore this element - it has language and territory elements that aren't locale data
pushIgnoredContainer(qName);
break;
case "type":
if ("calendar".equals(attributes.getValue("key"))) {
pushStringEntry(qName, attributes, CLDRConverter.CALENDAR_NAME_PREFIX + attributes.getValue("type"));
} else {
pushIgnoredContainer(qName);
}
// for LocaleNames
// copy string
case "localeSeparator":
pushStringEntry(qName, attributes,
CLDRConverter.LOCALE_SEPARATOR);
break;
case "localeKeyTypePattern":
pushStringEntry(qName, attributes,
CLDRConverter.LOCALE_KEYTYPE);
break;
case "language":
@ -96,6 +100,24 @@ class LDMLParseHandler extends AbstractLDMLHandler<Object> {
attributes.getValue("type"));
break;
case "key":
// for LocaleNames
// copy string
pushStringEntry(qName, attributes,
CLDRConverter.LOCALE_KEY_PREFIX +
convertOldKeyName(attributes.getValue("type")));
break;
case "type":
// for LocaleNames/CalendarNames
// copy string
pushStringEntry(qName, attributes,
CLDRConverter.LOCALE_TYPE_PREFIX +
convertOldKeyName(attributes.getValue("key")) + "." +
attributes.getValue("type"));
break;
//
// Currency information
//
@ -515,26 +537,10 @@ class LDMLParseHandler extends AbstractLDMLHandler<Object> {
currentNumberingSystem = script + ".";
String digits = CLDRConverter.handlerNumbering.get(script);
if (digits == null) {
throw new InternalError("null digits for " + script);
}
if (Character.isSurrogate(digits.charAt(0))) {
// DecimalFormatSymbols doesn't support supplementary characters as digit zero.
pushIgnoredContainer(qName);
break;
}
// in case digits are in the reversed order, reverse back the order.
if (digits.charAt(0) > digits.charAt(digits.length() - 1)) {
StringBuilder sb = new StringBuilder(digits);
digits = sb.reverse().toString();
}
// Check if the order is sequential.
char c0 = digits.charAt(0);
for (int i = 1; i < digits.length(); i++) {
if (digits.charAt(i) != c0 + i) {
pushIgnoredContainer(qName);
break symbols;
}
}
@SuppressWarnings("unchecked")
List<String> numberingScripts = (List<String>) get("numberingScripts");
if (numberingScripts == null) {
@ -924,17 +930,35 @@ class LDMLParseHandler extends AbstractLDMLHandler<Object> {
}
}
} else if (currentContainer instanceof Entry) {
Entry<?> entry = (Entry<?>) currentContainer;
Object value = entry.getValue();
if (value != null) {
String key = entry.getKey();
// Tweak for MonthNames for the root locale, Needed for
// SimpleDateFormat.format()/parse() roundtrip.
if (id.equals("root") && key.startsWith("MonthNames")) {
value = new DateFormatSymbols(Locale.US).getShortMonths();
}
put(entry.getKey(), value);
Entry<?> entry = (Entry<?>) currentContainer;
Object value = entry.getValue();
if (value != null) {
String key = entry.getKey();
// Tweak for MonthNames for the root locale, Needed for
// SimpleDateFormat.format()/parse() roundtrip.
if (id.equals("root") && key.startsWith("MonthNames")) {
value = new DateFormatSymbols(Locale.US).getShortMonths();
}
put(entry.getKey(), value);
}
}
}
public String convertOldKeyName(String key) {
// Explicitly obtained from "alias" attribute in each "key" element.
switch (key) {
case "calendar":
return "ca";
case "currency":
return "cu";
case "collation":
return "co";
case "numbers":
return "nu";
case "timezone":
return "tz";
default:
return key;
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -54,9 +54,32 @@ class NumberingSystemsParseHandler extends AbstractLDMLHandler<String> {
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
switch (qName) {
case "numberingSystem":
if ("numeric".equals(attributes.getValue("type"))) {
// eg, <numberingSystem id="latn" type="numeric" digits="0123456789"/>
put(attributes.getValue("id"), attributes.getValue("digits"));
numberingSystem: {
if ("numeric".equals(attributes.getValue("type"))) {
// eg, <numberingSystem id="latn" type="numeric" digits="0123456789"/>
String script = attributes.getValue("id");
String digits = attributes.getValue("digits");
if (Character.isSurrogate(digits.charAt(0))) {
// DecimalFormatSymbols doesn't support supplementary characters as digit zero.
break numberingSystem;
}
// in case digits are in the reversed order, reverse back the order.
if (digits.charAt(0) > digits.charAt(digits.length() - 1)) {
StringBuilder sb = new StringBuilder(digits);
digits = sb.reverse().toString();
}
// Check if the order is sequential.
char c0 = digits.charAt(0);
for (int i = 1; i < digits.length(); i++) {
if (digits.charAt(i) != c0 + i) {
break numberingSystem;
}
}
// script/digits are acceptable.
put(script, digits);
}
}
pushIgnoredContainer(qName);
break;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -256,20 +256,21 @@ class ResourceBundleGenerator implements BundleGenerator {
CLDRConverter.info("Generating file " + file);
try (PrintWriter out = new PrintWriter(file, "us-ascii")) {
out.println(CopyrightHeaders.getOpenJDKCopyright());
out.printf(CopyrightHeaders.getOpenJDKCopyright());
out.println((CLDRConverter.isBaseModule ? "package sun.util.cldr;\n\n" :
out.printf((CLDRConverter.isBaseModule ? "package sun.util.cldr;\n\n" :
"package sun.util.resources.cldr.provider;\n\n")
+ "import java.util.HashMap;\n"
+ "import java.util.Locale;\n"
+ "import java.util.Map;\n"
+ "import sun.util.locale.provider.LocaleProviderAdapter;\n"
+ "import sun.util.locale.provider.LocaleDataMetaInfo;\n");
+ "import sun.util.locale.provider.LocaleDataMetaInfo;\n"
+ "import sun.util.locale.provider.LocaleProviderAdapter;\n\n");
out.printf("public class %s implements LocaleDataMetaInfo {\n", className);
out.println(" private static final Map<String, String> resourceNameToLocales = new HashMap<>();\n" +
(CLDRConverter.isBaseModule ?
" private static final Map<Locale, String[]> parentLocalesMap = new HashMap<>();\n\n" : "\n") +
" static {\n");
out.printf(" private static final Map<String, String> resourceNameToLocales = new HashMap<>();\n" +
(CLDRConverter.isBaseModule ?
" private static final Map<Locale, String[]> parentLocalesMap = new HashMap<>();\n\n" :
"\n") +
" static {\n");
for (String key : metaInfo.keySet()) {
if (key.startsWith(CLDRConverter.PARENT_LOCALE_PREFIX)) {
@ -296,30 +297,50 @@ class ResourceBundleGenerator implements BundleGenerator {
}
out.printf("\n });\n");
} else {
out.printf(" resourceNameToLocales.put(\"%s\",\n", key);
out.printf(" \"%s\");\n",
toLocaleList(key.equals("FormatData") ? metaInfo.get("AvailableLocales") :
metaInfo.get(key), false));
if ("AvailableLocales".equals(key)) {
out.printf(" resourceNameToLocales.put(\"%s\",\n", key);
out.printf(" \"%s\");\n", toLocaleList(metaInfo.get(key), false));
}
}
}
out.println(" }\n\n");
out.println(" @Override\n" +
out.printf(" }\n\n");
// end of static initializer block.
// Short TZ names for delayed initialization
if (CLDRConverter.isBaseModule) {
out.printf(" private static class TZShortIDMapHolder {\n");
out.printf(" static final Map<String, String> tzShortIDMap = new HashMap<>();\n");
out.printf(" static {\n");
CLDRConverter.handlerTimeZone.getData().entrySet().stream()
.forEach(e -> {
out.printf(" tzShortIDMap.put(\"%s\", \"%s\");\n", e.getKey(),
((String)e.getValue()));
});
out.printf(" }\n }\n\n");
}
out.printf(" @Override\n" +
" public LocaleProviderAdapter.Type getType() {\n" +
" return LocaleProviderAdapter.Type.CLDR;\n" +
" }\n\n");
out.println(" @Override\n" +
out.printf(" @Override\n" +
" public String availableLanguageTags(String category) {\n" +
" return resourceNameToLocales.getOrDefault(category, \"\");\n" +
" }\n\n");
if (CLDRConverter.isBaseModule) {
out.printf(" @Override\n" +
" public Map<String, String> tzShortIDs() {\n" +
" return TZShortIDMapHolder.tzShortIDMap;\n" +
" }\n\n");
out.printf(" public Map<Locale, String[]> parentLocales() {\n" +
" return parentLocalesMap;\n" +
" }\n}");
} else {
out.println("}");
out.printf("}");
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -84,53 +84,18 @@ class SupplementDataParseHandler extends AbstractLDMLHandler<Object> {
values.put(CLDRConverter.PARENT_LOCALE_PREFIX+key,
parentLocalesMap.get(key));
});
} else {
String countryData = getWeekData(id, JAVA_FIRSTDAY, firstDayMap);
if (countryData != null) {
values.put(JAVA_FIRSTDAY, countryData);
}
String minDaysData = getWeekData(id, JAVA_MINDAY, minDaysMap);
if (minDaysData != null) {
values.put(JAVA_MINDAY, minDaysData);
}
firstDayMap.keySet().forEach(key -> {
values.put(CLDRConverter.CALENDAR_FIRSTDAY_PREFIX+firstDayMap.get(key),
key);
});
minDaysMap.keySet().forEach(key -> {
values.put(CLDRConverter.CALENDAR_MINDAYS_PREFIX+minDaysMap.get(key),
key);
});
}
return values.isEmpty() ? null : values;
}
/**
* It returns either firstDay or minDays in the JRE format for the country.
*
* @param country territory code of the requested data
* @param jreDataName JAVA_FIRSTDAY or JAVA_MINDAY
* @param dataMap firstDayMap or minDaysMap
* @return the value for the given jreDataName, or null if requested value
* (firstDay/minDays) is not available although that is highly unlikely
* because of the default value for the world (001).
*/
String getWeekData(String country, final String jreDataName, final Map<String, Object> dataMap) {
String countryValue = null;
String defaultWorldValue = null;
for (String key : dataMap.keySet()) {
if (key.contains(country)) {
if (jreDataName.equals(JAVA_FIRSTDAY)) {
countryValue = DAY_OF_WEEK_MAP.get((String) dataMap.get(key));
} else if (jreDataName.equals(JAVA_MINDAY)) {
countryValue = (String) dataMap.get(key);
}
if (countryValue != null) {
return countryValue;
}
} else if (key.contains(WORLD)) {
if (jreDataName.equals(JAVA_FIRSTDAY)) {
defaultWorldValue = DAY_OF_WEEK_MAP.get((String) dataMap.get(key));
} else if (jreDataName.equals(JAVA_MINDAY)) {
defaultWorldValue = (String) dataMap.get(key);
}
}
}
return defaultWorldValue;
}
@Override
public InputSource resolveEntity(String publicID, String systemID) throws IOException, SAXException {
// avoid HTTP traffic to unicode.org
@ -152,7 +117,33 @@ class SupplementDataParseHandler extends AbstractLDMLHandler<Object> {
switch (qName) {
case "firstDay":
if (!isIgnored(attributes)) {
firstDayMap.put(attributes.getValue("territories"), attributes.getValue("day"));
String fd;
switch (attributes.getValue("day")) {
case "sun":
fd = "1";
break;
default:
case "mon":
fd = "2";
break;
case "tue":
fd = "3";
break;
case "wed":
fd = "4";
break;
case "thu":
fd = "5";
break;
case "fri":
fd = "6";
break;
case "sat":
fd = "7";
break;
}
firstDayMap.put(attributes.getValue("territories"), fd);
}
break;
case "minDays":

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package build.tools.cldrconverter;
import java.io.File;
import java.io.IOException;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* Handles parsing of timezone.xml and produces a map from short timezone IDs to
* tz database IDs.
*/
class TimeZoneParseHandler extends AbstractLDMLHandler<Object> {
@Override
public InputSource resolveEntity(String publicID, String systemID) throws IOException, SAXException {
// avoid HTTP traffic to unicode.org
if (systemID.startsWith(CLDRConverter.BCP47_LDML_DTD_SYSTEM_ID)) {
return new InputSource((new File(CLDRConverter.LOCAL_BCP47_LDML_DTD)).toURI().toString());
}
return null;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
switch (qName) {
case "type":
if (!isIgnored(attributes) && !attributes.getValue("deprecated").equals("true")) {
put(attributes.getValue("name"), attributes.getValue("alias"));
}
break;
default:
// treat anything else as a container
pushContainer(qName, attributes);
break;
}
}
}

View File

@ -265,7 +265,7 @@
</target>
<!-- generate javadoc for Nashorn classes -->
<target name="javadoc" depends="jar">
<target name="javadoc" depends="jar" unless="test.class">
<javadoc destdir="${dist.javadoc.dir}" use="yes"
windowtitle="${nashorn.product.name} ${nashorn.version}"
additionalparam="-quiet" failonerror="true" useexternalfile="true">

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1994, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,6 +25,7 @@
package java.io;
import java.nio.charset.Charset;
import java.util.Arrays;
/**
@ -223,14 +224,27 @@ public class ByteArrayOutputStream extends OutputStream {
/**
* Converts the buffer's contents into a string by decoding the bytes using
* the named {@link java.nio.charset.Charset charset}. The length of the new
* {@code String} is a function of the charset, and hence may not be equal
* to the length of the byte array.
* the named {@link java.nio.charset.Charset charset}.
*
* <p> This method is equivalent to {@code #toString(charset)} that takes a
* {@link java.nio.charset.Charset charset}.
*
* <p> An invocation of this method of the form
*
* <pre> {@code
* ByteArrayOutputStream b = ...
* b.toString("UTF-8")
* }
* </pre>
*
* behaves in exactly the same way as the expression
*
* <pre> {@code
* ByteArrayOutputStream b = ...
* b.toString(StandardCharsets.UTF_8)
* }
* </pre>
*
* <p> This method always replaces malformed-input and unmappable-character
* sequences with this charset's default replacement string. The {@link
* java.nio.charset.CharsetDecoder} class should be used when more control
* over the decoding process is required.
*
* @param charsetName the name of a supported
* {@link java.nio.charset.Charset charset}
@ -245,6 +259,26 @@ public class ByteArrayOutputStream extends OutputStream {
return new String(buf, 0, count, charsetName);
}
/**
* Converts the buffer's contents into a string by decoding the bytes using
* the specified {@link java.nio.charset.Charset charset}. The length of the new
* {@code String} is a function of the charset, and hence may not be equal
* to the length of the byte array.
*
* <p> This method always replaces malformed-input and unmappable-character
* sequences with the charset's default replacement string. The {@link
* java.nio.charset.CharsetDecoder} class should be used when more control
* over the decoding process is required.
*
* @param charset the {@linkplain java.nio.charset.Charset charset}
* to be used to decode the {@code bytes}
* @return String decoded from the buffer's contents.
* @since 10
*/
public synchronized String toString(Charset charset) {
return new String(buf, 0, count, charset);
}
/**
* Creates a newly allocated string. Its size is the current size of
* the output stream and the valid contents of the buffer have been
@ -257,9 +291,10 @@ public class ByteArrayOutputStream extends OutputStream {
*
* @deprecated This method does not properly convert bytes into characters.
* As of JDK&nbsp;1.1, the preferred way to do this is via the
* {@code toString(String enc)} method, which takes an encoding-name
* argument, or the {@code toString()} method, which uses the
* platform's default character encoding.
* {@link #toString(String charsetName)} or {@link #toString(Charset charset)}
* method, which takes an encoding-name or charset argument,
* or the {@code toString()} method, which uses the platform's default
* character encoding.
*
* @param hibyte the high byte of each resulting Unicode character.
* @return the current contents of the output stream, as a string.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -45,10 +45,16 @@ import java.nio.charset.UnsupportedCharsetException;
* ({@code '\n'}) is written.
*
* <p> All characters printed by a {@code PrintStream} are converted into
* bytes using the platform's default character encoding.
* bytes using the given encoding or charset, or platform's default character
* encoding if not specified.
* The {@link PrintWriter} class should be used in situations that require
* writing characters rather than bytes.
*
* <p> This class always replaces malformed and unmappable character sequences with
* the charset's default replacement string.
* The {@linkplain java.nio.charset.CharsetEncoder} class should be used when more
* control over the encoding process is required.
*
* @author Frank Yellin
* @author Mark Reinhold
* @since 1.0
@ -105,22 +111,13 @@ public class PrintStream extends FilterOutputStream
this.textOut = new BufferedWriter(charOut);
}
private PrintStream(boolean autoFlush, OutputStream out, Charset charset) {
super(out);
this.autoFlush = autoFlush;
this.charOut = new OutputStreamWriter(this, charset);
this.textOut = new BufferedWriter(charOut);
}
/* Variant of the private constructor so that the given charset name
* can be verified before evaluating the OutputStream argument. Used
* by constructors creating a FileOutputStream that also take a
* charset name.
*/
private PrintStream(boolean autoFlush, Charset charset, OutputStream out)
throws UnsupportedEncodingException
{
this(autoFlush, out, charset);
private PrintStream(boolean autoFlush, Charset charset, OutputStream out) {
this(out, autoFlush, charset);
}
/**
@ -172,9 +169,30 @@ public class PrintStream extends FilterOutputStream
public PrintStream(OutputStream out, boolean autoFlush, String encoding)
throws UnsupportedEncodingException
{
this(autoFlush,
requireNonNull(out, "Null output stream"),
toCharset(encoding));
this(requireNonNull(out, "Null output stream"), autoFlush, toCharset(encoding));
}
/**
* Creates a new print stream, with the specified OutputStream, automatic line
* flushing and charset. This convenience constructor creates the necessary
* intermediate {@link java.io.OutputStreamWriter OutputStreamWriter},
* which will encode characters using the provided charset.
*
* @param out The output stream to which values and objects will be
* printed
* @param autoFlush A boolean; if true, the output buffer will be flushed
* whenever a byte array is written, one of the
* {@code println} methods is invoked, or a newline
* character or byte ({@code '\n'}) is written
* @param charset A {@linkplain java.nio.charset.Charset charset}
*
* @since 10
*/
public PrintStream(OutputStream out, boolean autoFlush, Charset charset) {
super(out);
this.autoFlush = autoFlush;
this.charOut = new OutputStreamWriter(this, charset);
this.textOut = new BufferedWriter(charOut);
}
/**
@ -248,6 +266,36 @@ public class PrintStream extends FilterOutputStream
this(false, toCharset(csn), new FileOutputStream(fileName));
}
/**
* Creates a new print stream, without automatic line flushing, with the
* specified file name and charset. This convenience constructor creates
* the necessary intermediate {@link java.io.OutputStreamWriter
* OutputStreamWriter}, which will encode characters using the provided
* charset.
*
* @param fileName
* The name of the file to use as the destination of this print
* stream. If the file exists, then it will be truncated to
* zero size; otherwise, a new file will be created. The output
* will be written to the file and is buffered.
*
* @param charset
* A {@linkplain java.nio.charset.Charset charset}
*
* @throws IOException
* if an I/O error occurs while opening or creating the file
*
* @throws SecurityException
* If a security manager is present and {@link
* SecurityManager#checkWrite checkWrite(fileName)} denies write
* access to the file
*
* @since 10
*/
public PrintStream(String fileName, Charset charset) throws IOException {
this(false, requireNonNull(charset, "charset"), new FileOutputStream(fileName));
}
/**
* Creates a new print stream, without automatic line flushing, with the
* specified file. This convenience constructor creates the necessary
@ -319,6 +367,37 @@ public class PrintStream extends FilterOutputStream
this(false, toCharset(csn), new FileOutputStream(file));
}
/**
* Creates a new print stream, without automatic line flushing, with the
* specified file and charset. This convenience constructor creates
* the necessary intermediate {@link java.io.OutputStreamWriter
* OutputStreamWriter}, which will encode characters using the provided
* charset.
*
* @param file
* The file to use as the destination of this print stream. If the
* file exists, then it will be truncated to zero size; otherwise,
* a new file will be created. The output will be written to the
* file and is buffered.
*
* @param charset
* A {@linkplain java.nio.charset.Charset charset}
*
* @throws IOException
* if an I/O error occurs while opening or creating the file
*
* @throws SecurityException
* If a security manager is present and {@link
* SecurityManager#checkWrite checkWrite(file.getPath())}
* denies write access to the file
*
* @since 10
*/
public PrintStream(File file, Charset charset) throws IOException {
this(false, requireNonNull(charset, "charset"), new FileOutputStream(file));
}
/** Check to make sure that the stream has not been closed */
private void ensureOpen() throws IOException {
if (out == null)

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -48,6 +48,11 @@ import java.nio.charset.UnsupportedCharsetException;
* constructors may. The client may inquire as to whether any errors have
* occurred by invoking {@link #checkError checkError()}.
*
* <p> This class always replaces malformed and unmappable character sequences with
* the charset's default replacement string.
* The {@linkplain java.nio.charset.CharsetEncoder} class should be used when more
* control over the encoding process is required.
*
* @author Frank Yellin
* @author Mark Reinhold
* @since 1.1
@ -137,7 +142,26 @@ public class PrintWriter extends Writer {
* @see java.io.OutputStreamWriter#OutputStreamWriter(java.io.OutputStream)
*/
public PrintWriter(OutputStream out, boolean autoFlush) {
this(new BufferedWriter(new OutputStreamWriter(out)), autoFlush);
this(out, autoFlush, Charset.defaultCharset());
}
/**
* Creates a new PrintWriter from an existing OutputStream. This
* convenience constructor creates the necessary intermediate
* OutputStreamWriter, which will convert characters into bytes using the
* specified charset.
*
* @param out An output stream
* @param autoFlush A boolean; if true, the {@code println},
* {@code printf}, or {@code format} methods will
* flush the output buffer
* @param charset
* A {@linkplain java.nio.charset.Charset charset}
*
* @since 10
*/
public PrintWriter(OutputStream out, boolean autoFlush, Charset charset) {
this(new BufferedWriter(new OutputStreamWriter(out, charset)), autoFlush);
// save print stream for error propagation
if (out instanceof java.io.PrintStream) {
@ -224,6 +248,36 @@ public class PrintWriter extends Writer {
this(toCharset(csn), new File(fileName));
}
/**
* Creates a new PrintWriter, without automatic line flushing, with the
* specified file name and charset. This convenience constructor creates
* the necessary intermediate {@link java.io.OutputStreamWriter
* OutputStreamWriter}, which will encode characters using the provided
* charset.
*
* @param fileName
* The name of the file to use as the destination of this writer.
* If the file exists then it will be truncated to zero size;
* otherwise, a new file will be created. The output will be
* written to the file and is buffered.
*
* @param charset
* A {@linkplain java.nio.charset.Charset charset}
*
* @throws IOException
* if an I/O error occurs while opening or creating the file
*
* @throws SecurityException
* If a security manager is present and {@link
* SecurityManager#checkWrite checkWrite(fileName)} denies write
* access to the file
*
* @since 10
*/
public PrintWriter(String fileName, Charset charset) throws IOException {
this(Objects.requireNonNull(charset, "charset"), new File(fileName));
}
/**
* Creates a new PrintWriter, without automatic line flushing, with the
* specified file. This convenience constructor creates the necessary
@ -295,6 +349,36 @@ public class PrintWriter extends Writer {
this(toCharset(csn), file);
}
/**
* Creates a new PrintWriter, without automatic line flushing, with the
* specified file and charset. This convenience constructor creates the
* necessary intermediate {@link java.io.OutputStreamWriter
* OutputStreamWriter}, which will encode characters using the provided
* charset.
*
* @param file
* The file to use as the destination of this writer. If the file
* exists then it will be truncated to zero size; otherwise, a new
* file will be created. The output will be written to the file
* and is buffered.
*
* @param charset
* A {@linkplain java.nio.charset.Charset charset}
*
* @throws IOException
* if an I/O error occurs while opening or creating the file
*
* @throws SecurityException
* If a security manager is present and {@link
* SecurityManager#checkWrite checkWrite(file.getPath())}
* denies write access to the file
*
* @since 10
*/
public PrintWriter(File file, Charset charset) throws IOException {
this(Objects.requireNonNull(charset, "charset"), file);
}
/** Checks to make sure that the stream has not been closed */
private void ensureOpen() throws IOException {
if (out == null)

View File

@ -3046,6 +3046,10 @@ public final class String
return COMPACT_STRINGS ? coder : UTF16;
}
byte[] value() {
return value;
}
private boolean isLatin1() {
return COMPACT_STRINGS && coder == LATIN1;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -47,6 +47,11 @@ import sun.nio.cs.StandardCharsets;
import static java.lang.String.LATIN1;
import static java.lang.String.UTF16;
import static java.lang.String.COMPACT_STRINGS;
import static java.lang.Character.isSurrogate;
import static java.lang.Character.highSurrogate;
import static java.lang.Character.lowSurrogate;
import static java.lang.Character.isSupplementaryCodePoint;
import static java.lang.StringUTF16.putChar;
/**
* Utility class for string encoding and decoding.
@ -66,8 +71,6 @@ class StringCoding {
private static final Charset US_ASCII = sun.nio.cs.US_ASCII.INSTANCE;
private static final Charset UTF_8 = sun.nio.cs.UTF_8.INSTANCE;
private static boolean warnUnsupportedCharset = true;
private static <T> T deref(ThreadLocal<SoftReference<T>> tl) {
SoftReference<T> sr = tl.get();
if (sr == null)
@ -80,7 +83,6 @@ class StringCoding {
}
// Trim the given byte array to the given length
//
private static byte[] safeTrim(byte[] ba, int len, boolean isTrusted) {
if (len == ba.length && (isTrusted || System.getSecurityManager() == null))
return ba;
@ -105,17 +107,6 @@ class StringCoding {
return null;
}
private static void warnUnsupportedCharset(String csn) {
if (warnUnsupportedCharset) {
// Use err(String) rather than the Logging API or System.err
// since this method may be called during VM initialization
// before either is available.
err("WARNING: Default charset " + csn +
" not supported, using ISO-8859-1 instead\n");
warnUnsupportedCharset = false;
}
}
static class Result {
byte[] value;
byte coder;
@ -224,19 +215,6 @@ class StringCoding {
}
}
private static class StringDecoder8859_1 extends StringDecoder {
StringDecoder8859_1(Charset cs, String rcn) {
super(cs, rcn);
}
Result decode(byte[] ba, int off, int len) {
if (COMPACT_STRINGS) {
return result.with(Arrays.copyOfRange(ba, off, off + len), LATIN1);
} else {
return result.with(StringLatin1.inflate(ba, off, len), UTF16);
}
}
}
static Result decode(String charsetName, byte[] ba, int off, int len)
throws UnsupportedEncodingException
{
@ -249,12 +227,15 @@ class StringCoding {
Charset cs = lookupCharset(csn);
if (cs != null) {
if (cs == UTF_8) {
sd = new StringDecoderUTF8(cs, csn);
} else if (cs == ISO_8859_1) {
sd = new StringDecoder8859_1(cs, csn);
} else {
sd = new StringDecoder(cs, csn);
return decodeUTF8(ba, off, len, true);
}
if (cs == ISO_8859_1) {
return decodeLatin1(ba, off, len);
}
if (cs == US_ASCII) {
return decodeASCII(ba, off, len);
}
sd = new StringDecoder(cs, csn);
}
} catch (IllegalCharsetNameException x) {}
if (sd == null)
@ -265,6 +246,16 @@ class StringCoding {
}
static Result decode(Charset cs, byte[] ba, int off, int len) {
if (cs == UTF_8) {
return decodeUTF8(ba, off, len, true);
}
if (cs == ISO_8859_1) {
return decodeLatin1(ba, off, len);
}
if (cs == US_ASCII) {
return decodeASCII(ba, off, len);
}
// (1)We never cache the "external" cs, the only benefit of creating
// an additional StringDe/Encoder object to wrap it is to share the
// de/encode() method. These SD/E objects are short-lived, the young-gen
@ -280,39 +271,29 @@ class StringCoding {
// check (... && (isTrusted || SM == null || getClassLoader0())) in trim
// but it then can be argued that the SM is null when the operation
// is started...
if (cs == UTF_8) {
return StringDecoderUTF8.decode(ba, off, len, new Result());
}
CharsetDecoder cd = cs.newDecoder();
// ascii fastpath
if (cs == ISO_8859_1 || ((cd instanceof ArrayDecoder) &&
((ArrayDecoder)cd).isASCIICompatible() &&
!hasNegatives(ba, off, len))) {
if (COMPACT_STRINGS) {
return new Result().with(Arrays.copyOfRange(ba, off, off + len),
LATIN1);
} else {
return new Result().with(StringLatin1.inflate(ba, off, len), UTF16);
}
if ((cd instanceof ArrayDecoder) &&
((ArrayDecoder)cd).isASCIICompatible() && !hasNegatives(ba, off, len)) {
return decodeLatin1(ba, off, len);
}
int en = scale(len, cd.maxCharsPerByte());
if (len == 0) {
return new Result().with();
}
if (cs.getClass().getClassLoader0() != null &&
System.getSecurityManager() != null) {
ba = Arrays.copyOfRange(ba, off, off + len);
off = 0;
}
cd.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE)
.reset();
char[] ca = new char[en];
if (cd instanceof ArrayDecoder) {
int clen = ((ArrayDecoder)cd).decode(ba, off, len, ca);
return new Result().with(ca, 0, clen);
}
if (cs.getClass().getClassLoader0() != null &&
System.getSecurityManager() != null) {
ba = Arrays.copyOfRange(ba, off, off + len);
off = 0;
}
ByteBuffer bb = ByteBuffer.wrap(ba, off, len);
CharBuffer cb = CharBuffer.wrap(ca);
try {
@ -331,24 +312,22 @@ class StringCoding {
}
static Result decode(byte[] ba, int off, int len) {
String csn = Charset.defaultCharset().name();
try {
// use charset name decode() variant which provides caching.
return decode(csn, ba, off, len);
} catch (UnsupportedEncodingException x) {
warnUnsupportedCharset(csn);
Charset cs = Charset.defaultCharset();
if (cs == UTF_8) {
return decodeUTF8(ba, off, len, true);
}
try {
return decode("ISO-8859-1", ba, off, len);
} catch (UnsupportedEncodingException x) {
// If this code is hit during VM initialization, err(String) is
// the only way we will be able to get any kind of error message.
err("ISO-8859-1 charset not available: " + x.toString() + "\n");
// If we can not find ISO-8859-1 (a required encoding) then things
// are seriously wrong with the installation.
System.exit(1);
return null;
if (cs == ISO_8859_1) {
return decodeLatin1(ba, off, len);
}
if (cs == US_ASCII) {
return decodeASCII(ba, off, len);
}
StringDecoder sd = deref(decoder);
if (sd == null || !cs.name().equals(sd.cs.name())) {
sd = new StringDecoder(cs, cs.name());
set(decoder, sd);
}
return sd.decode(ba, off, len);
}
// -- Encoding --
@ -393,9 +372,6 @@ class StringCoding {
return ba;
}
if (ce instanceof ArrayEncoder) {
if (!isTrusted) {
val = Arrays.copyOf(val, val.length);
}
int blen = (coder == LATIN1 ) ? ((ArrayEncoder)ce).encodeFromLatin1(val, 0, len, ba)
: ((ArrayEncoder)ce).encodeFromUTF16(val, 0, len, ba);
if (blen != -1) {
@ -423,49 +399,140 @@ class StringCoding {
}
}
@HotSpotIntrinsicCandidate
private static int implEncodeISOArray(byte[] sa, int sp,
byte[] da, int dp, int len) {
int i = 0;
for (; i < len; i++) {
char c = StringUTF16.getChar(sa, sp++);
if (c > '\u00FF')
break;
da[dp++] = (byte)c;
static byte[] encode(String charsetName, byte coder, byte[] val)
throws UnsupportedEncodingException
{
StringEncoder se = deref(encoder);
String csn = (charsetName == null) ? "ISO-8859-1" : charsetName;
if ((se == null) || !(csn.equals(se.requestedCharsetName())
|| csn.equals(se.charsetName()))) {
se = null;
try {
Charset cs = lookupCharset(csn);
if (cs != null) {
if (cs == UTF_8) {
return encodeUTF8(coder, val, true);
}
if (cs == ISO_8859_1) {
return encode8859_1(coder, val);
}
if (cs == US_ASCII) {
return encodeASCII(coder, val);
}
se = new StringEncoder(cs, csn);
}
} catch (IllegalCharsetNameException x) {}
if (se == null) {
throw new UnsupportedEncodingException (csn);
}
set(encoder, se);
}
return i;
return se.encode(coder, val);
}
static byte[] encode8859_1(byte coder, byte[] val) {
if (coder == LATIN1) {
static byte[] encode(Charset cs, byte coder, byte[] val) {
if (cs == UTF_8) {
return encodeUTF8(coder, val, true);
}
if (cs == ISO_8859_1) {
return encode8859_1(coder, val);
}
if (cs == US_ASCII) {
return encodeASCII(coder, val);
}
CharsetEncoder ce = cs.newEncoder();
// fastpath for ascii compatible
if (coder == LATIN1 && (((ce instanceof ArrayEncoder) &&
((ArrayEncoder)ce).isASCIICompatible() &&
!hasNegatives(val, 0, val.length)))) {
return Arrays.copyOf(val, val.length);
}
int len = val.length >> 1;
byte[] dst = new byte[len];
int dp = 0;
int sp = 0;
int sl = len;
while (sp < sl) {
int ret = implEncodeISOArray(val, sp, dst, dp, len);
sp = sp + ret;
dp = dp + ret;
if (ret != len) {
char c = StringUTF16.getChar(val, sp++);
if (Character.isHighSurrogate(c) && sp < sl &&
Character.isLowSurrogate(StringUTF16.getChar(val, sp))) {
sp++;
}
dst[dp++] = '?';
len = sl - sp;
int len = val.length >> coder; // assume LATIN1=0/UTF16=1;
int en = scale(len, ce.maxBytesPerChar());
byte[] ba = new byte[en];
if (len == 0) {
return ba;
}
ce.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE)
.reset();
if (ce instanceof ArrayEncoder) {
int blen = (coder == LATIN1 ) ? ((ArrayEncoder)ce).encodeFromLatin1(val, 0, len, ba)
: ((ArrayEncoder)ce).encodeFromUTF16(val, 0, len, ba);
if (blen != -1) {
return safeTrim(ba, blen, true);
}
}
if (dp == dst.length) {
return dst;
boolean isTrusted = cs.getClass().getClassLoader0() == null ||
System.getSecurityManager() == null;
char[] ca = (coder == LATIN1 ) ? StringLatin1.toChars(val)
: StringUTF16.toChars(val);
ByteBuffer bb = ByteBuffer.wrap(ba);
CharBuffer cb = CharBuffer.wrap(ca, 0, len);
try {
CoderResult cr = ce.encode(cb, bb, true);
if (!cr.isUnderflow())
cr.throwException();
cr = ce.flush(bb);
if (!cr.isUnderflow())
cr.throwException();
} catch (CharacterCodingException x) {
throw new Error(x);
}
return Arrays.copyOf(dst, dp);
return safeTrim(ba, bb.position(), isTrusted);
}
static byte[] encodeASCII(byte coder, byte[] val) {
static byte[] encode(byte coder, byte[] val) {
Charset cs = Charset.defaultCharset();
if (cs == UTF_8) {
return encodeUTF8(coder, val, true);
}
if (cs == ISO_8859_1) {
return encode8859_1(coder, val);
}
if (cs == US_ASCII) {
return encodeASCII(coder, val);
}
StringEncoder se = deref(encoder);
if (se == null || !cs.name().equals(se.cs.name())) {
se = new StringEncoder(cs, cs.name());
set(encoder, se);
}
return se.encode(coder, val);
}
/**
* Print a message directly to stderr, bypassing all character conversion
* methods.
* @param msg message to print
*/
private static native void err(String msg);
/* The cached Result for each thread */
private static final ThreadLocal<StringCoding.Result>
resultCached = new ThreadLocal<>() {
protected StringCoding.Result initialValue() {
return new StringCoding.Result();
}};
////////////////////////// ascii //////////////////////////////
private static Result decodeASCII(byte[] ba, int off, int len) {
Result result = resultCached.get();
if (COMPACT_STRINGS && !hasNegatives(ba, off, len)) {
return result.with(Arrays.copyOfRange(ba, off, off + len),
LATIN1);
}
byte[] dst = new byte[len<<1];
int dp = 0;
while (dp < len) {
int b = ba[off++];
putChar(dst, dp++, (b >= 0) ? (char)b : repl);
}
return result.with(dst, UTF16);
}
private static byte[] encodeASCII(byte coder, byte[] val) {
if (coder == LATIN1) {
byte[] dst = new byte[val.length];
for (int i = 0; i < val.length; i++) {
@ -498,59 +565,51 @@ class StringCoding {
return Arrays.copyOf(dst, dp);
}
static byte[] encodeUTF8(byte coder, byte[] val) {
int dp = 0;
byte[] dst;
////////////////////////// latin1/8859_1 ///////////////////////////
private static Result decodeLatin1(byte[] ba, int off, int len) {
Result result = resultCached.get();
if (COMPACT_STRINGS) {
return result.with(Arrays.copyOfRange(ba, off, off + len), LATIN1);
} else {
return result.with(StringLatin1.inflate(ba, off, len), UTF16);
}
}
@HotSpotIntrinsicCandidate
private static int implEncodeISOArray(byte[] sa, int sp,
byte[] da, int dp, int len) {
int i = 0;
for (; i < len; i++) {
char c = StringUTF16.getChar(sa, sp++);
if (c > '\u00FF')
break;
da[dp++] = (byte)c;
}
return i;
}
private static byte[] encode8859_1(byte coder, byte[] val) {
if (coder == LATIN1) {
dst = new byte[val.length << 1];
for (int sp = 0; sp < val.length; sp++) {
byte c = val[sp];
if (c < 0) {
dst[dp++] = (byte)(0xc0 | ((c & 0xff) >> 6));
dst[dp++] = (byte)(0x80 | (c & 0x3f));
} else {
dst[dp++] = c;
}
}
} else {
int sp = 0;
int sl = val.length >> 1;
dst = new byte[sl * 3];
char c;
while (sp < sl && (c = StringUTF16.getChar(val, sp)) < '\u0080') {
// ascii fast loop;
dst[dp++] = (byte)c;
sp++;
}
while (sp < sl) {
c = StringUTF16.getChar(val, sp++);
if (c < 0x80) {
dst[dp++] = (byte)c;
} else if (c < 0x800) {
dst[dp++] = (byte)(0xc0 | (c >> 6));
dst[dp++] = (byte)(0x80 | (c & 0x3f));
} else if (Character.isSurrogate(c)) {
int uc = -1;
char c2;
if (Character.isHighSurrogate(c) && sp < sl &&
Character.isLowSurrogate(c2 = StringUTF16.getChar(val, sp))) {
uc = Character.toCodePoint(c, c2);
}
if (uc < 0) {
dst[dp++] = '?';
} else {
dst[dp++] = (byte)(0xf0 | ((uc >> 18)));
dst[dp++] = (byte)(0x80 | ((uc >> 12) & 0x3f));
dst[dp++] = (byte)(0x80 | ((uc >> 6) & 0x3f));
dst[dp++] = (byte)(0x80 | (uc & 0x3f));
sp++; // 2 chars
}
} else {
// 3 bytes, 16 bits
dst[dp++] = (byte)(0xe0 | ((c >> 12)));
dst[dp++] = (byte)(0x80 | ((c >> 6) & 0x3f));
dst[dp++] = (byte)(0x80 | (c & 0x3f));
return Arrays.copyOf(val, val.length);
}
int len = val.length >> 1;
byte[] dst = new byte[len];
int dp = 0;
int sp = 0;
int sl = len;
while (sp < sl) {
int ret = implEncodeISOArray(val, sp, dst, dp, len);
sp = sp + ret;
dp = dp + ret;
if (ret != len) {
char c = StringUTF16.getChar(val, sp++);
if (Character.isHighSurrogate(c) && sp < sl &&
Character.isLowSurrogate(StringUTF16.getChar(val, sp))) {
sp++;
}
dst[dp++] = '?';
len = sl - sp;
}
}
if (dp == dst.length) {
@ -559,113 +618,333 @@ class StringCoding {
return Arrays.copyOf(dst, dp);
}
static byte[] encode(String charsetName, byte coder, byte[] val)
throws UnsupportedEncodingException
{
StringEncoder se = deref(encoder);
String csn = (charsetName == null) ? "ISO-8859-1" : charsetName;
if ((se == null) || !(csn.equals(se.requestedCharsetName())
|| csn.equals(se.charsetName()))) {
se = null;
try {
Charset cs = lookupCharset(csn);
if (cs != null) {
if (cs == UTF_8) {
return encodeUTF8(coder, val);
} else if (cs == ISO_8859_1) {
return encode8859_1(coder, val);
} else if (cs == US_ASCII) {
return encodeASCII(coder, val);
}
se = new StringEncoder(cs, csn);
//////////////////////////////// utf8 ////////////////////////////////////
private static boolean isNotContinuation(int b) {
return (b & 0xc0) != 0x80;
}
private static boolean isMalformed3(int b1, int b2, int b3) {
return (b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) ||
(b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80;
}
private static boolean isMalformed3_2(int b1, int b2) {
return (b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) ||
(b2 & 0xc0) != 0x80;
}
private static boolean isMalformed4(int b2, int b3, int b4) {
return (b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80 ||
(b4 & 0xc0) != 0x80;
}
private static boolean isMalformed4_2(int b1, int b2) {
return (b1 == 0xf0 && (b2 < 0x90 || b2 > 0xbf)) ||
(b1 == 0xf4 && (b2 & 0xf0) != 0x80) ||
(b2 & 0xc0) != 0x80;
}
private static boolean isMalformed4_3(int b3) {
return (b3 & 0xc0) != 0x80;
}
// for nb == 3/4
private static int malformedN(byte[] src, int sp, int nb) {
if (nb == 3) {
int b1 = src[sp++];
int b2 = src[sp++]; // no need to lookup b3
return ((b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) ||
isNotContinuation(b2)) ? 1 : 2;
} else if (nb == 4) { // we don't care the speed here
int b1 = src[sp++] & 0xff;
int b2 = src[sp++] & 0xff;
if (b1 > 0xf4 ||
(b1 == 0xf0 && (b2 < 0x90 || b2 > 0xbf)) ||
(b1 == 0xf4 && (b2 & 0xf0) != 0x80) ||
isNotContinuation(b2))
return 1;
if (isNotContinuation(src[sp++]))
return 2;
return 3;
}
assert false;
return -1;
}
private static void throwMalformed(int off, int nb) {
throw new IllegalArgumentException("malformed input off : " + off +
", length : " + nb);
}
private static char repl = '\ufffd';
private static Result decodeUTF8(byte[] src, int sp, int len, boolean doReplace) {
// ascii-bais, which has a relative impact to the non-ascii-only bytes
if (COMPACT_STRINGS && !hasNegatives(src, sp, len))
return resultCached.get().with(Arrays.copyOfRange(src, sp, sp + len),
LATIN1);
return decodeUTF8_0(src, sp, len, doReplace);
}
private static Result decodeUTF8_0(byte[] src, int sp, int len, boolean doReplace) {
Result ret = resultCached.get();
int sl = sp + len;
int dp = 0;
byte[] dst = new byte[len];
if (COMPACT_STRINGS) {
while (sp < sl) {
int b1 = src[sp];
if (b1 >= 0) {
dst[dp++] = (byte)b1;
sp++;
continue;
}
} catch (IllegalCharsetNameException x) {}
if (se == null) {
throw new UnsupportedEncodingException (csn);
if ((b1 == (byte)0xc2 || b1 == (byte)0xc3) &&
sp + 1 < sl) {
int b2 = src[sp + 1];
if (!isNotContinuation(b2)) {
dst[dp++] = (byte)(((b1 << 6) ^ b2)^
(((byte) 0xC0 << 6) ^
((byte) 0x80 << 0)));
sp += 2;
continue;
}
}
// anything not a latin1, including the repl
// we have to go with the utf16
break;
}
if (sp == sl) {
if (dp != dst.length) {
dst = Arrays.copyOf(dst, dp);
}
return ret.with(dst, LATIN1);
}
set(encoder, se);
}
return se.encode(coder, val);
if (dp == 0) {
dst = new byte[len << 1];
} else {
byte[] buf = new byte[len << 1];
StringLatin1.inflate(dst, 0, buf, 0, dp);
dst = buf;
}
while (sp < sl) {
int b1 = src[sp++];
if (b1 >= 0) {
putChar(dst, dp++, (char) b1);
} else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) {
if (sp < sl) {
int b2 = src[sp++];
if (isNotContinuation(b2)) {
if (!doReplace) {
throwMalformed(sp - 1, 1);
}
putChar(dst, dp++, repl);
sp--;
} else {
putChar(dst, dp++, (char)(((b1 << 6) ^ b2)^
(((byte) 0xC0 << 6) ^
((byte) 0x80 << 0))));
}
continue;
}
if (!doReplace) {
throwMalformed(sp, 1); // underflow()
}
putChar(dst, dp++, repl);
break;
} else if ((b1 >> 4) == -2) {
if (sp + 1 < sl) {
int b2 = src[sp++];
int b3 = src[sp++];
if (isMalformed3(b1, b2, b3)) {
if (!doReplace) {
throwMalformed(sp - 3, 3);
}
putChar(dst, dp++, repl);
sp -= 3;
sp += malformedN(src, sp, 3);
} else {
char c = (char)((b1 << 12) ^
(b2 << 6) ^
(b3 ^
(((byte) 0xE0 << 12) ^
((byte) 0x80 << 6) ^
((byte) 0x80 << 0))));
if (isSurrogate(c)) {
if (!doReplace) {
throwMalformed(sp - 3, 3);
}
putChar(dst, dp++, repl);
} else {
putChar(dst, dp++, c);
}
}
continue;
}
if (sp < sl && isMalformed3_2(b1, src[sp])) {
if (!doReplace) {
throwMalformed(sp - 1, 2);
}
putChar(dst, dp++, repl);
continue;
}
if (!doReplace){
throwMalformed(sp, 1);
}
putChar(dst, dp++, repl);
break;
} else if ((b1 >> 3) == -2) {
if (sp + 2 < sl) {
int b2 = src[sp++];
int b3 = src[sp++];
int b4 = src[sp++];
int uc = ((b1 << 18) ^
(b2 << 12) ^
(b3 << 6) ^
(b4 ^
(((byte) 0xF0 << 18) ^
((byte) 0x80 << 12) ^
((byte) 0x80 << 6) ^
((byte) 0x80 << 0))));
if (isMalformed4(b2, b3, b4) ||
!isSupplementaryCodePoint(uc)) { // shortest form check
if (!doReplace) {
throwMalformed(sp - 4, 4);
}
putChar(dst, dp++, repl);
sp -= 4;
sp += malformedN(src, sp, 4);
} else {
putChar(dst, dp++, highSurrogate(uc));
putChar(dst, dp++, lowSurrogate(uc));
}
continue;
}
b1 &= 0xff;
if (b1 > 0xf4 ||
sp < sl && isMalformed4_2(b1, src[sp] & 0xff)) {
if (!doReplace) {
throwMalformed(sp - 1, 1); // or 2
}
putChar(dst, dp++, repl);
continue;
}
if (!doReplace) {
throwMalformed(sp - 1, 1);
}
sp++;
putChar(dst, dp++, repl);
if (sp < sl && isMalformed4_3(src[sp])) {
continue;
}
break;
} else {
if (!doReplace) {
throwMalformed(sp - 1, 1);
}
putChar(dst, dp++, repl);
}
}
if (dp != len) {
dst = Arrays.copyOf(dst, dp << 1);
}
return ret.with(dst, UTF16);
}
static byte[] encode(Charset cs, byte coder, byte[] val) {
if (cs == UTF_8) {
return encodeUTF8(coder, val);
} else if (cs == ISO_8859_1) {
return encode8859_1(coder, val);
} else if (cs == US_ASCII) {
return encodeASCII(coder, val);
}
CharsetEncoder ce = cs.newEncoder();
// fastpath for ascii compatible
if (coder == LATIN1 && (((ce instanceof ArrayEncoder) &&
((ArrayEncoder)ce).isASCIICompatible() &&
!hasNegatives(val, 0, val.length)))) {
private static byte[] encodeUTF8(byte coder, byte[] val, boolean doReplace) {
if (coder == UTF16)
return encodeUTF8_UTF16(val, doReplace);
if (!hasNegatives(val, 0, val.length))
return Arrays.copyOf(val, val.length);
}
int len = val.length >> coder; // assume LATIN1=0/UTF16=1;
int en = scale(len, ce.maxBytesPerChar());
byte[] ba = new byte[en];
if (len == 0) {
return ba;
}
boolean isTrusted = cs.getClass().getClassLoader0() == null ||
System.getSecurityManager() == null;
ce.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE)
.reset();
if (ce instanceof ArrayEncoder) {
if (!isTrusted) {
val = Arrays.copyOf(val, val.length);
}
int blen = (coder == LATIN1 ) ? ((ArrayEncoder)ce).encodeFromLatin1(val, 0, len, ba)
: ((ArrayEncoder)ce).encodeFromUTF16(val, 0, len, ba);
if (blen != -1) {
return safeTrim(ba, blen, isTrusted);
int dp = 0;
byte[] dst = new byte[val.length << 1];
for (int sp = 0; sp < val.length; sp++) {
byte c = val[sp];
if (c < 0) {
dst[dp++] = (byte)(0xc0 | ((c & 0xff) >> 6));
dst[dp++] = (byte)(0x80 | (c & 0x3f));
} else {
dst[dp++] = c;
}
}
char[] ca = (coder == LATIN1 ) ? StringLatin1.toChars(val)
: StringUTF16.toChars(val);
ByteBuffer bb = ByteBuffer.wrap(ba);
CharBuffer cb = CharBuffer.wrap(ca, 0, len);
try {
CoderResult cr = ce.encode(cb, bb, true);
if (!cr.isUnderflow())
cr.throwException();
cr = ce.flush(bb);
if (!cr.isUnderflow())
cr.throwException();
} catch (CharacterCodingException x) {
throw new Error(x);
}
return safeTrim(ba, bb.position(), isTrusted);
if (dp == dst.length)
return dst;
return Arrays.copyOf(dst, dp);
}
static byte[] encode(byte coder, byte[] val) {
String csn = Charset.defaultCharset().name();
try {
// use charset name encode() variant which provides caching.
return encode(csn, coder, val);
} catch (UnsupportedEncodingException x) {
warnUnsupportedCharset(csn);
private static byte[] encodeUTF8_UTF16(byte[] val, boolean doReplace) {
int dp = 0;
int sp = 0;
int sl = val.length >> 1;
byte[] dst = new byte[sl * 3];
char c;
while (sp < sl && (c = StringUTF16.getChar(val, sp)) < '\u0080') {
// ascii fast loop;
dst[dp++] = (byte)c;
sp++;
}
try {
return encode("ISO-8859-1", coder, val);
} catch (UnsupportedEncodingException x) {
// If this code is hit during VM initialization, err(String) is
// the only way we will be able to get any kind of error message.
err("ISO-8859-1 charset not available: " + x.toString() + "\n");
// If we can not find ISO-8859-1 (a required encoding) then things
// are seriously wrong with the installation.
System.exit(1);
return null;
while (sp < sl) {
c = StringUTF16.getChar(val, sp++);
if (c < 0x80) {
dst[dp++] = (byte)c;
} else if (c < 0x800) {
dst[dp++] = (byte)(0xc0 | (c >> 6));
dst[dp++] = (byte)(0x80 | (c & 0x3f));
} else if (Character.isSurrogate(c)) {
int uc = -1;
char c2;
if (Character.isHighSurrogate(c) && sp < sl &&
Character.isLowSurrogate(c2 = StringUTF16.getChar(val, sp))) {
uc = Character.toCodePoint(c, c2);
}
if (uc < 0) {
if (doReplace) {
dst[dp++] = '?';
} else {
throwMalformed(sp - 1, 1); // or 2, does not matter here
}
} else {
dst[dp++] = (byte)(0xf0 | ((uc >> 18)));
dst[dp++] = (byte)(0x80 | ((uc >> 12) & 0x3f));
dst[dp++] = (byte)(0x80 | ((uc >> 6) & 0x3f));
dst[dp++] = (byte)(0x80 | (uc & 0x3f));
sp++; // 2 chars
}
} else {
// 3 bytes, 16 bits
dst[dp++] = (byte)(0xe0 | ((c >> 12)));
dst[dp++] = (byte)(0x80 | ((c >> 6) & 0x3f));
dst[dp++] = (byte)(0x80 | (c & 0x3f));
}
}
if (dp == dst.length) {
return dst;
}
return Arrays.copyOf(dst, dp);
}
/**
* Print a message directly to stderr, bypassing all character conversion
* methods.
* @param msg message to print
////////////////////// for j.u.z.ZipCoder //////////////////////////
/*
* Throws iae, instead of replacing, if malformed or unmappble.
*/
private static native void err(String msg);
static String newStringUTF8NoRepl(byte[] src, int off, int len) {
if (COMPACT_STRINGS && !hasNegatives(src, off, len))
return new String(Arrays.copyOfRange(src, off, off + len), LATIN1);
Result ret = decodeUTF8_0(src, off, len, false);
return new String(ret.value, ret.coder);
}
/*
* Throws iae, instead of replacing, if unmappble.
*/
static byte[] getBytesUTF8NoRepl(String s) {
return encodeUTF8(s.coder(), s.value(), false);
}
}

View File

@ -1,235 +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 java.lang;
import java.nio.charset.Charset;
import java.util.Arrays;
import static java.lang.String.LATIN1;
import static java.lang.String.UTF16;
import static java.lang.String.COMPACT_STRINGS;
import static java.lang.Character.isSurrogate;
import static java.lang.Character.highSurrogate;
import static java.lang.Character.lowSurrogate;
import static java.lang.Character.isSupplementaryCodePoint;
import static java.lang.StringUTF16.putChar;
class StringDecoderUTF8 extends StringCoding.StringDecoder {
StringDecoderUTF8(Charset cs, String rcn) {
super(cs, rcn);
}
private static boolean isNotContinuation(int b) {
return (b & 0xc0) != 0x80;
}
private static boolean isMalformed3(int b1, int b2, int b3) {
return (b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) ||
(b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80;
}
private static boolean isMalformed3_2(int b1, int b2) {
return (b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) ||
(b2 & 0xc0) != 0x80;
}
private static boolean isMalformed4(int b2, int b3, int b4) {
return (b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80 ||
(b4 & 0xc0) != 0x80;
}
private static boolean isMalformed4_2(int b1, int b2) {
return (b1 == 0xf0 && (b2 < 0x90 || b2 > 0xbf)) ||
(b1 == 0xf4 && (b2 & 0xf0) != 0x80) ||
(b2 & 0xc0) != 0x80;
}
private static boolean isMalformed4_3(int b3) {
return (b3 & 0xc0) != 0x80;
}
// for nb == 3/4
private static int malformedN(byte[] src, int sp, int nb) {
if (nb == 3) {
int b1 = src[sp++];
int b2 = src[sp++]; // no need to lookup b3
return ((b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) ||
isNotContinuation(b2)) ? 1 : 2;
} else if (nb == 4) { // we don't care the speed here
int b1 = src[sp++] & 0xff;
int b2 = src[sp++] & 0xff;
if (b1 > 0xf4 ||
(b1 == 0xf0 && (b2 < 0x90 || b2 > 0xbf)) ||
(b1 == 0xf4 && (b2 & 0xf0) != 0x80) ||
isNotContinuation(b2))
return 1;
if (isNotContinuation(src[sp++]))
return 2;
return 3;
}
assert false;
return -1;
}
private static char repl = '\ufffd';
StringCoding.Result decode(byte[] src, int sp, int len) {
return decode(src, sp, len, result);
}
static StringCoding.Result decode(byte[] src, int sp, int len,
StringCoding.Result ret) {
int sl = sp + len;
byte[] dst = new byte[len];
int dp = 0;
if (COMPACT_STRINGS) { // Latin1 only loop
while (sp < sl) {
int b1 = src[sp];
if (b1 >= 0) {
dst[dp++] = (byte)b1;
sp++;
continue;
}
if ((b1 == (byte)0xc2 || b1 == (byte)0xc3) &&
sp + 1 < sl) {
int b2 = src[sp + 1];
if (!isNotContinuation(b2)) {
dst[dp++] = (byte)(((b1 << 6) ^ b2)^
(((byte) 0xC0 << 6) ^
((byte) 0x80 << 0)));
sp += 2;
continue;
}
}
// anything not a latin1, including the repl
// we have to go with the utf16
break;
}
if (sp == sl) {
if (dp != dst.length) {
dst = Arrays.copyOf(dst, dp);
}
return ret.with(dst, LATIN1);
}
}
if (dp == 0) {
dst = new byte[len << 1];
} else {
byte[] buf = new byte[len << 1];
StringLatin1.inflate(dst, 0, buf, 0, dp);
dst = buf;
}
while (sp < sl) {
int b1 = src[sp++];
if (b1 >= 0) {
putChar(dst, dp++, (char) b1);
} else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) {
if (sp < sl) {
int b2 = src[sp++];
if (isNotContinuation(b2)) {
putChar(dst, dp++, repl);
sp--;
} else {
putChar(dst, dp++, (char)(((b1 << 6) ^ b2)^
(((byte) 0xC0 << 6) ^
((byte) 0x80 << 0))));
}
continue;
}
putChar(dst, dp++, repl);
break;
} else if ((b1 >> 4) == -2) {
if (sp + 1 < sl) {
int b2 = src[sp++];
int b3 = src[sp++];
if (isMalformed3(b1, b2, b3)) {
putChar(dst, dp++, repl);
sp -= 3;
sp += malformedN(src, sp, 3);
} else {
char c = (char)((b1 << 12) ^
(b2 << 6) ^
(b3 ^
(((byte) 0xE0 << 12) ^
((byte) 0x80 << 6) ^
((byte) 0x80 << 0))));
putChar(dst, dp++, isSurrogate(c) ? repl : c);
}
continue;
}
if (sp < sl && isMalformed3_2(b1, src[sp])) {
putChar(dst, dp++, repl);
continue;
}
putChar(dst, dp++, repl);
break;
} else if ((b1 >> 3) == -2) {
if (sp + 2 < sl) {
int b2 = src[sp++];
int b3 = src[sp++];
int b4 = src[sp++];
int uc = ((b1 << 18) ^
(b2 << 12) ^
(b3 << 6) ^
(b4 ^
(((byte) 0xF0 << 18) ^
((byte) 0x80 << 12) ^
((byte) 0x80 << 6) ^
((byte) 0x80 << 0))));
if (isMalformed4(b2, b3, b4) ||
!isSupplementaryCodePoint(uc)) { // shortest form check
putChar(dst, dp++, repl);
sp -= 4;
sp += malformedN(src, sp, 4);
} else {
putChar(dst, dp++, highSurrogate(uc));
putChar(dst, dp++, lowSurrogate(uc));
}
continue;
}
b1 &= 0xff;
if (b1 > 0xf4 ||
sp < sl && isMalformed4_2(b1, src[sp] & 0xff)) {
putChar(dst, dp++, repl);
continue;
}
sp++;
putChar(dst, dp++, repl);
if (sp < sl && isMalformed4_3(src[sp])) {
continue;
}
break;
} else {
putChar(dst, dp++, repl);
}
}
if (dp != len) {
dst = Arrays.copyOf(dst, dp << 1);
}
return ret.with(dst, UTF16);
}
}

View File

@ -2184,6 +2184,15 @@ public final class System {
public Stream<ModuleLayer> layers(ClassLoader loader) {
return ModuleLayer.layers(loader);
}
public String newStringUTF8NoRepl(byte[] bytes, int off, int len) {
return StringCoding.newStringUTF8NoRepl(bytes, off, len);
}
public byte[] getBytesUTF8NoRepl(String s) {
return StringCoding.getBytesUTF8NoRepl(s);
}
});
}
}

View File

@ -105,23 +105,10 @@ class MethodType implements java.io.Serializable {
private @Stable String methodDescriptor; // cache for toMethodDescriptorString
/**
* Check the given parameters for validity and store them into the final fields.
* Constructor that performs no copying or validation.
* Should only be called from the factory method makeImpl
*/
private MethodType(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
checkRtype(rtype);
checkPtypes(ptypes);
this.rtype = rtype;
// defensively copy the array passed in by the user
this.ptypes = trusted ? ptypes : Arrays.copyOf(ptypes, ptypes.length);
}
/**
* Construct a temporary unchecked instance of MethodType for use only as a key to the intern table.
* Does not check the given parameters for validity, and must discarded (if untrusted) or checked
* (if trusted) after it has been used as a searching key.
* The parameters are reversed for this constructor, so that it is not accidentally used.
*/
private MethodType(Class<?>[] ptypes, Class<?> rtype) {
private MethodType(Class<?> rtype, Class<?>[] ptypes) {
this.rtype = rtype;
this.ptypes = ptypes;
}
@ -308,18 +295,21 @@ class MethodType implements java.io.Serializable {
if (ptypes.length == 0) {
ptypes = NO_PTYPES; trusted = true;
}
MethodType primordialMT = new MethodType(ptypes, rtype);
MethodType primordialMT = new MethodType(rtype, ptypes);
MethodType mt = internTable.get(primordialMT);
if (mt != null)
return mt;
// promote the object to the Real Thing, and reprobe
MethodType.checkRtype(rtype);
if (trusted) {
MethodType.checkRtype(rtype);
MethodType.checkPtypes(ptypes);
mt = primordialMT;
} else {
mt = new MethodType(rtype, ptypes, false);
// Make defensive copy then validate
ptypes = Arrays.copyOf(ptypes, ptypes.length);
MethodType.checkPtypes(ptypes);
mt = new MethodType(rtype, ptypes);
}
mt.form = MethodTypeForm.findForm(mt);
return internTable.add(mt);

View File

@ -39,6 +39,7 @@ import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
@ -2603,7 +2604,8 @@ public class ModuleDescriptor
* Returns a string containing the given set of modifiers and label.
*/
private static <M> String toString(Set<M> mods, String what) {
return (Stream.concat(mods.stream().map(e -> e.toString().toLowerCase()),
return (Stream.concat(mods.stream().map(e -> e.toString()
.toLowerCase(Locale.ROOT)),
Stream.of(what)))
.collect(Collectors.joining(" "));
}

View File

@ -658,8 +658,8 @@ public class URLClassLoader extends SecureClassLoader implements Closeable {
*
* @param name the resource name
* @exception IOException if an I/O exception occurs
* @return an {@code Enumeration} of {@code URL}s
* If the loader is closed, the Enumeration will be empty.
* @return An {@code Enumeration} of {@code URL}s.
* If the loader is closed, the Enumeration contains no elements.
*/
public Enumeration<URL> findResources(final String name)
throws IOException

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -26,6 +26,10 @@
package java.net;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
import java.util.Objects;
/**
* Utility class for HTML form decoding. This class contains static methods
@ -108,7 +112,43 @@ public class URLDecoder {
/**
* Decodes an {@code application/x-www-form-urlencoded} string using
* a specific encoding scheme.
* The supplied encoding is used to determine
*
* <p>
* This method behaves the same as {@linkplain decode(String s, Charset charset)}
* except that it will {@linkplain java.nio.charset.Charset#forName look up the charset}
* using the given encoding name.
*
* @implNote This implementation will throw an {@link java.lang.IllegalArgumentException}
* when illegal strings are encountered.
*
* @param s the {@code String} to decode
* @param enc The name of a supported
* <a href="../lang/package-summary.html#charenc">character
* encoding</a>.
* @return the newly decoded {@code String}
* @throws UnsupportedEncodingException
* If character encoding needs to be consulted, but
* named character encoding is not supported
* @see URLEncoder#encode(java.lang.String, java.lang.String)
* @since 1.4
*/
public static String decode(String s, String enc) throws UnsupportedEncodingException {
if (enc.length() == 0) {
throw new UnsupportedEncodingException ("URLDecoder: empty string enc parameter");
}
try {
Charset charset = Charset.forName(enc);
return decode(s, charset);
} catch (IllegalCharsetNameException | UnsupportedCharsetException e) {
throw new UnsupportedEncodingException(enc);
}
}
/**
* Decodes an {@code application/x-www-form-urlencoded} string using
* a specific {@linkplain java.nio.charset.Charset Charset}.
* The supplied charset is used to determine
* what characters are represented by any consecutive sequences of the
* form "<i>{@code %xy}</i>".
* <p>
@ -118,29 +158,25 @@ public class URLDecoder {
* UTF-8 should be used. Not doing so may introduce
* incompatibilities.</em>
*
* @implNote This implementation will throw an {@link java.lang.IllegalArgumentException}
* when illegal strings are encountered.
*
* @param s the {@code String} to decode
* @param enc The name of a supported
* <a href="../lang/package-summary.html#charenc">character
* encoding</a>.
* @param charset the given charset
* @return the newly decoded {@code String}
* @exception UnsupportedEncodingException
* If character encoding needs to be consulted, but
* named character encoding is not supported
* @see URLEncoder#encode(java.lang.String, java.lang.String)
* @since 1.4
* @throws NullPointerException if {@code s} or {@code charset} is {@code null}
* @throws IllegalArgumentException if the implementation encounters illegal
* characters
* @see URLEncoder#encode(java.lang.String, java.nio.charset.Charset)
* @since 10
*/
public static String decode(String s, String enc)
throws UnsupportedEncodingException{
public static String decode(String s, Charset charset) {
Objects.requireNonNull(charset, "Charset");
boolean needToChange = false;
int numChars = s.length();
StringBuilder sb = new StringBuilder(numChars > 500 ? numChars / 2 : numChars);
int i = 0;
if (enc.length() == 0) {
throw new UnsupportedEncodingException ("URLDecoder: empty string enc parameter");
}
char c;
byte[] bytes = null;
while (i < numChars) {
@ -173,7 +209,9 @@ public class URLDecoder {
(c=='%')) {
int v = Integer.parseInt(s, i + 1, i + 3, 16);
if (v < 0)
throw new IllegalArgumentException("URLDecoder: Illegal hex characters in escape (%) pattern - negative value");
throw new IllegalArgumentException(
"URLDecoder: Illegal hex characters in escape "
+ "(%) pattern - negative value");
bytes[pos++] = (byte) v;
i+= 3;
if (i < numChars)
@ -187,7 +225,7 @@ public class URLDecoder {
throw new IllegalArgumentException(
"URLDecoder: Incomplete trailing escape (%) pattern");
sb.append(new String(bytes, 0, pos, enc));
sb.append(new String(bytes, 0, pos, charset));
} catch (NumberFormatException e) {
throw new IllegalArgumentException(
"URLDecoder: Illegal hex characters in escape (%) pattern - "

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1995, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -31,6 +31,7 @@ import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException ;
import java.util.BitSet;
import java.util.Objects;
import sun.security.action.GetPropertyAction;
/**
@ -168,45 +169,61 @@ public class URLEncoder {
/**
* Translates a string into {@code application/x-www-form-urlencoded}
* format using a specific encoding scheme. This method uses the
* supplied encoding scheme to obtain the bytes for unsafe
* characters.
* format using a specific encoding scheme.
* <p>
* <em><strong>Note:</strong> The <a href=
* "http://www.w3.org/TR/html40/appendix/notes.html#non-ascii-chars">
* World Wide Web Consortium Recommendation</a> states that
* UTF-8 should be used. Not doing so may introduce
* incompatibilities.</em>
* This method behaves the same as {@linkplain encode(String s, Charset charset)}
* except that it will {@linkplain java.nio.charset.Charset#forName look up the charset}
* using the given encoding name.
*
* @param s {@code String} to be translated.
* @param enc The name of a supported
* <a href="../lang/package-summary.html#charenc">character
* encoding</a>.
* @return the translated {@code String}.
* @exception UnsupportedEncodingException
* @throws UnsupportedEncodingException
* If the named encoding is not supported
* @see URLDecoder#decode(java.lang.String, java.lang.String)
* @since 1.4
*/
public static String encode(String s, String enc)
throws UnsupportedEncodingException {
if (enc == null) {
throw new NullPointerException("charsetName");
}
try {
Charset charset = Charset.forName(enc);
return encode(s, charset);
} catch (IllegalCharsetNameException | UnsupportedCharsetException e) {
throw new UnsupportedEncodingException(enc);
}
}
/**
* Translates a string into {@code application/x-www-form-urlencoded}
* format using a specific {@linkplain java.nio.charset.Charset Charset}.
* This method uses the supplied charset to obtain the bytes for unsafe
* characters.
* <p>
* <em><strong>Note:</strong> The <a href=
* "http://www.w3.org/TR/html40/appendix/notes.html#non-ascii-chars">
* World Wide Web Consortium Recommendation</a> states that
* UTF-8 should be used. Not doing so may introduce incompatibilities.</em>
*
* @param s {@code String} to be translated.
* @param charset the given charset
* @return the translated {@code String}.
* @throws NullPointerException if {@code s} or {@code charset} is {@code null}.
* @see URLDecoder#decode(java.lang.String, java.nio.charset.Charset)
* @since 10
*/
public static String encode(String s, Charset charset) {
Objects.requireNonNull(charset, "charset");
boolean needToChange = false;
StringBuilder out = new StringBuilder(s.length());
Charset charset;
CharArrayWriter charArrayWriter = new CharArrayWriter();
if (enc == null)
throw new NullPointerException("charsetName");
try {
charset = Charset.forName(enc);
} catch (IllegalCharsetNameException e) {
throw new UnsupportedEncodingException(enc);
} catch (UnsupportedCharsetException e) {
throw new UnsupportedEncodingException(enc);
}
for (int i = 0; i < s.length();) {
int c = (int) s.charAt(i);
//System.out.println("Examining character: " + c);

View File

@ -480,39 +480,14 @@ public abstract class URLStreamHandler {
* @return a string representation of the {@code URL} argument.
*/
protected String toExternalForm(URL u) {
// pre-compute length of StringBuffer
int len = u.getProtocol().length() + 1;
if (u.getAuthority() != null && u.getAuthority().length() > 0)
len += 2 + u.getAuthority().length();
if (u.getPath() != null) {
len += u.getPath().length();
}
if (u.getQuery() != null) {
len += 1 + u.getQuery().length();
}
if (u.getRef() != null)
len += 1 + u.getRef().length();
StringBuilder result = new StringBuilder(len);
result.append(u.getProtocol());
result.append(":");
if (u.getAuthority() != null && u.getAuthority().length() > 0) {
result.append("//");
result.append(u.getAuthority());
}
if (u.getPath() != null) {
result.append(u.getPath());
}
if (u.getQuery() != null) {
result.append('?');
result.append(u.getQuery());
}
if (u.getRef() != null) {
result.append("#");
result.append(u.getRef());
}
return result.toString();
String s;
return u.getProtocol()
+ ':'
+ (((s = u.getAuthority()) != null && s.length() > 0)
? "//" + s : "")
+ (((s = u.getPath()) != null) ? s : "")
+ (((s = u.getQuery()) != null) ? '?' + s : "")
+ (((s = u.getRef()) != null) ? '#' + s : "");
}
/**

View File

@ -527,7 +527,7 @@ public final class Channels {
* behaves in exactly the same way as the expression
*
* <pre> {@code
* Channels.newReader(ch, Charset.forName(csName).newDecoder(), -1)
* Channels.newReader(ch, Charset.forName(csName))
* } </pre>
*
* @param ch
@ -549,6 +549,38 @@ public final class Channels {
return newReader(ch, Charset.forName(csName).newDecoder(), -1);
}
/**
* Constructs a reader that decodes bytes from the given channel according
* to the given charset.
*
* <p> An invocation of this method of the form
*
* <pre> {@code
* Channels.newReader(ch, charset)
* } </pre>
*
* behaves in exactly the same way as the expression
*
* <pre> {@code
* Channels.newReader(ch, Charset.forName(csName).newDecoder(), -1)
* } </pre>
*
* <p> The reader's default action for malformed-input and unmappable-character
* errors is to {@linkplain java.nio.charset.CodingErrorAction#REPORT report}
* them. When more control over the error handling is required, the constructor
* that takes a {@linkplain java.nio.charset.CharsetDecoder} should be used.
*
* @param ch The channel from which bytes will be read
*
* @param charset The charset to be used
*
* @return A new reader
*/
public static Reader newReader(ReadableByteChannel ch, Charset charset) {
Objects.requireNonNull(charset, "charset");
return newReader(ch, charset.newDecoder(), -1);
}
/**
* Constructs a writer that encodes characters using the given encoder and
* writes the resulting bytes to the given channel.
@ -595,7 +627,7 @@ public final class Channels {
* behaves in exactly the same way as the expression
*
* <pre> {@code
* Channels.newWriter(ch, Charset.forName(csName).newEncoder(), -1)
* Channels.newWriter(ch, Charset.forName(csName))
* } </pre>
*
* @param ch
@ -616,4 +648,38 @@ public final class Channels {
Objects.requireNonNull(csName, "csName");
return newWriter(ch, Charset.forName(csName).newEncoder(), -1);
}
/**
* Constructs a writer that encodes characters according to the given
* charset and writes the resulting bytes to the given channel.
*
* <p> An invocation of this method of the form
*
* <pre> {@code
* Channels.newWriter(ch, charset)
* } </pre>
*
* behaves in exactly the same way as the expression
*
* <pre> {@code
* Channels.newWriter(ch, Charset.forName(csName).newEncoder(), -1)
* } </pre>
*
* <p> The writer's default action for malformed-input and unmappable-character
* errors is to {@linkplain java.nio.charset.CodingErrorAction#REPORT report}
* them. When more control over the error handling is required, the constructor
* that takes a {@linkplain java.nio.charset.CharsetEncoder} should be used.
*
* @param ch
* The channel to which bytes will be written
*
* @param charset
* The charset to be used
*
* @return A new writer
*/
public static Writer newWriter(WritableByteChannel ch, Charset charset) {
Objects.requireNonNull(charset, "charset");
return newWriter(ch, charset.newEncoder(), -1);
}
}

View File

@ -97,6 +97,13 @@ import sun.util.locale.provider.LocaleServiceProviderPool;
* DateFormat df = DateFormat.getDateInstance(DateFormat.LONG, Locale.FRANCE);
* }</pre>
* </blockquote>
*
* <p>If the specified locale contains "ca" (calendar), "rg" (region override),
* and/or "tz" (timezone) <a href="../util/Locale.html#def_locale_extension">Unicode
* extensions</a>, the calendar, the country and/or the time zone for formatting
* are overridden. If both "ca" and "rg" are specified, the calendar from the "ca"
* extension supersedes the implicit one from the "rg" extension.
*
* <p>You can use a DateFormat to parse also.
* <blockquote>
* <pre>{@code

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -49,6 +49,7 @@ import java.util.Objects;
import java.util.ResourceBundle;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import sun.util.locale.provider.CalendarDataUtility;
import sun.util.locale.provider.LocaleProviderAdapter;
import sun.util.locale.provider.LocaleServiceProviderPool;
import sun.util.locale.provider.ResourceBundleBasedAdapter;
@ -82,6 +83,10 @@ import sun.util.locale.provider.TimeZoneNameUtility;
* </pre>
* </blockquote>
*
* <p>If the locale contains "rg" (region override)
* <a href="../util/Locale.html#def_locale_extension">Unicode extension</a>,
* the symbols are overridden for the designated region.
*
* <p>
* <code>DateFormatSymbols</code> objects are cloneable. When you obtain
* a <code>DateFormatSymbols</code> object, feel free to modify the
@ -716,15 +721,18 @@ public class DateFormatSymbols implements Serializable, Cloneable {
}
dfs = new DateFormatSymbols(false);
// check for region override
Locale override = CalendarDataUtility.findRegionOverride(locale);
// Initialize the fields from the ResourceBundle for locale.
LocaleProviderAdapter adapter
= LocaleProviderAdapter.getAdapter(DateFormatSymbolsProvider.class, locale);
= LocaleProviderAdapter.getAdapter(DateFormatSymbolsProvider.class, override);
// Avoid any potential recursions
if (!(adapter instanceof ResourceBundleBasedAdapter)) {
adapter = LocaleProviderAdapter.getResourceBundleBased();
}
ResourceBundle resource
= ((ResourceBundleBasedAdapter)adapter).getLocaleData().getDateFormatData(locale);
= ((ResourceBundleBasedAdapter)adapter).getLocaleData().getDateFormatData(override);
dfs.locale = locale;
// JRE and CLDR use different keys

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -44,6 +44,7 @@ import java.io.Serializable;
import java.text.spi.DecimalFormatSymbolsProvider;
import java.util.Currency;
import java.util.Locale;
import sun.util.locale.provider.CalendarDataUtility;
import sun.util.locale.provider.LocaleProviderAdapter;
import sun.util.locale.provider.LocaleServiceProviderPool;
import sun.util.locale.provider.ResourceBundleBasedAdapter;
@ -56,6 +57,10 @@ import sun.util.locale.provider.ResourceBundleBasedAdapter;
* of these symbols, you can get the <code>DecimalFormatSymbols</code> object from
* your <code>DecimalFormat</code> and modify it.
*
* <p>If the locale contains "rg" (region override)
* <a href="../util/Locale.html#def_locale_extension">Unicode extension</a>,
* the symbols are overridden for the designated region.
*
* @see java.util.Locale
* @see DecimalFormat
* @author Mark Davis
@ -609,13 +614,18 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
private void initialize( Locale locale ) {
this.locale = locale;
// check for region override
Locale override = locale.getUnicodeLocaleType("nu") == null ?
CalendarDataUtility.findRegionOverride(locale) :
locale;
// get resource bundle data
LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(DecimalFormatSymbolsProvider.class, locale);
LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(DecimalFormatSymbolsProvider.class, override);
// Avoid potential recursions
if (!(adapter instanceof ResourceBundleBasedAdapter)) {
adapter = LocaleProviderAdapter.getResourceBundleBased();
}
Object[] data = adapter.getLocaleResources(locale).getDecimalFormatSymbolsData();
Object[] data = adapter.getLocaleResources(override).getDecimalFormatSymbolsData();
String[] numberElements = (String[]) data[0];
decimalSeparator = numberElements[0].charAt(0);

View File

@ -96,7 +96,14 @@ import sun.util.locale.provider.LocaleServiceProviderPool;
* NumberFormat nf = NumberFormat.getInstance(Locale.FRENCH);
* }</pre>
* </blockquote>
* You can also use a <code>NumberFormat</code> to parse numbers:
*
* <p>If the locale contains "nu" (numbers) and/or "rg" (region override)
* <a href="../util/Locale.html#def_locale_extension">Unicode extensions</a>,
* the decimal digits, and/or the country used for formatting are overridden.
* If both "nu" and "rg" are specified, the decimal digits from the "nu"
* extension supersedes the implicit one from the "rg" extension.
*
* <p>You can also use a {@code NumberFormat} to parse numbers:
* <blockquote>
* <pre>{@code
* myNumber = nf.parse(myString);

View File

@ -672,7 +672,7 @@ public class SimpleDateFormat extends DateFormat {
// However, the calendar should use the current default TimeZone.
// If this is not contained in the locale zone strings, then the zone
// will be formatted using generic GMT+/-H:MM nomenclature.
calendar = Calendar.getInstance(TimeZone.getDefault(), loc);
calendar = Calendar.getInstance(loc);
}
}

View File

@ -97,6 +97,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import sun.util.locale.provider.TimeZoneNameUtility;
/**
* Formatter for printing and parsing date-time objects.
@ -548,7 +549,7 @@ public final class DateTimeFormatter {
* For example, {@code d MMM uuuu} will format 2011-12-03 as '3 Dec 2011'.
* <p>
* The formatter will use the {@link Locale#getDefault(Locale.Category) default FORMAT locale}.
* This can be changed using {@link DateTimeFormatter#withLocale(Locale)} on the returned formatter
* This can be changed using {@link DateTimeFormatter#withLocale(Locale)} on the returned formatter.
* Alternatively use the {@link #ofPattern(String, Locale)} variant of this method.
* <p>
* The returned formatter has no override chronology or zone.
@ -572,7 +573,7 @@ public final class DateTimeFormatter {
* For example, {@code d MMM uuuu} will format 2011-12-03 as '3 Dec 2011'.
* <p>
* The formatter will use the specified locale.
* This can be changed using {@link DateTimeFormatter#withLocale(Locale)} on the returned formatter
* This can be changed using {@link DateTimeFormatter#withLocale(Locale)} on the returned formatter.
* <p>
* The returned formatter has no override chronology or zone.
* It uses {@link ResolverStyle#SMART SMART} resolver style.
@ -1443,10 +1444,17 @@ public final class DateTimeFormatter {
* This is used to lookup any part of the formatter needing specific
* localization, such as the text or localized pattern.
* <p>
* The locale is stored as passed in, without further processing.
* If the locale has <a href="../../util/Locale.html#def_locale_extension">
* Unicode extensions</a>, they may be used later in text
* processing. To set the chronology, time-zone and decimal style from
* unicode extensions, see {@link #localizedBy localizedBy()}.
* <p>
* This instance is immutable and unaffected by this method call.
*
* @param locale the new locale, not null
* @return a formatter based on this formatter with the requested locale, not null
* @see #localizedBy(Locale)
*/
public DateTimeFormatter withLocale(Locale locale) {
if (this.locale.equals(locale)) {
@ -1455,6 +1463,52 @@ public final class DateTimeFormatter {
return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
}
/**
* Returns a copy of this formatter with localized values of the locale,
* calendar, region, decimal style and/or timezone, that supercede values in
* this formatter.
* <p>
* This is used to lookup any part of the formatter needing specific
* localization, such as the text or localized pattern. If the locale contains the
* "ca" (calendar), "nu" (numbering system), "rg" (region override), and/or
* "tz" (timezone)
* <a href="../../util/Locale.html#def_locale_extension">Unicode extensions</a>,
* the chronology, numbering system and/or the zone are overridden. If both "ca"
* and "rg" are specified, the chronology from the "ca" extension supersedes the
* implicit one from the "rg" extension. Same is true for the "nu" extension.
* <p>
* Unlike the {@link #withLocale withLocale} method, the call to this method may
* produce a different formatter depending on the order of method chaining with
* other withXXXX() methods.
* <p>
* This instance is immutable and unaffected by this method call.
*
* @param locale the locale, not null
* @return a formatter based on this formatter with localized values of
* the calendar, decimal style and/or timezone, that supercede values in this
* formatter.
* @see #withLocale(Locale)
* @since 10
*/
public DateTimeFormatter localizedBy(Locale locale) {
if (this.locale.equals(locale)) {
return this;
}
// Check for decimalStyle/chronology/timezone in locale object
Chronology c = locale.getUnicodeLocaleType("ca") != null ?
Chronology.ofLocale(locale) : chrono;
DecimalStyle ds = locale.getUnicodeLocaleType("nu") != null ?
DecimalStyle.of(locale) : decimalStyle;
String tzType = locale.getUnicodeLocaleType("tz");
ZoneId z = tzType != null ?
TimeZoneNameUtility.convertLDMLShortID(tzType)
.map(ZoneId::of)
.orElse(zone) :
zone;
return new DateTimeFormatter(printerParser, locale, ds, resolverStyle, resolverFields, c, z);
}
//-----------------------------------------------------------------------
/**
* Gets the DecimalStyle to be used during formatting.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -120,6 +120,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import sun.text.spi.JavaTimeDateTimePatternProvider;
import sun.util.locale.provider.CalendarDataUtility;
import sun.util.locale.provider.LocaleProviderAdapter;
import sun.util.locale.provider.LocaleResources;
import sun.util.locale.provider.TimeZoneNameUtility;
@ -198,6 +199,10 @@ public final class DateTimeFormatterBuilder {
* Gets the formatting pattern for date and time styles for a locale and chronology.
* The locale and chronology are used to lookup the locale specific format
* for the requested dateStyle and/or timeStyle.
* <p>
* If the locale contains the "rg" (region override)
* <a href="../../util/Locale.html#def_locale_extension">Unicode extensions</a>,
* the formatting pattern is overridden with the one appropriate for the region.
*
* @param dateStyle the FormatStyle for the date, null for time-only pattern
* @param timeStyle the FormatStyle for the time, null for date-only pattern
@ -216,7 +221,8 @@ public final class DateTimeFormatterBuilder {
LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(JavaTimeDateTimePatternProvider.class, locale);
JavaTimeDateTimePatternProvider provider = adapter.getJavaTimeDateTimePatternProvider();
String pattern = provider.getJavaTimeDateTimePattern(convertStyle(timeStyle),
convertStyle(dateStyle), chrono.getCalendarType(), locale);
convertStyle(dateStyle), chrono.getCalendarType(),
CalendarDataUtility.findRegionOverride(locale));
return pattern;
}

View File

@ -510,7 +510,8 @@ class DateTimeTextProvider {
@SuppressWarnings("unchecked")
static <T> T getLocalizedResource(String key, Locale locale) {
LocaleResources lr = LocaleProviderAdapter.getResourceBundleBased()
.getLocaleResources(locale);
.getLocaleResources(
CalendarDataUtility.findRegionOverride(locale));
ResourceBundle rb = lr.getJavaTimeFormatData();
return rb.containsKey(key) ? (T) rb.getObject(key) : null;
}

View File

@ -147,6 +147,11 @@ public final class DecimalStyle {
* Obtains the DecimalStyle for the specified locale.
* <p>
* This method provides access to locale sensitive decimal style symbols.
* If the locale contains "nu" (Numbering System) and/or "rg"
* (Region Override) <a href="../../util/Locale.html#def_locale_extension">
* Unicode extensions</a>, returned instance will reflect the values specified with
* those extensions. If both "nu" and "rg" are specified, the value from
* the "nu" extension supersedes the implicit one from the "rg" extension.
*
* @param locale the locale, not null
* @return the decimal style, not null

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -79,6 +79,7 @@ import java.time.chrono.Chronology;
import java.util.Locale;
import java.util.Objects;
import java.util.ResourceBundle;
import sun.util.locale.provider.CalendarDataUtility;
import sun.util.locale.provider.LocaleProviderAdapter;
import sun.util.locale.provider.LocaleResources;
@ -632,7 +633,9 @@ public enum ChronoField implements TemporalField {
}
LocaleResources lr = LocaleProviderAdapter.getResourceBundleBased()
.getLocaleResources(locale);
.getLocaleResources(
CalendarDataUtility
.findRegionOverride(locale));
ResourceBundle rb = lr.getJavaTimeFormatData();
String key = "field." + displayNameKey;
return rb.containsKey(key) ? rb.getString(key) : name;

View File

@ -81,6 +81,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.ResourceBundle;
import sun.util.locale.provider.CalendarDataUtility;
import sun.util.locale.provider.LocaleProviderAdapter;
import sun.util.locale.provider.LocaleResources;
@ -430,7 +431,9 @@ public final class IsoFields {
public String getDisplayName(Locale locale) {
Objects.requireNonNull(locale, "locale");
LocaleResources lr = LocaleProviderAdapter.getResourceBundleBased()
.getLocaleResources(locale);
.getLocaleResources(
CalendarDataUtility
.findRegionOverride(locale));
ResourceBundle rb = lr.getJavaTimeFormatData();
return rb.containsKey("field.week") ? rb.getString("field.week") : toString();
}

View File

@ -286,13 +286,17 @@ public final class WeekFields implements Serializable {
* Obtains an instance of {@code WeekFields} appropriate for a locale.
* <p>
* This will look up appropriate values from the provider of localization data.
* If the locale contains "fw" (First day of week) and/or "rg"
* (Region Override) <a href="../../util/Locale.html#def_locale_extension">
* Unicode extensions</a>, returned instance will reflect the values specified with
* those extensions. If both "fw" and "rg" are specified, the value from
* the "fw" extension supersedes the implicit one from the "rg" extension.
*
* @param locale the locale to use, not null
* @return the week-definition, not null
*/
public static WeekFields of(Locale locale) {
Objects.requireNonNull(locale, "locale");
locale = new Locale(locale.getLanguage(), locale.getCountry()); // elminate variants
int calDow = CalendarDataUtility.retrieveFirstDayOfWeek(locale);
DayOfWeek dow = DayOfWeek.SUNDAY.plus(calDow - 1);
@ -1041,7 +1045,8 @@ public final class WeekFields implements Serializable {
Objects.requireNonNull(locale, "locale");
if (rangeUnit == YEARS) { // only have values for week-of-year
LocaleResources lr = LocaleProviderAdapter.getResourceBundleBased()
.getLocaleResources(locale);
.getLocaleResources(
CalendarDataUtility.findRegionOverride(locale));
ResourceBundle rb = lr.getJavaTimeFormatData();
return rb.containsKey("field.week") ? rb.getString("field.week") : name;
}

View File

@ -58,6 +58,7 @@ import sun.util.BuddhistCalendar;
import sun.util.calendar.ZoneInfo;
import sun.util.locale.provider.CalendarDataUtility;
import sun.util.locale.provider.LocaleProviderAdapter;
import sun.util.locale.provider.TimeZoneNameUtility;
import sun.util.spi.CalendarProvider;
/**
@ -128,9 +129,14 @@ import sun.util.spi.CalendarProvider;
*
* <code>Calendar</code> defines a locale-specific seven day week using two
* parameters: the first day of the week and the minimal days in first week
* (from 1 to 7). These numbers are taken from the locale resource data when a
* <code>Calendar</code> is constructed. They may also be specified explicitly
* through the methods for setting their values.
* (from 1 to 7). These numbers are taken from the locale resource data or the
* locale itself when a {@code Calendar} is constructed. If the designated
* locale contains "fw" and/or "rg" <a href="./Locale.html#def_locale_extension">
* Unicode extensions</a>, the first day of the week will be obtained according to
* those extensions. If both "fw" and "rg" are specified, the value from the "fw"
* extension supersedes the implicit one from the "rg" extension.
* They may also be specified explicitly through the methods for setting their
* values.
*
* <p>When setting or getting the <code>WEEK_OF_MONTH</code> or
* <code>WEEK_OF_YEAR</code> fields, <code>Calendar</code> must determine the
@ -1444,6 +1450,11 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
*
* <p>The default values are used for locale and time zone if these
* parameters haven't been given explicitly.
* <p>
* If the locale contains the time zone with "tz"
* <a href="Locale.html#def_locale_extension">Unicode extension</a>,
* and time zone hasn't been given explicitly, time zone in the locale
* is used.
*
* <p>Any out of range field values are either normalized in lenient
* mode or detected as an invalid value in non-lenient mode.
@ -1463,7 +1474,7 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
locale = Locale.getDefault();
}
if (zone == null) {
zone = TimeZone.getDefault();
zone = defaultTimeZone(locale);
}
Calendar cal;
if (type == null) {
@ -1605,12 +1616,17 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
* <code>Calendar</code> returned is based on the current time
* in the default time zone with the default
* {@link Locale.Category#FORMAT FORMAT} locale.
* <p>
* If the locale contains the time zone with "tz"
* <a href="Locale.html#def_locale_extension">Unicode extension</a>,
* that time zone is used instead.
*
* @return a Calendar.
*/
public static Calendar getInstance()
{
return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
Locale aLocale = Locale.getDefault(Locale.Category.FORMAT);
return createCalendar(defaultTimeZone(aLocale), aLocale);
}
/**
@ -1631,13 +1647,17 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
* Gets a calendar using the default time zone and specified locale.
* The <code>Calendar</code> returned is based on the current time
* in the default time zone with the given locale.
* <p>
* If the locale contains the time zone with "tz"
* <a href="Locale.html#def_locale_extension">Unicode extension</a>,
* that time zone is used instead.
*
* @param aLocale the locale for the week data
* @return a Calendar.
*/
public static Calendar getInstance(Locale aLocale)
{
return createCalendar(TimeZone.getDefault(), aLocale);
return createCalendar(defaultTimeZone(aLocale), aLocale);
}
/**
@ -1655,6 +1675,16 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
return createCalendar(zone, aLocale);
}
private static TimeZone defaultTimeZone(Locale l) {
TimeZone defaultTZ = TimeZone.getDefault();
String shortTZID = l.getUnicodeLocaleType("tz");
return shortTZID != null ?
TimeZoneNameUtility.convertLDMLShortID(shortTZID)
.map(TimeZone::getTimeZone)
.orElse(defaultTZ) :
defaultTZ;
}
private static Calendar createCalendar(TimeZone zone,
Locale aLocale)
{

View File

@ -24,9 +24,10 @@
*/
package java.util;
import java.io.Serializable;
import java.io.ObjectOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
@ -5164,14 +5165,19 @@ public class Collections {
* specified comparator.
* @since 1.5
*/
@SuppressWarnings("unchecked")
public static <T> Comparator<T> reverseOrder(Comparator<T> cmp) {
if (cmp == null)
return reverseOrder();
if (cmp instanceof ReverseComparator2)
return ((ReverseComparator2<T>)cmp).cmp;
return new ReverseComparator2<>(cmp);
if (cmp == null) {
return (Comparator<T>) ReverseComparator.REVERSE_ORDER;
} else if (cmp == ReverseComparator.REVERSE_ORDER) {
return (Comparator<T>) Comparators.NaturalOrderComparator.INSTANCE;
} else if (cmp == Comparators.NaturalOrderComparator.INSTANCE) {
return (Comparator<T>) ReverseComparator.REVERSE_ORDER;
} else if (cmp instanceof ReverseComparator2) {
return ((ReverseComparator2<T>) cmp).cmp;
} else {
return new ReverseComparator2<>(cmp);
}
}
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -28,7 +28,6 @@ package java.util;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.InputStream;
import java.io.IOException;
@ -42,6 +41,7 @@ import java.util.concurrent.ConcurrentMap;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.spi.CurrencyNameProvider;
import sun.util.locale.provider.CalendarDataUtility;
import sun.util.locale.provider.LocaleServiceProviderPool;
import sun.util.logging.PlatformLogger;
@ -348,6 +348,13 @@ public final class Currency implements Serializable {
* until December 31, 2001, and the Euro from January 1, 2002, local time
* of the respective countries.
* <p>
* If the specified {@code locale} contains "cu" and/or "rg"
* <a href="./Locale.html#def_locale_extension">Unicode extensions</a>,
* the instance returned from this method reflects
* the values specified with those extensions. If both "cu" and "rg" are
* specified, the currency from the "cu" extension supersedes the implicit one
* from the "rg" extension.
* <p>
* The method returns <code>null</code> for territories that don't
* have a currency, such as Antarctica.
*
@ -361,12 +368,19 @@ public final class Currency implements Serializable {
* is not a supported ISO 3166 country code.
*/
public static Currency getInstance(Locale locale) {
String country = locale.getCountry();
if (country == null) {
throw new NullPointerException();
// check for locale overrides
String override = locale.getUnicodeLocaleType("cu");
if (override != null) {
try {
return getInstance(override.toUpperCase(Locale.ROOT));
} catch (IllegalArgumentException iae) {
// override currency is invalid. Fall through.
}
}
if (country.length() != 2) {
String country = CalendarDataUtility.findRegionOverride(locale).getCountry();
if (country == null || !country.matches("^[a-zA-Z]{2}$")) {
throw new IllegalArgumentException();
}
@ -482,6 +496,12 @@ public final class Currency implements Serializable {
* locale is the US, while for other locales it may be "US$". If no
* symbol can be determined, the ISO 4217 currency code is returned.
* <p>
* If the default {@link Locale.Category#DISPLAY DISPLAY} locale
* contains "rg" (region override)
* <a href="./Locale.html#def_locale_extension">Unicode extension</a>,
* the symbol returned from this method reflects
* the value specified with that extension.
* <p>
* This is equivalent to calling
* {@link #getSymbol(Locale)
* getSymbol(Locale.getDefault(Locale.Category.DISPLAY))}.
@ -498,6 +518,11 @@ public final class Currency implements Serializable {
* For example, for the US Dollar, the symbol is "$" if the specified
* locale is the US, while for other locales it may be "US$". If no
* symbol can be determined, the ISO 4217 currency code is returned.
* <p>
* If the specified {@code locale} contains "rg" (region override)
* <a href="./Locale.html#def_locale_extension">Unicode extension</a>,
* the symbol returned from this method reflects
* the value specified with that extension.
*
* @param locale the locale for which a display name for this currency is
* needed
@ -507,6 +532,7 @@ public final class Currency implements Serializable {
public String getSymbol(Locale locale) {
LocaleServiceProviderPool pool =
LocaleServiceProviderPool.getPool(CurrencyNameProvider.class);
locale = CalendarDataUtility.findRegionOverride(locale);
String symbol = pool.getLocalizedObject(
CurrencyNameGetter.INSTANCE,
locale, currencyCode, SYMBOL);

View File

@ -2136,6 +2136,39 @@ public final class Formatter implements Closeable, Flushable {
this(toCharset(csn), l, new File(fileName));
}
/**
* Constructs a new formatter with the specified file name, charset, and
* locale.
*
* @param fileName
* The name of the file to use as the destination of this
* formatter. If the file exists then it will be truncated to
* zero size; otherwise, a new file will be created. The output
* will be written to the file and is buffered.
*
* @param charset
* A {@linkplain java.nio.charset.Charset charset}
*
* @param l
* The {@linkplain java.util.Locale locale} to apply during
* formatting. If {@code l} is {@code null} then no localization
* is applied.
*
* @throws IOException
* if an I/O error occurs while opening or creating the file
*
* @throws SecurityException
* If a security manager is present and {@link
* SecurityManager#checkWrite checkWrite(fileName)} denies write
* access to the file
*
* @throws NullPointerException
* if {@code fileName} or {@code charset} is {@code null}.
*/
public Formatter(String fileName, Charset charset, Locale l) throws IOException {
this(Objects.requireNonNull(charset, "charset"), l, new File(fileName));
}
/**
* Constructs a new formatter with the specified file.
*
@ -2247,6 +2280,40 @@ public final class Formatter implements Closeable, Flushable {
this(toCharset(csn), l, file);
}
/**
* Constructs a new formatter with the specified file, charset, and
* locale.
*
* @param file
* The file to use as the destination of this formatter. If the
* file exists then it will be truncated to zero size; otherwise,
* a new file will be created. The output will be written to the
* file and is buffered.
*
* @param charset
* A {@linkplain java.nio.charset.Charset charset}
*
* @param l
* The {@linkplain java.util.Locale locale} to apply during
* formatting. If {@code l} is {@code null} then no localization
* is applied.
*
* @throws IOException
* if an I/O error occurs while opening or creating the file
*
* @throws SecurityException
* If a security manager is present and {@link
* SecurityManager#checkWrite checkWrite(file.getPath())} denies
* write access to the file
*
* @throws NullPointerException
* if {@code file} or {@code charset} is {@code null}.
*/
public Formatter(File file, Charset charset, Locale l) throws IOException {
this(Objects.requireNonNull(charset, "charset"), l, file);
}
/**
* Constructs a new formatter with the specified print stream.
*
@ -2340,6 +2407,29 @@ public final class Formatter implements Closeable, Flushable {
this(l, new BufferedWriter(new OutputStreamWriter(os, csn)));
}
/**
* Constructs a new formatter with the specified output stream, charset,
* and locale.
*
* @param os
* The output stream to use as the destination of this formatter.
* The output will be buffered.
*
* @param charset
* A {@linkplain java.nio.charset.Charset charset}
*
* @param l
* The {@linkplain java.util.Locale locale} to apply during
* formatting. If {@code l} is {@code null} then no localization
* is applied.
*
* @throws NullPointerException
* if {@code os} or {@code charset} is {@code null}.
*/
public Formatter(OutputStream os, Charset charset, Locale l) {
this(l, new BufferedWriter(new OutputStreamWriter(os, charset)));
}
private static char getZero(Locale l) {
if ((l != null) && !l.equals(Locale.US)) {
DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l);

View File

@ -48,6 +48,7 @@ import java.io.Serializable;
import java.text.MessageFormat;
import java.util.concurrent.ConcurrentHashMap;
import java.util.spi.LocaleNameProvider;
import java.util.stream.Collectors;
import sun.security.action.GetPropertyAction;
import sun.util.locale.BaseLocale;
@ -62,6 +63,7 @@ import sun.util.locale.ParseStatus;
import sun.util.locale.provider.LocaleProviderAdapter;
import sun.util.locale.provider.LocaleResources;
import sun.util.locale.provider.LocaleServiceProviderPool;
import sun.util.locale.provider.TimeZoneNameUtility;
/**
* A <code>Locale</code> object represents a specific geographical, political,
@ -665,10 +667,12 @@ public final class Locale implements Cloneable, Serializable {
/**
* Display types for retrieving localized names from the name providers.
*/
private static final int DISPLAY_LANGUAGE = 0;
private static final int DISPLAY_COUNTRY = 1;
private static final int DISPLAY_VARIANT = 2;
private static final int DISPLAY_SCRIPT = 3;
private static final int DISPLAY_LANGUAGE = 0;
private static final int DISPLAY_COUNTRY = 1;
private static final int DISPLAY_VARIANT = 2;
private static final int DISPLAY_SCRIPT = 3;
private static final int DISPLAY_UEXT_KEY = 4;
private static final int DISPLAY_UEXT_TYPE = 5;
/**
* Private constructor used by getInstance method
@ -942,11 +946,14 @@ public final class Locale implements Cloneable, Serializable {
variant = props.getProperty("user.variant", "");
}
return getInstance(language, script, country, variant, null);
return getInstance(language, script, country, variant,
getDefaultExtensions(props.getProperty("user.extensions", ""))
.orElse(null));
}
private static Locale initDefault(Locale.Category category) {
Properties props = GetPropertyAction.privilegedGetProperties();
return getInstance(
props.getProperty(category.languageKey,
defaultLocale.getLanguage()),
@ -956,7 +963,22 @@ public final class Locale implements Cloneable, Serializable {
defaultLocale.getCountry()),
props.getProperty(category.variantKey,
defaultLocale.getVariant()),
null);
getDefaultExtensions(props.getProperty(category.extensionsKey, ""))
.orElse(defaultLocale.getLocaleExtensions()));
}
private static Optional<LocaleExtensions> getDefaultExtensions(String extensionsProp) {
LocaleExtensions exts = null;
try {
exts = new InternalLocaleBuilder()
.setExtensions(extensionsProp)
.getLocaleExtensions();
} catch (LocaleSyntaxException e) {
// just ignore this incorrect property
}
return Optional.ofNullable(exts);
}
/**
@ -1771,7 +1793,7 @@ public final class Locale implements Cloneable, Serializable {
* @exception NullPointerException if <code>inLocale</code> is <code>null</code>
*/
public String getDisplayLanguage(Locale inLocale) {
return getDisplayString(baseLocale.getLanguage(), inLocale, DISPLAY_LANGUAGE);
return getDisplayString(baseLocale.getLanguage(), null, inLocale, DISPLAY_LANGUAGE);
}
/**
@ -1801,7 +1823,7 @@ public final class Locale implements Cloneable, Serializable {
* @since 1.7
*/
public String getDisplayScript(Locale inLocale) {
return getDisplayString(baseLocale.getScript(), inLocale, DISPLAY_SCRIPT);
return getDisplayString(baseLocale.getScript(), null, inLocale, DISPLAY_SCRIPT);
}
/**
@ -1844,29 +1866,24 @@ public final class Locale implements Cloneable, Serializable {
* @exception NullPointerException if <code>inLocale</code> is <code>null</code>
*/
public String getDisplayCountry(Locale inLocale) {
return getDisplayString(baseLocale.getRegion(), inLocale, DISPLAY_COUNTRY);
return getDisplayString(baseLocale.getRegion(), null, inLocale, DISPLAY_COUNTRY);
}
private String getDisplayString(String code, Locale inLocale, int type) {
if (code.length() == 0) {
return "";
}
private String getDisplayString(String code, String cat, Locale inLocale, int type) {
Objects.requireNonNull(inLocale);
Objects.requireNonNull(code);
if (inLocale == null) {
throw new NullPointerException();
if (code.isEmpty()) {
return "";
}
LocaleServiceProviderPool pool =
LocaleServiceProviderPool.getPool(LocaleNameProvider.class);
String key = (type == DISPLAY_VARIANT ? "%%"+code : code);
String rbKey = (type == DISPLAY_VARIANT ? "%%"+code : code);
String result = pool.getLocalizedObject(
LocaleNameGetter.INSTANCE,
inLocale, key, type, code);
if (result != null) {
return result;
}
return code;
inLocale, rbKey, type, code, cat);
return result != null ? result : code;
}
/**
@ -1894,29 +1911,31 @@ public final class Locale implements Cloneable, Serializable {
if (baseLocale.getVariant().length() == 0)
return "";
LocaleResources lr = LocaleProviderAdapter.forJRE().getLocaleResources(inLocale);
LocaleResources lr = LocaleProviderAdapter
.getResourceBundleBased()
.getLocaleResources(inLocale);
String names[] = getDisplayVariantArray(inLocale);
// Get the localized patterns for formatting a list, and use
// them to format the list.
return formatList(names,
lr.getLocaleName("ListPattern"),
lr.getLocaleName("ListCompositionPattern"));
}
/**
* Returns a name for the locale that is appropriate for display to the
* user. This will be the values returned by getDisplayLanguage(),
* getDisplayScript(), getDisplayCountry(), and getDisplayVariant() assembled
* into a single string. The non-empty values are used in order,
* with the second and subsequent names in parentheses. For example:
* getDisplayScript(), getDisplayCountry(), getDisplayVariant() and
* optional <a href="./Locale.html#def_locale_extension">Unicode extensions</a>
* assembled into a single string. The non-empty values are used in order, with
* the second and subsequent names in parentheses. For example:
* <blockquote>
* language (script, country, variant)<br>
* language (country)<br>
* language (variant)<br>
* script (country)<br>
* country<br>
* language (script, country, variant(, extension)*)<br>
* language (country(, extension)*)<br>
* language (variant(, extension)*)<br>
* script (country(, extension)*)<br>
* country (extension)*<br>
* </blockquote>
* depending on which fields are specified in the locale. If the
* language, script, country, and variant fields are all empty,
@ -1931,16 +1950,17 @@ public final class Locale implements Cloneable, Serializable {
/**
* Returns a name for the locale that is appropriate for display
* to the user. This will be the values returned by
* getDisplayLanguage(), getDisplayScript(),getDisplayCountry(),
* and getDisplayVariant() assembled into a single string.
* The non-empty values are used in order,
* with the second and subsequent names in parentheses. For example:
* getDisplayLanguage(), getDisplayScript(),getDisplayCountry()
* getDisplayVariant(), and optional <a href="./Locale.html#def_locale_extension">
* Unicode extensions</a> assembled into a single string. The non-empty
* values are used in order, with the second and subsequent names in
* parentheses. For example:
* <blockquote>
* language (script, country, variant)<br>
* language (country)<br>
* language (variant)<br>
* script (country)<br>
* country<br>
* language (script, country, variant(, extension)*)<br>
* language (country(, extension)*)<br>
* language (variant(, extension)*)<br>
* script (country(, extension)*)<br>
* country (extension)*<br>
* </blockquote>
* depending on which fields are specified in the locale. If the
* language, script, country, and variant fields are all empty,
@ -1951,7 +1971,9 @@ public final class Locale implements Cloneable, Serializable {
* @throws NullPointerException if <code>inLocale</code> is <code>null</code>
*/
public String getDisplayName(Locale inLocale) {
LocaleResources lr = LocaleProviderAdapter.forJRE().getLocaleResources(inLocale);
LocaleResources lr = LocaleProviderAdapter
.getResourceBundleBased()
.getLocaleResources(inLocale);
String languageName = getDisplayLanguage(inLocale);
String scriptName = getDisplayScript(inLocale);
@ -1960,7 +1982,6 @@ public final class Locale implements Cloneable, Serializable {
// Get the localized patterns for formatting a display name.
String displayNamePattern = lr.getLocaleName("DisplayNamePattern");
String listPattern = lr.getLocaleName("ListPattern");
String listCompositionPattern = lr.getLocaleName("ListCompositionPattern");
// The display name consists of a main name, followed by qualifiers.
@ -1977,7 +1998,7 @@ public final class Locale implements Cloneable, Serializable {
if (variantNames.length == 0) {
return "";
} else {
return formatList(variantNames, listPattern, listCompositionPattern);
return formatList(variantNames, listCompositionPattern);
}
}
ArrayList<String> names = new ArrayList<>(4);
@ -1994,6 +2015,16 @@ public final class Locale implements Cloneable, Serializable {
names.addAll(Arrays.asList(variantNames));
}
// add Unicode extensions
if (localeExtensions != null) {
localeExtensions.getUnicodeLocaleAttributes().stream()
.map(key -> getDisplayString(key, null, inLocale, DISPLAY_UEXT_KEY))
.forEach(names::add);
localeExtensions.getUnicodeLocaleKeys().stream()
.map(key -> getDisplayKeyTypeExtensionString(key, lr, inLocale))
.forEach(names::add);
}
// The first one in the main name
mainName = names.get(0);
@ -2014,7 +2045,7 @@ public final class Locale implements Cloneable, Serializable {
// list case, but this is more efficient, and we want it to be
// efficient since all the language-only locales will not have any
// qualifiers.
qualifierNames.length != 0 ? formatList(qualifierNames, listPattern, listCompositionPattern) : null
qualifierNames.length != 0 ? formatList(qualifierNames, listCompositionPattern) : null
};
if (displayNamePattern != null) {
@ -2121,74 +2152,78 @@ public final class Locale implements Cloneable, Serializable {
// For each variant token, lookup the display name. If
// not found, use the variant name itself.
for (int i=0; i<names.length; ++i) {
names[i] = getDisplayString(tokenizer.nextToken(),
names[i] = getDisplayString(tokenizer.nextToken(), null,
inLocale, DISPLAY_VARIANT);
}
return names;
}
private String getDisplayKeyTypeExtensionString(String key, LocaleResources lr, Locale inLocale) {
String type = localeExtensions.getUnicodeLocaleType(key);
String ret = getDisplayString(type, key, inLocale, DISPLAY_UEXT_TYPE);
if (ret == null || ret.equals(type)) {
// no localization for this type. try combining key/type separately
String displayType = type;
switch (key) {
case "cu":
displayType = lr.getCurrencyName(type.toLowerCase(Locale.ROOT));
break;
case "rg":
if (type != null &&
// UN M.49 code should not be allowed here
type.matches("^[a-zA-Z]{2}[zZ]{4}$")) {
displayType = lr.getLocaleName(type.substring(0, 2).toUpperCase(Locale.ROOT));
}
break;
case "tz":
displayType = TimeZoneNameUtility.retrieveGenericDisplayName(
TimeZoneNameUtility.convertLDMLShortID(type).orElse(type),
TimeZone.LONG, inLocale);
break;
}
ret = MessageFormat.format(lr.getLocaleName("ListKeyTypePattern"),
getDisplayString(key, null, inLocale, DISPLAY_UEXT_KEY),
Optional.ofNullable(displayType).orElse(type));
}
return ret;
}
/**
* Format a list using given pattern strings.
* If either of the patterns is null, then a the list is
* formatted by concatenation with the delimiter ','.
* @param stringList the list of strings to be formatted.
* @param listPattern should create a MessageFormat taking 0-3 arguments
* and formatting them into a list.
* @param listCompositionPattern should take 2 arguments
* and is used by composeList.
* @param pattern should take 2 arguments for reduction
* @return a string representing the list.
*/
private static String formatList(String[] stringList, String listPattern, String listCompositionPattern) {
private static String formatList(String[] stringList, String pattern) {
// If we have no list patterns, compose the list in a simple,
// non-localized way.
if (listPattern == null || listCompositionPattern == null) {
StringJoiner sj = new StringJoiner(",");
for (int i = 0; i < stringList.length; ++i) {
sj.add(stringList[i]);
}
return sj.toString();
if (pattern == null) {
return Arrays.stream(stringList).collect(Collectors.joining(","));
}
// Compose the list down to three elements if necessary
if (stringList.length > 3) {
MessageFormat format = new MessageFormat(listCompositionPattern);
stringList = composeList(format, stringList);
switch (stringList.length) {
case 0:
return "";
case 1:
return stringList[0];
default:
return Arrays.stream(stringList).reduce("",
(s1, s2) -> {
if (s1.equals("")) {
return s2;
}
if (s2.equals("")) {
return s1;
}
return MessageFormat.format(pattern, s1, s2);
});
}
// Rebuild the argument list with the list length as the first element
Object[] args = new Object[stringList.length + 1];
System.arraycopy(stringList, 0, args, 1, stringList.length);
args[0] = stringList.length;
// Format it using the pattern in the resource
MessageFormat format = new MessageFormat(listPattern);
return format.format(args);
}
/**
* Given a list of strings, return a list shortened to three elements.
* Shorten it by applying the given format to the first two elements
* recursively.
* @param format a format which takes two arguments
* @param list a list of strings
* @return if the list is three elements or shorter, the same list;
* otherwise, a new list of three elements.
*/
private static String[] composeList(MessageFormat format, String[] list) {
if (list.length <= 3) return list;
// Use the given format to compose the first two elements into one
String[] listItems = { list[0], list[1] };
String newItem = format.format(listItems);
// Form a new list one element shorter
String[] newList = new String[list.length-1];
System.arraycopy(list, 2, newList, 1, newList.length-1);
newList[0] = newItem;
// Recurse
return composeList(format, newList);
}
// Duplicate of sun.util.locale.UnicodeLocaleExtension.isKey in order to
@ -2345,9 +2380,10 @@ public final class Locale implements Cloneable, Serializable {
Locale locale,
String key,
Object... params) {
assert params.length == 2;
assert params.length == 3;
int type = (Integer)params[0];
String code = (String)params[1];
String cat = (String)params[2];
switch(type) {
case DISPLAY_LANGUAGE:
@ -2358,6 +2394,10 @@ public final class Locale implements Cloneable, Serializable {
return localeNameProvider.getDisplayVariant(code, locale);
case DISPLAY_SCRIPT:
return localeNameProvider.getDisplayScript(code, locale);
case DISPLAY_UEXT_KEY:
return localeNameProvider.getDisplayUnicodeExtensionKey(code, locale);
case DISPLAY_UEXT_TYPE:
return localeNameProvider.getDisplayUnicodeExtensionType(code, cat, locale);
default:
assert false; // shouldn't happen
}
@ -2384,7 +2424,8 @@ public final class Locale implements Cloneable, Serializable {
DISPLAY("user.language.display",
"user.script.display",
"user.country.display",
"user.variant.display"),
"user.variant.display",
"user.extensions.display"),
/**
* Category used to represent the default locale for
@ -2393,19 +2434,23 @@ public final class Locale implements Cloneable, Serializable {
FORMAT("user.language.format",
"user.script.format",
"user.country.format",
"user.variant.format");
"user.variant.format",
"user.extensions.format");
Category(String languageKey, String scriptKey, String countryKey, String variantKey) {
Category(String languageKey, String scriptKey, String countryKey,
String variantKey, String extensionsKey) {
this.languageKey = languageKey;
this.scriptKey = scriptKey;
this.countryKey = countryKey;
this.variantKey = variantKey;
this.extensionsKey = extensionsKey;
}
final String languageKey;
final String scriptKey;
final String countryKey;
final String variantKey;
final String extensionsKey;
}
/**

View File

@ -37,6 +37,10 @@ import java.io.BufferedWriter;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.StreamCorruptedException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
@ -997,6 +1001,11 @@ class Properties extends Hashtable<Object,Object> {
*
* <p>The specified stream remains open after this method returns.
*
* <p>This method behaves the same as
* {@linkplain #storeToXML(OutputStream os, String comment, Charset charset)}
* except that it will {@linkplain java.nio.charset.Charset#forName look up the charset}
* using the given encoding name.
*
* @param os the output stream on which to emit the XML document.
* @param comment a description of the property list, or {@code null}
* if no comment is desired.
@ -1011,20 +1020,67 @@ class Properties extends Hashtable<Object,Object> {
* @throws NullPointerException if {@code os} is {@code null},
* or if {@code encoding} is {@code null}.
* @throws ClassCastException if this {@code Properties} object
* contains any keys or values that are not
* {@code Strings}.
* contains any keys or values that are not {@code Strings}.
* @see #loadFromXML(InputStream)
* @see <a href="http://www.w3.org/TR/REC-xml/#charencoding">Character
* Encoding in Entities</a>
* @since 1.5
*/
public void storeToXML(OutputStream os, String comment, String encoding)
throws IOException
{
throws IOException {
Objects.requireNonNull(os);
Objects.requireNonNull(encoding);
try {
Charset charset = Charset.forName(encoding);
storeToXML(os, comment, charset);
} catch (IllegalCharsetNameException | UnsupportedCharsetException e) {
throw new UnsupportedEncodingException(encoding);
}
}
/**
* Emits an XML document representing all of the properties contained
* in this table, using the specified encoding.
*
* <p>The XML document will have the following DOCTYPE declaration:
* <pre>
* &lt;!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"&gt;
* </pre>
*
* <p>If the specified comment is {@code null} then no comment
* will be stored in the document.
*
* <p> An implementation is required to support writing of XML documents
* that use the "{@code UTF-8}" or "{@code UTF-16}" encoding. An
* implementation may support additional encodings.
*
* <p> Unmappable characters for the specified charset will be encoded as
* numeric character references.
*
* <p>The specified stream remains open after this method returns.
*
* @param os the output stream on which to emit the XML document.
* @param comment a description of the property list, or {@code null}
* if no comment is desired.
* @param charset the charset
*
* @throws IOException if writing to the specified output stream
* results in an {@code IOException}.
* @throws NullPointerException if {@code os} or {@code charset} is {@code null}.
* @throws ClassCastException if this {@code Properties} object
* contains any keys or values that are not {@code Strings}.
* @see #loadFromXML(InputStream)
* @see <a href="http://www.w3.org/TR/REC-xml/#charencoding">Character
* Encoding in Entities</a>
* @since 10
*/
public void storeToXML(OutputStream os, String comment, Charset charset)
throws IOException {
Objects.requireNonNull(os, "OutputStream");
Objects.requireNonNull(charset, "Charset");
PropertiesDefaultHandler handler = new PropertiesDefaultHandler();
handler.store(this, os, comment, encoding);
handler.store(this, os, comment, charset);
}
/**

View File

@ -33,10 +33,13 @@ import java.nio.charset.*;
import java.nio.file.Path;
import java.nio.file.Files;
import java.text.*;
import java.text.spi.NumberFormatProvider;
import java.util.function.Consumer;
import java.util.regex.*;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import sun.util.locale.provider.LocaleProviderAdapter;
import sun.util.locale.provider.ResourceBundleBasedAdapter;
/**
* A simple text scanner which can parse primitive types and strings using
@ -575,7 +578,21 @@ public final class Scanner implements Iterator<String>, Closeable {
* does not exist
*/
public Scanner(InputStream source, String charsetName) {
this(makeReadable(Objects.requireNonNull(source, "source"), toCharset(charsetName)),
this(source, toCharset(charsetName));
}
/**
* Constructs a new {@code Scanner} that produces values scanned
* from the specified input stream. Bytes from the stream are converted
* into characters using the specified charset.
*
* @param source an input stream to be scanned
* @param charset the charset used to convert bytes from the file
* into characters to be scanned
* @since 10
*/
public Scanner(InputStream source, Charset charset) {
this(makeReadable(Objects.requireNonNull(source, "source"), charset),
WHITESPACE_PATTERN);
}
@ -594,7 +611,18 @@ public final class Scanner implements Iterator<String>, Closeable {
}
}
/*
* This method is added so that null-check on charset can be performed before
* creating InputStream as an existing test required it.
*/
private static Readable makeReadable(Path source, Charset charset)
throws IOException {
Objects.requireNonNull(charset, "charset");
return makeReadable(Files.newInputStream(source), charset);
}
private static Readable makeReadable(InputStream source, Charset charset) {
Objects.requireNonNull(charset, "charset");
return new InputStreamReader(source, charset);
}
@ -629,6 +657,22 @@ public final class Scanner implements Iterator<String>, Closeable {
this(Objects.requireNonNull(source), toDecoder(charsetName));
}
/**
* Constructs a new {@code Scanner} that produces values scanned
* from the specified file. Bytes from the file are converted into
* characters using the specified charset.
*
* @param source A file to be scanned
* @param charset The charset used to convert bytes from the file
* into characters to be scanned
* @throws IOException
* if an I/O error occurs opening the source
* @since 10
*/
public Scanner(File source, Charset charset) throws IOException {
this(Objects.requireNonNull(source), charset.newDecoder());
}
private Scanner(File source, CharsetDecoder dec)
throws FileNotFoundException
{
@ -649,6 +693,12 @@ public final class Scanner implements Iterator<String>, Closeable {
return Channels.newReader(source, dec, -1);
}
private static Readable makeReadable(ReadableByteChannel source,
Charset charset) {
Objects.requireNonNull(charset, "charset");
return Channels.newReader(source, charset);
}
/**
* Constructs a new {@code Scanner} that produces values scanned
* from the specified file. Bytes from the file are converted into
@ -688,8 +738,22 @@ public final class Scanner implements Iterator<String>, Closeable {
this(Objects.requireNonNull(source), toCharset(charsetName));
}
private Scanner(Path source, Charset charset) throws IOException {
this(makeReadable(Files.newInputStream(source), charset));
/**
* Constructs a new {@code Scanner} that produces values scanned
* from the specified file. Bytes from the file are converted into
* characters using the specified charset.
*
* @param source
* the path to the file to be scanned
* @param charset
* the charset used to convert bytes from the file
* into characters to be scanned
* @throws IOException
* if an I/O error occurs opening the source
* @since 10
*/
public Scanner(Path source, Charset charset) throws IOException {
this(makeReadable(source, charset));
}
/**
@ -735,6 +799,21 @@ public final class Scanner implements Iterator<String>, Closeable {
WHITESPACE_PATTERN);
}
/**
* Constructs a new {@code Scanner} that produces values scanned
* from the specified channel. Bytes from the source are converted into
* characters using the specified charset.
*
* @param source a channel to scan
* @param charset the encoding type used to convert bytes from the
* channel into characters to be scanned
* @since 10
*/
public Scanner(ReadableByteChannel source, Charset charset) {
this(makeReadable(Objects.requireNonNull(source, "source"), charset),
WHITESPACE_PATTERN);
}
// Private primitives used to support scanning
private void saveState() {
@ -1186,9 +1265,27 @@ public final class Scanner implements Iterator<String>, Closeable {
modCount++;
this.locale = locale;
DecimalFormat df =
(DecimalFormat)NumberFormat.getNumberInstance(locale);
DecimalFormat df = null;
NumberFormat nf = NumberFormat.getNumberInstance(locale);
DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(locale);
if (nf instanceof DecimalFormat) {
df = (DecimalFormat) nf;
} else {
// In case where NumberFormat.getNumberInstance() returns
// other instance (non DecimalFormat) based on the provider
// used and java.text.spi.NumberFormatProvider implementations,
// DecimalFormat constructor is used to obtain the instance
LocaleProviderAdapter adapter = LocaleProviderAdapter
.getAdapter(NumberFormatProvider.class, locale);
if (!(adapter instanceof ResourceBundleBasedAdapter)) {
adapter = LocaleProviderAdapter.getResourceBundleBased();
}
String[] all = adapter.getLocaleResources(locale)
.getNumberPatterns();
df = new DecimalFormat(all[0], dfs);
}
// These must be literalized to avoid collision with regex
// metacharacters such as dot or parenthesis

View File

@ -548,12 +548,11 @@ public class SimpleTimeZone extends TimeZone {
computeOffset:
if (useDaylight) {
synchronized (this) {
if (cacheStart != 0) {
if (date >= cacheStart && date < cacheEnd) {
offset += dstSavings;
break computeOffset;
}
Cache cache = this.cache;
if (cache != null) {
if (date >= cache.start && date < cache.end) {
offset += dstSavings;
break computeOffset;
}
}
BaseCalendar cal = date >= GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER ?
@ -671,14 +670,13 @@ public class SimpleTimeZone extends TimeZone {
}
private int getOffset(BaseCalendar cal, BaseCalendar.Date cdate, int year, long time) {
synchronized (this) {
if (cacheStart != 0) {
if (time >= cacheStart && time < cacheEnd) {
return rawOffset + dstSavings;
}
if (year == cacheYear) {
return rawOffset;
}
Cache cache = this.cache;
if (cache != null) {
if (time >= cache.start && time < cache.end) {
return rawOffset + dstSavings;
}
if (year == cache.year) {
return rawOffset;
}
}
@ -689,11 +687,7 @@ public class SimpleTimeZone extends TimeZone {
if (time >= start && time < end) {
offset += dstSavings;
}
synchronized (this) {
cacheYear = year;
cacheStart = start;
cacheEnd = end;
}
this.cache = new Cache(year, start, end);
} else {
if (time < end) {
// TODO: support Gregorian cutover. The previous year
@ -711,12 +705,7 @@ public class SimpleTimeZone extends TimeZone {
}
}
if (start <= end) {
synchronized (this) {
// The start and end transitions are in multiple years.
cacheYear = (long) startYear - 1;
cacheStart = start;
cacheEnd = end;
}
this.cache = new Cache((long) startYear - 1, start, end);
}
}
return offset;
@ -876,7 +865,7 @@ public class SimpleTimeZone extends TimeZone {
* Generates the hash code for the SimpleDateFormat object.
* @return the hash code for this object
*/
public synchronized int hashCode()
public int hashCode()
{
return startMonth ^ startDay ^ startDayOfWeek ^ startTime ^
endMonth ^ endDay ^ endDayOfWeek ^ endTime ^ rawOffset;
@ -1201,19 +1190,27 @@ public class SimpleTimeZone extends TimeZone {
/**
* Cache values representing a single period of daylight saving
* time. When the cache values are valid, cacheStart is the start
* time (inclusive) of daylight saving time and cacheEnd is the
* end time (exclusive).
* time. Cache.start is the start time (inclusive) of daylight
* saving time and Cache.end is the end time (exclusive).
*
* cacheYear has a year value if both cacheStart and cacheEnd are
* in the same year. cacheYear is set to startYear - 1 if
* cacheStart and cacheEnd are in different years. cacheStart is 0
* if the cache values are void. cacheYear is a long to support
* Integer.MIN_VALUE - 1 (JCK requirement).
* Cache.year has a year value if both Cache.start and Cache.end are
* in the same year. Cache.year is set to startYear - 1 if
* Cache.start and Cache.end are in different years.
* Cache.year is a long to support Integer.MIN_VALUE - 1 (JCK requirement).
*/
private transient long cacheYear;
private transient long cacheStart;
private transient long cacheEnd;
private static final class Cache {
final long year;
final long start;
final long end;
Cache(long year, long start, long end) {
this.year = year;
this.start = start;
this.end = end;
}
}
private transient volatile Cache cache;
/**
* Constants specifying values of startMode and endMode.
@ -1282,9 +1279,8 @@ public class SimpleTimeZone extends TimeZone {
// Maximum number of rules.
private static final int MAX_RULE_NUM = 6;
private synchronized void invalidateCache() {
cacheYear = startYear - 1;
cacheStart = cacheEnd = 0;
private void invalidateCache() {
cache = null;
}
//----------------------------------------------------------------------

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -26,6 +26,7 @@
package java.util.spi;
import java.util.Locale;
import java.util.Objects;
/**
* An abstract class for service providers that
@ -141,4 +142,54 @@ public abstract class LocaleNameProvider extends LocaleServiceProvider {
* @see java.util.Locale#getDisplayVariant(java.util.Locale)
*/
public abstract String getDisplayVariant(String variant, Locale locale);
/**
* Returns a localized name for the given
* <a href="../Locale.html#def_locale_extension">Unicode extension</a> key,
* and the given locale that is appropriate for display to the user.
* If the name returned cannot be localized according to {@code locale},
* this method returns null.
* @implSpec the default implementation returns {@code null}.
* @param key the Unicode Extension key, not null.
* @param locale the desired locale, not null.
* @return the name of the given key string for the specified locale,
* or null if it's not available.
* @exception NullPointerException if {@code key} or {@code locale} is null
* @exception IllegalArgumentException if {@code locale} isn't
* one of the locales returned from
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
* getAvailableLocales()}.
* @since 10
*/
public String getDisplayUnicodeExtensionKey(String key, Locale locale) {
Objects.requireNonNull(key);
Objects.requireNonNull(locale);
return null;
}
/**
* Returns a localized name for the given
* <a href="../Locale.html#def_locale_extension">Unicode extension</a> type,
* and the given locale that is appropriate for display to the user.
* If the name returned cannot be localized according to {@code locale},
* this method returns null.
* @implSpec the default implementation returns {@code null}.
* @param type the Unicode Extension type, not null.
* @param key the Unicode Extension key for this {@code type}, not null.
* @param locale the desired locale, not null.
* @return the name of the given type string for the specified locale,
* or null if it's not available.
* @exception NullPointerException if {@code key}, {@code type} or {@code locale} is null
* @exception IllegalArgumentException if {@code locale} isn't
* one of the locales returned from
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
* getAvailableLocales()}.
* @since 10
*/
public String getDisplayUnicodeExtensionType(String type, String key, Locale locale) {
Objects.requireNonNull(type);
Objects.requireNonNull(key);
Objects.requireNonNull(locale);
return null;
}
}

View File

@ -67,12 +67,26 @@ package java.util.zip;
* }
* </pre></blockquote>
*
* @apiNote
* To release resources used by this {@code Deflater}, the {@link #end()} method
* should be called explicitly. Subclasses are responsible for the cleanup of resources
* acquired by the subclass. Subclasses that override {@link #finalize()} in order
* to perform cleanup should be modified to use alternative cleanup mechanisms such
* as {@link java.lang.ref.Cleaner} and remove the overriding {@code finalize} method.
*
* @implSpec
* If this {@code Deflater} has been subclassed and the {@code end} method has been
* overridden, the {@code end} method will be called by the finalization when the
* deflater is unreachable. But the subclasses should not depend on this specific
* implementation; the finalization is not reliable and the {@code finalize} method
* is deprecated to be removed.
*
* @see Inflater
* @author David Connelly
* @since 1.1
*/
public
class Deflater {
public class Deflater {
private final ZStreamRef zsRef;
private byte[] buf = new byte[0];
@ -169,7 +183,9 @@ class Deflater {
public Deflater(int level, boolean nowrap) {
this.level = level;
this.strategy = DEFAULT_STRATEGY;
this.zsRef = new ZStreamRef(init(level, DEFAULT_STRATEGY, nowrap));
this.zsRef = ZStreamRef.get(this,
() -> init(level, DEFAULT_STRATEGY, nowrap),
Deflater::end);
}
/**
@ -534,38 +550,32 @@ class Deflater {
/**
* Closes the compressor and discards any unprocessed input.
*
* This method should be called when the compressor is no longer
* being used, but will also be called automatically by the
* finalize() method. Once this method is called, the behavior
* of the Deflater object is undefined.
* being used. Once this method is called, the behavior of the
* Deflater object is undefined.
*/
public void end() {
synchronized (zsRef) {
long addr = zsRef.address();
zsRef.clear();
if (addr != 0) {
end(addr);
buf = null;
}
zsRef.clean();
buf = null;
}
}
/**
* Closes the compressor when garbage is collected.
*
* @deprecated The {@code finalize} method has been deprecated.
* Subclasses that override {@code finalize} in order to perform cleanup
* should be modified to use alternative cleanup mechanisms and
* to remove the overriding {@code finalize} method.
* When overriding the {@code finalize} method, its implementation must explicitly
* ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}.
* See the specification for {@link Object#finalize()} for further
* information about migration options.
* @deprecated The {@code finalize} method has been deprecated and will be
* removed. It is implemented as a no-op. Subclasses that override
* {@code finalize} in order to perform cleanup should be modified to use
* alternative cleanup mechanisms and to remove the overriding {@code finalize}
* method. The recommended cleanup for compressor is to explicitly call
* {@code end} method when it is no longer in use. If the {@code end} is
* not invoked explicitly the resource of the compressor will be released
* when the instance becomes unreachable.
*/
@Deprecated(since="9")
protected void finalize() {
end();
}
@Deprecated(since="9", forRemoval=true)
protected void finalize() {}
private void ensureOpen() {
assert Thread.holdsLock(zsRef);

View File

@ -66,13 +66,27 @@ package java.util.zip;
* }
* </pre></blockquote>
*
* @apiNote
* To release resources used by this {@code Inflater}, the {@link #end()} method
* should be called explicitly. Subclasses are responsible for the cleanup of resources
* acquired by the subclass. Subclasses that override {@link #finalize()} in order
* to perform cleanup should be modified to use alternative cleanup mechanisms such
* as {@link java.lang.ref.Cleaner} and remove the overriding {@code finalize} method.
*
* @implSpec
* If this {@code Inflater} has been subclassed and the {@code end} method has been
* overridden, the {@code end} method will be called by the finalization when the
* inflater is unreachable. But the subclasses should not depend on this specific
* implementation; the finalization is not reliable and the {@code finalize} method
* is deprecated to be removed.
*
* @see Deflater
* @author David Connelly
* @since 1.1
*
*/
public
class Inflater {
public class Inflater {
private final ZStreamRef zsRef;
private byte[] buf = defaultBuf;
@ -101,7 +115,7 @@ class Inflater {
* @param nowrap if true then support GZIP compatible compression
*/
public Inflater(boolean nowrap) {
zsRef = new ZStreamRef(init(nowrap));
this.zsRef = ZStreamRef.get(this, () -> init(nowrap), Inflater::end);
}
/**
@ -361,38 +375,37 @@ class Inflater {
/**
* Closes the decompressor and discards any unprocessed input.
*
* This method should be called when the decompressor is no longer
* being used, but will also be called automatically by the finalize()
* method. Once this method is called, the behavior of the Inflater
* object is undefined.
* being used. Once this method is called, the behavior of the
* Inflater object is undefined.
*/
public void end() {
synchronized (zsRef) {
long addr = zsRef.address();
zsRef.clear();
if (addr != 0) {
end(addr);
buf = null;
}
zsRef.clean();
buf = null;
}
}
/**
* Closes the decompressor when garbage is collected.
*
* @deprecated The {@code finalize} method has been deprecated.
* Subclasses that override {@code finalize} in order to perform cleanup
* should be modified to use alternative cleanup mechanisms and
* to remove the overriding {@code finalize} method.
* When overriding the {@code finalize} method, its implementation must explicitly
* ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}.
* See the specification for {@link Object#finalize()} for further
* information about migration options.
* @implSpec
* If this {@code Inflater} has been subclassed and the {@code end} method
* has been overridden, the {@code end} method will be called when the
* inflater is unreachable.
*
* @deprecated The {@code finalize} method has been deprecated and will be
* removed. It is implemented as a no-op. Subclasses that override
* {@code finalize} in order to perform cleanup should be modified to use
* alternative cleanup mechanisms and remove the overriding {@code finalize}
* method. The recommended cleanup for compressor is to explicitly call
* {@code end} method when it is no longer in use. If the {@code end} is
* not invoked explicitly the resource of the compressor will be released
* when the instance becomes unreachable,
*/
@Deprecated(since="9")
protected void finalize() {
end();
}
@Deprecated(since="9", forRemoval=true)
protected void finalize() {}
private void ensureOpen () {
assert Thread.holdsLock(zsRef);

View File

@ -25,22 +25,89 @@
package java.util.zip;
import java.util.function.LongConsumer;
import java.util.function.LongSupplier;
import java.lang.ref.Cleaner.Cleanable;
import jdk.internal.ref.CleanerFactory;
/**
* A reference to the native zlib's z_stream structure.
* A reference to the native zlib's z_stream structure. It also
* serves as the "cleaner" to clean up the native resource when
* the deflater or infalter is ended, closed or cleaned.
*/
class ZStreamRef implements Runnable {
class ZStreamRef {
private LongConsumer end;
private long address;
private final Cleanable cleanable;
private volatile long address;
ZStreamRef (long address) {
this.address = address;
private ZStreamRef (Object owner, LongSupplier addr, LongConsumer end) {
this.cleanable = CleanerFactory.cleaner().register(owner, this);
this.end = end;
this.address = addr.getAsLong();
}
long address() {
return address;
}
void clear() {
void clean() {
cleanable.clean();
}
public synchronized void run() {
long addr = address;
address = 0;
if (addr != 0) {
end.accept(addr);
}
}
private ZStreamRef (LongSupplier addr, LongConsumer end) {
this.cleanable = null;
this.end = end;
this.address = addr.getAsLong();
}
/*
* If {@code Inflater/Deflater} has been subclassed and the {@code end} method
* is overridden, uses {@code finalizer} mechanism for resource cleanup. So
* {@code end} method can be called when the {@code Inflater/Deflater} is
* unreachable. This mechanism will be removed when the {@code finalize} method
* is removed from {@code Inflater/Deflater}.
*/
static ZStreamRef get(Object owner, LongSupplier addr, LongConsumer end) {
Class<?> clz = owner.getClass();
while (clz != Deflater.class && clz != Inflater.class) {
try {
clz.getDeclaredMethod("end");
return new FinalizableZStreamRef(owner, addr, end);
} catch (NoSuchMethodException nsme) {}
clz = clz.getSuperclass();
}
return new ZStreamRef(owner, addr, end);
}
private static class FinalizableZStreamRef extends ZStreamRef {
final Object owner;
FinalizableZStreamRef (Object owner, LongSupplier addr, LongConsumer end) {
super(addr, end);
this.owner = owner;
}
@Override
void clean() {
run();
}
@Override
@SuppressWarnings("deprecation")
protected void finalize() {
if (owner instanceof Inflater)
((Inflater)owner).end();
else
((Deflater)owner).end();
}
}
}

View File

@ -28,72 +28,60 @@ package java.util.zip;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.CodingErrorAction;
import java.util.Arrays;
import sun.nio.cs.ArrayDecoder;
import sun.nio.cs.ArrayEncoder;
import static java.nio.charset.StandardCharsets.UTF_8;
/**
* Utility class for zipfile name and comment decoding and encoding
*/
final class ZipCoder {
class ZipCoder {
private static boolean isASCII(byte[] ba, int off, int len) {
for (int i = off; i < off + len; i++) {
if (ba[i] < 0)
return false;
private static final jdk.internal.misc.JavaLangAccess JLA =
jdk.internal.misc.SharedSecrets.getJavaLangAccess();
static final class UTF8 extends ZipCoder {
UTF8(Charset utf8) {
super(utf8);
}
@Override
boolean isUTF8() {
return true;
}
@Override
String toString(byte[] ba, int off, int length) {
return JLA.newStringUTF8NoRepl(ba, off, length);
}
@Override
byte[] getBytes(String s) {
return JLA.getBytesUTF8NoRepl(s);
}
return true;
}
private static boolean hasReplaceChar(byte[] ba) {
for (int i = 0; i < ba.length; i++) {
if (ba[i] == (byte)'?')
return true;
}
return false;
// UTF_8.ArrayEn/Decoder is stateless, so make it singleton.
private static ZipCoder utf8 = new UTF8(UTF_8);
public static ZipCoder get(Charset charset) {
if (charset == UTF_8)
return utf8;
return new ZipCoder(charset);
}
String toString(byte[] ba, int off, int length) {
try {
return decoder().decode(ByteBuffer.wrap(ba, off, length)).toString();
// fastpath for UTF-8 cs and ascii only name, leverage the
// compact string impl to avoid the unnecessary char[] copy/
// paste. A temporary workaround before we have better approach,
// such as a String constructor that throws exception for
// malformed and/or unmappable characters, instead of silently
// replacing with repl char
if (isUTF8 && isASCII(ba, off, length)) {
return new String(ba, off, length, cs);
} catch (CharacterCodingException x) {
throw new IllegalArgumentException(x);
}
CharsetDecoder cd = decoder().reset();
int len = (int)(length * cd.maxCharsPerByte());
char[] ca = new char[len];
if (len == 0)
return new String(ca);
// UTF-8 only for now. Other ArrayDeocder only handles
// CodingErrorAction.REPLACE mode. ZipCoder uses
// REPORT mode.
if (isUTF8 && cd instanceof ArrayDecoder) {
int clen = ((ArrayDecoder)cd).decode(ba, off, length, ca);
if (clen == -1) // malformed
throw new IllegalArgumentException("MALFORMED");
return new String(ca, 0, clen);
}
ByteBuffer bb = ByteBuffer.wrap(ba, off, length);
CharBuffer cb = CharBuffer.wrap(ca);
CoderResult cr = cd.decode(bb, cb, true);
if (!cr.isUnderflow())
throw new IllegalArgumentException(cr.toString());
cr = cd.flush(cb);
if (!cr.isUnderflow())
throw new IllegalArgumentException(cr.toString());
return new String(ca, 0, cb.position());
}
String toString(byte[] ba, int length) {
@ -105,84 +93,47 @@ final class ZipCoder {
}
byte[] getBytes(String s) {
if (isUTF8) {
// fastpath for UTF8. should only occur when the string
// has malformed surrogates. A postscan should still be
// faster and use less memory.
byte[] ba = s.getBytes(cs);
if (!hasReplaceChar(ba)) {
return ba;
try {
ByteBuffer bb = encoder().encode(CharBuffer.wrap(s));
int pos = bb.position();
int limit = bb.limit();
if (bb.hasArray() && pos == 0 && limit == bb.capacity()) {
return bb.array();
}
byte[] bytes = new byte[bb.limit() - bb.position()];
bb.get(bytes);
return bytes;
} catch (CharacterCodingException x) {
throw new IllegalArgumentException(x);
}
CharsetEncoder ce = encoder().reset();
char[] ca = s.toCharArray();
int len = (int)(ca.length * ce.maxBytesPerChar());
byte[] ba = new byte[len];
if (len == 0)
return ba;
// UTF-8 only for now. Other ArrayDeocder only handles
// CodingErrorAction.REPLACE mode.
if (isUTF8 && ce instanceof ArrayEncoder) {
int blen = ((ArrayEncoder)ce).encode(ca, 0, ca.length, ba);
if (blen == -1) // malformed
throw new IllegalArgumentException("MALFORMED");
return Arrays.copyOf(ba, blen);
}
ByteBuffer bb = ByteBuffer.wrap(ba);
CharBuffer cb = CharBuffer.wrap(ca);
CoderResult cr = ce.encode(cb, bb, true);
if (!cr.isUnderflow())
throw new IllegalArgumentException(cr.toString());
cr = ce.flush(bb);
if (!cr.isUnderflow())
throw new IllegalArgumentException(cr.toString());
if (bb.position() == ba.length) // defensive copy?
return ba;
else
return Arrays.copyOf(ba, bb.position());
}
// assume invoked only if "this" is not utf8
byte[] getBytesUTF8(String s) {
if (isUTF8)
return getBytes(s);
if (utf8 == null)
utf8 = new ZipCoder(StandardCharsets.UTF_8);
return utf8.getBytes(s);
}
String toStringUTF8(byte[] ba, int len) {
return toStringUTF8(ba, 0, len);
return utf8.toString(ba, 0, len);
}
String toStringUTF8(byte[] ba, int off, int len) {
if (isUTF8)
return toString(ba, off, len);
if (utf8 == null)
utf8 = new ZipCoder(StandardCharsets.UTF_8);
return utf8.toString(ba, off, len);
}
boolean isUTF8() {
return isUTF8;
return false;
}
private Charset cs;
private CharsetDecoder dec;
private CharsetEncoder enc;
private boolean isUTF8;
private ZipCoder utf8;
private ZipCoder(Charset cs) {
this.cs = cs;
this.isUTF8 = cs.name().equals(StandardCharsets.UTF_8.name());
}
static ZipCoder get(Charset charset) {
return new ZipCoder(charset);
}
private CharsetDecoder decoder() {
protected CharsetDecoder decoder() {
if (dec == null) {
dec = cs.newDecoder()
.onMalformedInput(CodingErrorAction.REPORT)
@ -191,7 +142,7 @@ final class ZipCoder {
return dec;
}
private CharsetEncoder encoder() {
protected CharsetEncoder encoder() {
if (enc == null) {
enc = cs.newEncoder()
.onMalformedInput(CodingErrorAction.REPORT)

View File

@ -31,22 +31,24 @@ import java.io.IOException;
import java.io.EOFException;
import java.io.File;
import java.io.RandomAccessFile;
import java.io.UncheckedIOException;
import java.lang.ref.Cleaner.Cleanable;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.Path;
import java.nio.file.Files;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Deque;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.WeakHashMap;
@ -61,8 +63,8 @@ import jdk.internal.misc.JavaUtilZipFileAccess;
import jdk.internal.misc.SharedSecrets;
import jdk.internal.misc.VM;
import jdk.internal.perf.PerfCounter;
import jdk.internal.ref.CleanerFactory;
import static java.util.zip.ZipConstants.*;
import static java.util.zip.ZipConstants64.*;
import static java.util.zip.ZipUtils.*;
@ -73,6 +75,21 @@ import static java.util.zip.ZipUtils.*;
* or method in this class will cause a {@link NullPointerException} to be
* thrown.
*
* @apiNote
* To release resources used by this {@code ZipFile}, the {@link #close()} method
* should be called explicitly or by try-with-resources. Subclasses are responsible
* for the cleanup of resources acquired by the subclass. Subclasses that override
* {@link #finalize()} in order to perform cleanup should be modified to use alternative
* cleanup mechanisms such as {@link java.lang.ref.Cleaner} and remove the overriding
* {@code finalize} method.
*
* @implSpec
* If this {@code ZipFile} has been subclassed and the {@code close} method has
* been overridden, the {@code close} method will be called by the finalization
* when {@code ZipFile} is unreachable. But the subclasses should not depend on
* this specific implementation; the finalization is not reliable and the
* {@code finalize} method is deprecated to be removed.
*
* @author David Connelly
* @since 1.1
*/
@ -81,9 +98,15 @@ class ZipFile implements ZipConstants, Closeable {
private final String name; // zip file name
private volatile boolean closeRequested;
private Source zsrc;
private ZipCoder zc;
// The "resource" used by this zip file that needs to be
// cleaned after use.
// a) the input streams that need to be closed
// b) the list of cached Inflater objects
// c) the "native" source of this zip file.
private final CleanableResource res;
private static final int STORED = ZipEntry.STORED;
private static final int DEFLATED = ZipEntry.DEFLATED;
@ -214,10 +237,13 @@ class ZipFile implements ZipConstants, Closeable {
}
}
Objects.requireNonNull(charset, "charset");
this.zc = ZipCoder.get(charset);
this.name = name;
long t0 = System.nanoTime();
this.zsrc = Source.get(file, (mode & OPEN_DELETE) != 0);
this.res = CleanableResource.get(this, file, mode);
PerfCounter.getZipFileOpenTime().addElapsedTimeFrom(t0);
PerfCounter.getZipFileCount().increment();
}
@ -284,10 +310,10 @@ class ZipFile implements ZipConstants, Closeable {
public String getComment() {
synchronized (this) {
ensureOpen();
if (zsrc.comment == null) {
if (res.zsrc.comment == null) {
return null;
}
return zc.toString(zsrc.comment);
return zc.toString(res.zsrc.comment);
}
}
@ -318,7 +344,7 @@ class ZipFile implements ZipConstants, Closeable {
synchronized (this) {
ensureOpen();
byte[] bname = zc.getBytes(name);
int pos = zsrc.getEntryPos(bname, true);
int pos = res.zsrc.getEntryPos(bname, true);
if (pos != -1) {
return getZipEntry(name, bname, pos, func);
}
@ -326,10 +352,6 @@ class ZipFile implements ZipConstants, Closeable {
return null;
}
// The outstanding inputstreams that need to be closed,
// mapped to the inflater objects they use.
private final Map<InputStream, Inflater> streams = new WeakHashMap<>();
/**
* Returns an input stream for reading the contents of the specified
* zip file entry.
@ -348,6 +370,8 @@ class ZipFile implements ZipConstants, Closeable {
Objects.requireNonNull(entry, "entry");
int pos = -1;
ZipFileInputStream in = null;
Source zsrc = res.zsrc;
Set<InputStream> istreams = res.istreams;
synchronized (this) {
ensureOpen();
if (Objects.equals(lastEntryName, entry.name)) {
@ -363,8 +387,8 @@ class ZipFile implements ZipConstants, Closeable {
in = new ZipFileInputStream(zsrc.cen, pos);
switch (CENHOW(zsrc.cen, pos)) {
case STORED:
synchronized (streams) {
streams.put(in, null);
synchronized (istreams) {
istreams.add(in);
}
return in;
case DEFLATED:
@ -377,10 +401,9 @@ class ZipFile implements ZipConstants, Closeable {
if (size <= 0) {
size = 4096;
}
Inflater inf = getInflater();
InputStream is = new ZipFileInflaterInputStream(in, inf, (int)size);
synchronized (streams) {
streams.put(is, inf);
InputStream is = new ZipFileInflaterInputStream(in, res, (int)size);
synchronized (istreams) {
istreams.add(is);
}
return is;
default:
@ -392,25 +415,30 @@ class ZipFile implements ZipConstants, Closeable {
private class ZipFileInflaterInputStream extends InflaterInputStream {
private volatile boolean closeRequested;
private boolean eof = false;
private final Cleanable cleanable;
ZipFileInflaterInputStream(ZipFileInputStream zfin, Inflater inf,
int size) {
super(zfin, inf, size);
ZipFileInflaterInputStream(ZipFileInputStream zfin,
CleanableResource res, int size) {
this(zfin, res, res.getInflater(), size);
}
private ZipFileInflaterInputStream(ZipFileInputStream zfin,
CleanableResource res,
Inflater inf, int size) {
super(zfin, inf, size);
this.cleanable = CleanerFactory.cleaner().register(this,
() -> res.releaseInflater(inf));
}
public void close() throws IOException {
if (closeRequested)
return;
closeRequested = true;
super.close();
Inflater inf;
synchronized (streams) {
inf = streams.remove(this);
}
if (inf != null) {
releaseInflater(inf);
synchronized (res.istreams) {
res.istreams.remove(this);
}
cleanable.clean();
}
// Override fill() method to provide an extra "dummy" byte
@ -436,44 +464,8 @@ class ZipFile implements ZipConstants, Closeable {
return (avail > (long) Integer.MAX_VALUE ?
Integer.MAX_VALUE : (int) avail);
}
@SuppressWarnings("deprecation")
protected void finalize() throws Throwable {
close();
}
}
/*
* Gets an inflater from the list of available inflaters or allocates
* a new one.
*/
private Inflater getInflater() {
Inflater inf;
synchronized (inflaterCache) {
while ((inf = inflaterCache.poll()) != null) {
if (!inf.ended()) {
return inf;
}
}
}
return new Inflater(true);
}
/*
* Releases the specified inflater to the list of available inflaters.
*/
private void releaseInflater(Inflater inf) {
if (!inf.ended()) {
inf.reset();
synchronized (inflaterCache) {
inflaterCache.add(inf);
}
}
}
// List of available Inflater objects for decompression
private final Deque<Inflater> inflaterCache = new ArrayDeque<>();
/**
* Returns the path name of the ZIP file.
* @return the path name of the ZIP file
@ -518,7 +510,7 @@ class ZipFile implements ZipConstants, Closeable {
throw new NoSuchElementException();
}
// each "entry" has 3 ints in table entries
return (T)getZipEntry(null, null, zsrc.getEntryPos(i++ * 3), gen);
return (T)getZipEntry(null, null, res.zsrc.getEntryPos(i++ * 3), gen);
}
}
@ -536,14 +528,14 @@ class ZipFile implements ZipConstants, Closeable {
public Enumeration<? extends ZipEntry> entries() {
synchronized (this) {
ensureOpen();
return new ZipEntryIterator<ZipEntry>(zsrc.total, ZipEntry::new);
return new ZipEntryIterator<ZipEntry>(res.zsrc.total, ZipEntry::new);
}
}
private Enumeration<JarEntry> entries(Function<String, JarEntry> func) {
synchronized (this) {
ensureOpen();
return new ZipEntryIterator<JarEntry>(zsrc.total, func);
return new ZipEntryIterator<JarEntry>(res.zsrc.total, func);
}
}
@ -568,7 +560,7 @@ class ZipFile implements ZipConstants, Closeable {
if (index >= 0 && index < fence) {
synchronized (ZipFile.this) {
ensureOpen();
action.accept(gen.apply(zsrc.getEntryPos(index++ * 3)));
action.accept(gen.apply(res.zsrc.getEntryPos(index++ * 3)));
}
return true;
}
@ -589,13 +581,13 @@ class ZipFile implements ZipConstants, Closeable {
public Stream<? extends ZipEntry> stream() {
synchronized (this) {
ensureOpen();
return StreamSupport.stream(new EntrySpliterator<>(0, zsrc.total,
return StreamSupport.stream(new EntrySpliterator<>(0, res.zsrc.total,
pos -> getZipEntry(null, null, pos, ZipEntry::new)), false);
}
}
private String getEntryName(int pos) {
byte[] cen = zsrc.cen;
byte[] cen = res.zsrc.cen;
int nlen = CENNAM(cen, pos);
int clen = CENCOM(cen, pos);
int flag = CENFLG(cen, pos);
@ -620,7 +612,7 @@ class ZipFile implements ZipConstants, Closeable {
synchronized (this) {
ensureOpen();
return StreamSupport.stream(
new EntrySpliterator<>(0, zsrc.total, this::getEntryName), false);
new EntrySpliterator<>(0, res.zsrc.total, this::getEntryName), false);
}
}
@ -638,7 +630,7 @@ class ZipFile implements ZipConstants, Closeable {
private Stream<JarEntry> stream(Function<String, JarEntry> func) {
synchronized (this) {
ensureOpen();
return StreamSupport.stream(new EntrySpliterator<>(0, zsrc.total,
return StreamSupport.stream(new EntrySpliterator<>(0, res.zsrc.total,
pos -> (JarEntry)getZipEntry(null, null, pos, func)), false);
}
}
@ -649,7 +641,7 @@ class ZipFile implements ZipConstants, Closeable {
/* Checks ensureOpen() before invoke this method */
private ZipEntry getZipEntry(String name, byte[] bname, int pos,
Function<String, ? extends ZipEntry> func) {
byte[] cen = zsrc.cen;
byte[] cen = res.zsrc.cen;
int nlen = CENNAM(cen, pos);
int elen = CENEXT(cen, pos);
int clen = CENCOM(cen, pos);
@ -698,12 +690,170 @@ class ZipFile implements ZipConstants, Closeable {
public int size() {
synchronized (this) {
ensureOpen();
return zsrc.total;
return res.zsrc.total;
}
}
private static class CleanableResource implements Runnable {
// The outstanding inputstreams that need to be closed
final Set<InputStream> istreams;
// List of cached Inflater objects for decompression
Deque<Inflater> inflaterCache;
final Cleanable cleanable;
Source zsrc;
CleanableResource(ZipFile zf, File file, int mode) throws IOException {
this.cleanable = CleanerFactory.cleaner().register(zf, this);
this.istreams = Collections.newSetFromMap(new WeakHashMap<>());
this.inflaterCache = new ArrayDeque<>();
this.zsrc = Source.get(file, (mode & OPEN_DELETE) != 0);
}
void clean() {
cleanable.clean();
}
/*
* Gets an inflater from the list of available inflaters or allocates
* a new one.
*/
Inflater getInflater() {
Inflater inf;
synchronized (inflaterCache) {
if ((inf = inflaterCache.poll()) != null) {
return inf;
}
}
return new Inflater(true);
}
/*
* Releases the specified inflater to the list of available inflaters.
*/
void releaseInflater(Inflater inf) {
Deque<Inflater> inflaters = this.inflaterCache;
if (inflaters != null) {
synchronized (inflaters) {
// double checked!
if (inflaters == this.inflaterCache) {
inf.reset();
inflaters.add(inf);
return;
}
}
}
// inflaters cache already closed - just end it.
inf.end();
}
public void run() {
IOException ioe = null;
// Release cached inflaters and close the cache first
Deque<Inflater> inflaters = this.inflaterCache;
if (inflaters != null) {
synchronized (inflaters) {
// no need to double-check as only one thread gets a
// chance to execute run() (Cleaner guarantee)...
Inflater inf;
while ((inf = inflaters.poll()) != null) {
inf.end();
}
// close inflaters cache
this.inflaterCache = null;
}
}
// Close streams, release their inflaters
if (istreams != null) {
synchronized (istreams) {
if (!istreams.isEmpty()) {
InputStream[] copy = istreams.toArray(new InputStream[0]);
istreams.clear();
for (InputStream is : copy) {
try {
is.close();
} catch (IOException e) {
if (ioe == null) ioe = e;
else ioe.addSuppressed(e);
}
}
}
}
}
// Release zip src
if (zsrc != null) {
synchronized (zsrc) {
try {
Source.release(zsrc);
zsrc = null;
} catch (IOException e) {
if (ioe == null) ioe = e;
else ioe.addSuppressed(e);
}
}
}
if (ioe != null) {
throw new UncheckedIOException(ioe);
}
}
CleanableResource(File file, int mode)
throws IOException {
this.cleanable = null;
this.istreams = Collections.newSetFromMap(new WeakHashMap<>());
this.inflaterCache = new ArrayDeque<>();
this.zsrc = Source.get(file, (mode & OPEN_DELETE) != 0);
}
/*
* If {@code ZipFile} has been subclassed and the {@code close} method is
* overridden, uses the {@code finalizer} mechanism for resource cleanup.
* So {@code close} method can be called when the the {@code ZipFile} is
* unreachable. This mechanism will be removed when {@code finalize} method
* is removed from {@code ZipFile}.
*/
static CleanableResource get(ZipFile zf, File file, int mode)
throws IOException {
Class<?> clz = zf.getClass();
while (clz != ZipFile.class) {
try {
clz.getDeclaredMethod("close");
return new FinalizableResource(zf, file, mode);
} catch (NoSuchMethodException nsme) {}
clz = clz.getSuperclass();
}
return new CleanableResource(zf, file, mode);
}
static class FinalizableResource extends CleanableResource {
ZipFile zf;
FinalizableResource(ZipFile zf, File file, int mode)
throws IOException {
super(file, mode);
this.zf = zf;
}
@Override
void clean() {
run();
}
@Override
@SuppressWarnings("deprecation")
protected void finalize() throws IOException {
zf.close();
}
}
}
/**
* Closes the ZIP file.
*
* <p> Closing this ZIP file will close all of the input streams
* previously returned by invocations of the {@link #getInputStream
* getInputStream} method.
@ -717,31 +867,12 @@ class ZipFile implements ZipConstants, Closeable {
closeRequested = true;
synchronized (this) {
// Close streams, release their inflaters
synchronized (streams) {
if (!streams.isEmpty()) {
Map<InputStream, Inflater> copy = new HashMap<>(streams);
streams.clear();
for (Map.Entry<InputStream, Inflater> e : copy.entrySet()) {
e.getKey().close();
Inflater inf = e.getValue();
if (inf != null) {
inf.end();
}
}
}
}
// Release cached inflaters
synchronized (inflaterCache) {
Inflater inf;
while ((inf = inflaterCache.poll()) != null) {
inf.end();
}
}
// Release zip src
if (zsrc != null) {
Source.close(zsrc);
zsrc = null;
// Close streams, release their inflaters, release cached inflaters
// and release zip source
try {
res.clean();
} catch (UncheckedIOException ioe) {
throw ioe.getCause();
}
}
}
@ -750,34 +881,26 @@ class ZipFile implements ZipConstants, Closeable {
* Ensures that the system resources held by this ZipFile object are
* released when there are no more references to it.
*
* <p>
* Since the time when GC would invoke this method is undetermined,
* it is strongly recommended that applications invoke the {@code close}
* method as soon they have finished accessing this {@code ZipFile}.
* This will prevent holding up system resources for an undetermined
* length of time.
* @deprecated The {@code finalize} method has been deprecated and will be
* removed. It is implemented as a no-op. Subclasses that override
* {@code finalize} in order to perform cleanup should be modified to
* use alternative cleanup mechanisms and to remove the overriding
* {@code finalize} method. The recommended cleanup for ZipFile object
* is to explicitly invoke {@code close} method when it is no longer in
* use, or use try-with-resources. If the {@code close} is not invoked
* explicitly the resources held by this object will be released when
* the instance becomes unreachable.
*
* @deprecated The {@code finalize} method has been deprecated.
* Subclasses that override {@code finalize} in order to perform cleanup
* should be modified to use alternative cleanup mechanisms and
* to remove the overriding {@code finalize} method.
* When overriding the {@code finalize} method, its implementation must explicitly
* ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}.
* See the specification for {@link Object#finalize()} for further
* information about migration options.
* @throws IOException if an I/O error has occurred
* @see java.util.zip.ZipFile#close()
*/
@Deprecated(since="9")
protected void finalize() throws IOException {
close();
}
@Deprecated(since="9", forRemoval=true)
protected void finalize() throws IOException {}
private void ensureOpen() {
if (closeRequested) {
throw new IllegalStateException("zip file closed");
}
if (zsrc == null) {
if (res.zsrc == null) {
throw new IllegalStateException("The object is not initialized.");
}
}
@ -798,7 +921,7 @@ class ZipFile implements ZipConstants, Closeable {
protected long rem; // number of remaining bytes within entry
protected long size; // uncompressed size of this entry
ZipFileInputStream(byte[] cen, int cenpos) throws IOException {
ZipFileInputStream(byte[] cen, int cenpos) {
rem = CENSIZ(cen, cenpos);
size = CENLEN(cen, cenpos);
pos = CENOFF(cen, cenpos);
@ -808,10 +931,10 @@ class ZipFile implements ZipConstants, Closeable {
checkZIP64(cen, cenpos);
}
// negative for lazy initialization, see getDataOffset();
pos = - (pos + ZipFile.this.zsrc.locpos);
pos = - (pos + ZipFile.this.res.zsrc.locpos);
}
private void checkZIP64(byte[] cen, int cenpos) throws IOException {
private void checkZIP64(byte[] cen, int cenpos) {
int off = cenpos + CENHDR + CENNAM(cen, cenpos);
int end = off + CENEXT(cen, cenpos);
while (off + 4 < end) {
@ -857,7 +980,7 @@ class ZipFile implements ZipConstants, Closeable {
if (pos <= 0) {
byte[] loc = new byte[LOCHDR];
pos = -pos;
int len = ZipFile.this.zsrc.readFullyAt(loc, 0, loc.length, pos);
int len = ZipFile.this.res.zsrc.readFullyAt(loc, 0, loc.length, pos);
if (len != LOCHDR) {
throw new ZipException("ZipFile error reading zip file");
}
@ -882,7 +1005,7 @@ class ZipFile implements ZipConstants, Closeable {
if (len <= 0) {
return 0;
}
len = ZipFile.this.zsrc.readAt(b, off, len, pos);
len = ZipFile.this.res.zsrc.readAt(b, off, len, pos);
if (len > 0) {
pos += len;
rem -= len;
@ -932,15 +1055,11 @@ class ZipFile implements ZipConstants, Closeable {
}
closeRequested = true;
rem = 0;
synchronized (streams) {
streams.remove(this);
synchronized (res.istreams) {
res.istreams.remove(this);
}
}
@SuppressWarnings("deprecation")
protected void finalize() {
close();
}
}
/**
@ -952,6 +1071,7 @@ class ZipFile implements ZipConstants, Closeable {
private String[] getMetaInfEntryNames() {
synchronized (this) {
ensureOpen();
Source zsrc = res.zsrc;
if (zsrc.metanames == null) {
return null;
}
@ -972,7 +1092,7 @@ class ZipFile implements ZipConstants, Closeable {
new JavaUtilZipFileAccess() {
@Override
public boolean startsWithLocHeader(ZipFile zip) {
return zip.zsrc.startsWithLoc;
return zip.res.zsrc.startsWithLoc;
}
@Override
public String[] getMetaInfEntryNames(ZipFile zip) {
@ -1080,7 +1200,7 @@ class ZipFile implements ZipConstants, Closeable {
private static final HashMap<Key, Source> files = new HashMap<>();
public static Source get(File file, boolean toDelete) throws IOException {
static Source get(File file, boolean toDelete) throws IOException {
Key key = new Key(file,
Files.readAttributes(file.toPath(), BasicFileAttributes.class));
Source src = null;
@ -1105,9 +1225,9 @@ class ZipFile implements ZipConstants, Closeable {
}
}
private static void close(Source src) throws IOException {
static void release(Source src) throws IOException {
synchronized (files) {
if (--src.refs == 0) {
if (src != null && --src.refs == 0) {
files.remove(src.key);
src.close();
}

View File

@ -254,4 +254,23 @@ public interface JavaLangAccess {
* given class loader.
*/
Stream<ModuleLayer> layers(ClassLoader loader);
/**
* Returns a new string by decoding from the given utf8 bytes array.
*
* @param off the index of the first byte to decode
* @param len the number of bytes to decode
* @return the newly created string
* @throws IllegalArgumentException for malformed or unmappable bytes.
*/
String newStringUTF8NoRepl(byte[] bytes, int off, int len);
/**
* Encode the given string into a sequence of bytes using utf8.
*
* @param s the string to encode
* @return the encoded bytes in utf8
* @throws IllegalArgumentException for malformed surrogates
*/
byte[] getBytesUTF8NoRepl(String s);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -26,6 +26,7 @@
package jdk.internal.util.xml;
import java.io.*;
import java.nio.charset.Charset;
import java.util.InvalidPropertiesFormatException;
import java.util.Map.Entry;
import java.util.Properties;
@ -94,11 +95,11 @@ public class PropertiesDefaultHandler extends DefaultHandler {
*/
}
public void store(Properties props, OutputStream os, String comment, String encoding)
public void store(Properties props, OutputStream os, String comment, Charset charset)
throws IOException
{
try {
XMLStreamWriter writer = new XMLStreamWriterImpl(os, encoding);
XMLStreamWriter writer = new XMLStreamWriterImpl(os, charset);
writer.writeStartDocument();
writer.writeDTD(PROPS_DTD_DECL);
writer.writeStartElement(ELEMENT_ROOT);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,6 +25,9 @@
package jdk.internal.util.xml;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
/**
* Basic XMLStreamWriter for writing simple XML files such as those
* defined in java.util.Properties
@ -38,6 +41,7 @@ public interface XMLStreamWriter {
//Defaults the XML version to 1.0, and the encoding to utf-8
public static final String DEFAULT_XML_VERSION = "1.0";
public static final String DEFAULT_ENCODING = "UTF-8";
public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
/**
* Writes a start tag to the output. All writeStartElement methods

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -66,7 +66,7 @@ public class XMLStreamWriterImpl implements XMLStreamWriter {
private int _state = 0;
private Element _currentEle;
private XMLWriter _writer;
private String _encoding;
private Charset _charset;
/**
* This flag can be used to turn escaping off for content. It does
* not apply to attribute content.
@ -79,26 +79,23 @@ public class XMLStreamWriterImpl implements XMLStreamWriter {
System.getProperty("line.separator").toCharArray();
public XMLStreamWriterImpl(OutputStream os) throws XMLStreamException {
this(os, XMLStreamWriter.DEFAULT_ENCODING);
this(os, XMLStreamWriter.DEFAULT_CHARSET);
}
public XMLStreamWriterImpl(OutputStream os, String encoding)
public XMLStreamWriterImpl(OutputStream os, Charset cs)
throws XMLStreamException
{
Charset cs = null;
if (encoding == null) {
_encoding = XMLStreamWriter.DEFAULT_ENCODING;
if (cs == null) {
_charset = XMLStreamWriter.DEFAULT_CHARSET;
} else {
try {
cs = getCharset(encoding);
_charset = checkCharset(cs);
} catch (UnsupportedEncodingException e) {
throw new XMLStreamException(e);
}
this._encoding = encoding;
}
_writer = new XMLWriter(os, encoding, cs);
_writer = new XMLWriter(os, null, _charset);
}
/**
@ -108,7 +105,7 @@ public class XMLStreamWriterImpl implements XMLStreamWriter {
* @throws XMLStreamException
*/
public void writeStartDocument() throws XMLStreamException {
writeStartDocument(_encoding, XMLStreamWriter.DEFAULT_XML_VERSION);
writeStartDocument(_charset.name(), XMLStreamWriter.DEFAULT_XML_VERSION);
}
/**
@ -118,7 +115,7 @@ public class XMLStreamWriterImpl implements XMLStreamWriter {
* @throws XMLStreamException
*/
public void writeStartDocument(String version) throws XMLStreamException {
writeStartDocument(_encoding, version, null);
writeStartDocument(_charset.name(), version, null);
}
/**
@ -155,7 +152,7 @@ public class XMLStreamWriterImpl implements XMLStreamWriter {
_state = STATE_XML_DECL;
String enc = encoding;
if (enc == null) {
enc = _encoding;
enc = _charset.name();
} else {
//check if the encoding is supported
try {
@ -564,6 +561,20 @@ public class XMLStreamWriterImpl implements XMLStreamWriter {
return cs;
}
/**
* Checks for charset support.
* @param charset the specified charset
* @return the charset
* @throws UnsupportedEncodingException if the charset is not supported
*/
private Charset checkCharset(Charset charset) throws UnsupportedEncodingException {
if (charset.name().equalsIgnoreCase("UTF-32")) {
throw new UnsupportedEncodingException("The basic XMLWriter does "
+ "not support " + charset.name());
}
return charset;
}
/*
* Start of Internal classes.
*

View File

@ -268,7 +268,7 @@ public final class LauncherHelper {
Locale locale = Locale.getDefault();
ostream.println(LOCALE_SETTINGS);
ostream.println(INDENT + "default locale = " +
locale.getDisplayLanguage());
locale.getDisplayName());
ostream.println(INDENT + "default display locale = " +
Locale.getDefault(Category.DISPLAY).getDisplayName());
ostream.println(INDENT + "default format locale = " +

View File

@ -63,8 +63,8 @@ public class ISO_8859_1
return new Encoder(this);
}
private static class Decoder extends CharsetDecoder
implements ArrayDecoder {
private static class Decoder extends CharsetDecoder {
private Decoder(Charset cs) {
super(cs, 1.0f, 1.0f);
}
@ -124,23 +124,10 @@ public class ISO_8859_1
else
return decodeBufferLoop(src, dst);
}
public int decode(byte[] src, int sp, int len, char[] dst) {
if (len > dst.length)
len = dst.length;
int dp = 0;
while (dp < len)
dst[dp++] = (char)(src[sp++] & 0xff);
return dp;
}
public boolean isASCIICompatible() {
return true;
}
}
private static class Encoder extends CharsetEncoder
implements ArrayEncoder {
private static class Encoder extends CharsetEncoder {
private Encoder(Charset cs) {
super(cs, 1.0f, 1.0f);
}
@ -271,39 +258,5 @@ public class ISO_8859_1
else
return encodeBufferLoop(src, dst);
}
private byte repl = (byte)'?';
protected void implReplaceWith(byte[] newReplacement) {
repl = newReplacement[0];
}
public int encode(char[] src, int sp, int len, byte[] dst) {
int dp = 0;
int slen = Math.min(len, dst.length);
int sl = sp + slen;
while (sp < sl) {
int ret = encodeISOArray(src, sp, dst, dp, slen);
sp = sp + ret;
dp = dp + ret;
if (ret != slen) {
char c = src[sp++];
if (Character.isHighSurrogate(c) && sp < sl &&
Character.isLowSurrogate(src[sp])) {
if (len > dst.length) {
sl++;
len--;
}
sp++;
}
dst[dp++] = repl;
slen = Math.min((sl - sp), (dst.length - dp));
}
}
return dp;
}
public boolean isASCIICompatible() {
return true;
}
}
}

View File

@ -58,8 +58,7 @@ public class US_ASCII
return new Encoder(this);
}
private static class Decoder extends CharsetDecoder
implements ArrayDecoder {
private static class Decoder extends CharsetDecoder {
private Decoder(Charset cs) {
super(cs, 1.0f, 1.0f);
@ -128,32 +127,9 @@ public class US_ASCII
else
return decodeBufferLoop(src, dst);
}
private char repl = '\uFFFD';
protected void implReplaceWith(String newReplacement) {
repl = newReplacement.charAt(0);
}
public int decode(byte[] src, int sp, int len, char[] dst) {
int dp = 0;
len = Math.min(len, dst.length);
while (dp < len) {
byte b = src[sp++];
if (b >= 0)
dst[dp++] = (char)b;
else
dst[dp++] = repl;
}
return dp;
}
public boolean isASCIICompatible() {
return true;
}
}
private static class Encoder extends CharsetEncoder
implements ArrayEncoder {
private static class Encoder extends CharsetEncoder {
private Encoder(Charset cs) {
super(cs, 1.0f, 1.0f);
@ -237,36 +213,5 @@ public class US_ASCII
return encodeBufferLoop(src, dst);
}
private byte repl = (byte)'?';
protected void implReplaceWith(byte[] newReplacement) {
repl = newReplacement[0];
}
public int encode(char[] src, int sp, int len, byte[] dst) {
int dp = 0;
int sl = sp + Math.min(len, dst.length);
while (sp < sl) {
char c = src[sp++];
if (c < 0x80) {
dst[dp++] = (byte)c;
continue;
}
if (Character.isHighSurrogate(c) && sp < sl &&
Character.isLowSurrogate(src[sp])) {
if (len > dst.length) {
sl++;
len--;
}
sp++;
}
dst[dp++] = repl;
}
return dp;
}
public boolean isASCIICompatible() {
return true;
}
}
}

View File

@ -80,8 +80,8 @@ public final class UTF_8 extends Unicode {
dst.position(dp - dst.arrayOffset());
}
private static class Decoder extends CharsetDecoder
implements ArrayDecoder {
private static class Decoder extends CharsetDecoder {
private Decoder(Charset cs) {
super(cs, 1.0f, 1.0f);
}
@ -423,142 +423,9 @@ public final class UTF_8 extends Unicode {
bb.position(sp);
return bb;
}
// returns -1 if there is/are malformed byte(s) and the
// "action" for malformed input is not REPLACE.
public int decode(byte[] sa, int sp, int len, char[] da) {
final int sl = sp + len;
int dp = 0;
int dlASCII = Math.min(len, da.length);
ByteBuffer bb = null; // only necessary if malformed
// ASCII only optimized loop
while (dp < dlASCII && sa[sp] >= 0)
da[dp++] = (char) sa[sp++];
while (sp < sl) {
int b1 = sa[sp++];
if (b1 >= 0) {
// 1 byte, 7 bits: 0xxxxxxx
da[dp++] = (char) b1;
} else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) {
// 2 bytes, 11 bits: 110xxxxx 10xxxxxx
if (sp < sl) {
int b2 = sa[sp++];
if (isNotContinuation(b2)) {
if (malformedInputAction() != CodingErrorAction.REPLACE)
return -1;
da[dp++] = replacement().charAt(0);
sp--; // malformedN(bb, 2) always returns 1
} else {
da[dp++] = (char) (((b1 << 6) ^ b2)^
(((byte) 0xC0 << 6) ^
((byte) 0x80 << 0)));
}
continue;
}
if (malformedInputAction() != CodingErrorAction.REPLACE)
return -1;
da[dp++] = replacement().charAt(0);
return dp;
} else if ((b1 >> 4) == -2) {
// 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx
if (sp + 1 < sl) {
int b2 = sa[sp++];
int b3 = sa[sp++];
if (isMalformed3(b1, b2, b3)) {
if (malformedInputAction() != CodingErrorAction.REPLACE)
return -1;
da[dp++] = replacement().charAt(0);
sp -= 3;
bb = getByteBuffer(bb, sa, sp);
sp += malformedN(bb, 3).length();
} else {
char c = (char)((b1 << 12) ^
(b2 << 6) ^
(b3 ^
(((byte) 0xE0 << 12) ^
((byte) 0x80 << 6) ^
((byte) 0x80 << 0))));
if (Character.isSurrogate(c)) {
if (malformedInputAction() != CodingErrorAction.REPLACE)
return -1;
da[dp++] = replacement().charAt(0);
} else {
da[dp++] = c;
}
}
continue;
}
if (malformedInputAction() != CodingErrorAction.REPLACE)
return -1;
if (sp < sl && isMalformed3_2(b1, sa[sp])) {
da[dp++] = replacement().charAt(0);
continue;
}
da[dp++] = replacement().charAt(0);
return dp;
} else if ((b1 >> 3) == -2) {
// 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
if (sp + 2 < sl) {
int b2 = sa[sp++];
int b3 = sa[sp++];
int b4 = sa[sp++];
int uc = ((b1 << 18) ^
(b2 << 12) ^
(b3 << 6) ^
(b4 ^
(((byte) 0xF0 << 18) ^
((byte) 0x80 << 12) ^
((byte) 0x80 << 6) ^
((byte) 0x80 << 0))));
if (isMalformed4(b2, b3, b4) ||
// shortest form check
!Character.isSupplementaryCodePoint(uc)) {
if (malformedInputAction() != CodingErrorAction.REPLACE)
return -1;
da[dp++] = replacement().charAt(0);
sp -= 4;
bb = getByteBuffer(bb, sa, sp);
sp += malformedN(bb, 4).length();
} else {
da[dp++] = Character.highSurrogate(uc);
da[dp++] = Character.lowSurrogate(uc);
}
continue;
}
if (malformedInputAction() != CodingErrorAction.REPLACE)
return -1;
b1 &= 0xff;
if (b1 > 0xf4 ||
sp < sl && isMalformed4_2(b1, sa[sp] & 0xff)) {
da[dp++] = replacement().charAt(0);
continue;
}
sp++;
if (sp < sl && isMalformed4_3(sa[sp])) {
da[dp++] = replacement().charAt(0);
continue;
}
da[dp++] = replacement().charAt(0);
return dp;
} else {
if (malformedInputAction() != CodingErrorAction.REPLACE)
return -1;
da[dp++] = replacement().charAt(0);
}
}
return dp;
}
public boolean isASCIICompatible() {
return true;
}
}
private static final class Encoder extends CharsetEncoder
implements ArrayEncoder {
private static final class Encoder extends CharsetEncoder {
private Encoder(Charset cs) {
super(cs, 1.1f, 3.0f);
@ -699,58 +566,5 @@ public final class UTF_8 extends Unicode {
return encodeBufferLoop(src, dst);
}
private byte repl = (byte)'?';
protected void implReplaceWith(byte[] newReplacement) {
repl = newReplacement[0];
}
// returns -1 if there is malformed char(s) and the
// "action" for malformed input is not REPLACE.
public int encode(char[] sa, int sp, int len, byte[] da) {
int sl = sp + len;
int dp = 0;
int dlASCII = dp + Math.min(len, da.length);
// ASCII only optimized loop
while (dp < dlASCII && sa[sp] < '\u0080')
da[dp++] = (byte) sa[sp++];
while (sp < sl) {
char c = sa[sp++];
if (c < 0x80) {
// Have at most seven bits
da[dp++] = (byte)c;
} else if (c < 0x800) {
// 2 bytes, 11 bits
da[dp++] = (byte)(0xc0 | (c >> 6));
da[dp++] = (byte)(0x80 | (c & 0x3f));
} else if (Character.isSurrogate(c)) {
if (sgp == null)
sgp = new Surrogate.Parser();
int uc = sgp.parse(c, sa, sp - 1, sl);
if (uc < 0) {
if (malformedInputAction() != CodingErrorAction.REPLACE)
return -1;
da[dp++] = repl;
} else {
da[dp++] = (byte)(0xf0 | ((uc >> 18)));
da[dp++] = (byte)(0x80 | ((uc >> 12) & 0x3f));
da[dp++] = (byte)(0x80 | ((uc >> 6) & 0x3f));
da[dp++] = (byte)(0x80 | (uc & 0x3f));
sp++; // 2 chars
}
} else {
// 3 bytes, 16 bits
da[dp++] = (byte)(0xe0 | ((c >> 12)));
da[dp++] = (byte)(0x80 | ((c >> 6) & 0x3f));
da[dp++] = (byte)(0x80 | (c & 0x3f));
}
}
return dp;
}
public boolean isASCIICompatible() {
return true;
}
}
}

View File

@ -0,0 +1,106 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.cldr;
import static sun.util.locale.provider.LocaleProviderAdapter.Type;
import java.util.Arrays;
import java.util.Map;
import java.util.Locale;
import java.util.Set;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import sun.util.locale.provider.LocaleProviderAdapter;
import sun.util.locale.provider.LocaleResources;
import sun.util.locale.provider.CalendarDataProviderImpl;
import sun.util.locale.provider.CalendarDataUtility;
/**
* Concrete implementation of the
* {@link java.util.spi.CalendarDataProvider CalendarDataProvider} class
* for the CLDR LocaleProviderAdapter.
*
* @author Naoto Sato
*/
public class CLDRCalendarDataProviderImpl extends CalendarDataProviderImpl {
private static Map<String, Integer> firstDay = new ConcurrentHashMap<>();
private static Map<String, Integer> minDays = new ConcurrentHashMap<>();
public CLDRCalendarDataProviderImpl(Type type, Set<String> langtags) {
super(type, langtags);
}
@Override
public int getFirstDayOfWeek(Locale locale) {
return findValue(CalendarDataUtility.FIRST_DAY_OF_WEEK, locale);
}
@Override
public int getMinimalDaysInFirstWeek(Locale locale) {
return findValue(CalendarDataUtility.MINIMAL_DAYS_IN_FIRST_WEEK, locale);
}
/**
* Finds the requested integer value for the locale.
* Each resource consists of the following:
*
* (n: cc1 cc2 ... ccx;)*
*
* where 'n' is the integer for the following region codes, terminated by
* a ';'.
*
*/
private static int findValue(String key, Locale locale) {
Map<String, Integer> map = CalendarDataUtility.FIRST_DAY_OF_WEEK.equals(key) ?
firstDay : minDays;
String region = locale.getCountry();
if (region.isEmpty()) {
return 0;
}
Integer val = map.get(region);
if (val == null) {
String valStr =
LocaleProviderAdapter.forType(Type.CLDR).getLocaleResources(Locale.ROOT)
.getCalendarData(key);
val = retrieveInteger(valStr, region)
.orElse(retrieveInteger(valStr, "001").orElse(0));
map.putIfAbsent(region, val);
}
return val;
}
private static Optional<Integer> retrieveInteger(String src, String region) {
return Arrays.stream(src.split(";"))
.filter(entry -> entry.contains(region))
.map(entry -> entry.substring(0, entry.indexOf(":")))
.findAny()
.map(Integer::parseInt);
}
}

View File

@ -27,6 +27,7 @@ package sun.util.cldr;
import java.security.AccessController;
import java.security.AccessControlException;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.text.spi.BreakIteratorProvider;
@ -37,15 +38,16 @@ import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.ServiceConfigurationError;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import java.util.spi.CalendarDataProvider;
import sun.util.locale.provider.JRELocaleProviderAdapter;
import sun.util.locale.provider.LocaleProviderAdapter;
import sun.util.locale.provider.LocaleDataMetaInfo;
import sun.util.locale.provider.LocaleProviderAdapter;
/**
* LocaleProviderAdapter implementation for the CLDR locale data.
@ -105,6 +107,24 @@ public class CLDRLocaleProviderAdapter extends JRELocaleProviderAdapter {
return null;
}
@Override
public CalendarDataProvider getCalendarDataProvider() {
if (calendarDataProvider == null) {
CalendarDataProvider provider = AccessController.doPrivileged(
(PrivilegedAction<CalendarDataProvider>) () ->
new CLDRCalendarDataProviderImpl(
getAdapterType(),
getLanguageTagSet("CalendarData")));
synchronized (this) {
if (calendarDataProvider == null) {
calendarDataProvider = provider;
}
}
}
return calendarDataProvider;
}
@Override
public CollatorProvider getCollatorProvider() {
return null;
@ -123,6 +143,10 @@ public class CLDRLocaleProviderAdapter extends JRELocaleProviderAdapter {
@Override
protected Set<String> createLanguageTagSet(String category) {
// Assume all categories support the same set as AvailableLocales
// in CLDR adapter.
category = "AvailableLocales";
// Directly call Base tags, as we know it's in the base module.
String supportedLocaleString = baseMetaInfo.availableLanguageTags(category);
String nonBaseTags = null;
@ -220,4 +244,11 @@ public class CLDRLocaleProviderAdapter extends JRELocaleProviderAdapter {
|| langtags.contains(locale.stripExtensions().toLanguageTag())
|| langtags.contains(getEquivalentLoc(locale).toLanguageTag());
}
/**
* Returns the time zone ID from an LDML's short ID
*/
public Optional<String> getTimeZoneID(String shortID) {
return Optional.ofNullable(baseMetaInfo.tzShortIDs().get(shortID));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -46,14 +46,16 @@ public class CalendarDataProviderImpl extends CalendarDataProvider implements Av
@Override
public int getFirstDayOfWeek(Locale locale) {
return LocaleProviderAdapter.forType(type).getLocaleResources(locale)
String fw = LocaleProviderAdapter.forType(type).getLocaleResources(locale)
.getCalendarData(CalendarDataUtility.FIRST_DAY_OF_WEEK);
return convertToCalendarData(fw);
}
@Override
public int getMinimalDaysInFirstWeek(Locale locale) {
return LocaleProviderAdapter.forType(type).getLocaleResources(locale)
String md = LocaleProviderAdapter.forType(type).getLocaleResources(locale)
.getCalendarData(CalendarDataUtility.MINIMAL_DAYS_IN_FIRST_WEEK);
return convertToCalendarData(md);
}
@Override
@ -65,4 +67,9 @@ public class CalendarDataProviderImpl extends CalendarDataProvider implements Av
public Set<String> getAvailableLanguageTags() {
return langtags;
}
private int convertToCalendarData(String src) {
int val = Integer.parseInt(src);
return (src.isEmpty() || val <= 0 || val > 7) ? 0 : val;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -47,10 +47,34 @@ public class CalendarDataUtility {
}
public static int retrieveFirstDayOfWeek(Locale locale) {
// Look for the Unicode Extension in the locale parameter
if (locale.hasExtensions()) {
String fw = locale.getUnicodeLocaleType("fw");
if (fw != null) {
switch (fw.toLowerCase(Locale.ROOT)) {
case "mon":
return MONDAY;
case "tue":
return TUESDAY;
case "wed":
return WEDNESDAY;
case "thu":
return THURSDAY;
case "fri":
return FRIDAY;
case "sat":
return SATURDAY;
case "sun":
return SUNDAY;
}
}
}
LocaleServiceProviderPool pool =
LocaleServiceProviderPool.getPool(CalendarDataProvider.class);
Integer value = pool.getLocalizedObject(CalendarWeekParameterGetter.INSTANCE,
locale, true, FIRST_DAY_OF_WEEK);
findRegionOverride(locale),
true, FIRST_DAY_OF_WEEK);
return (value != null && (value >= SUNDAY && value <= SATURDAY)) ? value : SUNDAY;
}
@ -58,7 +82,8 @@ public class CalendarDataUtility {
LocaleServiceProviderPool pool =
LocaleServiceProviderPool.getPool(CalendarDataProvider.class);
Integer value = pool.getLocalizedObject(CalendarWeekParameterGetter.INSTANCE,
locale, true, MINIMAL_DAYS_IN_FIRST_WEEK);
findRegionOverride(locale),
true, MINIMAL_DAYS_IN_FIRST_WEEK);
return (value != null && (value >= 1 && value <= 7)) ? value : 1;
}
@ -102,6 +127,32 @@ public class CalendarDataUtility {
return map;
}
/**
* Utility to look for a region override extension.
* If no region override is found, returns the original locale.
*/
public static Locale findRegionOverride(Locale l) {
String rg = l.getUnicodeLocaleType("rg");
Locale override = l;
if (rg != null && rg.length() == 6) {
// UN M.49 code should not be allowed here
// cannot use regex here, as it could be a recursive call
rg = rg.toUpperCase(Locale.ROOT);
if (rg.charAt(0) >= 0x0041 &&
rg.charAt(0) <= 0x005A &&
rg.charAt(1) >= 0x0041 &&
rg.charAt(1) <= 0x005A &&
rg.substring(2).equals("ZZZZ")) {
override = new Locale.Builder().setLocale(l)
.setRegion(rg.substring(0, 2))
.build();
}
}
return override;
}
static String normalizeCalendarType(String requestID) {
String type;
if (requestID.equals("gregorian") || requestID.equals("iso8601")) {
@ -179,7 +230,7 @@ public class CalendarDataUtility {
}
}
private static class CalendarWeekParameterGetter
private static class CalendarWeekParameterGetter
implements LocaleServiceProviderPool.LocalizedObjectGetter<CalendarDataProvider,
Integer> {
private static final CalendarWeekParameterGetter INSTANCE =

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -32,6 +32,7 @@ import java.util.Calendar;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.Set;
import java.util.TimeZone;
/**
* Concrete implementation of the {@link java.text.spi.DateFormatProvider
@ -147,11 +148,14 @@ public class DateFormatProviderImpl extends DateFormatProvider implements Availa
throw new NullPointerException();
}
SimpleDateFormat sdf = new SimpleDateFormat("", locale);
// Check for region override
Locale rg = CalendarDataUtility.findRegionOverride(locale);
SimpleDateFormat sdf = new SimpleDateFormat("", rg);
Calendar cal = sdf.getCalendar();
try {
String pattern = LocaleProviderAdapter.forType(type)
.getLocaleResources(locale).getDateTimePattern(timeStyle, dateStyle,
.getLocaleResources(rg).getDateTimePattern(timeStyle, dateStyle,
cal);
sdf.applyPattern(pattern);
} catch (MissingResourceException mre) {
@ -159,6 +163,15 @@ public class DateFormatProviderImpl extends DateFormatProvider implements Availa
sdf.applyPattern("M/d/yy h:mm a");
}
// Check for timezone override
String tz = locale.getUnicodeLocaleType("tz");
if (tz != null) {
sdf.setTimeZone(
TimeZoneNameUtility.convertLDMLShortID(tz)
.map(TimeZone::getTimeZone)
.orElseGet(sdf::getTimeZone));
}
return sdf;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -130,7 +130,7 @@ public class JRELocaleProviderAdapter extends LocaleProviderAdapter implements R
private volatile CurrencyNameProvider currencyNameProvider;
private volatile LocaleNameProvider localeNameProvider;
private volatile TimeZoneNameProvider timeZoneNameProvider;
private volatile CalendarDataProvider calendarDataProvider;
protected volatile CalendarDataProvider calendarDataProvider;
private volatile CalendarNameProvider calendarNameProvider;
private volatile CalendarProvider calendarProvider;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,6 +25,8 @@
package sun.util.locale.provider;
import java.util.Map;
/**
* LocaleData meta info SPI
*
@ -46,4 +48,13 @@ public interface LocaleDataMetaInfo {
* @return concatenated language tags, separated by a space.
*/
public String availableLanguageTags(String category);
/**
* Returns a map for short time zone ids in BCP47 Unicode extension and
* the long time zone ids.
* @return map of short id to long ids, separated by a space.
*/
default public Map<String, String> tzShortIDs() {
return null;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -168,6 +168,28 @@ public class LocaleNameProviderImpl extends LocaleNameProvider implements Availa
return getDisplayString("%%"+vrnt, locale);
}
/**
* @inheritDoc
*/
@Override
public String getDisplayUnicodeExtensionKey(String key, Locale locale) {
super.getDisplayUnicodeExtensionKey(key, locale); // null check
String rbKey = "key." + key;
String name = getDisplayString(rbKey, locale);
return rbKey.equals(name) ? key : name;
}
/**
* @inheritDoc
*/
@Override
public String getDisplayUnicodeExtensionType(String extType, String key, Locale locale) {
super.getDisplayUnicodeExtensionType(extType, key, locale); // null check
String rbKey = "type." + key + "." + extType;
String name = getDisplayString(rbKey, locale);
return rbKey.equals(name) ? extType : name;
}
private String getDisplayString(String key, Locale locale) {
if (key == null || locale == null) {
throw new NullPointerException();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -122,23 +122,21 @@ public class LocaleResources {
return (byte[]) localeData.getBreakIteratorResources(locale).getObject(key);
}
int getCalendarData(String key) {
Integer caldata;
public String getCalendarData(String key) {
String caldata = "";
String cacheKey = CALENDAR_DATA + key;
removeEmptyReferences();
ResourceReference data = cache.get(cacheKey);
if (data == null || ((caldata = (Integer) data.get()) == null)) {
if (data == null || ((caldata = (String) data.get()) == null)) {
ResourceBundle rb = localeData.getCalendarData(locale);
if (rb.containsKey(key)) {
caldata = Integer.parseInt(rb.getString(key));
} else {
caldata = 0;
caldata = rb.getString(key);
}
cache.put(cacheKey,
new ResourceReference(cacheKey, (Object) caldata, referenceQueue));
new ResourceReference(cacheKey, caldata, referenceQueue));
}
return caldata;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -173,9 +173,14 @@ public class NumberFormatProviderImpl extends NumberFormatProvider implements Av
throw new NullPointerException();
}
// Check for region override
Locale override = locale.getUnicodeLocaleType("nu") == null ?
CalendarDataUtility.findRegionOverride(locale) :
locale;
LocaleProviderAdapter adapter = LocaleProviderAdapter.forType(type);
String[] numberPatterns = adapter.getLocaleResources(locale).getNumberPatterns();
DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(locale);
String[] numberPatterns = adapter.getLocaleResources(override).getNumberPatterns();
DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(override);
int entry = (choice == INTEGERSTYLE) ? NUMBERSTYLE : choice;
DecimalFormat format = new DecimalFormat(numberPatterns[entry], symbols);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -160,28 +160,24 @@ public class SPILocaleProviderAdapter extends AuxLocaleProviderAdapter {
@Override
public BreakIterator getWordInstance(Locale locale) {
BreakIteratorProvider bip = getImpl(locale);
assert bip != null;
return bip.getWordInstance(locale);
}
@Override
public BreakIterator getLineInstance(Locale locale) {
BreakIteratorProvider bip = getImpl(locale);
assert bip != null;
return bip.getLineInstance(locale);
}
@Override
public BreakIterator getCharacterInstance(Locale locale) {
BreakIteratorProvider bip = getImpl(locale);
assert bip != null;
return bip.getCharacterInstance(locale);
}
@Override
public BreakIterator getSentenceInstance(Locale locale) {
BreakIteratorProvider bip = getImpl(locale);
assert bip != null;
return bip.getSentenceInstance(locale);
}
@ -215,7 +211,6 @@ public class SPILocaleProviderAdapter extends AuxLocaleProviderAdapter {
@Override
public Collator getInstance(Locale locale) {
CollatorProvider cp = getImpl(locale);
assert cp != null;
return cp.getInstance(locale);
}
}
@ -249,21 +244,18 @@ public class SPILocaleProviderAdapter extends AuxLocaleProviderAdapter {
@Override
public DateFormat getTimeInstance(int style, Locale locale) {
DateFormatProvider dfp = getImpl(locale);
assert dfp != null;
return dfp.getTimeInstance(style, locale);
}
@Override
public DateFormat getDateInstance(int style, Locale locale) {
DateFormatProvider dfp = getImpl(locale);
assert dfp != null;
return dfp.getDateInstance(style, locale);
}
@Override
public DateFormat getDateTimeInstance(int dateStyle, int timeStyle, Locale locale) {
DateFormatProvider dfp = getImpl(locale);
assert dfp != null;
return dfp.getDateTimeInstance(dateStyle, timeStyle, locale);
}
}
@ -297,7 +289,6 @@ public class SPILocaleProviderAdapter extends AuxLocaleProviderAdapter {
@Override
public DateFormatSymbols getInstance(Locale locale) {
DateFormatSymbolsProvider dfsp = getImpl(locale);
assert dfsp != null;
return dfsp.getInstance(locale);
}
}
@ -331,7 +322,6 @@ public class SPILocaleProviderAdapter extends AuxLocaleProviderAdapter {
@Override
public DecimalFormatSymbols getInstance(Locale locale) {
DecimalFormatSymbolsProvider dfsp = getImpl(locale);
assert dfsp != null;
return dfsp.getInstance(locale);
}
}
@ -365,28 +355,24 @@ public class SPILocaleProviderAdapter extends AuxLocaleProviderAdapter {
@Override
public NumberFormat getCurrencyInstance(Locale locale) {
NumberFormatProvider nfp = getImpl(locale);
assert nfp != null;
return nfp.getCurrencyInstance(locale);
}
@Override
public NumberFormat getIntegerInstance(Locale locale) {
NumberFormatProvider nfp = getImpl(locale);
assert nfp != null;
return nfp.getIntegerInstance(locale);
}
@Override
public NumberFormat getNumberInstance(Locale locale) {
NumberFormatProvider nfp = getImpl(locale);
assert nfp != null;
return nfp.getNumberInstance(locale);
}
@Override
public NumberFormat getPercentInstance(Locale locale) {
NumberFormatProvider nfp = getImpl(locale);
assert nfp != null;
return nfp.getPercentInstance(locale);
}
}
@ -420,14 +406,12 @@ public class SPILocaleProviderAdapter extends AuxLocaleProviderAdapter {
@Override
public int getFirstDayOfWeek(Locale locale) {
CalendarDataProvider cdp = getImpl(locale);
assert cdp != null;
return cdp.getFirstDayOfWeek(locale);
}
@Override
public int getMinimalDaysInFirstWeek(Locale locale) {
CalendarDataProvider cdp = getImpl(locale);
assert cdp != null;
return cdp.getMinimalDaysInFirstWeek(locale);
}
}
@ -463,7 +447,6 @@ public class SPILocaleProviderAdapter extends AuxLocaleProviderAdapter {
int field, int value,
int style, Locale locale) {
CalendarNameProvider cdp = getImpl(locale);
assert cdp != null;
return cdp.getDisplayName(calendarType, field, value, style, locale);
}
@ -472,7 +455,6 @@ public class SPILocaleProviderAdapter extends AuxLocaleProviderAdapter {
int field, int style,
Locale locale) {
CalendarNameProvider cdp = getImpl(locale);
assert cdp != null;
return cdp.getDisplayNames(calendarType, field, style, locale);
}
}
@ -506,14 +488,12 @@ public class SPILocaleProviderAdapter extends AuxLocaleProviderAdapter {
@Override
public String getSymbol(String currencyCode, Locale locale) {
CurrencyNameProvider cnp = getImpl(locale);
assert cnp != null;
return cnp.getSymbol(currencyCode, locale);
}
@Override
public String getDisplayName(String currencyCode, Locale locale) {
CurrencyNameProvider cnp = getImpl(locale);
assert cnp != null;
return cnp.getDisplayName(currencyCode, locale);
}
}
@ -547,30 +527,38 @@ public class SPILocaleProviderAdapter extends AuxLocaleProviderAdapter {
@Override
public String getDisplayLanguage(String languageCode, Locale locale) {
LocaleNameProvider lnp = getImpl(locale);
assert lnp != null;
return lnp.getDisplayLanguage(languageCode, locale);
}
@Override
public String getDisplayScript(String scriptCode, Locale locale) {
LocaleNameProvider lnp = getImpl(locale);
assert lnp != null;
return lnp.getDisplayScript(scriptCode, locale);
}
@Override
public String getDisplayCountry(String countryCode, Locale locale) {
LocaleNameProvider lnp = getImpl(locale);
assert lnp != null;
return lnp.getDisplayCountry(countryCode, locale);
}
@Override
public String getDisplayVariant(String variant, Locale locale) {
LocaleNameProvider lnp = getImpl(locale);
assert lnp != null;
return lnp.getDisplayVariant(variant, locale);
}
@Override
public String getDisplayUnicodeExtensionKey(String key, Locale locale) {
LocaleNameProvider lnp = getImpl(locale);
return lnp.getDisplayUnicodeExtensionKey(key, locale);
}
@Override
public String getDisplayUnicodeExtensionType(String extType, String key, Locale locale) {
LocaleNameProvider lnp = getImpl(locale);
return lnp.getDisplayUnicodeExtensionType(extType, key, locale);
}
}
static class TimeZoneNameProviderDelegate extends TimeZoneNameProvider
@ -602,14 +590,12 @@ public class SPILocaleProviderAdapter extends AuxLocaleProviderAdapter {
@Override
public String getDisplayName(String ID, boolean daylight, int style, Locale locale) {
TimeZoneNameProvider tznp = getImpl(locale);
assert tznp != null;
return tznp.getDisplayName(ID, daylight, style, locale);
}
@Override
public String getGenericDisplayName(String ID, int style, Locale locale) {
TimeZoneNameProvider tznp = getImpl(locale);
assert tznp != null;
return tznp.getGenericDisplayName(ID, style, locale);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -31,10 +31,13 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.spi.TimeZoneNameProvider;
import sun.util.calendar.ZoneInfo;
import sun.util.cldr.CLDRLocaleProviderAdapter;
import static sun.util.locale.provider.LocaleProviderAdapter.Type;
/**
* Utility class that deals with the localized time zone names
@ -152,6 +155,18 @@ public final class TimeZoneNameUtility {
}
}
/**
* Converts the time zone id from LDML's 5-letter id to tzdb's id
*
* @param shortID time zone short ID defined in LDML
* @return the tzdb's time zone ID
*/
public static Optional<String> convertLDMLShortID(String shortID) {
return ((CLDRLocaleProviderAdapter)LocaleProviderAdapter.forType(Type.CLDR))
.getTimeZoneID(shortID)
.map(id -> id.replaceAll("\\s.*", ""));
}
private static String[] retrieveDisplayNamesImpl(String id, Locale locale) {
LocaleServiceProviderPool pool =
LocaleServiceProviderPool.getPool(TimeZoneNameProvider.class);

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@ -1164,8 +1164,7 @@ ZW=Zimbabwe
# locale name patterns
# rarely localized
DisplayNamePattern={0,choice,0#|1#{1}|2#{1} ({2})}
ListPattern={0,choice,0#|1#{1}|2#{1},{2}|3#{1},{2},{3}}
ListKeyTypePattern={0}:{1}
ListCompositionPattern={0},{1}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -179,7 +179,7 @@ Java_sun_nio_ch_SocketDispatcher_write0(JNIEnv *env, jclass clazz, jobject fdo,
}
}
count += written;
count += (jint)written;
address += written;
} while ((count < total) && (written == MAX_BUFFER_SIZE));

View File

@ -51,12 +51,13 @@ import org.w3c.dom.DOMException;
* binding-specific casting methods on an instance of the
* <code>DOMImplementation</code> interface or, if the <code>Document</code>
* supports the feature <code>"Core"</code> version <code>"3.0"</code>
* defined in [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>]
* defined in
* [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>]
* , by using the method <code>DOMImplementation.getFeature</code> with
* parameter values <code>"LS"</code> (or <code>"LS-Async"</code>) and
* <code>"3.0"</code> (respectively).
* <p>See also the <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407'>Document Object Model (DOM) Level 3 Load
and Save Specification</a>.
* <p>See also the <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407'>
Document Object Model (DOM) Level 3 Load and Save Specification</a>.
*
* @since 1.5
*/
@ -90,9 +91,11 @@ public interface DOMImplementationLS {
* <code>LSParser</code> for any kind of schema types (i.e. the
* LSParser will be free to use any schema found), use the value
* <code>null</code>.
* <p ><b>Note:</b> For W3C XML Schema [<a href='http://www.w3.org/TR/2001/REC-xmlschema-1-20010502/'>XML Schema Part 1</a>]
* <p ><b>Note:</b> For W3C XML Schema
* [<a href='http://www.w3.org/TR/2001/REC-xmlschema-1-20010502/'>XML Schema Part 1</a>]
* , applications must use the value
* <code>"http://www.w3.org/2001/XMLSchema"</code>. For XML DTD [<a href='http://www.w3.org/TR/2004/REC-xml-20040204'>XML 1.0</a>],
* <code>"http://www.w3.org/2001/XMLSchema"</code>. For XML DTD
* [<a href='http://www.w3.org/TR/2004/REC-xml-20040204'>XML 1.0</a>],
* applications must use the value
* <code>"http://www.w3.org/TR/REC-xml"</code>. Other Schema languages
* are outside the scope of the W3C and therefore should recommend an
@ -102,8 +105,8 @@ public interface DOMImplementationLS {
* depending on the value of the <code>mode</code> argument.
* <p ><b>Note:</b> By default, the newly created <code>LSParser</code>
* does not contain a <code>DOMErrorHandler</code>, i.e. the value of
* the "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-error-handler'>
* error-handler</a>" configuration parameter is <code>null</code>. However, implementations
* the "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-error-handler'>error-handler</a>"
* configuration parameter is <code>null</code>. However, implementations
* may provide a default error handler at creation time. In that case,
* the initial value of the <code>"error-handler"</code> configuration
* parameter on the new <code>LSParser</code> object contains a

View File

@ -53,7 +53,8 @@ import org.w3c.dom.DOMException;
* corresponding DOM document structure. A <code>LSParser</code> instance
* can be obtained by invoking the
* <code>DOMImplementationLS.createLSParser()</code> method.
* <p> As specified in [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>]
* <p> As specified in
* [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>]
* , when a document is first made available via the LSParser:
* <ul>
* <li> there will
@ -63,16 +64,18 @@ import org.w3c.dom.DOMException;
* <li> it is expected that the <code>value</code> and
* <code>nodeValue</code> attributes of an <code>Attr</code> node initially
* return the <a href='http://www.w3.org/TR/2004/REC-xml-20040204#AVNormalize'>XML 1.0
* normalized value</a>. However, if the parameters "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-validate-if-schema'>
* validate-if-schema</a>" and "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-datatype-normalization'>
* datatype-normalization</a>" are set to <code>true</code>, depending on the attribute normalization
* normalized value</a>. However, if the parameters
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-validate-if-schema'>validate-if-schema</a>" and
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-datatype-normalization'>datatype-normalization</a>"
* are set to <code>true</code>, depending on the attribute normalization
* used, the attribute values may differ from the ones obtained by the XML
* 1.0 attribute normalization. If the parameters "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-datatype-normalization'>
* datatype-normalization</a>" is set to <code>false</code>, the XML 1.0 attribute normalization is
* 1.0 attribute normalization. If the parameters
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-datatype-normalization'>datatype-normalization</a>"
* is set to <code>false</code>, the XML 1.0 attribute normalization is
* guaranteed to occur, and if the attributes list does not contain
* namespace declarations, the <code>attributes</code> attribute on
* <code>Element</code> node represents the property <b>[attributes]</b> defined in [<a href='http://www.w3.org/TR/2004/REC-xml-infoset-20040204/'>XML Information Set</a>]
* .
* <code>Element</code> node represents the property <b>[attributes]</b> defined in
* [<a href='http://www.w3.org/TR/2004/REC-xml-infoset-20040204/'>XML Information Set</a>].
* </li>
* </ul>
* <p> Asynchronous <code>LSParser</code> objects are expected to also
@ -102,17 +105,18 @@ import org.w3c.dom.DOMException;
* <p ><b>Note:</b> All events defined in this specification use the
* namespace URI <code>"http://www.w3.org/2002/DOMLS"</code>.
* <p> While parsing an input source, errors are reported to the application
* through the error handler (<code>LSParser.domConfig</code>'s "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-error-handler'>
* error-handler</a>" parameter). This specification does in no way try to define all possible
* through the error handler (<code>LSParser.domConfig</code>'s
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-error-handler'>error-handler</a>"
* parameter). This specification does in no way try to define all possible
* errors that can occur while parsing XML, or any other markup, but some
* common error cases are defined. The types (<code>DOMError.type</code>) of
* errors and warnings defined by this specification are:
* <dl>
* <dt>
* <code>"check-character-normalization-failure" [error]</code> </dt>
* <dd> Raised if
* the parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-check-character-normalization'>
* check-character-normalization</a>" is set to true and a string is encountered that fails normalization
* <dd> Raised if the parameter
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-check-character-normalization'>check-character-normalization</a>"
* is set to true and a string is encountered that fails normalization
* checking. </dd>
* <dt><code>"doctype-not-allowed" [fatal]</code></dt>
* <dd> Raised if the
@ -127,8 +131,9 @@ import org.w3c.dom.DOMException;
* <dd> Raised if a processing
* instruction is encountered in a location where the base URI of the
* processing instruction can not be preserved. One example of a case where
* this warning will be raised is if the configuration parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-entities'>
* entities</a>" is set to <code>false</code> and the following XML file is parsed:
* this warning will be raised is if the configuration parameter
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-entities'>entities</a>"
* is set to <code>false</code> and the following XML file is parsed:
* <pre>
* &lt;!DOCTYPE root [ &lt;!ENTITY e SYSTEM 'subdir/myentity.ent' ]&gt;
* &lt;root&gt; &amp;e; &lt;/root&gt;</pre>
@ -139,9 +144,9 @@ import org.w3c.dom.DOMException;
* </dd>
* <dt><code>"unbound-prefix-in-entity" [warning]</code></dt>
* <dd> An
* implementation dependent warning that may be raised if the configuration
* parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-namespaces'>
* namespaces</a>" is set to <code>true</code> and an unbound namespace prefix is
* implementation dependent warning that may be raised if the configuration parameter
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-namespaces'>namespaces</a>"
* is set to <code>true</code> and an unbound namespace prefix is
* encountered in an entity's replacement text. Raising this warning is not
* enforced since some existing parsers may not recognize unbound namespace
* prefixes in the replacement text of entities. </dd>
@ -164,8 +169,8 @@ import org.w3c.dom.DOMException;
* are expected to raise implementation specific errors and warnings for any
* other error and warning cases such as IO errors (file not found,
* permission denied,...), XML well-formedness errors, and so on.
* <p>See also the <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407'>Document Object Model (DOM) Level 3 Load
and Save Specification</a>.
* <p>See also the
* <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407'>Document Object Model (DOM) Level 3 Load and Save Specification</a>.
*
* @since 1.5
*/
@ -180,8 +185,10 @@ public interface LSParser {
* needed parameter values from this <code>DOMConfiguration</code>
* object to the <code>DOMConfiguration</code> object referenced by the
* <code>Document</code> object.
* <br> In addition to the parameters recognized in on the <a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#DOMConfiguration'>
* DOMConfiguration</a> interface defined in [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>]
* <br> In addition to the parameters recognized in on the
* <a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#DOMConfiguration'>DOMConfiguration</a>
* interface defined in
* [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>]
* , the <code>DOMConfiguration</code> objects for <code>LSParser</code>
* add or modify the following parameters:
* <dl>
@ -190,7 +197,8 @@ public interface LSParser {
* <dd>
* <dl>
* <dt><code>true</code></dt>
* <dd>[<em>optional</em>] (<em>default</em>) If a higher level protocol such as HTTP [<a href='http://www.ietf.org/rfc/rfc2616.txt'>IETF RFC 2616</a>] provides an
* <dd>[<em>optional</em>] (<em>default</em>) If a higher level protocol such as HTTP
* [<a href='http://www.ietf.org/rfc/rfc2616.txt'>IETF RFC 2616</a>] provides an
* indication of the character encoding of the input stream being
* processed, that will override any encoding specified in the XML
* declaration or the Text declaration (see also section 4.3.3,
@ -206,7 +214,8 @@ public interface LSParser {
* <dl>
* <dt>
* <code>true</code></dt>
* <dd>[<em>optional</em>] Throw a fatal <b>"doctype-not-allowed"</b> error if a doctype node is found while parsing the document. This is
* <dd>[<em>optional</em>] Throw a fatal <b>"doctype-not-allowed"</b> error
* if a doctype node is found while parsing the document. This is
* useful when dealing with things like SOAP envelopes where doctype
* nodes are not allowed. </dd>
* <dt><code>false</code></dt>
@ -218,14 +227,17 @@ public interface LSParser {
* <dl>
* <dt>
* <code>true</code></dt>
* <dd>[<em>required</em>] (<em>default</em>) If, while verifying full normalization when [<a href='http://www.w3.org/TR/2004/REC-xml11-20040204/'>XML 1.1</a>] is
* <dd>[<em>required</em>] (<em>default</em>) If, while verifying full normalization when
* [<a href='http://www.w3.org/TR/2004/REC-xml11-20040204/'>XML 1.1</a>] is
* supported, a processor encounters characters for which it cannot
* determine the normalization properties, then the processor will
* ignore any possible denormalizations caused by these characters.
* This parameter is ignored for [<a href='http://www.w3.org/TR/2004/REC-xml-20040204'>XML 1.0</a>]. </dd>
* This parameter is ignored for [<a href='http://www.w3.org/TR/2004/REC-xml-20040204'>XML 1.0</a>].
* </dd>
* <dt>
* <code>false</code></dt>
* <dd>[<em>optional</em>] Report an fatal <b>"unknown-character-denormalization"</b> error if a character is encountered for which the processor cannot
* <dd>[<em>optional</em>] Report an fatal <b>"unknown-character-denormalization"</b>
* error if a character is encountered for which the processor cannot
* determine the normalization properties. </dd>
* </dl></dd>
* <dt><code>"infoset"</code></dt>
@ -238,7 +250,8 @@ public interface LSParser {
* <dd>
* <dl>
* <dt><code>true</code></dt>
* <dd>[<em>required</em>] (<em>default</em>) Perform the namespace processing as defined in [<a href='http://www.w3.org/TR/1999/REC-xml-names-19990114/'>XML Namespaces</a>]
* <dd>[<em>required</em>] (<em>default</em>) Perform the namespace processing as defined in
* [<a href='http://www.w3.org/TR/1999/REC-xml-names-19990114/'>XML Namespaces</a>]
* and [<a href='http://www.w3.org/TR/2004/REC-xml-names11-20040204/'>XML Namespaces 1.1</a>]
* . </dd>
* <dt><code>false</code></dt>
@ -259,7 +272,8 @@ public interface LSParser {
* <code>true</code></dt>
* <dd>[<em>optional</em>] Check that the media type of the parsed resource is a supported media
* type. If an unsupported media type is encountered, a fatal error of
* type <b>"unsupported-media-type"</b> will be raised. The media types defined in [<a href='http://www.ietf.org/rfc/rfc3023.txt'>IETF RFC 3023</a>] must always
* type <b>"unsupported-media-type"</b> will be raised. The media types defined in
* [<a href='http://www.ietf.org/rfc/rfc3023.txt'>IETF RFC 3023</a>] must always
* be accepted. </dd>
* <dt><code>false</code></dt>
* <dd>[<em>required</em>] (<em>default</em>) Accept any media type. </dd>
@ -294,8 +308,8 @@ public interface LSParser {
* terminate the parsing early.
* <br> The filter is invoked after the operations requested by the
* <code>DOMConfiguration</code> parameters have been applied. For
* example, if "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-validate'>
* validate</a>" is set to <code>true</code>, the validation is done before invoking the
* example, if "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-validate'>validate</a>"
* is set to <code>true</code>, the validation is done before invoking the
* filter.
*/
public LSParserFilter getFilter();
@ -306,8 +320,8 @@ public interface LSParser {
* terminate the parsing early.
* <br> The filter is invoked after the operations requested by the
* <code>DOMConfiguration</code> parameters have been applied. For
* example, if "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-validate'>
* validate</a>" is set to <code>true</code>, the validation is done before invoking the
* example, if "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-validate'>validate</a>"
* is set to <code>true</code>, the validation is done before invoking the
* filter.
*/
public void setFilter(LSParserFilter filter);
@ -340,15 +354,18 @@ public interface LSParser {
* @exception LSException
* PARSE_ERR: Raised if the <code>LSParser</code> was unable to load
* the XML document. DOM applications should attach a
* <code>DOMErrorHandler</code> using the parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-error-handler'>
* error-handler</a>" if they wish to get details on the error.
* <code>DOMErrorHandler</code> using the parameter
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-error-handler'>error-handler</a>"
* if they wish to get details on the error.
*/
public Document parse(LSInput input)
throws DOMException, LSException;
/**
* Parse an XML document from a location identified by a URI reference [<a href='http://www.ietf.org/rfc/rfc2396.txt'>IETF RFC 2396</a>]. If the URI
* contains a fragment identifier (see section 4.1 in [<a href='http://www.ietf.org/rfc/rfc2396.txt'>IETF RFC 2396</a>]), the
* Parse an XML document from a location identified by a URI reference
* [<a href='http://www.ietf.org/rfc/rfc2396.txt'>IETF RFC 2396</a>]. If the URI
* contains a fragment identifier (see section 4.1 in
* [<a href='http://www.ietf.org/rfc/rfc2396.txt'>IETF RFC 2396</a>]), the
* behavior is not defined by this specification, future versions of
* this specification may define the behavior.
* @param uri The location of the XML document to be read.
@ -364,8 +381,9 @@ public interface LSParser {
* @exception LSException
* PARSE_ERR: Raised if the <code>LSParser</code> was unable to load
* the XML document. DOM applications should attach a
* <code>DOMErrorHandler</code> using the parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-error-handler'>
* error-handler</a>" if they wish to get details on the error.
* <code>DOMErrorHandler</code> using the parameter
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-error-handler'>error-handler</a>"
* if they wish to get details on the error.
*/
public Document parseURI(String uri)
throws DOMException, LSException;
@ -431,14 +449,17 @@ public interface LSParser {
* <code>LSParser</code> is asynchronous (<code>LSParser.async</code> is
* <code>true</code>).
* <br> If an error occurs while parsing, the caller is notified through
* the <code>ErrorHandler</code> instance associated with the "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-error-handler'>
* error-handler</a>" parameter of the <code>DOMConfiguration</code>.
* the <code>ErrorHandler</code> instance associated with the
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-error-handler'>error-handler</a>"
* parameter of the <code>DOMConfiguration</code>.
* <br> When calling <code>parseWithContext</code>, the values of the
* following configuration parameters will be ignored and their default
* values will always be used instead: "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-validate'>
* validate</a>", "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-validate-if-schema'>
* validate-if-schema</a>", and "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-element-content-whitespace'>
* element-content-whitespace</a>". Other parameters will be treated normally, and the parser is expected
* values will always be used instead:
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-validate'>validate</a>",
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-validate-if-schema'>validate-if-schema</a>",
* and
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-element-content-whitespace'>element-content-whitespace</a>".
* Other parameters will be treated normally, and the parser is expected
* to call the <code>LSParserFilter</code> just as if a whole document
* was parsed.
* @param input The <code>LSInput</code> from which the source document
@ -463,7 +484,8 @@ public interface LSParser {
* @exception DOMException
* HIERARCHY_REQUEST_ERR: Raised if the content cannot replace, be
* inserted before, after, or as a child of the context node (see also
* <code>Node.insertBefore</code> or <code>Node.replaceChild</code> in [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>]
* <code>Node.insertBefore</code> or <code>Node.replaceChild</code> in
* [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>]
* ).
* <br> NOT_SUPPORTED_ERR: Raised if the <code>LSParser</code> doesn't
* support this method, or if the context node is of type
@ -479,8 +501,9 @@ public interface LSParser {
* @exception LSException
* PARSE_ERR: Raised if the <code>LSParser</code> was unable to load
* the XML fragment. DOM applications should attach a
* <code>DOMErrorHandler</code> using the parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-error-handler'>
* error-handler</a>" if they wish to get details on the error.
* <code>DOMErrorHandler</code> using the parameter
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-error-handler'>error-handler</a>"
* if they wish to get details on the error.
*/
public Node parseWithContext(LSInput input,
Node contextArg,

View File

@ -56,10 +56,11 @@ import org.w3c.dom.Element;
* <code>Document</code>, <code>DocumentType</code>, <code>Notation</code>,
* <code>Entity</code>, and <code>Attr</code> nodes are never passed to the
* <code>acceptNode</code> method on the filter. The child nodes of an
* <code>EntityReference</code> node are passed to the filter if the
* parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-entities'>
* entities</a>" is set to <code>false</code>. Note that, as described by the parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-entities'>
* entities</a>", unexpanded entity reference nodes are never discarded and are always
* <code>EntityReference</code> node are passed to the filter if the parameter
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-entities'>entities</a>"
* is set to <code>false</code>. Note that, as described by the parameter
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-entities'>entities</a>",
* unexpanded entity reference nodes are never discarded and are always
* passed to the filter.
* <p> All validity checking while parsing a document occurs on the source
* document as it appears on the input stream, not on the DOM document as it
@ -71,8 +72,8 @@ import org.w3c.dom.Element;
* passed to the filter methods.
* <p> DOM applications must not raise exceptions in a filter. The effect of
* throwing exceptions from a filter is DOM implementation dependent.
* <p>See also the <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407'>Document Object Model (DOM) Level 3 Load
and Save Specification</a>.
* <p>See also the <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407'>
Document Object Model (DOM) Level 3 Load and Save Specification</a>.
*
* @since 1.5
*/
@ -195,8 +196,8 @@ public interface LSParserFilter {
* <code>SHOW_NOTATION</code>, <code>SHOW_ENTITY</code>, and
* <code>SHOW_DOCUMENT_FRAGMENT</code> are meaningless here. Those nodes
* will never be passed to <code>LSParserFilter.acceptNode</code>.
* <br> The constants used here are defined in [<a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113'>DOM Level 2 Traversal and Range</a>]
* .
* <br> The constants used here are defined in
* [<a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113'>DOM Level 2 Traversal and Range</a>].
*/
public int getWhatToShow();

View File

@ -51,7 +51,8 @@ import org.w3c.dom.DOMException;
* output stream. Any changes or fixups made during the serialization affect
* only the serialized data. The <code>Document</code> object and its
* children are never altered by the serialization operation.
* <p> During serialization of XML data, namespace fixup is done as defined in [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>]
* <p> During serialization of XML data, namespace fixup is done as defined in
* [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>]
* , Appendix B. [<a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113'>DOM Level 2 Core</a>]
* allows empty strings as a real namespace URI. If the
* <code>namespaceURI</code> of a <code>Node</code> is empty string, the
@ -80,12 +81,14 @@ import org.w3c.dom.DOMException;
* namespace fixup is done. The resulting output will be valid as an
* external entity.
* </li>
* <li> If the parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-entities'>
* entities</a>" is set to <code>true</code>, <code>EntityReference</code> nodes are
* <li> If the parameter
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-entities'>entities</a>"
* is set to <code>true</code>, <code>EntityReference</code> nodes are
* serialized as an entity reference of the form "
* <code>&amp;entityName;</code>" in the output. Child nodes (the expansion)
* of the entity reference are ignored. If the parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-entities'>
* entities</a>" is set to <code>false</code>, only the children of the entity reference
* of the entity reference are ignored. If the parameter
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-entities'>entities</a>"
* is set to <code>false</code>, only the children of the entity reference
* are serialized. <code>EntityReference</code> nodes with no children (no
* corresponding <code>Entity</code> node or the corresponding
* <code>Entity</code> nodes have no children) are always serialized.
@ -93,15 +96,16 @@ import org.w3c.dom.DOMException;
* <li>
* <code>CDATAsections</code> containing content characters that cannot be
* represented in the specified output encoding are handled according to the
* "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-split-cdata-sections'>
* split-cdata-sections</a>" parameter. If the parameter is set to <code>true</code>,
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-split-cdata-sections'>split-cdata-sections</a>"
* parameter. If the parameter is set to <code>true</code>,
* <code>CDATAsections</code> are split, and the unrepresentable characters
* are serialized as numeric character references in ordinary content. The
* exact position and number of splits is not specified. If the parameter
* is set to <code>false</code>, unrepresentable characters in a
* <code>CDATAsection</code> are reported as
* <code>"wf-invalid-character"</code> errors if the parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-well-formed'>
* well-formed</a>" is set to <code>true</code>. The error is not recoverable - there is no
* <code>"wf-invalid-character"</code> errors if the parameter
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-well-formed'>well-formed</a>"
* is set to <code>true</code>. The error is not recoverable - there is no
* mechanism for supplying alternative characters and continuing with the
* serialization.
* </li>
@ -138,12 +142,15 @@ import org.w3c.dom.DOMException;
* as a <code>DOMError</code> fatal error. An example would be serializing
* the element &lt;LaCa&ntilde;ada/&gt; with <code>encoding="us-ascii"</code>.
* This will result with a generation of a <code>DOMError</code>
* "wf-invalid-character-in-node-name" (as proposed in "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-well-formed'>
* well-formed</a>").
* <p> When requested by setting the parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-normalize-characters'>
* normalize-characters</a>" on <code>LSSerializer</code> to true, character normalization is
* performed according to the definition of <a href='http://www.w3.org/TR/2004/REC-xml11-20040204/#dt-fullnorm'>fully
* normalized</a> characters included in appendix E of [<a href='http://www.w3.org/TR/2004/REC-xml11-20040204/'>XML 1.1</a>] on all
* "wf-invalid-character-in-node-name" (as proposed in
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-well-formed'>well-formed</a>").
* <p> When requested by setting the parameter
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-normalize-characters'>normalize-characters</a>"
* on <code>LSSerializer</code> to true, character normalization is
* performed according to the definition of
* <a href='http://www.w3.org/TR/2004/REC-xml11-20040204/#dt-fullnorm'>fully
* normalized</a> characters included in appendix E of
* [<a href='http://www.w3.org/TR/2004/REC-xml11-20040204/'>XML 1.1</a>] on all
* data to be serialized, both markup and character data. The character
* normalization process affects only the data as it is being written; it
* does not alter the DOM's view of the document after serialization has
@ -170,13 +177,15 @@ import org.w3c.dom.DOMException;
* inconsistencies are found, the serialized form of the document will be
* altered to remove them. The method used for doing the namespace fixup
* while serializing a document is the algorithm defined in Appendix B.1,
* "Namespace normalization", of [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>]
* "Namespace normalization", of
* [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>]
* .
* <p> While serializing a document, the parameter "discard-default-content"
* controls whether or not non-specified data is serialized.
* <p> While serializing, errors and warnings are reported to the application
* through the error handler (<code>LSSerializer.domConfig</code>'s "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-error-handler'>
* error-handler</a>" parameter). This specification does in no way try to define all possible
* through the error handler (<code>LSSerializer.domConfig</code>'s
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-error-handler'>error-handler</a>"
* parameter). This specification does in no way try to define all possible
* errors and warnings that can occur while serializing a DOM node, but some
* common error and warning cases are defined. The types (
* <code>DOMError.type</code>) of errors and warnings defined by this
@ -189,8 +198,9 @@ import org.w3c.dom.DOMException;
* <dt>
* <code>"unbound-prefix-in-entity-reference" [fatal]</code> </dt>
* <dd> Raised if the
* configuration parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-namespaces'>
* namespaces</a>" is set to <code>true</code> and an entity whose replacement text
* configuration parameter
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-namespaces'>namespaces</a>"
* is set to <code>true</code> and an entity whose replacement text
* contains unbound namespace prefixes is referenced in a location where
* there are no bindings for the namespace prefixes. </dd>
* <dt>
@ -202,8 +212,9 @@ import org.w3c.dom.DOMException;
* are expected to raise implementation specific errors and warnings for any
* other error and warning cases such as IO errors (file not found,
* permission denied,...) and so on.
* <p>See also the <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407'>Document Object Model (DOM) Level 3 Load
and Save Specification</a>.
* <p>See also the
* <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407'>
Document Object Model (DOM) Level 3 Load and Save Specification</a>.
*
* @since 1.5
*/
@ -211,8 +222,10 @@ public interface LSSerializer {
/**
* The <code>DOMConfiguration</code> object used by the
* <code>LSSerializer</code> when serializing a DOM node.
* <br> In addition to the parameters recognized by the <a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#DOMConfiguration'>
* DOMConfiguration</a> interface defined in [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>]
* <br> In addition to the parameters recognized by the
* <a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#DOMConfiguration'>DOMConfiguration</a>
* interface defined in
* [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>]
* , the <code>DOMConfiguration</code> objects for
* <code>LSSerializer</code> adds, or modifies, the following
* parameters:
@ -221,9 +234,11 @@ public interface LSSerializer {
* <dd>
* <dl>
* <dt><code>true</code></dt>
* <dd>[<em>optional</em>] Writes the document according to the rules specified in [<a href='http://www.w3.org/TR/2001/REC-xml-c14n-20010315'>Canonical XML</a>].
* In addition to the behavior described in "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-canonical-form'>
* canonical-form</a>" [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>]
* <dd>[<em>optional</em>] Writes the document according to the rules specified in
* [<a href='http://www.w3.org/TR/2001/REC-xml-c14n-20010315'>Canonical XML</a>].
* In addition to the behavior described in
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-canonical-form'>canonical-form</a>"
* [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>]
* , setting this parameter to <code>true</code> will set the parameters
* "format-pretty-print", "discard-default-content", and "xml-declaration
* ", to <code>false</code>. Setting one of those parameters to
@ -267,7 +282,8 @@ public interface LSSerializer {
* <dl>
* <dt>
* <code>true</code></dt>
* <dd>[<em>required</em>] (<em>default</em>) If, while verifying full normalization when [<a href='http://www.w3.org/TR/2004/REC-xml11-20040204/'>XML 1.1</a>] is
* <dd>[<em>required</em>] (<em>default</em>) If, while verifying full normalization when
* [<a href='http://www.w3.org/TR/2004/REC-xml11-20040204/'>XML 1.1</a>] is
* supported, a character is encountered for which the normalization
* properties cannot be determined, then raise a
* <code>"unknown-character-denormalization"</code> warning (instead of
@ -281,18 +297,21 @@ public interface LSSerializer {
* <dt>
* <code>"normalize-characters"</code></dt>
* <dd> This parameter is equivalent to
* the one defined by <code>DOMConfiguration</code> in [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>]
* the one defined by <code>DOMConfiguration</code> in
* [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>]
* . Unlike in the Core, the default value for this parameter is
* <code>true</code>. While DOM implementations are not required to
* support <a href='http://www.w3.org/TR/2004/REC-xml11-20040204/#dt-fullnorm'>fully
* normalizing</a> the characters in the document according to appendix E of [<a href='http://www.w3.org/TR/2004/REC-xml11-20040204/'>XML 1.1</a>], this
* normalizing</a> the characters in the document according to appendix E of
* [<a href='http://www.w3.org/TR/2004/REC-xml11-20040204/'>XML 1.1</a>], this
* parameter must be activated by default if supported. </dd>
* <dt>
* <code>"xml-declaration"</code></dt>
* <dd>
* <dl>
* <dt><code>true</code></dt>
* <dd>[<em>required</em>] (<em>default</em>) If a <code>Document</code>, <code>Element</code>, or <code>Entity</code>
* <dd>[<em>required</em>] (<em>default</em>) If a <code>Document</code>,
* <code>Element</code>, or <code>Entity</code>
* node is serialized, the XML declaration, or text declaration, should
* be included. The version (<code>Document.xmlVersion</code> if the
* document is a Level 3 document and the version is non-null, otherwise
@ -303,7 +322,8 @@ public interface LSSerializer {
* <code>false</code></dt>
* <dd>[<em>required</em>] Do not serialize the XML and text declarations. Report a
* <code>"xml-declaration-needed"</code> warning if this will cause
* problems (i.e. the serialized data is of an XML version other than [<a href='http://www.w3.org/TR/2004/REC-xml-20040204'>XML 1.0</a>], or an
* problems (i.e. the serialized data is of an XML version other than
* [<a href='http://www.w3.org/TR/2004/REC-xml-20040204'>XML 1.0</a>], or an
* encoding would be needed to be able to re-parse the serialized data). </dd>
* </dl></dd>
* </dl>
@ -314,8 +334,8 @@ public interface LSSerializer {
* The end-of-line sequence of characters to be used in the XML being
* written out. Any string is supported, but XML treats only a certain
* set of characters sequence as end-of-line (See section 2.11,
* "End-of-Line Handling" in [<a href='http://www.w3.org/TR/2004/REC-xml-20040204'>XML 1.0</a>], if the
* serialized content is XML 1.0 or section 2.11, "End-of-Line Handling"
* "End-of-Line Handling" in [<a href='http://www.w3.org/TR/2004/REC-xml-20040204'>XML 1.0</a>],
* if the serialized content is XML 1.0 or section 2.11, "End-of-Line Handling"
* in [<a href='http://www.w3.org/TR/2004/REC-xml11-20040204/'>XML 1.1</a>], if the
* serialized content is XML 1.1). Using other character sequences than
* the recommended ones can result in a document that is either not
@ -335,8 +355,8 @@ public interface LSSerializer {
* The end-of-line sequence of characters to be used in the XML being
* written out. Any string is supported, but XML treats only a certain
* set of characters sequence as end-of-line (See section 2.11,
* "End-of-Line Handling" in [<a href='http://www.w3.org/TR/2004/REC-xml-20040204'>XML 1.0</a>], if the
* serialized content is XML 1.0 or section 2.11, "End-of-Line Handling"
* "End-of-Line Handling" in [<a href='http://www.w3.org/TR/2004/REC-xml-20040204'>XML 1.0</a>],
* if the serialized content is XML 1.0 or section 2.11, "End-of-Line Handling"
* in [<a href='http://www.w3.org/TR/2004/REC-xml11-20040204/'>XML 1.1</a>], if the
* serialized content is XML 1.1). Using other character sequences than
* the recommended ones can result in a document that is either not
@ -360,8 +380,9 @@ public interface LSSerializer {
* serialization early.
* <br> The filter is invoked after the operations requested by the
* <code>DOMConfiguration</code> parameters have been applied. For
* example, CDATA sections won't be passed to the filter if "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-cdata-sections'>
* cdata-sections</a>" is set to <code>false</code>.
* example, CDATA sections won't be passed to the filter if
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-cdata-sections'>cdata-sections</a>"
* is set to <code>false</code>.
*/
public LSSerializerFilter getFilter();
/**
@ -371,8 +392,9 @@ public interface LSSerializer {
* serialization early.
* <br> The filter is invoked after the operations requested by the
* <code>DOMConfiguration</code> parameters have been applied. For
* example, CDATA sections won't be passed to the filter if "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-cdata-sections'>
* cdata-sections</a>" is set to <code>false</code>.
* example, CDATA sections won't be passed to the filter if
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-cdata-sections'>cdata-sections</a>"
* is set to <code>false</code>.
*/
public void setFilter(LSSerializerFilter filter);
@ -414,8 +436,9 @@ public interface LSSerializer {
* @exception LSException
* SERIALIZE_ERR: Raised if the <code>LSSerializer</code> was unable to
* serialize the node. DOM applications should attach a
* <code>DOMErrorHandler</code> using the parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-error-handler'>
* error-handler</a>" if they wish to get details on the error.
* <code>DOMErrorHandler</code> using the parameter
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-error-handler'>error-handler</a>"
* if they wish to get details on the error.
*/
public boolean write(Node nodeArg,
LSOutput destination)
@ -436,8 +459,9 @@ public interface LSSerializer {
* @exception LSException
* SERIALIZE_ERR: Raised if the <code>LSSerializer</code> was unable to
* serialize the node. DOM applications should attach a
* <code>DOMErrorHandler</code> using the parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-error-handler'>
* error-handler</a>" if they wish to get details on the error.
* <code>DOMErrorHandler</code> using the parameter
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-error-handler'>error-handler</a>"
* if they wish to get details on the error.
*/
public boolean writeToURI(Node nodeArg,
String uri)
@ -458,8 +482,9 @@ public interface LSSerializer {
* @exception LSException
* SERIALIZE_ERR: Raised if the <code>LSSerializer</code> was unable to
* serialize the node. DOM applications should attach a
* <code>DOMErrorHandler</code> using the parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-error-handler'>
* error-handler</a>" if they wish to get details on the error.
* <code>DOMErrorHandler</code> using the parameter
* "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-error-handler'>error-handler</a>"
* if they wish to get details on the error.
*/
public String writeToString(Node nodeArg)
throws DOMException, LSException;

View File

@ -4238,9 +4238,6 @@ public class Attr extends JCTree.Visitor {
public void visitTypeArray(JCArrayTypeTree tree) {
Type etype = attribType(tree.elemtype, env);
Type type = new ArrayType(etype, syms.arrayClass);
if (etype.isErroneous()) {
type = types.createErrorType(type);
}
result = check(tree, type, KindSelector.TYP, resultInfo);
}

View File

@ -196,13 +196,23 @@ public final class Secmod {
}
if (configDir != null) {
File configBase = new File(configDir);
if (configBase.isDirectory() == false ) {
throw new IOException("configDir must be a directory: " + configDir);
String configDirPath = null;
String sqlPrefix = "sql:/";
if (!configDir.startsWith(sqlPrefix)) {
configDirPath = configDir;
} else {
StringBuilder configDirPathSB = new StringBuilder(configDir);
configDirPath = configDirPathSB.substring(sqlPrefix.length());
}
File secmodFile = new File(configBase, "secmod.db");
if (secmodFile.isFile() == false) {
throw new FileNotFoundException(secmodFile.getPath());
File configBase = new File(configDirPath);
if (configBase.isDirectory() == false ) {
throw new IOException("configDir must be a directory: " + configDirPath);
}
if (!configDir.startsWith(sqlPrefix)) {
File secmodFile = new File(configBase, "secmod.db");
if (secmodFile.isFile() == false) {
throw new FileNotFoundException(secmodFile.getPath());
}
}
}

View File

@ -110,6 +110,15 @@ public enum StandardOperation implements Operation {
* or reference). This operation must always be used as part of a {@link NamespaceOperation}.
*/
SET,
/**
* Removes the value from a namespace defined on an object. Call sites with this
* operation should have a signature of
* <code>(receiver,&nbsp;name)&rarr;void</code> or
* <code>(receiver)&rarr;void</code> when used with {@link NamedOperation},
* with all parameters being of any type (either primitive
* or reference). This operation must always be used as part of a {@link NamespaceOperation}.
*/
REMOVE,
/**
* Call a callable object. Call sites with this operation should have a
* signature of <code>(callable,&nbsp;receiver,&nbsp;arguments...)&rarr;value</code>,

View File

@ -107,7 +107,8 @@ import jdk.dynalink.linker.support.TypeUtilities;
/**
* A class that provides linking capabilities for a single POJO class. Normally not used directly, but managed by
* {@link BeansLinker}.
* {@link BeansLinker}. Most of the functionality is provided by the {@link AbstractJavaLinker} superclass; this
* class adds length and element operations for arrays and collections.
*/
class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicLinker {
BeanLinker(final Class<?> clazz) {
@ -147,6 +148,8 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
return getElementGetter(req.popNamespace());
} else if (op == StandardOperation.SET) {
return getElementSetter(req.popNamespace());
} else if (op == StandardOperation.REMOVE) {
return getElementRemover(req.popNamespace());
}
}
}
@ -228,7 +231,7 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
// dealing with an array, or a list or map, but hey...
// Note that for arrays and lists, using LinkerServices.asType() will ensure that any language specific linkers
// in use will get a chance to perform any (if there's any) implicit conversion to integer for the indices.
if(declaredType.isArray()) {
if(declaredType.isArray() && arrayMethod != null) {
return new GuardedInvocationComponentAndCollectionType(
createInternalFilteredGuardedInvocationComponent(arrayMethod.apply(declaredType), linkerServices),
CollectionType.ARRAY);
@ -240,7 +243,7 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
return new GuardedInvocationComponentAndCollectionType(
createInternalFilteredGuardedInvocationComponent(mapMethod, linkerServices),
CollectionType.MAP);
} else if(clazz.isArray()) {
} else if(clazz.isArray() && arrayMethod != null) {
return new GuardedInvocationComponentAndCollectionType(
getClassGuardedInvocationComponent(linkerServices.filterInternalObjects(arrayMethod.apply(clazz)), callSiteType),
CollectionType.ARRAY);
@ -450,7 +453,7 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
}
@SuppressWarnings("unused")
private static void noOpSetter() {
private static void noOp() {
}
private static final MethodHandle SET_LIST_ELEMENT = Lookup.PUBLIC.findVirtual(List.class, "set",
@ -459,12 +462,14 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
private static final MethodHandle PUT_MAP_ELEMENT = Lookup.PUBLIC.findVirtual(Map.class, "put",
MethodType.methodType(Object.class, Object.class, Object.class));
private static final MethodHandle NO_OP_SETTER_2;
private static final MethodHandle NO_OP_SETTER_3;
private static final MethodHandle NO_OP_1;
private static final MethodHandle NO_OP_2;
private static final MethodHandle NO_OP_3;
static {
final MethodHandle noOpSetter = Lookup.findOwnStatic(MethodHandles.lookup(), "noOpSetter", void.class);
NO_OP_SETTER_2 = dropObjectArguments(noOpSetter, 2);
NO_OP_SETTER_3 = dropObjectArguments(noOpSetter, 3);
final MethodHandle noOp = Lookup.findOwnStatic(MethodHandles.lookup(), "noOp", void.class);
NO_OP_1 = dropObjectArguments(noOp, 1);
NO_OP_2 = dropObjectArguments(noOp, 2);
NO_OP_3 = dropObjectArguments(noOp, 3);
}
private GuardedInvocationComponent getElementSetter(final ComponentLinkRequest req) throws Exception {
@ -503,7 +508,39 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
return gic.replaceInvocation(binder.bind(invocation));
}
return guardComponentWithRangeCheck(gicact, callSiteType, nextComponent, binder, isFixedKey ? NO_OP_SETTER_2 : NO_OP_SETTER_3);
return guardComponentWithRangeCheck(gicact, callSiteType, nextComponent, binder, isFixedKey ? NO_OP_2 : NO_OP_3);
}
private static final MethodHandle REMOVE_LIST_ELEMENT = Lookup.PUBLIC.findVirtual(List.class, "remove",
MethodType.methodType(Object.class, int.class));
private static final MethodHandle REMOVE_MAP_ELEMENT = Lookup.PUBLIC.findVirtual(Map.class, "remove",
MethodType.methodType(Object.class, Object.class));
private GuardedInvocationComponent getElementRemover(final ComponentLinkRequest req) throws Exception {
final CallSiteDescriptor callSiteDescriptor = req.getDescriptor();
final Object name = req.name;
final boolean isFixedKey = name != null;
assertParameterCount(callSiteDescriptor, isFixedKey ? 1 : 2);
final LinkerServices linkerServices = req.linkerServices;
final MethodType callSiteType = callSiteDescriptor.getMethodType();
final GuardedInvocationComponent nextComponent = getNextComponent(req);
final GuardedInvocationComponentAndCollectionType gicact = guardedInvocationComponentAndCollectionType(
callSiteType, linkerServices, null, REMOVE_LIST_ELEMENT, REMOVE_MAP_ELEMENT);
if (gicact == null) {
// Can't remove elements for objects that are neither lists, nor maps.
return nextComponent;
}
final Object typedName = getTypedName(name, gicact.collectionType == CollectionType.MAP, linkerServices);
if (typedName == INVALID_NAME) {
return nextComponent;
}
return guardComponentWithRangeCheck(gicact, callSiteType, nextComponent,
new Binder(linkerServices, callSiteType, typedName), isFixedKey ? NO_OP_1: NO_OP_2);
}
private static final MethodHandle GET_COLLECTION_LENGTH = Lookup.PUBLIC.findVirtual(Collection.class, "size",

View File

@ -113,6 +113,8 @@ import jdk.dynalink.linker.TypeBasedGuardingDynamicLinker;
* <li> expose elements of native Java arrays, {@link java.util.List} and {@link java.util.Map} objects as
* {@link StandardOperation#GET} and {@link StandardOperation#SET} operations in the
* {@link StandardNamespace#ELEMENT} namespace;</li>
* <li> expose removal of elements of {@link java.util.List} and {@link java.util.Map} objects as
* {@link StandardOperation#REMOVE} operation in the {@link StandardNamespace#ELEMENT} namespace;</li>
* <li>expose a virtual property named {@code length} on Java arrays, {@link java.util.Collection} and
* {@link java.util.Map} objects;</li>
* <li>expose {@link StandardOperation#NEW} on instances of {@link StaticClass}

View File

@ -128,6 +128,9 @@ public class CompiledVFrame extends JavaVFrame {
/** Returns List<MonitorInfo> */
public List<MonitorInfo> getMonitors() {
if (getScope() == null) {
return new ArrayList<>();
}
List monitors = getScope().getMonitors();
if (monitors == null) {
return new ArrayList<>();

View File

@ -36,6 +36,8 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CompletableFuture;
import jdk.incubator.http.internal.common.Log;
import jdk.incubator.http.internal.common.MinimalFuture;
import jdk.incubator.http.internal.common.Utils;
import jdk.incubator.http.internal.frame.SettingsFrame;
@ -78,10 +80,6 @@ class Http2ClientImpl {
}
}
// boolean haveConnectionFor(URI uri, InetSocketAddress proxy) {
// return connections.containsKey(Http2Connection.keyFor(uri,proxy));
// }
/**
* If a https request then async waits until a connection is opened.
* Returns null if the request is 'http' as a different (upgrade)
@ -188,18 +186,64 @@ class Http2ClientImpl {
private static final int K = 1024;
private static int getParameter(String property, int min, int max, int defaultValue) {
int value = Utils.getIntegerNetProperty(property, defaultValue);
// use default value if misconfigured
if (value < min || value > max) {
Log.logError("Property value for {0}={1} not in [{2}..{3}]: " +
"using default={4}", property, value, min, max, defaultValue);
value = defaultValue;
}
return value;
}
// used for the connection window, to have a connection window size
// bigger than the initial stream window size.
int getConnectionWindowSize(SettingsFrame clientSettings) {
// Maximum size is 2^31-1. Don't allow window size to be less
// than the stream window size. HTTP/2 specify a default of 64 * K -1,
// but we use 2^26 by default for better performance.
int streamWindow = clientSettings.getParameter(INITIAL_WINDOW_SIZE);
// The default is the max between the stream window size
// and the connection window size.
int defaultValue = Math.min(Integer.MAX_VALUE,
Math.max(streamWindow, K*K*32));
return getParameter(
"jdk.httpclient.connectionWindowSize",
streamWindow, Integer.MAX_VALUE, defaultValue);
}
SettingsFrame getClientSettings() {
SettingsFrame frame = new SettingsFrame();
frame.setParameter(HEADER_TABLE_SIZE, Utils.getIntegerNetProperty(
"jdk.httpclient.hpack.maxheadertablesize", 16 * K));
frame.setParameter(ENABLE_PUSH, Utils.getIntegerNetProperty(
"jdk.httpclient.enablepush", 1));
frame.setParameter(MAX_CONCURRENT_STREAMS, Utils.getIntegerNetProperty(
"jdk.httpclient.maxstreams", 16));
frame.setParameter(INITIAL_WINDOW_SIZE, Utils.getIntegerNetProperty(
"jdk.httpclient.windowsize", 64 * K - 1));
frame.setParameter(MAX_FRAME_SIZE, Utils.getIntegerNetProperty(
"jdk.httpclient.maxframesize", 16 * K));
// default defined for HTTP/2 is 4 K, we use 16 K.
frame.setParameter(HEADER_TABLE_SIZE, getParameter(
"jdk.httpclient.hpack.maxheadertablesize",
0, Integer.MAX_VALUE, 16 * K));
// O: does not accept push streams. 1: accepts push streams.
frame.setParameter(ENABLE_PUSH, getParameter(
"jdk.httpclient.enablepush",
0, 1, 1));
// HTTP/2 recommends to set the number of concurrent streams
// no lower than 100. We use 100. 0 means no stream would be
// accepted. That would render the client to be non functional,
// so we won't let 0 be configured for our Http2ClientImpl.
frame.setParameter(MAX_CONCURRENT_STREAMS, getParameter(
"jdk.httpclient.maxstreams",
1, Integer.MAX_VALUE, 100));
// Maximum size is 2^31-1. Don't allow window size to be less
// than the minimum frame size as this is likely to be a
// configuration error. HTTP/2 specify a default of 64 * K -1,
// but we use 16 M for better performance.
frame.setParameter(INITIAL_WINDOW_SIZE, getParameter(
"jdk.httpclient.windowsize",
16 * K, Integer.MAX_VALUE, 16*K*K));
// HTTP/2 specify a minimum size of 16 K, a maximum size of 2^24-1,
// and a default of 16 K. We use 16 K as default.
frame.setParameter(MAX_FRAME_SIZE, getParameter(
"jdk.httpclient.maxframesize",
16 * K, 16 * K * K -1, 16 * K));
return frame;
}
}

View File

@ -228,7 +228,7 @@ class Http2Connection {
private final WindowController windowController = new WindowController();
private final FramesController framesController = new FramesController();
private final Http2TubeSubscriber subscriber = new Http2TubeSubscriber();
final WindowUpdateSender windowUpdater;
final ConnectionWindowUpdateSender windowUpdater;
private volatile Throwable cause;
private volatile Supplier<ByteBuffer> initial;
@ -247,7 +247,8 @@ class Http2Connection {
this.nextstreamid = nextstreamid;
this.key = key;
this.clientSettings = this.client2.getClientSettings();
this.framesDecoder = new FramesDecoder(this::processFrame, clientSettings.getParameter(SettingsFrame.MAX_FRAME_SIZE));
this.framesDecoder = new FramesDecoder(this::processFrame,
clientSettings.getParameter(SettingsFrame.MAX_FRAME_SIZE));
// serverSettings will be updated by server
this.serverSettings = SettingsFrame.getDefaultSettings();
this.hpackOut = new Encoder(serverSettings.getParameter(HEADER_TABLE_SIZE));
@ -255,7 +256,8 @@ class Http2Connection {
debugHpack.log(Level.DEBUG, () -> "For the record:" + super.toString());
debugHpack.log(Level.DEBUG, "Decoder created: %s", hpackIn);
debugHpack.log(Level.DEBUG, "Encoder created: %s", hpackOut);
this.windowUpdater = new ConnectionWindowUpdateSender(this, client().getReceiveBufferSize());
this.windowUpdater = new ConnectionWindowUpdateSender(this,
client2.getConnectionWindowSize(clientSettings));
}
/**
@ -774,7 +776,8 @@ class Http2Connection {
Log.logTrace("{0}: start sending connection preface to {1}",
connection.channel().getLocalAddress(),
connection.address());
SettingsFrame sf = client2.getClientSettings();
SettingsFrame sf = new SettingsFrame(clientSettings);
int initialWindowSize = sf.getParameter(INITIAL_WINDOW_SIZE);
ByteBuffer buf = framesEncoder.encodeConnectionPreface(PREFACE_BYTES, sf);
Log.logFrames(sf, "OUT");
// send preface bytes and SettingsFrame together
@ -788,8 +791,10 @@ class Http2Connection {
// send a Window update for the receive buffer we are using
// minus the initial 64 K specified in protocol
final int len = client2.client().getReceiveBufferSize() - (64 * 1024 - 1);
windowUpdater.sendWindowUpdate(len);
final int len = windowUpdater.initialWindowSize - initialWindowSize;
if (len > 0) {
windowUpdater.sendWindowUpdate(len);
}
// there will be an ACK to the windows update - which should
// cause any pending data stored before the preface was sent to be
// flushed (see PrefaceController).
@ -1202,9 +1207,11 @@ class Http2Connection {
static final class ConnectionWindowUpdateSender extends WindowUpdateSender {
final int initialWindowSize;
public ConnectionWindowUpdateSender(Http2Connection connection,
int initialWindowSize) {
super(connection, initialWindowSize);
this.initialWindowSize = initialWindowSize;
}
@Override

View File

@ -1038,7 +1038,7 @@ class HttpClientImpl extends HttpClient {
// used for the connection window
int getReceiveBufferSize() {
return Utils.getIntegerNetProperty(
"jdk.httpclient.connectionWindowSize", 256 * 1024
"jdk.httpclient.receiveBufferSize", 2 * 1024 * 1024
);
}
}

View File

@ -143,7 +143,9 @@ class PlainHttpConnection extends HttpConnection {
this.chan = SocketChannel.open();
chan.configureBlocking(false);
int bufsize = client.getReceiveBufferSize();
chan.setOption(StandardSocketOptions.SO_RCVBUF, bufsize);
if (!trySetReceiveBufferSize(bufsize)) {
trySetReceiveBufferSize(256*1024);
}
chan.setOption(StandardSocketOptions.TCP_NODELAY, true);
// wrap the connected channel in a Tube for async reading and writing
tube = new SocketTube(client(), chan, Utils::getBuffer);
@ -152,6 +154,18 @@ class PlainHttpConnection extends HttpConnection {
}
}
private boolean trySetReceiveBufferSize(int bufsize) {
try {
chan.setOption(StandardSocketOptions.SO_RCVBUF, bufsize);
return true;
} catch(IOException x) {
debug.log(Level.DEBUG,
"Failed to set receive buffer size to %d on %s",
bufsize, chan);
}
return false;
}
@Override
HttpPublisher publisher() { return writePublisher; }

View File

@ -59,6 +59,8 @@ abstract class WindowUpdateSender {
// or
// - remaining window size reached max frame size.
limit = Math.min(v0, v1);
debug.log(Level.DEBUG, "maxFrameSize=%d, initWindowSize=%d, limit=%d",
maxFrameSize, initWindowSize, limit);
}
abstract int getStreamId();

View File

@ -100,6 +100,11 @@ public class SettingsFrame extends Http2Frame {
this(0);
}
public SettingsFrame(SettingsFrame other) {
super(0, other.flags);
parameters = Arrays.copyOf(other.parameters, MAX_PARAM);
}
@Override
public int type() {
return TYPE;

View File

@ -117,8 +117,10 @@ public class HtmlDoclet extends AbstractDoclet {
SourceToHTMLConverter.convertRoot(configuration,
docEnv, DocPaths.SOURCE_OUTPUT);
}
if (configuration.topFile.isEmpty()) {
// Modules with no documented classes may be specified on the
// command line to specify a service provider, allow these.
if (configuration.getSpecifiedModuleElements().isEmpty() &&
configuration.topFile.isEmpty()) {
messages.error("doclet.No_Non_Deprecated_Classes_To_Document");
return;
}

View File

@ -193,7 +193,11 @@ public abstract class AbstractDoclet implements Doclet {
* @throws DocletException if there is a problem while generating the documentation
*/
private void startGeneration(DocletEnvironment docEnv) throws DocletException {
if (configuration.getIncludedTypeElements().isEmpty()) {
// Modules with no documented classes may be specified on the
// command line to specify a service provider, allow these.
if (configuration.getSpecifiedModuleElements().isEmpty() &&
configuration.getIncludedTypeElements().isEmpty()) {
messages.error("doclet.No_Public_Classes_To_Document");
return;
}

View File

@ -489,6 +489,10 @@ public abstract class MemberSummaryBuilder extends AbstractMemberBuilder {
continue;
}
// Skip static methods in interfaces they are not inherited
if (utils.isInterface(inheritedClass) && utils.isStatic(inheritedMember))
continue;
// If applicable, filter those overridden methods that
// should not be documented in the summary/detail sections,
// and instead document them in the footnote. Care must be taken
@ -496,9 +500,8 @@ public abstract class MemberSummaryBuilder extends AbstractMemberBuilder {
// but comments for these are synthesized on the output.
ExecutableElement inheritedMethod = (ExecutableElement)inheritedMember;
if (enclosedSuperMethods.stream()
.anyMatch(e -> utils.executableMembersEqual(inheritedMethod, e)
&& (!utils.isSimpleOverride(e)
|| visibleMemberMap.getPropertyElement(e) != null))) {
.anyMatch(e -> utils.executableMembersEqual(inheritedMethod, e) &&
(!utils.isSimpleOverride(e) || visibleMemberMap.getPropertyElement(e) != null))) {
inheritedMembers.add(inheritedMember);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,18 +25,14 @@
package com.sun.tools.jdeps;
import java.io.PrintWriter;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleFinder;
import java.lang.module.ModuleReference;
import java.util.ArrayDeque;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -161,7 +157,7 @@ public final class Graph<T> {
* Returns all nodes reachable from the given set of roots.
*/
public Set<T> dfs(Set<T> roots) {
Deque<T> deque = new LinkedList<>(roots);
Deque<T> deque = new ArrayDeque<>(roots);
Set<T> visited = new HashSet<>();
while (!deque.isEmpty()) {
T u = deque.pop();
@ -197,7 +193,7 @@ public final class Graph<T> {
if (includeAdjacent && isAdjacent(u, v)) {
return true;
}
Deque<T> stack = new LinkedList<>();
Deque<T> stack = new ArrayDeque<>();
Set<T> visited = new HashSet<>();
stack.push(u);
while (!stack.isEmpty()) {
@ -292,12 +288,10 @@ public final class Graph<T> {
* Topological sort
*/
static class TopoSorter<T> {
final Deque<T> result = new LinkedList<>();
final Deque<T> nodes;
final Deque<T> result = new ArrayDeque<>();
final Graph<T> graph;
TopoSorter(Graph<T> graph) {
this.graph = graph;
this.nodes = new LinkedList<>(graph.nodes);
sort();
}
@ -310,17 +304,16 @@ public final class Graph<T> {
}
private void sort() {
Deque<T> visited = new LinkedList<>();
Deque<T> done = new LinkedList<>();
T node;
while ((node = nodes.poll()) != null) {
Set<T> visited = new HashSet<>();
Set<T> done = new HashSet<>();
for (T node : graph.nodes()) {
if (!visited.contains(node)) {
visit(node, visited, done);
}
}
}
private void visit(T node, Deque<T> visited, Deque<T> done) {
private void visit(T node, Set<T> visited, Set<T> done) {
if (visited.contains(node)) {
if (!done.contains(node)) {
throw new IllegalArgumentException("Cyclic detected: " +
@ -330,7 +323,7 @@ public final class Graph<T> {
}
visited.add(node);
graph.edges().get(node).stream()
.forEach(x -> visit(x, visited, done));
.forEach(x -> visit(x, visited, done));
done.add(node);
result.addLast(node);
}

View File

@ -38,8 +38,6 @@ import java.io.InputStream;
import java.io.UncheckedIOException;
import java.lang.module.Configuration;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleDescriptor.Exports;
import java.lang.module.ModuleDescriptor.Opens;
import java.lang.module.ModuleFinder;
import java.lang.module.ModuleReader;
import java.lang.module.ModuleReference;
@ -71,6 +69,7 @@ public class JdepsConfiguration implements AutoCloseable {
public static final String ALL_MODULE_PATH = "ALL-MODULE-PATH";
public static final String ALL_DEFAULT = "ALL-DEFAULT";
public static final String ALL_SYSTEM = "ALL-SYSTEM";
public static final String MODULE_INFO = "module-info.class";
private final SystemModuleFinder system;
@ -91,8 +90,7 @@ public class JdepsConfiguration implements AutoCloseable {
Set<String> roots,
List<Path> classpaths,
List<Archive> initialArchives,
boolean allDefaultModules,
boolean allSystemModules,
Set<String> tokens,
Runtime.Version version)
throws IOException
{
@ -104,16 +102,13 @@ public class JdepsConfiguration implements AutoCloseable {
// build root set for resolution
Set<String> mods = new HashSet<>(roots);
// add all system modules to the root set for unnamed module or set explicitly
boolean unnamed = !initialArchives.isEmpty() || !classpaths.isEmpty();
if (allSystemModules || (unnamed && !allDefaultModules)) {
if (tokens.contains(ALL_SYSTEM)) {
systemModulePath.findAll().stream()
.map(mref -> mref.descriptor().name())
.forEach(mods::add);
}
if (allDefaultModules) {
if (tokens.contains(ALL_DEFAULT)) {
mods.addAll(systemModulePath.defaultSystemRoots());
}
@ -200,10 +195,10 @@ public class JdepsConfiguration implements AutoCloseable {
return m!= null ? Optional.of(m.descriptor()) : Optional.empty();
}
boolean isValidToken(String name) {
public static boolean isToken(String name) {
return ALL_MODULE_PATH.equals(name) ||
ALL_DEFAULT.equals(name) ||
ALL_SYSTEM.equals(name);
ALL_DEFAULT.equals(name) ||
ALL_SYSTEM.equals(name);
}
/**
@ -482,13 +477,10 @@ public class JdepsConfiguration implements AutoCloseable {
final List<Archive> initialArchives = new ArrayList<>();
final List<Path> paths = new ArrayList<>();
final List<Path> classPaths = new ArrayList<>();
final Set<String> tokens = new HashSet<>();
ModuleFinder upgradeModulePath;
ModuleFinder appModulePath;
boolean addAllApplicationModules;
boolean addAllDefaultModules;
boolean addAllSystemModules;
boolean allModules;
Runtime.Version version;
public Builder() {
@ -513,34 +505,15 @@ public class JdepsConfiguration implements AutoCloseable {
public Builder addmods(Set<String> addmods) {
for (String mn : addmods) {
switch (mn) {
case ALL_MODULE_PATH:
this.addAllApplicationModules = true;
break;
case ALL_DEFAULT:
this.addAllDefaultModules = true;
break;
case ALL_SYSTEM:
this.addAllSystemModules = true;
break;
default:
this.rootModules.add(mn);
if (isToken(mn)) {
tokens.add(mn);
} else {
rootModules.add(mn);
}
}
return this;
}
/*
* This method is for --check option to find all target modules specified
* in qualified exports.
*
* Include all system modules and modules found on modulepath
*/
public Builder allModules() {
this.allModules = true;
return this;
}
public Builder multiRelease(Runtime.Version version) {
this.version = version;
return this;
@ -579,7 +552,9 @@ public class JdepsConfiguration implements AutoCloseable {
.forEach(rootModules::add);
}
if ((addAllApplicationModules || allModules) && appModulePath != null) {
// add all modules to the root set for unnamed module or set explicitly
boolean unnamed = !initialArchives.isEmpty() || !classPaths.isEmpty();
if ((unnamed || tokens.contains(ALL_MODULE_PATH)) && appModulePath != null) {
appModulePath.findAll().stream()
.map(mref -> mref.descriptor().name())
.forEach(rootModules::add);
@ -587,7 +562,7 @@ public class JdepsConfiguration implements AutoCloseable {
// no archive is specified for analysis
// add all system modules as root if --add-modules ALL-SYSTEM is specified
if (addAllSystemModules && rootModules.isEmpty() &&
if (tokens.contains(ALL_SYSTEM) && rootModules.isEmpty() &&
initialArchives.isEmpty() && classPaths.isEmpty()) {
systemModulePath.findAll()
.stream()
@ -595,13 +570,16 @@ public class JdepsConfiguration implements AutoCloseable {
.forEach(rootModules::add);
}
if (unnamed && !tokens.contains(ALL_DEFAULT)) {
tokens.add(ALL_SYSTEM);
}
return new JdepsConfiguration(systemModulePath,
finder,
rootModules,
classPaths,
initialArchives,
addAllDefaultModules,
allModules,
tokens,
version);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -540,7 +540,7 @@ class JdepsTask {
}
boolean run() throws IOException {
try (JdepsConfiguration config = buildConfig(command.allModules())) {
try (JdepsConfiguration config = buildConfig()) {
if (!options.nowarning) {
// detect split packages
config.splitPackages().entrySet()
@ -553,7 +553,7 @@ class JdepsTask {
// check if any module specified in --add-modules, --require, and -m is missing
options.addmods.stream()
.filter(mn -> !config.isValidToken(mn))
.filter(mn -> !JdepsConfiguration.isToken(mn))
.forEach(mn -> config.findModule(mn).orElseThrow(() ->
new UncheckedBadArgs(new BadArgs("err.module.not.found", mn))));
@ -561,18 +561,14 @@ class JdepsTask {
}
}
private JdepsConfiguration buildConfig(boolean allModules) throws IOException {
private JdepsConfiguration buildConfig() throws IOException {
JdepsConfiguration.Builder builder =
new JdepsConfiguration.Builder(options.systemModulePath);
builder.upgradeModulePath(options.upgradeModulePath)
.appModulePath(options.modulePath)
.addmods(options.addmods);
if (allModules) {
// check all system modules in the image
builder.allModules();
}
.addmods(options.addmods)
.addmods(command.addModules());
if (options.classpath != null)
builder.addClassPath(options.classpath);
@ -655,8 +651,8 @@ class JdepsTask {
* only. The method should be overridden when this command should
* analyze all modules instead.
*/
boolean allModules() {
return false;
Set<String> addModules() {
return Set.of();
}
@Override
@ -871,8 +867,8 @@ class JdepsTask {
* analyzed to find all modules that depend on the modules specified in the
* --require option directly and indirectly
*/
public boolean allModules() {
return options.requires.size() > 0;
Set<String> addModules() {
return options.requires.size() > 0 ? Set.of("ALL-SYSTEM") : Set.of();
}
}
@ -975,8 +971,8 @@ class JdepsTask {
/*
* Returns true to analyze all modules
*/
public boolean allModules() {
return true;
Set<String> addModules() {
return Set.of("ALL-SYSTEM", "ALL-MODULE-PATH");
}
}

View File

@ -32,7 +32,6 @@ import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
/**
@ -138,7 +137,7 @@ enum Profile {
// for debugging
public static void main(String[] args) throws IOException {
// initialize Profiles
new JdepsConfiguration.Builder().allModules().build();
new JdepsConfiguration.Builder().addmods(Set.of("ALL-SYSTEM")).build();
// find platform modules
if (Profile.getProfileCount() == 0) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2003, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -111,7 +111,7 @@ packetToByteArray(JNIEnv *env, jdwpPacket *str)
jint tmpInt;
total_length = str->type.cmd.len;
data_length = total_length - 11;
data_length = total_length - JDWP_HEADER_SIZE;
/* total packet length is header + data */
array = (*env)->NewByteArray(env, total_length);
@ -142,7 +142,7 @@ packetToByteArray(JNIEnv *env, jdwpPacket *str)
/* finally the data */
if (data_length > 0) {
(*env)->SetByteArrayRegion(env, array, 11,
(*env)->SetByteArrayRegion(env, array, JDWP_HEADER_SIZE,
data_length, str->type.cmd.data);
if ((*env)->ExceptionOccurred(env)) {
return NULL;
@ -168,7 +168,7 @@ byteArrayToPacket(JNIEnv *env, jbyteArray b, jdwpPacket *str)
{
jsize total_length, data_length;
jbyte *data;
unsigned char pktHeader[11]; /* sizeof length + id + flags + cmdSet + cmd */
unsigned char pktHeader[JDWP_HEADER_SIZE];
/*
* Get the packet header

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -270,7 +270,7 @@ shmemWritePacket(jdwpTransportEnv* env, const jdwpPacket *packet)
if (packet == NULL) {
RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "packet is null");
}
if (packet->type.cmd.len < 11) {
if (packet->type.cmd.len < JDWP_HEADER_SIZE) {
RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "invalid length");
}
if (connection == NULL) {

View File

@ -1049,7 +1049,7 @@ shmemBase_sendPacket(SharedMemoryConnection *connection, const jdwpPacket *packe
CHECK_ERROR(sendBytes(connection, &packet->type.cmd.cmd, sizeof(jbyte)));
}
data_length = packet->type.cmd.len - 11;
data_length = packet->type.cmd.len - JDWP_HEADER_SIZE;
SHMEM_GUARANTEE(data_length >= 0);
CHECK_ERROR(sendBytes(connection, &data_length, sizeof(jint)));
@ -1125,10 +1125,10 @@ shmemBase_receivePacket(SharedMemoryConnection *connection, jdwpPacket *packet)
if (data_length < 0) {
return SYS_ERR;
} else if (data_length == 0) {
packet->type.cmd.len = 11;
packet->type.cmd.len = JDWP_HEADER_SIZE;
packet->type.cmd.data = NULL;
} else {
packet->type.cmd.len = data_length + 11;
packet->type.cmd.len = data_length + JDWP_HEADER_SIZE;
packet->type.cmd.data = (*callback->alloc)(data_length);
if (packet->type.cmd.data == NULL) {
return SYS_ERR;

View File

@ -96,6 +96,8 @@ typedef struct {
* See: http://java.sun.com/j2se/1.5/docs/guide/jpda/jdwp-spec.html
*/
#define JDWP_HEADER_SIZE 11
enum {
/*
* If additional flags are added that apply to jdwpCmdPacket,

View File

@ -70,7 +70,6 @@ static jdwpTransportEnv single_env = (jdwpTransportEnv)&interface;
RETURN_IO_ERROR("recv error"); \
}
#define HEADER_SIZE 11
#define MAX_DATA_SIZE 1000
static jint recv_fully(int, char *, int);
@ -790,7 +789,7 @@ socketTransport_writePacket(jdwpTransportEnv* env, const jdwpPacket *packet)
/*
* room for header and up to MAX_DATA_SIZE data bytes
*/
char header[HEADER_SIZE + MAX_DATA_SIZE];
char header[JDWP_HEADER_SIZE + MAX_DATA_SIZE];
jbyte *data;
/* packet can't be null */
@ -799,7 +798,7 @@ socketTransport_writePacket(jdwpTransportEnv* env, const jdwpPacket *packet)
}
len = packet->type.cmd.len; /* includes header */
data_len = len - HEADER_SIZE;
data_len = len - JDWP_HEADER_SIZE;
/* bad packet */
if (data_len < 0) {
@ -825,15 +824,15 @@ socketTransport_writePacket(jdwpTransportEnv* env, const jdwpPacket *packet)
data = packet->type.cmd.data;
/* Do one send for short packets, two for longer ones */
if (data_len <= MAX_DATA_SIZE) {
memcpy(header + HEADER_SIZE, data, data_len);
if (send_fully(socketFD, (char *)&header, HEADER_SIZE + data_len) !=
HEADER_SIZE + data_len) {
memcpy(header + JDWP_HEADER_SIZE, data, data_len);
if (send_fully(socketFD, (char *)&header, JDWP_HEADER_SIZE + data_len) !=
JDWP_HEADER_SIZE + data_len) {
RETURN_IO_ERROR("send failed");
}
} else {
memcpy(header + HEADER_SIZE, data, MAX_DATA_SIZE);
if (send_fully(socketFD, (char *)&header, HEADER_SIZE + MAX_DATA_SIZE) !=
HEADER_SIZE + MAX_DATA_SIZE) {
memcpy(header + JDWP_HEADER_SIZE, data, MAX_DATA_SIZE);
if (send_fully(socketFD, (char *)&header, JDWP_HEADER_SIZE + MAX_DATA_SIZE) !=
JDWP_HEADER_SIZE + MAX_DATA_SIZE) {
RETURN_IO_ERROR("send failed");
}
/* Send the remaining data bytes right out of the data area. */

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -43,7 +43,7 @@ inStream_init(PacketInputStream *stream, jdwpPacket packet)
{
stream->packet = packet;
stream->error = JDWP_ERROR(NONE);
stream->left = packet.type.cmd.len;
stream->left = packet.type.cmd.len - JDWP_HEADER_SIZE;
stream->current = packet.type.cmd.data;
stream->refs = bagCreateBag(sizeof(jobject), INITIAL_REF_ALLOC);
if (stream->refs == NULL) {
@ -411,12 +411,6 @@ inStream_readString(PacketInputStream *stream)
return string;
}
jboolean
inStream_endOfInput(PacketInputStream *stream)
{
return (stream->left > 0);
}
jdwpError
inStream_error(PacketInputStream *stream)
{
@ -424,7 +418,8 @@ inStream_error(PacketInputStream *stream)
}
void
inStream_clearError(PacketInputStream *stream) {
inStream_clearError(PacketInputStream *stream)
{
stream->error = JDWP_ERROR(NONE);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -74,7 +74,6 @@ jvalue inStream_readValue(struct PacketInputStream *in, jbyte *typeKeyPtr);
jdwpError inStream_skipBytes(PacketInputStream *stream, jint count);
jboolean inStream_endOfInput(PacketInputStream *stream);
jdwpError inStream_error(PacketInputStream *stream);
void inStream_clearError(PacketInputStream *stream);
void inStream_destroy(PacketInputStream *stream);

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