001: package net.sf.saxon.functions;
002:
003: import net.sf.saxon.expr.XPathContext;
004: import net.sf.saxon.expr.Expression;
005: import net.sf.saxon.expr.StaticContext;
006: import net.sf.saxon.om.*;
007: import net.sf.saxon.trans.DynamicError;
008: import net.sf.saxon.trans.XPathException;
009: import net.sf.saxon.value.NumericValue;
010: import net.sf.saxon.value.StringValue;
011:
012: /**
013: * This class supports the two functions string-to-codepoints() and codepoints-to-string()
014: */
015:
016: public class Unicode extends SystemFunction {
017:
018: public static final int TO_CODEPOINTS = 0;
019: public static final int FROM_CODEPOINTS = 1;
020:
021: /**
022: * Pre-evaluate a function at compile time. Functions that do not allow
023: * pre-evaluation, or that need access to context information, can override this method.
024: */
025:
026: public Expression preEvaluate(StaticContext env)
027: throws XPathException {
028: switch (operation) {
029: case TO_CODEPOINTS:
030: return super .preEvaluate(env);
031: case FROM_CODEPOINTS:
032: final XPathContext context = env
033: .makeEarlyEvaluationContext();
034: return StringValue.makeStringValue(unicodeToString(
035: argument[0].iterate(context), context));
036: default:
037: throw new UnsupportedOperationException(
038: "Unknown Unicode operation");
039: }
040: }
041:
042: /**
043: * Evaluate
044: */
045:
046: public Item evaluateItem(XPathContext c) throws XPathException {
047: switch (operation) {
048: case TO_CODEPOINTS:
049: throw new UnsupportedOperationException(
050: "Cannot call evaluateItem on a sequence");
051: case FROM_CODEPOINTS:
052: return StringValue.makeStringValue(unicodeToString(
053: argument[0].iterate(c), c));
054: default:
055: throw new UnsupportedOperationException(
056: "Unknown Unicode operation");
057: }
058: }
059:
060: public SequenceIterator iterate(XPathContext c)
061: throws XPathException {
062: switch (operation) {
063: case TO_CODEPOINTS:
064: Item item = argument[0].evaluateItem(c);
065: if (item == null) {
066: return EmptyIterator.getInstance();
067: }
068: return stringToUnicode(item.getStringValueCS());
069: case FROM_CODEPOINTS:
070: return SingletonIterator.makeIterator(evaluateItem(c));
071: default:
072: throw new UnsupportedOperationException(
073: "Unknown Unicode operation");
074: }
075: }
076:
077: /**
078: * Return a sequence of integers representing the Unicode code values of the characters in a given
079: * string.
080: */
081:
082: private static SequenceIterator stringToUnicode(CharSequence s) {
083: return StringValue.makeStringValue(s).iterateCharacters();
084: }
085:
086: /**
087: * Return the Unicode string corresponding to a given sequence of Unicode code values
088: * @param chars iterator delivering the characters as integer values
089: * @param context the evaluation context
090: * @throws XPathException if any of the integers is not the codepoint of a valid XML character
091: */
092:
093: private static CharSequence unicodeToString(SequenceIterator chars,
094: XPathContext context) throws XPathException {
095: FastStringBuffer sb = new FastStringBuffer(256);
096: NameChecker checker = context.getConfiguration()
097: .getNameChecker();
098: while (true) {
099: NumericValue nextInt = (NumericValue) chars.next();
100: if (nextInt == null) {
101: return sb.condense();
102: }
103: long next = nextInt.longValue();
104: if (next < 0 || next > Integer.MAX_VALUE
105: || !checker.isValidChar((int) next)) {
106: DynamicError e = new DynamicError(
107: "Invalid XML character [x "
108: + Integer.toHexString((int) next) + ']');
109: e.setErrorCode("FOCH0001");
110: if (context instanceof XPathContext) {
111: e.setXPathContext((XPathContext) context);
112: }
113: throw e;
114: }
115: if (next < 65536) {
116: sb.append((char) next);
117: } else { // output a surrogate pair
118: sb.append(XMLChar.highSurrogate((int) next));
119: sb.append(XMLChar.lowSurrogate((int) next));
120: }
121: }
122: }
123:
124: }
125:
126: //
127: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
128: // you may not use this file except in compliance with the License. You may obtain a copy of the
129: // License at http://www.mozilla.org/MPL/
130: //
131: // Software distributed under the License is distributed on an "AS IS" basis,
132: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
133: // See the License for the specific language governing rights and limitations under the License.
134: //
135: // The Original Code is: all this file.
136: //
137: // The Initial Developer of the Original Code is Michael H. Kay.
138: //
139: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
140: //
141: // Contributor(s): none.
142: //
|