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