2 *******************************************************************************
\r
3 * Copyright (C) 2009-2010, International Business Machines
\r
4 * Corporation and others. All Rights Reserved.
\r
5 *******************************************************************************
\r
7 package com.ibm.icu.impl;
\r
9 import java.io.IOException;
\r
10 import java.io.InputStream;
\r
11 import java.util.MissingResourceException;
\r
13 import com.ibm.icu.text.Normalizer;
\r
14 import com.ibm.icu.text.Normalizer2;
\r
16 public final class Norm2AllModes {
\r
17 // Public API dispatch via Normalizer2 subclasses -------------------------- ***
\r
19 // Normalizer2 implementation for the old UNORM_NONE.
\r
20 public static final class NoopNormalizer2 extends Normalizer2 {
\r
22 public StringBuilder normalize(CharSequence src, StringBuilder dest) {
\r
25 return dest.append(src);
\r
27 throw new IllegalArgumentException();
\r
31 public Appendable normalize(CharSequence src, Appendable dest) {
\r
34 return dest.append(src);
\r
35 } catch(IOException e) {
\r
36 throw new RuntimeException(e); // Avoid declaring "throws IOException".
\r
39 throw new IllegalArgumentException();
\r
43 public StringBuilder normalizeSecondAndAppend(StringBuilder first, CharSequence second) {
\r
45 return first.append(second);
\r
47 throw new IllegalArgumentException();
\r
51 public StringBuilder append(StringBuilder first, CharSequence second) {
\r
53 return first.append(second);
\r
55 throw new IllegalArgumentException();
\r
59 public boolean isNormalized(CharSequence s) { return true; }
\r
61 public Normalizer.QuickCheckResult quickCheck(CharSequence s) { return Normalizer.YES; }
\r
63 public int spanQuickCheckYes(CharSequence s) { return s.length(); }
\r
65 public boolean hasBoundaryBefore(int c) { return true; }
\r
67 public boolean hasBoundaryAfter(int c) { return true; }
\r
69 public boolean isInert(int c) { return true; }
\r
72 // Intermediate class:
\r
73 // Has Normalizer2Impl and does boilerplate argument checking and setup.
\r
74 public static abstract class Normalizer2WithImpl extends Normalizer2 {
\r
75 public Normalizer2WithImpl(Normalizer2Impl ni) {
\r
81 public StringBuilder normalize(CharSequence src, StringBuilder dest) {
\r
83 throw new IllegalArgumentException();
\r
86 normalize(src, new Normalizer2Impl.ReorderingBuffer(impl, dest, src.length()));
\r
90 public Appendable normalize(CharSequence src, Appendable dest) {
\r
92 throw new IllegalArgumentException();
\r
94 Normalizer2Impl.ReorderingBuffer buffer=
\r
95 new Normalizer2Impl.ReorderingBuffer(impl, dest, src.length());
\r
96 normalize(src, buffer);
\r
100 protected abstract void normalize(CharSequence src, Normalizer2Impl.ReorderingBuffer buffer);
\r
102 // normalize and append
\r
104 public StringBuilder normalizeSecondAndAppend(StringBuilder first, CharSequence second) {
\r
105 return normalizeSecondAndAppend(first, second, true);
\r
108 public StringBuilder append(StringBuilder first, CharSequence second) {
\r
109 return normalizeSecondAndAppend(first, second, false);
\r
111 public StringBuilder normalizeSecondAndAppend(
\r
112 StringBuilder first, CharSequence second, boolean doNormalize) {
\r
113 if(first==second) {
\r
114 throw new IllegalArgumentException();
\r
116 normalizeAndAppend(
\r
117 second, doNormalize,
\r
118 new Normalizer2Impl.ReorderingBuffer(impl, first, first.length()+second.length()));
\r
121 protected abstract void normalizeAndAppend(
\r
122 CharSequence src, boolean doNormalize, Normalizer2Impl.ReorderingBuffer buffer);
\r
126 public boolean isNormalized(CharSequence s) {
\r
127 return s.length()==spanQuickCheckYes(s);
\r
130 public Normalizer.QuickCheckResult quickCheck(CharSequence s) {
\r
131 return isNormalized(s) ? Normalizer.YES : Normalizer.NO;
\r
134 public int getQuickCheck(int c) {
\r
138 public final Normalizer2Impl impl;
\r
141 public static final class DecomposeNormalizer2 extends Normalizer2WithImpl {
\r
142 public DecomposeNormalizer2(Normalizer2Impl ni) {
\r
147 protected void normalize(CharSequence src, Normalizer2Impl.ReorderingBuffer buffer) {
\r
148 impl.decompose(src, 0, src.length(), buffer);
\r
151 protected void normalizeAndAppend(
\r
152 CharSequence src, boolean doNormalize, Normalizer2Impl.ReorderingBuffer buffer) {
\r
153 impl.decomposeAndAppend(src, doNormalize, buffer);
\r
156 public int spanQuickCheckYes(CharSequence s) {
\r
157 return impl.decompose(s, 0, s.length(), null);
\r
160 public int getQuickCheck(int c) {
\r
161 return impl.isDecompYes(impl.getNorm16(c)) ? 1 : 0;
\r
164 public boolean hasBoundaryBefore(int c) { return impl.hasDecompBoundary(c, true); }
\r
166 public boolean hasBoundaryAfter(int c) { return impl.hasDecompBoundary(c, false); }
\r
168 public boolean isInert(int c) { return impl.isDecompInert(c); }
\r
171 public static final class ComposeNormalizer2 extends Normalizer2WithImpl {
\r
172 public ComposeNormalizer2(Normalizer2Impl ni, boolean fcc) {
\r
174 onlyContiguous=fcc;
\r
178 protected void normalize(CharSequence src, Normalizer2Impl.ReorderingBuffer buffer) {
\r
179 impl.compose(src, 0, src.length(), onlyContiguous, true, buffer);
\r
182 protected void normalizeAndAppend(
\r
183 CharSequence src, boolean doNormalize, Normalizer2Impl.ReorderingBuffer buffer) {
\r
184 impl.composeAndAppend(src, doNormalize, onlyContiguous, buffer);
\r
188 public boolean isNormalized(CharSequence s) {
\r
189 // 5: small destCapacity for substring normalization
\r
190 return impl.compose(s, 0, s.length(),
\r
191 onlyContiguous, false,
\r
192 new Normalizer2Impl.ReorderingBuffer(impl, new StringBuilder(), 5));
\r
195 public Normalizer.QuickCheckResult quickCheck(CharSequence s) {
\r
196 int spanLengthAndMaybe=impl.composeQuickCheck(s, 0, s.length(), onlyContiguous, false);
\r
197 if((spanLengthAndMaybe&1)!=0) {
\r
198 return Normalizer.MAYBE;
\r
199 } else if((spanLengthAndMaybe>>>1)==s.length()) {
\r
200 return Normalizer.YES;
\r
202 return Normalizer.NO;
\r
206 public int spanQuickCheckYes(CharSequence s) {
\r
207 return impl.composeQuickCheck(s, 0, s.length(), onlyContiguous, true)>>>1;
\r
210 public int getQuickCheck(int c) {
\r
211 return impl.getCompQuickCheck(impl.getNorm16(c));
\r
214 public boolean hasBoundaryBefore(int c) { return impl.hasCompBoundaryBefore(c); }
\r
216 public boolean hasBoundaryAfter(int c) {
\r
217 return impl.hasCompBoundaryAfter(c, onlyContiguous, false);
\r
220 public boolean isInert(int c) {
\r
221 return impl.hasCompBoundaryAfter(c, onlyContiguous, true);
\r
224 private final boolean onlyContiguous;
\r
227 public static final class FCDNormalizer2 extends Normalizer2WithImpl {
\r
228 public FCDNormalizer2(Normalizer2Impl ni) {
\r
233 protected void normalize(CharSequence src, Normalizer2Impl.ReorderingBuffer buffer) {
\r
234 impl.makeFCD(src, 0, src.length(), buffer);
\r
237 protected void normalizeAndAppend(
\r
238 CharSequence src, boolean doNormalize, Normalizer2Impl.ReorderingBuffer buffer) {
\r
239 impl.makeFCDAndAppend(src, doNormalize, buffer);
\r
242 public int spanQuickCheckYes(CharSequence s) {
\r
243 return impl.makeFCD(s, 0, s.length(), null);
\r
246 public int getQuickCheck(int c) {
\r
247 return impl.isDecompYes(impl.getNorm16(c)) ? 1 : 0;
\r
250 public boolean hasBoundaryBefore(int c) { return impl.hasFCDBoundaryBefore(c); }
\r
252 public boolean hasBoundaryAfter(int c) { return impl.hasFCDBoundaryAfter(c); }
\r
254 public boolean isInert(int c) { return impl.isFCDInert(c); }
\r
257 // instance cache ---------------------------------------------------------- ***
\r
259 private Norm2AllModes(Normalizer2Impl ni) {
\r
261 comp=new ComposeNormalizer2(ni, false);
\r
262 decomp=new DecomposeNormalizer2(ni);
\r
263 fcd=new FCDNormalizer2(ni);
\r
264 fcc=new ComposeNormalizer2(ni, true);
\r
267 public final Normalizer2Impl impl;
\r
268 public final ComposeNormalizer2 comp;
\r
269 public final DecomposeNormalizer2 decomp;
\r
270 public final FCDNormalizer2 fcd;
\r
271 public final ComposeNormalizer2 fcc;
\r
273 private static Norm2AllModes getInstanceFromSingleton(Norm2AllModesSingleton singleton) {
\r
274 if(singleton.exception!=null) {
\r
275 throw singleton.exception;
\r
277 return singleton.allModes;
\r
279 public static Norm2AllModes getNFCInstance() {
\r
280 return getInstanceFromSingleton(NFCSingleton.INSTANCE);
\r
282 public static Norm2AllModes getNFKCInstance() {
\r
283 return getInstanceFromSingleton(NFKCSingleton.INSTANCE);
\r
285 public static Norm2AllModes getNFKC_CFInstance() {
\r
286 return getInstanceFromSingleton(NFKC_CFSingleton.INSTANCE);
\r
288 // For use in properties APIs.
\r
289 public static Normalizer2WithImpl getN2WithImpl(int index) {
\r
291 case 0: return getNFCInstance().decomp; // NFD
\r
292 case 1: return getNFKCInstance().decomp; // NFKD
\r
293 case 2: return getNFCInstance().comp; // NFC
\r
294 case 3: return getNFKCInstance().comp; // NFKC
\r
295 default: return null;
\r
298 public static Norm2AllModes getInstance(InputStream data, String name) {
\r
300 Norm2AllModesSingleton singleton;
\r
301 if(name.equals("nfc")) {
\r
302 singleton=NFCSingleton.INSTANCE;
\r
303 } else if(name.equals("nfkc")) {
\r
304 singleton=NFKCSingleton.INSTANCE;
\r
305 } else if(name.equals("nfkc_cf")) {
\r
306 singleton=NFKC_CFSingleton.INSTANCE;
\r
310 if(singleton!=null) {
\r
311 if(singleton.exception!=null) {
\r
312 throw singleton.exception;
\r
314 return singleton.allModes;
\r
317 return cache.getInstance(name, data);
\r
319 private static CacheBase<String, Norm2AllModes, InputStream> cache =
\r
320 new SoftCache<String, Norm2AllModes, InputStream>() {
\r
321 protected Norm2AllModes createInstance(String key, InputStream data) {
\r
323 throw new MissingResourceException(
\r
324 "No Normalizer2 data name \""+key+"\" cached, and InputStream is null",
\r
328 Normalizer2Impl impl=new Normalizer2Impl().load(data);
\r
329 return new Norm2AllModes(impl);
\r
333 public static final NoopNormalizer2 NOOP_NORMALIZER2=new NoopNormalizer2();
\r
335 * Gets the FCD normalizer, with the FCD data initialized.
\r
336 * @return FCD normalizer
\r
338 public static Normalizer2 getFCDNormalizer2() {
\r
339 Norm2AllModes allModes=getNFCInstance();
\r
340 allModes.impl.getFCDTrie();
\r
341 return allModes.fcd;
\r
344 private static final class Norm2AllModesSingleton {
\r
345 private Norm2AllModesSingleton(String name) {
\r
347 Normalizer2Impl impl=new Normalizer2Impl().load(
\r
348 ICUResourceBundle.ICU_BUNDLE+"/"+name+".nrm");
\r
349 allModes=new Norm2AllModes(impl);
\r
350 } catch(RuntimeException e) {
\r
355 private Norm2AllModes allModes;
\r
356 private RuntimeException exception;
\r
358 private static final class NFCSingleton {
\r
359 private static final Norm2AllModesSingleton INSTANCE=new Norm2AllModesSingleton("nfc");
\r
361 private static final class NFKCSingleton {
\r
362 private static final Norm2AllModesSingleton INSTANCE=new Norm2AllModesSingleton("nfkc");
\r
364 private static final class NFKC_CFSingleton {
\r
365 private static final Norm2AllModesSingleton INSTANCE=new Norm2AllModesSingleton("nfkc_cf");
\r