Merge
This commit is contained in:
commit
4b727d4f18
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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("}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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":
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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">
|
||||
|
@ -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 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.
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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(" "));
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 - "
|
||||
|
@ -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);
|
||||
|
@ -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 : "");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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>
|
||||
* <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
|
||||
* </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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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 = " +
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 =
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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}
|
||||
|
Binary file not shown.
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
* <!DOCTYPE root [ <!ENTITY e SYSTEM 'subdir/myentity.ent' ]>
|
||||
* <root> &e; </root></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,
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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>&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 <LaCañada/> 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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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, name)→void</code> or
|
||||
* <code>(receiver)→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, receiver, arguments...)→value</code>,
|
||||
|
@ -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",
|
||||
|
@ -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}
|
||||
|
@ -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<>();
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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. */
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user