8165804: Revisit the way of loading BreakIterator rules/dictionaries

Reviewed-by: naoto, peytoia, erikj
This commit is contained in:
Masayoshi Okutsu 2016-10-25 15:43:19 +09:00
parent bf19611451
commit 6ce08d0985
13 changed files with 359 additions and 258 deletions

View File

@ -55,7 +55,6 @@ $(eval $(call SetupJavaCompilation,BUILD_BREAKITERATOR_BASE, \
$(eval $(call SetupJavaCompilation,BUILD_BREAKITERATOR_LD, \ $(eval $(call SetupJavaCompilation,BUILD_BREAKITERATOR_LD, \
SETUP := GENERATE_OLDBYTECODE, \ SETUP := GENERATE_OLDBYTECODE, \
SRC := $(JDK_TOPDIR)/src/jdk.localedata/share/classes, \ SRC := $(JDK_TOPDIR)/src/jdk.localedata/share/classes, \
INCLUDES := $(TEXT_PKG_LD), \
INCLUDE_FILES := \ INCLUDE_FILES := \
$(TEXT_PKG_LD)/BreakIteratorRules_th.java \ $(TEXT_PKG_LD)/BreakIteratorRules_th.java \
$(TEXT_PKG_LD)/BreakIteratorInfo_th.java, \ $(TEXT_PKG_LD)/BreakIteratorInfo_th.java, \

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -37,15 +37,10 @@
* This notice and attribution to Taligent may not be removed. * This notice and attribution to Taligent may not be removed.
* Taligent is a registered trademark of Taligent, Inc. * Taligent is a registered trademark of Taligent, Inc.
*/ */
package sun.util.locale.provider; package sun.text;
import java.io.BufferedInputStream; import java.nio.BufferUnderflowException;
import java.io.InputStream; import java.nio.ByteBuffer;
import java.io.IOException;
import java.lang.reflect.Module;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.MissingResourceException; import java.util.MissingResourceException;
import sun.text.CompactByteArray; import sun.text.CompactByteArray;
import sun.text.SupplementaryCharacterData; import sun.text.SupplementaryCharacterData;
@ -137,131 +132,90 @@ class BreakDictionary {
// deserialization // deserialization
//========================================================================= //=========================================================================
BreakDictionary(Module module, String dictionaryName) BreakDictionary(String dictionaryName, byte[] dictionaryData) {
throws IOException, MissingResourceException { try {
setupDictionary(dictionaryName, dictionaryData);
readDictionaryFile(module, dictionaryName); } catch (BufferUnderflowException bue) {
MissingResourceException e;
e = new MissingResourceException("Corrupted dictionary data",
dictionaryName, "");
e.initCause(bue);
throw e;
}
} }
private void readDictionaryFile(final Module module, final String dictionaryName) private void setupDictionary(String dictionaryName, byte[] dictionaryData) {
throws IOException, MissingResourceException { ByteBuffer bb = ByteBuffer.wrap(dictionaryData);
BufferedInputStream in;
try {
PrivilegedExceptionAction<BufferedInputStream> pa = () -> {
String pathName = "jdk.localedata".equals(module.getName()) ?
"sun/text/resources/ext/" :
"sun/text/resources/";
InputStream is = module.getResourceAsStream(pathName + dictionaryName);
if (is == null) {
// Try to load the file with "java.base" module instance. Assumption
// here is that the fall back data files to be read should reside in
// java.base.
is = BreakDictionary.class.getModule().getResourceAsStream("sun/text/resources/" + dictionaryName);
}
return new BufferedInputStream(is);
};
in = AccessController.doPrivileged(pa);
}
catch (PrivilegedActionException e) {
throw new InternalError(e.toString(), e);
}
byte[] buf = new byte[8];
if (in.read(buf) != 8) {
throw new MissingResourceException("Wrong data length",
dictionaryName, "");
}
// check version // check version
int version = RuleBasedBreakIterator.getInt(buf, 0); int version = bb.getInt();
if (version != supportedVersion) { if (version != supportedVersion) {
throw new MissingResourceException("Dictionary version(" + version + ") is unsupported", throw new MissingResourceException("Dictionary version(" + version + ") is unsupported",
dictionaryName, "");
}
// get data size
int len = RuleBasedBreakIterator.getInt(buf, 4);
buf = new byte[len];
if (in.read(buf) != len) {
throw new MissingResourceException("Wrong data length",
dictionaryName, ""); dictionaryName, "");
} }
// close the stream // Check data size
in.close(); int len = bb.getInt();
if (bb.position() + len != bb.limit()) {
int l; throw new MissingResourceException("Dictionary size is wrong: " + bb.limit(),
int offset = 0; dictionaryName, "");
}
// read in the column map for BMP characteres (this is serialized in // read in the column map for BMP characteres (this is serialized in
// its internal form: an index array followed by a data array) // its internal form: an index array followed by a data array)
l = RuleBasedBreakIterator.getInt(buf, offset); len = bb.getInt();
offset += 4; short[] temp = new short[len];
short[] temp = new short[l]; for (int i = 0; i < len; i++) {
for (int i = 0; i < l; i++, offset+=2) { temp[i] = bb.getShort();
temp[i] = RuleBasedBreakIterator.getShort(buf, offset);
}
l = RuleBasedBreakIterator.getInt(buf, offset);
offset += 4;
byte[] temp2 = new byte[l];
for (int i = 0; i < l; i++, offset++) {
temp2[i] = buf[offset];
} }
len = bb.getInt();
byte[] temp2 = new byte[len];
bb.get(temp2);
columnMap = new CompactByteArray(temp, temp2); columnMap = new CompactByteArray(temp, temp2);
// read in numCols and numColGroups // read in numCols and numColGroups
numCols = RuleBasedBreakIterator.getInt(buf, offset); numCols = bb.getInt();
offset += 4; numColGroups = bb.getInt();
numColGroups = RuleBasedBreakIterator.getInt(buf, offset);
offset += 4;
// read in the row-number index // read in the row-number index
l = RuleBasedBreakIterator.getInt(buf, offset); len = bb.getInt();
offset += 4; rowIndex = new short[len];
rowIndex = new short[l]; for (int i = 0; i < len; i++) {
for (int i = 0; i < l; i++, offset+=2) { rowIndex[i] = bb.getShort();
rowIndex[i] = RuleBasedBreakIterator.getShort(buf, offset);
} }
// load in the populated-cells bitmap: index first, then bitmap list // load in the populated-cells bitmap: index first, then bitmap list
l = RuleBasedBreakIterator.getInt(buf, offset); len = bb.getInt();
offset += 4; rowIndexFlagsIndex = new short[len];
rowIndexFlagsIndex = new short[l]; for (int i = 0; i < len; i++) {
for (int i = 0; i < l; i++, offset+=2) { rowIndexFlagsIndex[i] = bb.getShort();
rowIndexFlagsIndex[i] = RuleBasedBreakIterator.getShort(buf, offset);
} }
l = RuleBasedBreakIterator.getInt(buf, offset); len = bb.getInt();
offset += 4; rowIndexFlags = new int[len];
rowIndexFlags = new int[l]; for (int i = 0; i < len; i++) {
for (int i = 0; i < l; i++, offset+=4) { rowIndexFlags[i] = bb.getInt();
rowIndexFlags[i] = RuleBasedBreakIterator.getInt(buf, offset);
} }
// load in the row-shift index // load in the row-shift index
l = RuleBasedBreakIterator.getInt(buf, offset); len = bb.getInt();
offset += 4; rowIndexShifts = new byte[len];
rowIndexShifts = new byte[l]; bb.get(rowIndexShifts);
for (int i = 0; i < l; i++, offset++) {
rowIndexShifts[i] = buf[offset];
}
// load in the actual state table // load in the actual state table
l = RuleBasedBreakIterator.getInt(buf, offset); len = bb.getInt();
offset += 4; table = new short[len];
table = new short[l]; for (int i = 0; i < len; i++) {
for (int i = 0; i < l; i++, offset+=2) { table[i] = bb.getShort();
table[i] = RuleBasedBreakIterator.getShort(buf, offset);
} }
// finally, prepare the column map for supplementary characters // finally, prepare the column map for supplementary characters
l = RuleBasedBreakIterator.getInt(buf, offset); len = bb.getInt();
offset += 4; int[] temp3 = new int[len];
int[] temp3 = new int[l]; for (int i = 0; i < len; i++) {
for (int i = 0; i < l; i++, offset+=4) { temp3[i] = bb.getInt();
temp3[i] = RuleBasedBreakIterator.getInt(buf, offset);
} }
assert bb.position() == bb.limit();
supplementaryCharColumnMap = new SupplementaryCharacterData(temp3); supplementaryCharColumnMap = new SupplementaryCharacterData(temp3);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -38,10 +38,8 @@
* Taligent is a registered trademark of Taligent, Inc. * Taligent is a registered trademark of Taligent, Inc.
*/ */
package sun.util.locale.provider; package sun.text;
import java.io.IOException;
import java.lang.reflect.Module;
import java.text.CharacterIterator; import java.text.CharacterIterator;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -72,7 +70,7 @@ import java.util.Stack;
* slow) BuildDictionaryFile utility for creating dictionary files, but aren't * slow) BuildDictionaryFile utility for creating dictionary files, but aren't
* currently making it public. Contact us for help. * currently making it public. Contact us for help.
*/ */
class DictionaryBasedBreakIterator extends RuleBasedBreakIterator { public class DictionaryBasedBreakIterator extends RuleBasedBreakIterator {
/** /**
* a list of known words that is used to divide up contiguous ranges of letters, * a list of known words that is used to divide up contiguous ranges of letters,
@ -109,18 +107,22 @@ class DictionaryBasedBreakIterator extends RuleBasedBreakIterator {
/** /**
* Constructs a DictionaryBasedBreakIterator. * Constructs a DictionaryBasedBreakIterator.
* @param module The module where the dictionary file resides *
* @param dictionaryFilename The filename of the dictionary file to use * @param ruleFile the name of the rule data file
* @param ruleData the rule data loaded from the rule data file
* @param dictionaryFile the name of the dictionary file
* @param dictionartData the dictionary data loaded from the dictionary file
* @throws MissingResourceException if rule data or dictionary initialization failed
*/ */
DictionaryBasedBreakIterator(Module module, String dataFile, String dictionaryFile) public DictionaryBasedBreakIterator(String ruleFile, byte[] ruleData,
throws IOException { String dictionaryFile, byte[] dictionaryData) {
super(module, dataFile); super(ruleFile, ruleData);
byte[] tmp = super.getAdditionalData(); byte[] tmp = super.getAdditionalData();
if (tmp != null) { if (tmp != null) {
prepareCategoryFlags(tmp); prepareCategoryFlags(tmp);
super.setAdditionalData(null); super.setAdditionalData(null);
} }
dictionary = new BreakDictionary(module, dictionaryFile); dictionary = new BreakDictionary(dictionaryFile, dictionaryData);
} }
private void prepareCategoryFlags(byte[] data) { private void prepareCategoryFlags(byte[] data) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -38,15 +38,10 @@
* Taligent is a registered trademark of Taligent, Inc. * Taligent is a registered trademark of Taligent, Inc.
*/ */
package sun.util.locale.provider; package sun.text;
import java.io.BufferedInputStream; import java.nio.BufferUnderflowException;
import java.io.InputStream; import java.nio.ByteBuffer;
import java.io.IOException;
import java.lang.reflect.Module;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.text.BreakIterator; import java.text.BreakIterator;
import java.text.CharacterIterator; import java.text.CharacterIterator;
import java.text.StringCharacterIterator; import java.text.StringCharacterIterator;
@ -218,7 +213,7 @@ import sun.text.SupplementaryCharacterData;
* *
* @author Richard Gillam * @author Richard Gillam
*/ */
class RuleBasedBreakIterator extends BreakIterator { public class RuleBasedBreakIterator extends BreakIterator {
/** /**
* A token used as a character-category value to identify ignore characters * A token used as a character-category value to identify ignore characters
@ -249,11 +244,6 @@ class RuleBasedBreakIterator extends BreakIterator {
*/ */
static final byte supportedVersion = 1; static final byte supportedVersion = 1;
/**
* Header size in byte count
*/
private static final int HEADER_LENGTH = 36;
/** /**
* An array length of indices for BMP characters * An array length of indices for BMP characters
*/ */
@ -315,16 +305,26 @@ class RuleBasedBreakIterator extends BreakIterator {
//======================================================================= //=======================================================================
/** /**
* Constructs a RuleBasedBreakIterator according to the module and the datafile * Constructs a RuleBasedBreakIterator using the given rule data.
* provided. *
* @throws MissingResourceException if the rule data is invalid or corrupted
*/ */
RuleBasedBreakIterator(Module module, String datafile) public RuleBasedBreakIterator(String ruleFile, byte[] ruleData) {
throws IOException, MissingResourceException { ByteBuffer bb = ByteBuffer.wrap(ruleData);
readTables(module, datafile); try {
validateRuleData(ruleFile, bb);
setupTables(ruleFile, bb);
} catch (BufferUnderflowException bue) {
MissingResourceException e;
e = new MissingResourceException("Corrupted rule data file", ruleFile, "");
e.initCause(bue);
throw e;
}
} }
/** /**
* Read datafile. The datafile's format is as follows: * Initializes the fields with the given rule data.
* The data format is as follows:
* <pre> * <pre>
* BreakIteratorData { * BreakIteratorData {
* u1 magic[7]; * u1 magic[7];
@ -370,133 +370,101 @@ class RuleBasedBreakIterator extends BreakIterator {
* u1 additionalData[additionalDataLength]; * u1 additionalData[additionalDataLength];
* } * }
* </pre> * </pre>
*
* @throws BufferUnderflowException if the end-of-data is reached before
* setting up all the tables
*/ */
protected final void readTables(Module module, String datafile) private void setupTables(String ruleFile, ByteBuffer bb) {
throws IOException, MissingResourceException {
byte[] buffer = readFile(module, datafile);
/* Read header_info. */ /* Read header_info. */
int stateTableLength = getInt(buffer, 0); int stateTableLength = bb.getInt();
int backwardsStateTableLength = getInt(buffer, 4); int backwardsStateTableLength = bb.getInt();
int endStatesLength = getInt(buffer, 8); int endStatesLength = bb.getInt();
int lookaheadStatesLength = getInt(buffer, 12); int lookaheadStatesLength = bb.getInt();
int BMPdataLength = getInt(buffer, 16); int BMPdataLength = bb.getInt();
int nonBMPdataLength = getInt(buffer, 20); int nonBMPdataLength = bb.getInt();
int additionalDataLength = getInt(buffer, 24); int additionalDataLength = bb.getInt();
checksum = getLong(buffer, 28); checksum = bb.getLong();
/* Read stateTable[numCategories * numRows] */ /* Read stateTable[numCategories * numRows] */
stateTable = new short[stateTableLength]; stateTable = new short[stateTableLength];
int offset = HEADER_LENGTH; for (int i = 0; i < stateTableLength; i++) {
for (int i = 0; i < stateTableLength; i++, offset+=2) { stateTable[i] = bb.getShort();
stateTable[i] = getShort(buffer, offset);
} }
/* Read backwardsStateTable[numCategories * numRows] */ /* Read backwardsStateTable[numCategories * numRows] */
backwardsStateTable = new short[backwardsStateTableLength]; backwardsStateTable = new short[backwardsStateTableLength];
for (int i = 0; i < backwardsStateTableLength; i++, offset+=2) { for (int i = 0; i < backwardsStateTableLength; i++) {
backwardsStateTable[i] = getShort(buffer, offset); backwardsStateTable[i] = bb.getShort();
} }
/* Read endStates[numRows] */ /* Read endStates[numRows] */
endStates = new boolean[endStatesLength]; endStates = new boolean[endStatesLength];
for (int i = 0; i < endStatesLength; i++, offset++) { for (int i = 0; i < endStatesLength; i++) {
endStates[i] = buffer[offset] == 1; endStates[i] = bb.get() == 1;
} }
/* Read lookaheadStates[numRows] */ /* Read lookaheadStates[numRows] */
lookaheadStates = new boolean[lookaheadStatesLength]; lookaheadStates = new boolean[lookaheadStatesLength];
for (int i = 0; i < lookaheadStatesLength; i++, offset++) { for (int i = 0; i < lookaheadStatesLength; i++) {
lookaheadStates[i] = buffer[offset] == 1; lookaheadStates[i] = bb.get() == 1;
} }
/* Read a category table and indices for BMP characters. */ /* Read a category table and indices for BMP characters. */
short[] temp1 = new short[BMP_INDICES_LENGTH]; // BMPindices short[] temp1 = new short[BMP_INDICES_LENGTH]; // BMPindices
for (int i = 0; i < BMP_INDICES_LENGTH; i++, offset+=2) { for (int i = 0; i < BMP_INDICES_LENGTH; i++) {
temp1[i] = getShort(buffer, offset); temp1[i] = bb.getShort();
} }
byte[] temp2 = new byte[BMPdataLength]; // BMPdata byte[] temp2 = new byte[BMPdataLength]; // BMPdata
System.arraycopy(buffer, offset, temp2, 0, BMPdataLength); bb.get(temp2);
offset += BMPdataLength;
charCategoryTable = new CompactByteArray(temp1, temp2); charCategoryTable = new CompactByteArray(temp1, temp2);
/* Read a category table for non-BMP characters. */ /* Read a category table for non-BMP characters. */
int[] temp3 = new int[nonBMPdataLength]; int[] temp3 = new int[nonBMPdataLength];
for (int i = 0; i < nonBMPdataLength; i++, offset+=4) { for (int i = 0; i < nonBMPdataLength; i++) {
temp3[i] = getInt(buffer, offset); temp3[i] = bb.getInt();
} }
supplementaryCharCategoryTable = new SupplementaryCharacterData(temp3); supplementaryCharCategoryTable = new SupplementaryCharacterData(temp3);
/* Read additional data */ /* Read additional data */
if (additionalDataLength > 0) { if (additionalDataLength > 0) {
additionalData = new byte[additionalDataLength]; additionalData = new byte[additionalDataLength];
System.arraycopy(buffer, offset, additionalData, 0, additionalDataLength); bb.get(additionalData);
} }
assert bb.position() == bb.limit();
/* Set numCategories */ /* Set numCategories */
numCategories = stateTable.length / endStates.length; numCategories = stateTable.length / endStates.length;
} }
protected byte[] readFile(final Module module, final String datafile) /**
throws IOException, MissingResourceException { * Validates the magic number, version, and the length of the given data.
*
BufferedInputStream is; * @throws BufferUnderflowException if the end-of-data is reached while
try { * validating data
PrivilegedExceptionAction<BufferedInputStream> pa = () -> { * @throws MissingResourceException if valification failed
String pathName = "jdk.localedata".equals(module.getName()) ? */
"sun/text/resources/ext/" : void validateRuleData(String ruleFile, ByteBuffer bb) {
"sun/text/resources/"; /* Verify the magic number. */
InputStream in = module.getResourceAsStream(pathName + datafile); for (int i = 0; i < LABEL_LENGTH; i++) {
if (in == null) { if (bb.get() != LABEL[i]) {
// Try to load the file with "java.base" module instance. Assumption
// here is that the fall back data files to be read should reside in
// java.base.
in = RuleBasedBreakIterator.class.getModule().getResourceAsStream("sun/text/resources/" + datafile);
}
return new BufferedInputStream(in);
};
is = AccessController.doPrivileged(pa);
} catch (PrivilegedActionException e) {
throw new InternalError(e.toString(), e);
}
int offset = 0;
/* First, read magic, version, and header_info. */
int len = LABEL_LENGTH + 5;
byte[] buf = new byte[len];
if (is.read(buf) != len) {
throw new MissingResourceException("Wrong header length",
datafile, "");
}
/* Validate the magic number. */
for (int i = 0; i < LABEL_LENGTH; i++, offset++) {
if (buf[offset] != LABEL[offset]) {
throw new MissingResourceException("Wrong magic number", throw new MissingResourceException("Wrong magic number",
datafile, ""); ruleFile, "");
} }
} }
/* Validate the version number. */ /* Verify the version number. */
if (buf[offset] != supportedVersion) { byte version = bb.get();
throw new MissingResourceException("Unsupported version(" + buf[offset] + ")", if (version != supportedVersion) {
datafile, ""); throw new MissingResourceException("Unsupported version(" + version + ")",
ruleFile, "");
} }
/* Read data: totalDataSize + 8(for checksum) */ // Check the length of the rest of data
len = getInt(buf, ++offset); int len = bb.getInt();
buf = new byte[len]; if (bb.position() + len != bb.limit()) {
if (is.read(buf) != len) {
throw new MissingResourceException("Wrong data length", throw new MissingResourceException("Wrong data length",
datafile, ""); ruleFile, "");
} }
is.close();
return buf;
} }
byte[] getAdditionalData() { byte[] getAdditionalData() {
@ -1061,28 +1029,6 @@ class RuleBasedBreakIterator extends BreakIterator {
return backwardsStateTable[state * numCategories + category]; return backwardsStateTable[state * numCategories + category];
} }
static long getLong(byte[] buf, int offset) {
long num = buf[offset]&0xFF;
for (int i = 1; i < 8; i++) {
num = num<<8 | (buf[offset+i]&0xFF);
}
return num;
}
static int getInt(byte[] buf, int offset) {
int num = buf[offset]&0xFF;
for (int i = 1; i < 4; i++) {
num = num<<8 | (buf[offset+i]&0xFF);
}
return num;
}
static short getShort(byte[] buf, int offset) {
short num = (short)(buf[offset]&0xFF);
num = (short)(num<<8 | (buf[offset+1]&0xFF));
return num;
}
/* /*
* This class exists to work around a bug in incorrect implementations * This class exists to work around a bug in incorrect implementations
* of CharacterIterator, which incorrectly handle setIndex(endIndex). * of CharacterIterator, which incorrectly handle setIndex(endIndex).

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.text.resources;
import java.util.ResourceBundle;
import sun.util.resources.BreakIteratorResourceBundle;
public class BreakIteratorResources extends BreakIteratorResourceBundle {
@Override
protected ResourceBundle getBreakIteratorInfo() {
return new BreakIteratorInfo();
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -32,6 +32,8 @@ import java.util.Locale;
import java.util.MissingResourceException; import java.util.MissingResourceException;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import sun.text.DictionaryBasedBreakIterator;
import sun.text.RuleBasedBreakIterator;
/** /**
* Concrete implementation of the {@link java.text.spi.BreakIteratorProvider * Concrete implementation of the {@link java.text.spi.BreakIteratorProvider
@ -153,29 +155,31 @@ public class BreakIteratorProviderImpl extends BreakIteratorProvider
} }
private BreakIterator getBreakInstance(Locale locale, private BreakIterator getBreakInstance(Locale locale,
int type, int type,
String dataName, String ruleName,
String dictionaryName) { String dictionaryName) {
Objects.requireNonNull(locale); Objects.requireNonNull(locale);
LocaleResources lr = LocaleProviderAdapter.forJRE().getLocaleResources(locale); LocaleResources lr = LocaleProviderAdapter.forJRE().getLocaleResources(locale);
String[] classNames = (String[]) lr.getBreakIteratorInfo("BreakIteratorClasses"); String[] classNames = (String[]) lr.getBreakIteratorInfo("BreakIteratorClasses");
String dataFile = (String) lr.getBreakIteratorInfo(dataName); String ruleFile = (String) lr.getBreakIteratorInfo(ruleName);
byte[] ruleData = lr.getBreakIteratorResources(ruleName);
try { try {
switch (classNames[type]) { switch (classNames[type]) {
case "RuleBasedBreakIterator": case "RuleBasedBreakIterator":
return new RuleBasedBreakIterator( return new RuleBasedBreakIterator(ruleFile, ruleData);
lr.getBreakIteratorDataModule(), dataFile);
case "DictionaryBasedBreakIterator": case "DictionaryBasedBreakIterator":
String dictionaryFile = (String) lr.getBreakIteratorInfo(dictionaryName); String dictionaryFile = (String) lr.getBreakIteratorInfo(dictionaryName);
return new DictionaryBasedBreakIterator( byte[] dictionaryData = lr.getBreakIteratorResources(dictionaryName);
lr.getBreakIteratorDataModule(), dataFile, dictionaryFile); return new DictionaryBasedBreakIterator(ruleFile, ruleData,
dictionaryFile, dictionaryData);
default: default:
throw new IllegalArgumentException("Invalid break iterator class \"" + throw new IllegalArgumentException("Invalid break iterator class \"" +
classNames[type] + "\""); classNames[type] + "\"");
} }
} catch (IOException | MissingResourceException | IllegalArgumentException e) { } catch (MissingResourceException | IllegalArgumentException e) {
throw new InternalError(e.toString(), e); throw new InternalError(e.toString(), e);
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -42,7 +42,6 @@ package sun.util.locale.provider;
import java.lang.ref.ReferenceQueue; import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference; import java.lang.ref.SoftReference;
import java.lang.reflect.Module;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Calendar; import java.util.Calendar;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
@ -113,13 +112,14 @@ public class LocaleResources {
if (data == null || ((biInfo = data.get()) == null)) { if (data == null || ((biInfo = data.get()) == null)) {
biInfo = localeData.getBreakIteratorInfo(locale).getObject(key); biInfo = localeData.getBreakIteratorInfo(locale).getObject(key);
cache.put(cacheKey, new ResourceReference(cacheKey, biInfo, referenceQueue)); cache.put(cacheKey, new ResourceReference(cacheKey, biInfo, referenceQueue));
} }
return biInfo; return biInfo;
} }
Module getBreakIteratorDataModule() { @SuppressWarnings("unchecked")
return localeData.getBreakIteratorInfo(locale).getClass().getModule(); byte[] getBreakIteratorResources(String key) {
return (byte[]) localeData.getBreakIteratorResources(locale).getObject(key);
} }
int getCalendarData(String key) { int getCalendarData(String key) {

View File

@ -0,0 +1,114 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.resources;
import java.io.InputStream;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Collections;
import java.util.Enumeration;
import java.util.ResourceBundle;
import java.util.Set;
/**
* BreakIteratorResourceBundle is an abstract class for loading BreakIterator
* data (rules or dictionary) from each module. An implementation class must
* implement getBreakIteratorInfo() that returns an instance of the
* corresponding BreakIteratorInfo (basename). The data name is taken from the
* BreakIteratorInfo instance.
*
* <p>For example, if the given key is "WordDictionary" and Locale is "th", the
* data name is taken from a BreakIteratorInfo_th and the key's value is
* "thai_dict". Its data thai_dict is loaded from the Module of the
* implementation class of this class.
*/
public abstract class BreakIteratorResourceBundle extends ResourceBundle {
// If any keys that are not for data names are added to BreakIteratorInfo*,
// those keys must be added to NON_DATA_KEYS.
private static final Set<String> NON_DATA_KEYS = Set.of("BreakIteratorClasses");
private volatile Set<String> keys;
/**
* Returns an instance of the corresponding {@code BreakIteratorInfo} (basename).
* The instance shouldn't have its parent.
*/
protected abstract ResourceBundle getBreakIteratorInfo();
@Override
protected Object handleGetObject(String key) {
if (NON_DATA_KEYS.contains(key)) {
return null;
}
ResourceBundle info = getBreakIteratorInfo();
if (!info.containsKey(key)) {
return null;
}
String path = getClass().getPackage().getName().replace('.', '/')
+ '/' + info.getString(key);
byte[] data;
try (InputStream is = getResourceAsStream(path)) {
data = is.readAllBytes();
} catch (Exception e) {
throw new InternalError("Can't load " + path, e);
}
return data;
}
private InputStream getResourceAsStream(String path) throws Exception {
PrivilegedExceptionAction<InputStream> pa;
pa = () -> getClass().getModule().getResourceAsStream(path);
InputStream is;
try {
is = AccessController.doPrivileged(pa);
} catch (PrivilegedActionException e) {
throw e.getException();
}
return is;
}
@Override
public Enumeration<String> getKeys() {
return Collections.enumeration(keySet());
}
@Override
protected Set<String> handleKeySet() {
if (keys == null) {
ResourceBundle info = getBreakIteratorInfo();
Set<String> k = info.keySet();
k.removeAll(NON_DATA_KEYS);
synchronized (this) {
if (keys == null) {
keys = k;
}
}
}
return keys;
}
}

View File

@ -122,6 +122,14 @@ public class LocaleData {
return getBundle(type.getTextResourcesPackage() + ".BreakIteratorInfo", locale); return getBundle(type.getTextResourcesPackage() + ".BreakIteratorInfo", locale);
} }
/**
* Gets a break iterator resources resource bundle, using
* privileges to allow accessing a sun.* package.
*/
public ResourceBundle getBreakIteratorResources(Locale locale) {
return getBundle(type.getTextResourcesPackage() + ".BreakIteratorResources", locale);
}
/** /**
* Gets a collation data resource bundle, using privileges * Gets a collation data resource bundle, using privileges
* to allow accessing a sun.* package. * to allow accessing a sun.* package.

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.text.resources.ext;
import java.util.ResourceBundle;
import sun.util.resources.BreakIteratorResourceBundle;
public class BreakIteratorResources_th extends BreakIteratorResourceBundle {
@Override
protected ResourceBundle getBreakIteratorInfo() {
return new BreakIteratorInfo_th();
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -89,7 +89,7 @@ public class BreakIteratorProviderTest extends ProviderTest {
String[] jresResult = new String[4]; String[] jresResult = new String[4];
if (jreSupportsLocale) { if (jreSupportsLocale) {
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
jresResult[i] = "sun.util.locale.provider."+classNames[i]; jresResult[i] = "sun.text." + classNames[i];
} }
} }

View File

@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
# #
# Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
@ -23,6 +23,6 @@
# #
# #
# @test # @test
# @bug 4052440 8062588 # @bug 4052440 8062588 8165804
# @summary BreakIteratorProvider tests # @summary BreakIteratorProvider tests
# @run shell ExecTest.sh foo BreakIteratorProviderTest # @run shell ExecTest.sh foo BreakIteratorProviderTest

View File

@ -40,7 +40,7 @@ import tests.Result;
/* /*
* @test * @test
* @bug 8152143 8152704 8155649 * @bug 8152143 8152704 8155649 8165804
* @summary IncludeLocalesPlugin tests * @summary IncludeLocalesPlugin tests
* @author Naoto Sato * @author Naoto Sato
* @library ../../lib * @library ../../lib
@ -236,6 +236,7 @@ public class IncludeLocalesPluginTest {
"/jdk.localedata/sun/text/resources/ext/thai_dict", "/jdk.localedata/sun/text/resources/ext/thai_dict",
"/jdk.localedata/sun/text/resources/ext/WordBreakIteratorData_th", "/jdk.localedata/sun/text/resources/ext/WordBreakIteratorData_th",
"/jdk.localedata/sun/text/resources/ext/BreakIteratorInfo_th.class", "/jdk.localedata/sun/text/resources/ext/BreakIteratorInfo_th.class",
"/jdk.localedata/sun/text/resources/ext/BreakIteratorResources_th.class",
"/jdk.localedata/sun/text/resources/ext/FormatData_en_GB.class", "/jdk.localedata/sun/text/resources/ext/FormatData_en_GB.class",
"/jdk.localedata/sun/text/resources/ext/FormatData_ja.class", "/jdk.localedata/sun/text/resources/ext/FormatData_ja.class",
"/jdk.localedata/sun/text/resources/ext/FormatData_th.class", "/jdk.localedata/sun/text/resources/ext/FormatData_th.class",
@ -261,6 +262,7 @@ public class IncludeLocalesPluginTest {
"/jdk.localedata/sun/text/resources/ext/thai_dict", "/jdk.localedata/sun/text/resources/ext/thai_dict",
"/jdk.localedata/sun/text/resources/ext/WordBreakIteratorData_th", "/jdk.localedata/sun/text/resources/ext/WordBreakIteratorData_th",
"/jdk.localedata/sun/text/resources/ext/BreakIteratorInfo_th.class", "/jdk.localedata/sun/text/resources/ext/BreakIteratorInfo_th.class",
"/jdk.localedata/sun/text/resources/ext/BreakIteratorResources_th.class",
"/jdk.localedata/sun/text/resources/ext/FormatData_th.class"), "/jdk.localedata/sun/text/resources/ext/FormatData_th.class"),
List.of( List.of(
"/jdk.localedata/sun/text/resources/ext/FormatData_en_GB.class", "/jdk.localedata/sun/text/resources/ext/FormatData_en_GB.class",