Norm2AllModes.java revision 12745:f068a4ffddd2
1/*
2 * Copyright (c) 2015, 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
33package sun.text.normalizer;
34
35import java.io.IOException;
36
37final 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
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
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
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
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
84        public String getDecomposition(int c) {
85            return null;
86        }
87
88        // No need to override the default getRawDecomposition().
89        @Override
90        public boolean isNormalized(CharSequence s) { return true; }
91
92        @Override
93        public int spanQuickCheckYes(CharSequence s) { return s.length(); }
94
95        @Override
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 {
102        public Normalizer2WithImpl(NormalizerImpl ni) {
103            impl=ni;
104        }
105
106        // normalize
107        @Override
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
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
129        protected abstract void normalize(CharSequence src, NormalizerImpl.ReorderingBuffer buffer);
130
131        // normalize and append
132        @Override
133        public StringBuilder normalizeSecondAndAppend(StringBuilder first, CharSequence second) {
134            return normalizeSecondAndAppend(first, second, true);
135        }
136
137        @Override
138        public StringBuilder append(StringBuilder first, CharSequence second) {
139            return normalizeSecondAndAppend(first, second, false);
140        }
141
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
153        protected abstract void normalizeAndAppend(
154                CharSequence src, boolean doNormalize, NormalizerImpl.ReorderingBuffer buffer);
155
156        @Override
157        public String getDecomposition(int c) {
158            return impl.getDecomposition(c);
159        }
160
161        @Override
162        public int getCombiningClass(int c) {
163            return impl.getCC(impl.getNorm16(c));
164        }
165
166        // quick checks
167        @Override
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 {
176        public DecomposeNormalizer2(NormalizerImpl ni) {
177            super(ni);
178        }
179
180        @Override
181        protected void normalize(CharSequence src, NormalizerImpl.ReorderingBuffer buffer) {
182            impl.decompose(src, 0, src.length(), buffer);
183        }
184
185        @Override
186        protected void normalizeAndAppend(
187                CharSequence src, boolean doNormalize, NormalizerImpl.ReorderingBuffer buffer) {
188            impl.decomposeAndAppend(src, doNormalize, buffer);
189        }
190
191        @Override
192        public int spanQuickCheckYes(CharSequence s) {
193            return impl.decompose(s, 0, s.length(), null);
194        }
195
196        @Override
197        public boolean hasBoundaryBefore(int c) { return impl.hasDecompBoundary(c, true); }
198    }
199
200    public static final class ComposeNormalizer2 extends Normalizer2WithImpl {
201        public ComposeNormalizer2(NormalizerImpl ni, boolean fcc) {
202            super(ni);
203            onlyContiguous=fcc;
204        }
205
206        @Override
207        protected void normalize(CharSequence src, NormalizerImpl.ReorderingBuffer buffer) {
208            impl.compose(src, 0, src.length(), onlyContiguous, true, buffer);
209        }
210
211        @Override
212        protected void normalizeAndAppend(
213                CharSequence src, boolean doNormalize, NormalizerImpl.ReorderingBuffer buffer) {
214            impl.composeAndAppend(src, doNormalize, onlyContiguous, buffer);
215        }
216
217        @Override
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
226        public int spanQuickCheckYes(CharSequence s) {
227            return impl.composeQuickCheck(s, 0, s.length(), onlyContiguous, true)>>>1;
228        }
229
230        @Override
231        public boolean hasBoundaryBefore(int c) { return impl.hasCompBoundaryBefore(c); }
232
233        private final boolean onlyContiguous;
234    }
235
236    // instance cache ---------------------------------------------------------- ***
237
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
248    private static Norm2AllModes getInstanceFromSingleton(Norm2AllModesSingleton singleton) {
249        if(singleton.exception!=null) {
250            throw singleton.exception;
251        }
252        return singleton.allModes;
253    }
254
255    public static Norm2AllModes getNFCInstance() {
256        return getInstanceFromSingleton(NFCSingleton.INSTANCE);
257    }
258
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 {
266        private Norm2AllModesSingleton(String name) {
267            try {
268                String DATA_FILE_NAME = "/sun/text/resources/" + name + ".icu";
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