2 *******************************************************************************
3 * Copyright (C) 2009-2011, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 *******************************************************************************
7 package com.ibm.icu.impl;
9 import java.io.IOException;
10 import java.io.InputStream;
12 import com.ibm.icu.text.Normalizer;
13 import com.ibm.icu.text.Normalizer2;
15 public final class Norm2AllModes {
16 // Public API dispatch via Normalizer2 subclasses -------------------------- ***
18 // Normalizer2 implementation for the old UNORM_NONE.
19 public static final class NoopNormalizer2 extends Normalizer2 {
21 public StringBuilder normalize(CharSequence src, StringBuilder dest) {
24 return dest.append(src);
26 throw new IllegalArgumentException();
30 public Appendable normalize(CharSequence src, Appendable dest) {
33 return dest.append(src);
34 } catch(IOException e) {
35 throw new RuntimeException(e); // Avoid declaring "throws IOException".
38 throw new IllegalArgumentException();
42 public StringBuilder normalizeSecondAndAppend(StringBuilder first, CharSequence second) {
44 return first.append(second);
46 throw new IllegalArgumentException();
50 public StringBuilder append(StringBuilder first, CharSequence second) {
52 return first.append(second);
54 throw new IllegalArgumentException();
58 public String getDecomposition(int c) {
61 // No need to override the default getRawDecomposition().
63 public boolean isNormalized(CharSequence s) { return true; }
65 public Normalizer.QuickCheckResult quickCheck(CharSequence s) { return Normalizer.YES; }
67 public int spanQuickCheckYes(CharSequence s) { return s.length(); }
69 public boolean hasBoundaryBefore(int c) { return true; }
71 public boolean hasBoundaryAfter(int c) { return true; }
73 public boolean isInert(int c) { return true; }
76 // Intermediate class:
77 // Has Normalizer2Impl and does boilerplate argument checking and setup.
78 public static abstract class Normalizer2WithImpl extends Normalizer2 {
79 public Normalizer2WithImpl(Normalizer2Impl ni) {
85 public StringBuilder normalize(CharSequence src, StringBuilder dest) {
87 throw new IllegalArgumentException();
90 normalize(src, new Normalizer2Impl.ReorderingBuffer(impl, dest, src.length()));
94 public Appendable normalize(CharSequence src, Appendable dest) {
96 throw new IllegalArgumentException();
98 Normalizer2Impl.ReorderingBuffer buffer=
99 new Normalizer2Impl.ReorderingBuffer(impl, dest, src.length());
100 normalize(src, buffer);
104 protected abstract void normalize(CharSequence src, Normalizer2Impl.ReorderingBuffer buffer);
106 // normalize and append
108 public StringBuilder normalizeSecondAndAppend(StringBuilder first, CharSequence second) {
109 return normalizeSecondAndAppend(first, second, true);
112 public StringBuilder append(StringBuilder first, CharSequence second) {
113 return normalizeSecondAndAppend(first, second, false);
115 public StringBuilder normalizeSecondAndAppend(
116 StringBuilder first, CharSequence second, boolean doNormalize) {
118 throw new IllegalArgumentException();
122 new Normalizer2Impl.ReorderingBuffer(impl, first, first.length()+second.length()));
125 protected abstract void normalizeAndAppend(
126 CharSequence src, boolean doNormalize, Normalizer2Impl.ReorderingBuffer buffer);
129 public String getDecomposition(int c) {
130 return impl.getDecomposition(c);
133 public String getRawDecomposition(int c) {
134 return impl.getRawDecomposition(c);
137 public int composePair(int a, int b) {
138 return impl.composePair(a, b);
142 public int getCombiningClass(int c) {
143 return impl.getCC(impl.getNorm16(c));
148 public boolean isNormalized(CharSequence s) {
149 return s.length()==spanQuickCheckYes(s);
152 public Normalizer.QuickCheckResult quickCheck(CharSequence s) {
153 return isNormalized(s) ? Normalizer.YES : Normalizer.NO;
156 public int getQuickCheck(int c) {
160 public final Normalizer2Impl impl;
163 public static final class DecomposeNormalizer2 extends Normalizer2WithImpl {
164 public DecomposeNormalizer2(Normalizer2Impl ni) {
169 protected void normalize(CharSequence src, Normalizer2Impl.ReorderingBuffer buffer) {
170 impl.decompose(src, 0, src.length(), buffer);
173 protected void normalizeAndAppend(
174 CharSequence src, boolean doNormalize, Normalizer2Impl.ReorderingBuffer buffer) {
175 impl.decomposeAndAppend(src, doNormalize, buffer);
178 public int spanQuickCheckYes(CharSequence s) {
179 return impl.decompose(s, 0, s.length(), null);
182 public int getQuickCheck(int c) {
183 return impl.isDecompYes(impl.getNorm16(c)) ? 1 : 0;
186 public boolean hasBoundaryBefore(int c) { return impl.hasDecompBoundary(c, true); }
188 public boolean hasBoundaryAfter(int c) { return impl.hasDecompBoundary(c, false); }
190 public boolean isInert(int c) { return impl.isDecompInert(c); }
193 public static final class ComposeNormalizer2 extends Normalizer2WithImpl {
194 public ComposeNormalizer2(Normalizer2Impl ni, boolean fcc) {
200 protected void normalize(CharSequence src, Normalizer2Impl.ReorderingBuffer buffer) {
201 impl.compose(src, 0, src.length(), onlyContiguous, true, buffer);
204 protected void normalizeAndAppend(
205 CharSequence src, boolean doNormalize, Normalizer2Impl.ReorderingBuffer buffer) {
206 impl.composeAndAppend(src, doNormalize, onlyContiguous, buffer);
210 public boolean isNormalized(CharSequence s) {
211 // 5: small destCapacity for substring normalization
212 return impl.compose(s, 0, s.length(),
213 onlyContiguous, false,
214 new Normalizer2Impl.ReorderingBuffer(impl, new StringBuilder(), 5));
217 public Normalizer.QuickCheckResult quickCheck(CharSequence s) {
218 int spanLengthAndMaybe=impl.composeQuickCheck(s, 0, s.length(), onlyContiguous, false);
219 if((spanLengthAndMaybe&1)!=0) {
220 return Normalizer.MAYBE;
221 } else if((spanLengthAndMaybe>>>1)==s.length()) {
222 return Normalizer.YES;
224 return Normalizer.NO;
228 public int spanQuickCheckYes(CharSequence s) {
229 return impl.composeQuickCheck(s, 0, s.length(), onlyContiguous, true)>>>1;
232 public int getQuickCheck(int c) {
233 return impl.getCompQuickCheck(impl.getNorm16(c));
236 public boolean hasBoundaryBefore(int c) { return impl.hasCompBoundaryBefore(c); }
238 public boolean hasBoundaryAfter(int c) {
239 return impl.hasCompBoundaryAfter(c, onlyContiguous, false);
242 public boolean isInert(int c) {
243 return impl.hasCompBoundaryAfter(c, onlyContiguous, true);
246 private final boolean onlyContiguous;
249 public static final class FCDNormalizer2 extends Normalizer2WithImpl {
250 public FCDNormalizer2(Normalizer2Impl ni) {
255 protected void normalize(CharSequence src, Normalizer2Impl.ReorderingBuffer buffer) {
256 impl.makeFCD(src, 0, src.length(), buffer);
259 protected void normalizeAndAppend(
260 CharSequence src, boolean doNormalize, Normalizer2Impl.ReorderingBuffer buffer) {
261 impl.makeFCDAndAppend(src, doNormalize, buffer);
264 public int spanQuickCheckYes(CharSequence s) {
265 return impl.makeFCD(s, 0, s.length(), null);
268 public int getQuickCheck(int c) {
269 return impl.isDecompYes(impl.getNorm16(c)) ? 1 : 0;
272 public boolean hasBoundaryBefore(int c) { return impl.hasFCDBoundaryBefore(c); }
274 public boolean hasBoundaryAfter(int c) { return impl.hasFCDBoundaryAfter(c); }
276 public boolean isInert(int c) { return impl.isFCDInert(c); }
279 // instance cache ---------------------------------------------------------- ***
281 private Norm2AllModes(Normalizer2Impl ni) {
283 comp=new ComposeNormalizer2(ni, false);
284 decomp=new DecomposeNormalizer2(ni);
285 fcd=new FCDNormalizer2(ni);
286 fcc=new ComposeNormalizer2(ni, true);
289 public final Normalizer2Impl impl;
290 public final ComposeNormalizer2 comp;
291 public final DecomposeNormalizer2 decomp;
292 public final FCDNormalizer2 fcd;
293 public final ComposeNormalizer2 fcc;
295 private static Norm2AllModes getInstanceFromSingleton(Norm2AllModesSingleton singleton) {
296 if(singleton.exception!=null) {
297 throw singleton.exception;
299 return singleton.allModes;
301 public static Norm2AllModes getNFCInstance() {
302 return getInstanceFromSingleton(NFCSingleton.INSTANCE);
304 public static Norm2AllModes getNFKCInstance() {
305 return getInstanceFromSingleton(NFKCSingleton.INSTANCE);
307 public static Norm2AllModes getNFKC_CFInstance() {
308 return getInstanceFromSingleton(NFKC_CFSingleton.INSTANCE);
310 // For use in properties APIs.
311 public static Normalizer2WithImpl getN2WithImpl(int index) {
313 case 0: return getNFCInstance().decomp; // NFD
314 case 1: return getNFKCInstance().decomp; // NFKD
315 case 2: return getNFCInstance().comp; // NFC
316 case 3: return getNFKCInstance().comp; // NFKC
317 default: return null;
320 public static Norm2AllModes getInstance(InputStream data, String name) {
322 Norm2AllModesSingleton singleton;
323 if(name.equals("nfc")) {
324 singleton=NFCSingleton.INSTANCE;
325 } else if(name.equals("nfkc")) {
326 singleton=NFKCSingleton.INSTANCE;
327 } else if(name.equals("nfkc_cf")) {
328 singleton=NFKC_CFSingleton.INSTANCE;
332 if(singleton!=null) {
333 if(singleton.exception!=null) {
334 throw singleton.exception;
336 return singleton.allModes;
339 return cache.getInstance(name, data);
341 private static CacheBase<String, Norm2AllModes, InputStream> cache =
342 new SoftCache<String, Norm2AllModes, InputStream>() {
343 protected Norm2AllModes createInstance(String key, InputStream data) {
344 Normalizer2Impl impl;
346 impl=new Normalizer2Impl().load(ICUResourceBundle.ICU_BUNDLE+"/"+key+".nrm");
348 impl=new Normalizer2Impl().load(data);
350 return new Norm2AllModes(impl);
354 public static final NoopNormalizer2 NOOP_NORMALIZER2=new NoopNormalizer2();
356 * Gets the FCD normalizer, with the FCD data initialized.
357 * @return FCD normalizer
359 public static Normalizer2 getFCDNormalizer2() {
360 return getNFCInstance().fcd;
363 private static final class Norm2AllModesSingleton {
364 private Norm2AllModesSingleton(String name) {
366 Normalizer2Impl impl=new Normalizer2Impl().load(
367 ICUResourceBundle.ICU_BUNDLE+"/"+name+".nrm");
368 allModes=new Norm2AllModes(impl);
369 } catch(RuntimeException e) {
374 private Norm2AllModes allModes;
375 private RuntimeException exception;
377 private static final class NFCSingleton {
378 private static final Norm2AllModesSingleton INSTANCE=new Norm2AllModesSingleton("nfc");
380 private static final class NFKCSingleton {
381 private static final Norm2AllModesSingleton INSTANCE=new Norm2AllModesSingleton("nfkc");
383 private static final class NFKC_CFSingleton {
384 private static final Norm2AllModesSingleton INSTANCE=new Norm2AllModesSingleton("nfkc_cf");