jdk/src/share/classes/sun/nio/cs/Surrogate.java
changeset 2 90ce3da70b43
child 3324 02cc89024ea2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/cs/Surrogate.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,366 @@
+/*
+ * Copyright 2000-2001 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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
+ */
+
+public class Surrogate {
+
+    private Surrogate() { }
+
+    // UTF-16 surrogate-character ranges
+    //
+    public static final char MIN_HIGH = '\uD800';
+    public static final char MAX_HIGH = '\uDBFF';
+    public static final char MIN_LOW  = '\uDC00';
+    public static final char MAX_LOW  = '\uDFFF';
+    public static final char MIN = MIN_HIGH;
+    public static final char MAX = MAX_LOW;
+
+    // Range of UCS-4 values that need surrogates in UTF-16
+    //
+    public static final int UCS4_MIN = 0x10000;
+    public static final int UCS4_MAX = (1 << 20) + UCS4_MIN - 1;
+
+    /**
+     * Tells whether or not the given UTF-16 value is a high surrogate.
+     */
+    public static boolean isHigh(int c) {
+        return (MIN_HIGH <= c) && (c <= MAX_HIGH);
+    }
+
+    /**
+     * Tells whether or not the given UTF-16 value is a low surrogate.
+     */
+    public static boolean isLow(int c) {
+        return (MIN_LOW <= c) && (c <= MAX_LOW);
+    }
+
+    /**
+     * Tells whether or not the given UTF-16 value is a surrogate character,
+     */
+    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.
+     */
+    public static boolean neededFor(int uc) {
+        return (uc >= UCS4_MIN) && (uc <= UCS4_MAX);
+    }
+
+    /**
+     * Returns the high UTF-16 surrogate for the given UCS-4 character.
+     */
+    public static char high(int uc) {
+        assert neededFor(uc);
+        return (char)(0xd800 | (((uc - UCS4_MIN) >> 10) & 0x3ff));
+    }
+
+    /**
+     * Returns the low UTF-16 surrogate for the given UCS-4 character.
+     */
+    public static char low(int uc) {
+        assert neededFor(uc);
+        return (char)(0xdc00 | ((uc - UCS4_MIN) & 0x3ff));
+    }
+
+    /**
+     * Converts the given surrogate pair into a 32-bit UCS-4 character.
+     */
+    public static int toUCS4(char c, char d) {
+        assert isHigh(c) && isLow(d);
+        return (((c & 0x3ff) << 10) | (d & 0x3ff)) + 0x10000;
+    }
+
+    /**
+     * 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
+         *
+         * @returns  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 (Surrogate.isHigh(c)) {
+                if (!in.hasRemaining()) {
+                    error = CoderResult.UNDERFLOW;
+                    return -1;
+                }
+                char d = in.get();
+                if (Surrogate.isLow(d)) {
+                    character = toUCS4(c, d);
+                    isPair = true;
+                    error = null;
+                    return character;
+                }
+                error = CoderResult.malformedForLength(1);
+                return -1;
+            }
+            if (Surrogate.isLow(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
+         *
+         * @returns  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 (Surrogate.isHigh(c)) {
+                if (il - ip < 2) {
+                    error = CoderResult.UNDERFLOW;
+                    return -1;
+                }
+                char d = ia[ip + 1];
+                if (Surrogate.isLow(d)) {
+                    character = toUCS4(c, d);
+                    isPair = true;
+                    error = null;
+                    return character;
+                }
+                error = CoderResult.malformedForLength(1);
+                return -1;
+            }
+            if (Surrogate.isLow(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
+         *
+         * @returns  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 (uc <= 0xffff) {
+                if (Surrogate.is(uc)) {
+                    error = CoderResult.malformedForLength(len);
+                    return -1;
+                }
+                if (dst.remaining() < 1) {
+                    error = CoderResult.OVERFLOW;
+                    return -1;
+                }
+                dst.put((char)uc);
+                error = null;
+                return 1;
+            }
+            if (uc < Surrogate.UCS4_MIN) {
+                error = CoderResult.malformedForLength(len);
+                return -1;
+            }
+            if (uc <= Surrogate.UCS4_MAX) {
+                if (dst.remaining() < 2) {
+                    error = CoderResult.OVERFLOW;
+                    return -1;
+                }
+                dst.put(Surrogate.high(uc));
+                dst.put(Surrogate.low(uc));
+                error = null;
+                return 2;
+            }
+            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
+         *
+         * @returns  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 (uc <= 0xffff) {
+                if (Surrogate.is(uc)) {
+                    error = CoderResult.malformedForLength(len);
+                    return -1;
+                }
+                if (dl - dp < 1) {
+                    error = CoderResult.OVERFLOW;
+                    return -1;
+                }
+                da[dp] = (char)uc;
+                error = null;
+                return 1;
+            }
+            if (uc < Surrogate.UCS4_MIN) {
+                error = CoderResult.malformedForLength(len);
+                return -1;
+            }
+            if (uc <= Surrogate.UCS4_MAX) {
+                if (dl - dp < 2) {
+                    error = CoderResult.OVERFLOW;
+                    return -1;
+                }
+                da[dp] = Surrogate.high(uc);
+                da[dp + 1] = Surrogate.low(uc);
+                error = null;
+                return 2;
+            }
+            error = CoderResult.unmappableForLength(len);
+            return -1;
+        }
+
+    }
+
+}