/* |
|
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. |
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
* |
|
* This code is free software; you can redistribute it and/or modify it |
|
* under the terms of the GNU General Public License version 2 only, as |
|
* published by the Free Software Foundation. Oracle designates this |
|
* particular file as subject to the "Classpath" exception as provided |
|
* by Oracle in the LICENSE file that accompanied this code. |
|
* |
|
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
* version 2 for more details (a copy is included in the LICENSE file that |
|
* accompanied this code). |
|
* |
|
* You should have received a copy of the GNU General Public License version |
|
* 2 along with this work; if not, write to the Free Software Foundation, |
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
* |
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
* or visit www.oracle.com if you need additional information or have any |
|
* questions. |
|
*/ |
|
package sun.nio.cs; |
|
import java.nio.CharBuffer; |
|
import java.nio.charset.CoderResult; |
|
import java.nio.charset.MalformedInputException; |
|
import java.nio.charset.UnmappableCharacterException; |
|
/** |
|
* Utility class for dealing with surrogates. |
|
* |
|
* @author Mark Reinhold |
|
* @author Martin Buchholz |
|
* @author Ulf Zibis |
|
*/ |
|
public class Surrogate { |
|
private Surrogate() { } |
|
// TODO: Deprecate/remove the following redundant definitions |
|
public static final char MIN_HIGH = Character.MIN_HIGH_SURROGATE; |
|
public static final char MAX_HIGH = Character.MAX_HIGH_SURROGATE; |
|
public static final char MIN_LOW = Character.MIN_LOW_SURROGATE; |
|
public static final char MAX_LOW = Character.MAX_LOW_SURROGATE; |
|
public static final char MIN = Character.MIN_SURROGATE; |
|
public static final char MAX = Character.MAX_SURROGATE; |
|
public static final int UCS4_MIN = Character.MIN_SUPPLEMENTARY_CODE_POINT; |
|
public static final int UCS4_MAX = Character.MAX_CODE_POINT; |
|
/** |
|
* Tells whether or not the given value is in the high surrogate range. |
|
* Use of {@link Character#isHighSurrogate} is generally preferred. |
|
*/ |
|
public static boolean isHigh(int c) { |
|
return (MIN_HIGH <= c) && (c <= MAX_HIGH); |
|
} |
|
/** |
|
* Tells whether or not the given value is in the low surrogate range. |
|
* Use of {@link Character#isLowSurrogate} is generally preferred. |
|
*/ |
|
public static boolean isLow(int c) { |
|
return (MIN_LOW <= c) && (c <= MAX_LOW); |
|
} |
|
/** |
|
* Tells whether or not the given value is in the surrogate range. |
|
* Use of {@link Character#isSurrogate} is generally preferred. |
|
*/ |
|
public static boolean is(int c) { |
|
return (MIN <= c) && (c <= MAX); |
|
} |
|
/** |
|
* Tells whether or not the given UCS-4 character must be represented as a |
|
* surrogate pair in UTF-16. |
|
* Use of {@link Character#isSupplementaryCodePoint} is generally preferred. |
|
*/ |
|
public static boolean neededFor(int uc) { |
|
return Character.isSupplementaryCodePoint(uc); |
|
} |
|
/** |
|
* Returns the high UTF-16 surrogate for the given supplementary UCS-4 character. |
|
* Use of {@link Character#highSurrogate} is generally preferred. |
|
*/ |
|
public static char high(int uc) { |
|
assert Character.isSupplementaryCodePoint(uc); |
|
return Character.highSurrogate(uc); |
|
} |
|
/** |
|
* Returns the low UTF-16 surrogate for the given supplementary UCS-4 character. |
|
* Use of {@link Character#lowSurrogate} is generally preferred. |
|
*/ |
|
public static char low(int uc) { |
|
assert Character.isSupplementaryCodePoint(uc); |
|
return Character.lowSurrogate(uc); |
|
} |
|
/** |
|
* Converts the given surrogate pair into a 32-bit UCS-4 character. |
|
* Use of {@link Character#toCodePoint} is generally preferred. |
|
*/ |
|
public static int toUCS4(char c, char d) { |
|
assert Character.isHighSurrogate(c) && Character.isLowSurrogate(d); |
|
return Character.toCodePoint(c, d); |
|
} |
|
/** |
|
* Surrogate parsing support. Charset implementations may use instances of |
|
* this class to handle the details of parsing UTF-16 surrogate pairs. |
|
*/ |
|
public static class Parser { |
|
public Parser() { } |
|
private int character; // UCS-4 |
|
private CoderResult error = CoderResult.UNDERFLOW; |
|
private boolean isPair; |
|
/** |
|
* Returns the UCS-4 character previously parsed. |
|
*/ |
|
public int character() { |
|
assert (error == null); |
|
return character; |
|
} |
|
/** |
|
* Tells whether or not the previously-parsed UCS-4 character was |
|
* originally represented by a surrogate pair. |
|
*/ |
|
public boolean isPair() { |
|
assert (error == null); |
|
return isPair; |
|
} |
|
/** |
|
* Returns the number of UTF-16 characters consumed by the previous |
|
* parse. |
|
*/ |
|
public int increment() { |
|
assert (error == null); |
|
return isPair ? 2 : 1; |
|
} |
|
/** |
|
* If the previous parse operation detected an error, return the object |
|
* describing that error. |
|
*/ |
|
public CoderResult error() { |
|
assert (error != null); |
|
return error; |
|
} |
|
/** |
|
* Returns an unmappable-input result object, with the appropriate |
|
* input length, for the previously-parsed character. |
|
*/ |
|
public CoderResult unmappableResult() { |
|
assert (error == null); |
|
return CoderResult.unmappableForLength(isPair ? 2 : 1); |
|
} |
|
/** |
|
* Parses a UCS-4 character from the given source buffer, handling |
|
* surrogates. |
|
* |
|
* @param c The first character |
|
* @param in The source buffer, from which one more character |
|
* will be consumed if c is a high surrogate |
|
* |
|
* @return Either a parsed UCS-4 character, in which case the isPair() |
|
* and increment() methods will return meaningful values, or |
|
* -1, in which case error() will return a descriptive result |
|
* object |
|
*/ |
|
public int parse(char c, CharBuffer in) { |
|
if (Character.isHighSurrogate(c)) { |
|
if (!in.hasRemaining()) { |
|
error = CoderResult.UNDERFLOW; |
|
return -1; |
|
} |
|
char d = in.get(); |
|
if (Character.isLowSurrogate(d)) { |
|
character = Character.toCodePoint(c, d); |
|
isPair = true; |
|
error = null; |
|
return character; |
|
} |
|
error = CoderResult.malformedForLength(1); |
|
return -1; |
|
} |
|
if (Character.isLowSurrogate(c)) { |
|
error = CoderResult.malformedForLength(1); |
|
return -1; |
|
} |
|
character = c; |
|
isPair = false; |
|
error = null; |
|
return character; |
|
} |
|
/** |
|
* Parses a UCS-4 character from the given source buffer, handling |
|
* surrogates. |
|
* |
|
* @param c The first character |
|
* @param ia The input array, from which one more character |
|
* will be consumed if c is a high surrogate |
|
* @param ip The input index |
|
* @param il The input limit |
|
* |
|
* @return Either a parsed UCS-4 character, in which case the isPair() |
|
* and increment() methods will return meaningful values, or |
|
* -1, in which case error() will return a descriptive result |
|
* object |
|
*/ |
|
public int parse(char c, char[] ia, int ip, int il) { |
|
assert (ia[ip] == c); |
|
if (Character.isHighSurrogate(c)) { |
|
if (il - ip < 2) { |
|
error = CoderResult.UNDERFLOW; |
|
return -1; |
|
} |
|
char d = ia[ip + 1]; |
|
if (Character.isLowSurrogate(d)) { |
|
character = Character.toCodePoint(c, d); |
|
isPair = true; |
|
error = null; |
|
return character; |
|
} |
|
error = CoderResult.malformedForLength(1); |
|
return -1; |
|
} |
|
if (Character.isLowSurrogate(c)) { |
|
error = CoderResult.malformedForLength(1); |
|
return -1; |
|
} |
|
character = c; |
|
isPair = false; |
|
error = null; |
|
return character; |
|
} |
|
} |
|
/** |
|
* Surrogate generation support. Charset implementations may use instances |
|
* of this class to handle the details of generating UTF-16 surrogate |
|
* pairs. |
|
*/ |
|
public static class Generator { |
|
public Generator() { } |
|
private CoderResult error = CoderResult.OVERFLOW; |
|
/** |
|
* If the previous generation operation detected an error, return the |
|
* object describing that error. |
|
*/ |
|
public CoderResult error() { |
|
assert error != null; |
|
return error; |
|
} |
|
/** |
|
* Generates one or two UTF-16 characters to represent the given UCS-4 |
|
* character. |
|
* |
|
* @param uc The UCS-4 character |
|
* @param len The number of input bytes from which the UCS-4 value |
|
* was constructed (used when creating result objects) |
|
* @param dst The destination buffer, to which one or two UTF-16 |
|
* characters will be written |
|
* |
|
* @return Either a positive count of the number of UTF-16 characters |
|
* written to the destination buffer, or -1, in which case |
|
* error() will return a descriptive result object |
|
*/ |
|
public int generate(int uc, int len, CharBuffer dst) { |
|
if (Character.isBmpCodePoint(uc)) { |
|
char c = (char) uc; |
|
if (Character.isSurrogate(c)) { |
|
error = CoderResult.malformedForLength(len); |
|
return -1; |
|
} |
|
if (dst.remaining() < 1) { |
|
error = CoderResult.OVERFLOW; |
|
return -1; |
|
} |
|
dst.put(c); |
|
error = null; |
|
return 1; |
|
} else if (Character.isValidCodePoint(uc)) { |
|
if (dst.remaining() < 2) { |
|
error = CoderResult.OVERFLOW; |
|
return -1; |
|
} |
|
dst.put(Character.highSurrogate(uc)); |
|
dst.put(Character.lowSurrogate(uc)); |
|
error = null; |
|
return 2; |
|
} else { |
|
error = CoderResult.unmappableForLength(len); |
|
return -1; |
|
} |
|
} |
|
/** |
|
* Generates one or two UTF-16 characters to represent the given UCS-4 |
|
* character. |
|
* |
|
* @param uc The UCS-4 character |
|
* @param len The number of input bytes from which the UCS-4 value |
|
* was constructed (used when creating result objects) |
|
* @param da The destination array, to which one or two UTF-16 |
|
* characters will be written |
|
* @param dp The destination position |
|
* @param dl The destination limit |
|
* |
|
* @return Either a positive count of the number of UTF-16 characters |
|
* written to the destination buffer, or -1, in which case |
|
* error() will return a descriptive result object |
|
*/ |
|
public int generate(int uc, int len, char[] da, int dp, int dl) { |
|
if (Character.isBmpCodePoint(uc)) { |
|
char c = (char) uc; |
|
if (Character.isSurrogate(c)) { |
|
error = CoderResult.malformedForLength(len); |
|
return -1; |
|
} |
|
if (dl - dp < 1) { |
|
error = CoderResult.OVERFLOW; |
|
return -1; |
|
} |
|
da[dp] = c; |
|
error = null; |
|
return 1; |
|
} else if (Character.isValidCodePoint(uc)) { |
|
if (dl - dp < 2) { |
|
error = CoderResult.OVERFLOW; |
|
return -1; |
|
} |
|
da[dp] = Character.highSurrogate(uc); |
|
da[dp + 1] = Character.lowSurrogate(uc); |
|
error = null; |
|
return 2; |
|
} else { |
|
error = CoderResult.unmappableForLength(len); |
|
return -1; |
|
} |
|
} |
|
} |
|
} |