1// © 2016 and later: Unicode, Inc. and others. 2// License & terms of use: http://www.unicode.org/copyright.html#License 3/* 4 ******************************************************************************* 5 * Copyright (C) 2009-2011, Google, International Business Machines Corporation 6 * and others. All Rights Reserved. 7 ******************************************************************************* 8 */ 9package com.ibm.icu.text; 10 11import com.ibm.icu.impl.UCaseProps; 12import com.ibm.icu.lang.UCharacter; 13 14/** 15 * A transliterator that performs locale-sensitive toLower() 16 * case mapping. 17 */ 18class CaseFoldTransliterator extends Transliterator{ 19 20 /** 21 * Package accessible ID. 22 */ 23 static final String _ID = "Any-CaseFold"; 24 25 // TODO: Add variants for tr, az, lt, default = default locale 26 27 /** 28 * System registration hook. 29 */ 30 static void register() { 31 Transliterator.registerFactory(_ID, new Transliterator.Factory() { 32 @Override 33 public Transliterator getInstance(String ID) { 34 return new CaseFoldTransliterator(); 35 } 36 }); 37 38 Transliterator.registerSpecialInverse("CaseFold", "Upper", false); 39 } 40 41 private final UCaseProps csp; 42 private ReplaceableContextIterator iter; 43 private StringBuilder result; 44 45 /** 46 * Constructs a transliterator. 47 */ 48 49 public CaseFoldTransliterator() { 50 super(_ID, null); 51 csp=UCaseProps.INSTANCE; 52 iter=new ReplaceableContextIterator(); 53 result = new StringBuilder(); 54 } 55 56 /** 57 * Implements {@link Transliterator#handleTransliterate}. 58 */ 59 @Override 60 protected synchronized void handleTransliterate(Replaceable text, 61 Position offsets, boolean isIncremental) { 62 if(csp==null) { 63 return; 64 } 65 66 if(offsets.start >= offsets.limit) { 67 return; 68 } 69 70 iter.setText(text); 71 result.setLength(0); 72 int c, delta; 73 74 // Walk through original string 75 // If there is a case change, modify corresponding position in replaceable 76 77 iter.setIndex(offsets.start); 78 iter.setLimit(offsets.limit); 79 iter.setContextLimits(offsets.contextStart, offsets.contextLimit); 80 while((c=iter.nextCaseMapCP())>=0) { 81 c=csp.toFullFolding(c, result, 0); // toFullFolding(int c, StringBuffer out, int options) 82 83 if(iter.didReachLimit() && isIncremental) { 84 // the case mapping function tried to look beyond the context limit 85 // wait for more input 86 offsets.start=iter.getCaseMapCPStart(); 87 return; 88 } 89 90 /* decode the result */ 91 if(c<0) { 92 /* c mapped to itself, no change */ 93 continue; 94 } else if(c<=UCaseProps.MAX_STRING_LENGTH) { 95 /* replace by the mapping string */ 96 delta=iter.replace(result.toString()); 97 result.setLength(0); 98 } else { 99 /* replace by single-code point mapping */ 100 delta=iter.replace(UTF16.valueOf(c)); 101 } 102 103 if(delta!=0) { 104 offsets.limit += delta; 105 offsets.contextLimit += delta; 106 } 107 } 108 offsets.start = offsets.limit; 109 } 110 111 static SourceTargetUtility sourceTargetUtility = null; 112 113 /* (non-Javadoc) 114 * @see com.ibm.icu.text.Transliterator#addSourceTargetSet(com.ibm.icu.text.UnicodeSet, com.ibm.icu.text.UnicodeSet, com.ibm.icu.text.UnicodeSet) 115 */ 116 @Override 117 public void addSourceTargetSet(UnicodeSet inputFilter, UnicodeSet sourceSet, UnicodeSet targetSet) { 118 synchronized (UppercaseTransliterator.class) { 119 if (sourceTargetUtility == null) { 120 sourceTargetUtility = new SourceTargetUtility(new Transform<String,String>() { 121 @Override 122 public String transform(String source) { 123 return UCharacter.foldCase(source, true); 124 } 125 }); 126 } 127 } 128 sourceTargetUtility.addSourceTargetSet(this, inputFilter, sourceSet, targetSet); 129 } 130} 131