You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
216 lines
7.7 KiB
216 lines
7.7 KiB
/*
|
|
* Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
|
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
*/
|
|
/*
|
|
* Copyright 1999-2004 The Apache Software Foundation.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
/*
|
|
* $Id: StringComparable.java,v 1.2.4.1 2005/09/15 08:15:55 suresh_emailid Exp $
|
|
*/
|
|
|
|
package com.sun.org.apache.xml.internal.utils;
|
|
|
|
import java.util.Vector;
|
|
import java.text.Collator;
|
|
import java.text.RuleBasedCollator;
|
|
import java.text.CollationElementIterator;
|
|
import java.util.Locale;
|
|
import java.text.CollationKey;
|
|
|
|
|
|
/**
|
|
* International friendly string comparison with case-order
|
|
* @author Igor Hersht, igorh@ca.ibm.com
|
|
*/
|
|
public class StringComparable implements Comparable {
|
|
|
|
public final static int UNKNOWN_CASE = -1;
|
|
public final static int UPPER_CASE = 1;
|
|
public final static int LOWER_CASE = 2;
|
|
|
|
private String m_text;
|
|
private Locale m_locale;
|
|
private RuleBasedCollator m_collator;
|
|
private String m_caseOrder;
|
|
private int m_mask = 0xFFFFFFFF;
|
|
|
|
public StringComparable(final String text, final Locale locale, final Collator collator, final String caseOrder){
|
|
m_text = text;
|
|
m_locale = locale;
|
|
m_collator = (RuleBasedCollator)collator;
|
|
m_caseOrder = caseOrder;
|
|
m_mask = getMask(m_collator.getStrength());
|
|
}
|
|
|
|
public final static Comparable getComparator( final String text, final Locale locale, final Collator collator, final String caseOrder){
|
|
if((caseOrder == null) ||(caseOrder.length() == 0)){// no case-order specified
|
|
return ((RuleBasedCollator)collator).getCollationKey(text);
|
|
}else{
|
|
return new StringComparable(text, locale, collator, caseOrder);
|
|
}
|
|
}
|
|
|
|
public final String toString(){return m_text;}
|
|
|
|
public int compareTo(Object o) {
|
|
final String pattern = ((StringComparable)o).toString();
|
|
if(m_text.equals(pattern)){//Code-point equals
|
|
return 0;
|
|
}
|
|
final int savedStrength = m_collator.getStrength();
|
|
int comp = 0;
|
|
// Is there difference more significant than case-order?
|
|
if(((savedStrength == Collator.PRIMARY) || (savedStrength == Collator.SECONDARY))){
|
|
comp = m_collator.compare(m_text, pattern );
|
|
}else{// more than SECONDARY
|
|
m_collator.setStrength(Collator.SECONDARY);
|
|
comp = m_collator.compare(m_text, pattern );
|
|
m_collator.setStrength(savedStrength);
|
|
}
|
|
if(comp != 0){//Difference more significant than case-order
|
|
return comp ;
|
|
}
|
|
|
|
// No difference more significant than case-order.
|
|
// Find case difference
|
|
comp = getCaseDiff(m_text, pattern);
|
|
if(comp != 0){
|
|
return comp;
|
|
}else{// No case differences. Less significant difference could exist
|
|
return m_collator.compare(m_text, pattern );
|
|
}
|
|
}
|
|
|
|
|
|
private final int getCaseDiff (final String text, final String pattern){
|
|
final int savedStrength = m_collator.getStrength();
|
|
final int savedDecomposition = m_collator.getDecomposition();
|
|
m_collator.setStrength(Collator.TERTIARY);// not to ignore case
|
|
m_collator.setDecomposition(Collator.CANONICAL_DECOMPOSITION );// corresponds NDF
|
|
|
|
final int diff[] =getFirstCaseDiff (text, pattern, m_locale);
|
|
m_collator.setStrength(savedStrength);// restore
|
|
m_collator.setDecomposition(savedDecomposition); //restore
|
|
if(diff != null){
|
|
if((m_caseOrder).equals("upper-first")){
|
|
if(diff[0] == UPPER_CASE){
|
|
return -1;
|
|
}else{
|
|
return 1;
|
|
}
|
|
}else{// lower-first
|
|
if(diff[0] == LOWER_CASE){
|
|
return -1;
|
|
}else{
|
|
return 1;
|
|
}
|
|
}
|
|
}else{// No case differences
|
|
return 0;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private final int[] getFirstCaseDiff(final String text, final String pattern, final Locale locale){
|
|
|
|
final CollationElementIterator targIter = m_collator.getCollationElementIterator(text);
|
|
final CollationElementIterator patIter = m_collator.getCollationElementIterator(pattern);
|
|
int startTarg = -1;
|
|
int endTarg = -1;
|
|
int startPatt = -1;
|
|
int endPatt = -1;
|
|
final int done = getElement(CollationElementIterator.NULLORDER);
|
|
int patternElement = 0, targetElement = 0;
|
|
boolean getPattern = true, getTarget = true;
|
|
|
|
while (true) {
|
|
if (getPattern){
|
|
startPatt = patIter.getOffset();
|
|
patternElement = getElement(patIter.next());
|
|
endPatt = patIter.getOffset();
|
|
}
|
|
if ((getTarget)){
|
|
startTarg = targIter.getOffset();
|
|
targetElement = getElement(targIter.next());
|
|
endTarg = targIter.getOffset();
|
|
}
|
|
getTarget = getPattern = true;
|
|
if ((patternElement == done) ||( targetElement == done)) {
|
|
return null;
|
|
} else if (targetElement == 0) {
|
|
getPattern = false;
|
|
} else if (patternElement == 0) {
|
|
getTarget = false;
|
|
} else if (targetElement != patternElement) {// mismatch
|
|
if((startPatt < endPatt) && (startTarg < endTarg)){
|
|
final String subText = text.substring(startTarg, endTarg);
|
|
final String subPatt = pattern.substring(startPatt, endPatt);
|
|
final String subTextUp = subText.toUpperCase(locale);
|
|
final String subPattUp = subPatt.toUpperCase(locale);
|
|
if(m_collator.compare(subTextUp, subPattUp) != 0){ // not case diffference
|
|
continue;
|
|
}
|
|
|
|
int diff[] = {UNKNOWN_CASE, UNKNOWN_CASE};
|
|
if(m_collator.compare(subText, subTextUp) == 0){
|
|
diff[0] = UPPER_CASE;
|
|
}else if(m_collator.compare(subText, subText.toLowerCase(locale)) == 0){
|
|
diff[0] = LOWER_CASE;
|
|
}
|
|
if(m_collator.compare(subPatt, subPattUp) == 0){
|
|
diff[1] = UPPER_CASE;
|
|
}else if(m_collator.compare(subPatt, subPatt.toLowerCase(locale)) == 0){
|
|
diff[1] = LOWER_CASE;
|
|
}
|
|
|
|
if(((diff[0] == UPPER_CASE) && ( diff[1] == LOWER_CASE)) ||
|
|
((diff[0] == LOWER_CASE) && ( diff[1] == UPPER_CASE))){
|
|
return diff;
|
|
}else{// not case diff
|
|
continue;
|
|
}
|
|
}else{
|
|
continue;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// Return a mask for the part of the order we're interested in
|
|
private static final int getMask(final int strength) {
|
|
switch (strength) {
|
|
case Collator.PRIMARY:
|
|
return 0xFFFF0000;
|
|
case Collator.SECONDARY:
|
|
return 0xFFFFFF00;
|
|
default:
|
|
return 0xFFFFFFFF;
|
|
}
|
|
}
|
|
//get collation element with given strength
|
|
// from the element with max strength
|
|
private final int getElement(int maxStrengthElement){
|
|
|
|
return (maxStrengthElement & m_mask);
|
|
}
|
|
|
|
}//StringComparable
|