1 /* 2 * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 ******************************************************************************* 28 * Copyright (C) 2009-2014, International Business Machines 29 * Corporation and others. All Rights Reserved. 30 ******************************************************************************* 31 */ 32 33 package sun.text.normalizer; 34 35 import java.io.IOException; 36 37 final class Norm2AllModes { 38 // Public API dispatch via Normalizer2 subclasses -------------------------- *** 39 40 // Normalizer2 implementation for the old UNORM_NONE. 41 public static final class NoopNormalizer2 extends Normalizer2 { 42 @Override normalize(CharSequence src, StringBuilder dest)43 public StringBuilder normalize(CharSequence src, StringBuilder dest) { 44 if(dest!=src) { 45 dest.setLength(0); 46 return dest.append(src); 47 } else { 48 throw new IllegalArgumentException(); 49 } 50 } 51 52 @Override normalize(CharSequence src, Appendable dest)53 public Appendable normalize(CharSequence src, Appendable dest) { 54 if(dest!=src) { 55 try { 56 return dest.append(src); 57 } catch(IOException e) { 58 throw new InternalError(e.toString(), e); 59 } 60 } else { 61 throw new IllegalArgumentException(); 62 } 63 } 64 65 @Override normalizeSecondAndAppend(StringBuilder first, CharSequence second)66 public StringBuilder normalizeSecondAndAppend(StringBuilder first, CharSequence second) { 67 if(first!=second) { 68 return first.append(second); 69 } else { 70 throw new IllegalArgumentException(); 71 } 72 } 73 74 @Override append(StringBuilder first, CharSequence second)75 public StringBuilder append(StringBuilder first, CharSequence second) { 76 if(first!=second) { 77 return first.append(second); 78 } else { 79 throw new IllegalArgumentException(); 80 } 81 } 82 83 @Override getDecomposition(int c)84 public String getDecomposition(int c) { 85 return null; 86 } 87 88 // No need to override the default getRawDecomposition(). 89 @Override isNormalized(CharSequence s)90 public boolean isNormalized(CharSequence s) { return true; } 91 92 @Override spanQuickCheckYes(CharSequence s)93 public int spanQuickCheckYes(CharSequence s) { return s.length(); } 94 95 @Override hasBoundaryBefore(int c)96 public boolean hasBoundaryBefore(int c) { return true; } 97 } 98 99 // Intermediate class: 100 // Has NormalizerImpl and does boilerplate argument checking and setup. 101 public abstract static class Normalizer2WithImpl extends Normalizer2 { Normalizer2WithImpl(NormalizerImpl ni)102 public Normalizer2WithImpl(NormalizerImpl ni) { 103 impl=ni; 104 } 105 106 // normalize 107 @Override normalize(CharSequence src, StringBuilder dest)108 public StringBuilder normalize(CharSequence src, StringBuilder dest) { 109 if(dest==src) { 110 throw new IllegalArgumentException(); 111 } 112 dest.setLength(0); 113 normalize(src, new NormalizerImpl.ReorderingBuffer(impl, dest, src.length())); 114 return dest; 115 } 116 117 @Override normalize(CharSequence src, Appendable dest)118 public Appendable normalize(CharSequence src, Appendable dest) { 119 if(dest==src) { 120 throw new IllegalArgumentException(); 121 } 122 NormalizerImpl.ReorderingBuffer buffer= 123 new NormalizerImpl.ReorderingBuffer(impl, dest, src.length()); 124 normalize(src, buffer); 125 buffer.flush(); 126 return dest; 127 } 128 normalize(CharSequence src, NormalizerImpl.ReorderingBuffer buffer)129 protected abstract void normalize(CharSequence src, NormalizerImpl.ReorderingBuffer buffer); 130 131 // normalize and append 132 @Override normalizeSecondAndAppend(StringBuilder first, CharSequence second)133 public StringBuilder normalizeSecondAndAppend(StringBuilder first, CharSequence second) { 134 return normalizeSecondAndAppend(first, second, true); 135 } 136 137 @Override append(StringBuilder first, CharSequence second)138 public StringBuilder append(StringBuilder first, CharSequence second) { 139 return normalizeSecondAndAppend(first, second, false); 140 } 141 normalizeSecondAndAppend( StringBuilder first, CharSequence second, boolean doNormalize)142 public StringBuilder normalizeSecondAndAppend( 143 StringBuilder first, CharSequence second, boolean doNormalize) { 144 if(first==second) { 145 throw new IllegalArgumentException(); 146 } 147 normalizeAndAppend( 148 second, doNormalize, 149 new NormalizerImpl.ReorderingBuffer(impl, first, first.length()+second.length())); 150 return first; 151 } 152 normalizeAndAppend( CharSequence src, boolean doNormalize, NormalizerImpl.ReorderingBuffer buffer)153 protected abstract void normalizeAndAppend( 154 CharSequence src, boolean doNormalize, NormalizerImpl.ReorderingBuffer buffer); 155 156 @Override getDecomposition(int c)157 public String getDecomposition(int c) { 158 return impl.getDecomposition(c); 159 } 160 161 @Override getCombiningClass(int c)162 public int getCombiningClass(int c) { 163 return impl.getCC(impl.getNorm16(c)); 164 } 165 166 // quick checks 167 @Override isNormalized(CharSequence s)168 public boolean isNormalized(CharSequence s) { 169 return s.length()==spanQuickCheckYes(s); 170 } 171 172 public final NormalizerImpl impl; 173 } 174 175 public static final class DecomposeNormalizer2 extends Normalizer2WithImpl { DecomposeNormalizer2(NormalizerImpl ni)176 public DecomposeNormalizer2(NormalizerImpl ni) { 177 super(ni); 178 } 179 180 @Override normalize(CharSequence src, NormalizerImpl.ReorderingBuffer buffer)181 protected void normalize(CharSequence src, NormalizerImpl.ReorderingBuffer buffer) { 182 impl.decompose(src, 0, src.length(), buffer); 183 } 184 185 @Override normalizeAndAppend( CharSequence src, boolean doNormalize, NormalizerImpl.ReorderingBuffer buffer)186 protected void normalizeAndAppend( 187 CharSequence src, boolean doNormalize, NormalizerImpl.ReorderingBuffer buffer) { 188 impl.decomposeAndAppend(src, doNormalize, buffer); 189 } 190 191 @Override spanQuickCheckYes(CharSequence s)192 public int spanQuickCheckYes(CharSequence s) { 193 return impl.decompose(s, 0, s.length(), null); 194 } 195 196 @Override hasBoundaryBefore(int c)197 public boolean hasBoundaryBefore(int c) { return impl.hasDecompBoundaryBefore(c); } 198 } 199 200 public static final class ComposeNormalizer2 extends Normalizer2WithImpl { ComposeNormalizer2(NormalizerImpl ni, boolean fcc)201 public ComposeNormalizer2(NormalizerImpl ni, boolean fcc) { 202 super(ni); 203 onlyContiguous=fcc; 204 } 205 206 @Override normalize(CharSequence src, NormalizerImpl.ReorderingBuffer buffer)207 protected void normalize(CharSequence src, NormalizerImpl.ReorderingBuffer buffer) { 208 impl.compose(src, 0, src.length(), onlyContiguous, true, buffer); 209 } 210 211 @Override normalizeAndAppend( CharSequence src, boolean doNormalize, NormalizerImpl.ReorderingBuffer buffer)212 protected void normalizeAndAppend( 213 CharSequence src, boolean doNormalize, NormalizerImpl.ReorderingBuffer buffer) { 214 impl.composeAndAppend(src, doNormalize, onlyContiguous, buffer); 215 } 216 217 @Override isNormalized(CharSequence s)218 public boolean isNormalized(CharSequence s) { 219 // 5: small destCapacity for substring normalization 220 return impl.compose(s, 0, s.length(), 221 onlyContiguous, false, 222 new NormalizerImpl.ReorderingBuffer(impl, new StringBuilder(), 5)); 223 } 224 225 @Override spanQuickCheckYes(CharSequence s)226 public int spanQuickCheckYes(CharSequence s) { 227 return impl.composeQuickCheck(s, 0, s.length(), onlyContiguous, true)>>>1; 228 } 229 230 @Override hasBoundaryBefore(int c)231 public boolean hasBoundaryBefore(int c) { return impl.hasCompBoundaryBefore(c); } 232 233 private final boolean onlyContiguous; 234 } 235 236 // instance cache ---------------------------------------------------------- *** 237 Norm2AllModes(NormalizerImpl ni)238 private Norm2AllModes(NormalizerImpl ni) { 239 impl=ni; 240 comp=new ComposeNormalizer2(ni, false); 241 decomp=new DecomposeNormalizer2(ni); 242 } 243 244 public final NormalizerImpl impl; 245 public final ComposeNormalizer2 comp; 246 public final DecomposeNormalizer2 decomp; 247 getInstanceFromSingleton(Norm2AllModesSingleton singleton)248 private static Norm2AllModes getInstanceFromSingleton(Norm2AllModesSingleton singleton) { 249 if(singleton.exception!=null) { 250 throw singleton.exception; 251 } 252 return singleton.allModes; 253 } 254 getNFCInstance()255 public static Norm2AllModes getNFCInstance() { 256 return getInstanceFromSingleton(NFCSingleton.INSTANCE); 257 } 258 getNFKCInstance()259 public static Norm2AllModes getNFKCInstance() { 260 return getInstanceFromSingleton(NFKCSingleton.INSTANCE); 261 } 262 263 public static final NoopNormalizer2 NOOP_NORMALIZER2=new NoopNormalizer2(); 264 265 private static final class Norm2AllModesSingleton { Norm2AllModesSingleton(String name)266 private Norm2AllModesSingleton(String name) { 267 try { 268 String DATA_FILE_NAME = "/sun/text/resources/" + name + ".nrm"; 269 NormalizerImpl impl=new NormalizerImpl().load(DATA_FILE_NAME); 270 allModes=new Norm2AllModes(impl); 271 } catch (RuntimeException e) { 272 exception=e; 273 } 274 } 275 276 private Norm2AllModes allModes; 277 private RuntimeException exception; 278 } 279 280 private static final class NFCSingleton { 281 private static final Norm2AllModesSingleton INSTANCE=new Norm2AllModesSingleton("nfc"); 282 } 283 284 private static final class NFKCSingleton { 285 private static final Norm2AllModesSingleton INSTANCE=new Norm2AllModesSingleton("nfkc"); 286 } 287 } 288