1 /* 2 * Copyright (c) 2015, 2020, 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 jdk.internal.icu.impl; 34 35 import java.io.IOException; 36 37 import jdk.internal.icu.text.Normalizer2; 38 import jdk.internal.icu.util.VersionInfo; 39 40 public final class Norm2AllModes { 41 // Public API dispatch via Normalizer2 subclasses -------------------------- *** 42 43 // Normalizer2 implementation for the old UNORM_NONE. 44 public static final class NoopNormalizer2 extends Normalizer2 { 45 @Override normalize(CharSequence src, StringBuilder dest)46 public StringBuilder normalize(CharSequence src, StringBuilder dest) { 47 if(dest!=src) { 48 dest.setLength(0); 49 return dest.append(src); 50 } else { 51 throw new IllegalArgumentException(); 52 } 53 } 54 55 @Override normalize(CharSequence src, Appendable dest)56 public Appendable normalize(CharSequence src, Appendable dest) { 57 if(dest!=src) { 58 try { 59 return dest.append(src); 60 } catch(IOException e) { 61 throw new InternalError(e.toString(), e); 62 } 63 } else { 64 throw new IllegalArgumentException(); 65 } 66 } 67 68 @Override normalizeSecondAndAppend(StringBuilder first, CharSequence second)69 public StringBuilder normalizeSecondAndAppend(StringBuilder first, CharSequence second) { 70 if(first!=second) { 71 return first.append(second); 72 } else { 73 throw new IllegalArgumentException(); 74 } 75 } 76 77 @Override append(StringBuilder first, CharSequence second)78 public StringBuilder append(StringBuilder first, CharSequence second) { 79 if(first!=second) { 80 return first.append(second); 81 } else { 82 throw new IllegalArgumentException(); 83 } 84 } 85 86 @Override getDecomposition(int c)87 public String getDecomposition(int c) { 88 return null; 89 } 90 91 // No need to override the default getRawDecomposition(). 92 @Override isNormalized(CharSequence s)93 public boolean isNormalized(CharSequence s) { return true; } 94 95 @Override spanQuickCheckYes(CharSequence s)96 public int spanQuickCheckYes(CharSequence s) { return s.length(); } 97 98 @Override hasBoundaryBefore(int c)99 public boolean hasBoundaryBefore(int c) { return true; } 100 } 101 102 // Intermediate class: 103 // Has NormalizerImpl and does boilerplate argument checking and setup. 104 public abstract static class Normalizer2WithImpl extends Normalizer2 { Normalizer2WithImpl(NormalizerImpl ni)105 public Normalizer2WithImpl(NormalizerImpl ni) { 106 impl=ni; 107 } 108 109 // normalize 110 @Override normalize(CharSequence src, StringBuilder dest)111 public StringBuilder normalize(CharSequence src, StringBuilder dest) { 112 if(dest==src) { 113 throw new IllegalArgumentException(); 114 } 115 dest.setLength(0); 116 normalize(src, new NormalizerImpl.ReorderingBuffer(impl, dest, src.length())); 117 return dest; 118 } 119 120 @Override normalize(CharSequence src, Appendable dest)121 public Appendable normalize(CharSequence src, Appendable dest) { 122 if(dest==src) { 123 throw new IllegalArgumentException(); 124 } 125 NormalizerImpl.ReorderingBuffer buffer= 126 new NormalizerImpl.ReorderingBuffer(impl, dest, src.length()); 127 normalize(src, buffer); 128 buffer.flush(); 129 return dest; 130 } 131 normalize(CharSequence src, NormalizerImpl.ReorderingBuffer buffer)132 protected abstract void normalize(CharSequence src, NormalizerImpl.ReorderingBuffer buffer); 133 134 // normalize and append 135 @Override normalizeSecondAndAppend(StringBuilder first, CharSequence second)136 public StringBuilder normalizeSecondAndAppend(StringBuilder first, CharSequence second) { 137 return normalizeSecondAndAppend(first, second, true); 138 } 139 140 @Override append(StringBuilder first, CharSequence second)141 public StringBuilder append(StringBuilder first, CharSequence second) { 142 return normalizeSecondAndAppend(first, second, false); 143 } 144 normalizeSecondAndAppend( StringBuilder first, CharSequence second, boolean doNormalize)145 public StringBuilder normalizeSecondAndAppend( 146 StringBuilder first, CharSequence second, boolean doNormalize) { 147 if(first==second) { 148 throw new IllegalArgumentException(); 149 } 150 normalizeAndAppend( 151 second, doNormalize, 152 new NormalizerImpl.ReorderingBuffer(impl, first, first.length()+second.length())); 153 return first; 154 } 155 normalizeAndAppend( CharSequence src, boolean doNormalize, NormalizerImpl.ReorderingBuffer buffer)156 protected abstract void normalizeAndAppend( 157 CharSequence src, boolean doNormalize, NormalizerImpl.ReorderingBuffer buffer); 158 159 @Override getDecomposition(int c)160 public String getDecomposition(int c) { 161 return impl.getDecomposition(c); 162 } 163 164 @Override getCombiningClass(int c)165 public int getCombiningClass(int c) { 166 return impl.getCC(impl.getNorm16(c)); 167 } 168 169 // quick checks 170 @Override isNormalized(CharSequence s)171 public boolean isNormalized(CharSequence s) { 172 return s.length()==spanQuickCheckYes(s); 173 } 174 175 public final NormalizerImpl impl; 176 } 177 178 public static final class DecomposeNormalizer2 extends Normalizer2WithImpl { DecomposeNormalizer2(NormalizerImpl ni)179 public DecomposeNormalizer2(NormalizerImpl ni) { 180 super(ni); 181 } 182 183 @Override normalize(CharSequence src, NormalizerImpl.ReorderingBuffer buffer)184 protected void normalize(CharSequence src, NormalizerImpl.ReorderingBuffer buffer) { 185 impl.decompose(src, 0, src.length(), buffer); 186 } 187 188 @Override normalizeAndAppend( CharSequence src, boolean doNormalize, NormalizerImpl.ReorderingBuffer buffer)189 protected void normalizeAndAppend( 190 CharSequence src, boolean doNormalize, NormalizerImpl.ReorderingBuffer buffer) { 191 impl.decomposeAndAppend(src, doNormalize, buffer); 192 } 193 194 @Override spanQuickCheckYes(CharSequence s)195 public int spanQuickCheckYes(CharSequence s) { 196 return impl.decompose(s, 0, s.length(), null); 197 } 198 199 @Override hasBoundaryBefore(int c)200 public boolean hasBoundaryBefore(int c) { return impl.hasDecompBoundaryBefore(c); } 201 } 202 203 public static final class ComposeNormalizer2 extends Normalizer2WithImpl { ComposeNormalizer2(NormalizerImpl ni, boolean fcc)204 public ComposeNormalizer2(NormalizerImpl ni, boolean fcc) { 205 super(ni); 206 onlyContiguous=fcc; 207 } 208 209 @Override normalize(CharSequence src, NormalizerImpl.ReorderingBuffer buffer)210 protected void normalize(CharSequence src, NormalizerImpl.ReorderingBuffer buffer) { 211 impl.compose(src, 0, src.length(), onlyContiguous, true, buffer); 212 } 213 214 @Override normalizeAndAppend( CharSequence src, boolean doNormalize, NormalizerImpl.ReorderingBuffer buffer)215 protected void normalizeAndAppend( 216 CharSequence src, boolean doNormalize, NormalizerImpl.ReorderingBuffer buffer) { 217 impl.composeAndAppend(src, doNormalize, onlyContiguous, buffer); 218 } 219 220 @Override isNormalized(CharSequence s)221 public boolean isNormalized(CharSequence s) { 222 // 5: small destCapacity for substring normalization 223 return impl.compose(s, 0, s.length(), 224 onlyContiguous, false, 225 new NormalizerImpl.ReorderingBuffer(impl, new StringBuilder(), 5)); 226 } 227 228 @Override spanQuickCheckYes(CharSequence s)229 public int spanQuickCheckYes(CharSequence s) { 230 return impl.composeQuickCheck(s, 0, s.length(), onlyContiguous, true)>>>1; 231 } 232 233 @Override hasBoundaryBefore(int c)234 public boolean hasBoundaryBefore(int c) { return impl.hasCompBoundaryBefore(c); } 235 236 private final boolean onlyContiguous; 237 } 238 239 // instance cache ---------------------------------------------------------- *** 240 Norm2AllModes(NormalizerImpl ni)241 private Norm2AllModes(NormalizerImpl ni) { 242 impl=ni; 243 comp=new ComposeNormalizer2(ni, false); 244 decomp=new DecomposeNormalizer2(ni); 245 } 246 247 public final NormalizerImpl impl; 248 public final ComposeNormalizer2 comp; 249 public final DecomposeNormalizer2 decomp; 250 getInstanceFromSingleton(Norm2AllModesSingleton singleton)251 private static Norm2AllModes getInstanceFromSingleton(Norm2AllModesSingleton singleton) { 252 if(singleton.exception!=null) { 253 throw singleton.exception; 254 } 255 return singleton.allModes; 256 } 257 getNFCInstance()258 public static Norm2AllModes getNFCInstance() { 259 return getInstanceFromSingleton(NFCSingleton.INSTANCE); 260 } 261 getNFKCInstance()262 public static Norm2AllModes getNFKCInstance() { 263 return getInstanceFromSingleton(NFKCSingleton.INSTANCE); 264 } 265 266 public static final NoopNormalizer2 NOOP_NORMALIZER2=new NoopNormalizer2(); 267 268 private static final class Norm2AllModesSingleton { Norm2AllModesSingleton(String name)269 private Norm2AllModesSingleton(String name) { 270 try { 271 @SuppressWarnings("deprecation") 272 String DATA_FILE_NAME = "/jdk/internal/icu/impl/data/icudt" + 273 VersionInfo.ICU_DATA_VERSION_PATH + "/" + name + ".nrm"; 274 NormalizerImpl impl=new NormalizerImpl().load(DATA_FILE_NAME); 275 allModes=new Norm2AllModes(impl); 276 } catch (RuntimeException e) { 277 exception=e; 278 } 279 } 280 281 private Norm2AllModes allModes; 282 private RuntimeException exception; 283 } 284 285 private static final class NFCSingleton { 286 private static final Norm2AllModesSingleton INSTANCE=new Norm2AllModesSingleton("nfc"); 287 } 288 289 private static final class NFKCSingleton { 290 private static final Norm2AllModesSingleton INSTANCE=new Norm2AllModesSingleton("nfkc"); 291 } 292 } 293