Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 282096
Collapse All | Expand All

(-)src/org/eclipse/wst/xml/xpath2/processor/test/AbstractPsychoPathTest.java (-10 / +39 lines)
Lines 12-17 Link Here
12
 *     Jesper S Moller - bug 283214 - fix XML result serialization
12
 *     Jesper S Moller - bug 283214 - fix XML result serialization
13
 *     Jesper S Moller - bug 283404 - fixed locale  
13
 *     Jesper S Moller - bug 283404 - fixed locale  
14
 *     Jesper S Moller - bug 281159 - fix document URIs and also filter XML namespace
14
 *     Jesper S Moller - bug 281159 - fix document URIs and also filter XML namespace
15
 *     Jesper Steen Moeller - bug 282096 - make test harness handle all string encoding                                       translate function surrogate aware
15
 *******************************************************************************/
16
 *******************************************************************************/
16
package org.eclipse.wst.xml.xpath2.processor.test;
17
package org.eclipse.wst.xml.xpath2.processor.test;
17
18
Lines 46-51 Link Here
46
import org.eclipse.wst.xml.xpath2.processor.internal.types.ElementType;
47
import org.eclipse.wst.xml.xpath2.processor.internal.types.ElementType;
47
import org.eclipse.wst.xml.xpath2.processor.internal.types.NodeType;
48
import org.eclipse.wst.xml.xpath2.processor.internal.types.NodeType;
48
import org.eclipse.wst.xml.xpath2.processor.internal.types.QName;
49
import org.eclipse.wst.xml.xpath2.processor.internal.types.QName;
50
import org.eclipse.wst.xml.xpath2.processor.testsuite.functions.EscapeHTMLURIFuncTest;
49
import org.osgi.framework.Bundle;
51
import org.osgi.framework.Bundle;
50
import org.w3c.dom.Document;
52
import org.w3c.dom.Document;
51
import org.w3c.dom.Node;
53
import org.w3c.dom.Node;
Lines 185-190 Link Here
185
	}
187
	}
186
188
187
	protected String getExpectedResult(String xqFile) {
189
	protected String getExpectedResult(String xqFile) {
190
		return getExpectedResult(xqFile, true);
191
	}
192
193
	protected String getExpectedResultNoEscape(String xqFile) {
194
		return getExpectedResult(xqFile, false);
195
	}
196
197
	protected String getExpectedResult(String xqFile, boolean unescape) {
188
		String resultFile = xqFile;
198
		String resultFile = xqFile;
189
		//
199
		//
190
		if (resultFile.length() < 10) { // <9 enough? like XPST0001
200
		if (resultFile.length() < 10) { // <9 enough? like XPST0001
Lines 226-231 Link Here
226
			// e.printStackTrace();
236
			// e.printStackTrace();
227
			content = "XPST0003";
237
			content = "XPST0003";
228
		}
238
		}
239
		if (unescape && content.contains("&")) return resolveCharacterReferences(content);
229
		return content;
240
		return content;
230
	}
241
	}
231
242
Lines 237-243 Link Here
237
		return unwrapResult(getExpectedResult(resultFile), elemName);
248
		return unwrapResult(getExpectedResult(resultFile), elemName);
238
	}
249
	}
239
250
251
	public String extractXPathExpressionNoEscape(String xqFile, String inputFile) {
252
		return extractXPathExpression(xqFile, inputFile, false);
253
	}
254
240
	public String extractXPathExpression(String xqFile, String inputFile) {
255
	public String extractXPathExpression(String xqFile, String inputFile) {
256
		return extractXPathExpression(xqFile, inputFile, true);
257
	}
258
259
	public String extractXPathExpression(String xqFile, String inputFile, boolean unescape) {
241
		// get the xpath2 expr from xq file, first
260
		// get the xpath2 expr from xq file, first
242
		char[] cbuf = new char[2048];//
261
		char[] cbuf = new char[2048];//
243
		String content = null;
262
		String content = null;
Lines 277-283 Link Here
277
			// TODO Auto-generated catch block
296
			// TODO Auto-generated catch block
278
			e.printStackTrace();
297
			e.printStackTrace();
279
		}
298
		}
280
		return xpath2Expr;
299
		if (unescape && xpath2Expr.contains("&")) {
300
			return resolveCharacterReferences(xpath2Expr);
301
		} else {
302
			return xpath2Expr;
303
		}
281
	}
304
	}
282
305
283
	protected String extractXPathExpression(String xqFile, String inputFile,
306
	protected String extractXPathExpression(String xqFile, String inputFile,
Lines 398-412 Link Here
398
		return expectedResult;
421
		return expectedResult;
399
	}
422
	}
400
423
401
	protected String resolveCharacterReferences(String xpath)
424
	protected String resolveCharacterReferences(String xpath) {
402
			throws IOException, DOMLoaderException {
425
		String docText = "<doc>" + xpath + "</doc>";
403
				   String docText = "<doc>" + xpath + "</doc>";
426
		InputStream is;
404
				   InputStream is = new ByteArrayInputStream(docText.getBytes("UTF-8"));
427
		try {
405
				   DOMLoader domloader = new XercesLoader();
428
			is = new ByteArrayInputStream(docText.getBytes("UTF-8"));
406
				   domloader.set_validating(false);
429
			DOMLoader domloader = new XercesLoader();
407
				   Document temp = domloader.load(is);
430
			domloader.set_validating(false);
408
				   return temp.getDocumentElement().getFirstChild().getTextContent();
431
			Document temp = domloader.load(is);
409
			   }
432
			return temp.getDocumentElement().getFirstChild().getTextContent();
433
		} catch (UnsupportedEncodingException e) {
434
			throw new RuntimeException(e);
435
		} catch (DOMLoaderException e) {
436
			throw new RuntimeException(e);
437
		}
438
	}
410
439
411
440
412
}
441
}
(-)src/org/eclipse/wst/xml/xpath2/processor/testsuite/functions/NormalizeUnicodeFuncTest.java (-14 / +13 lines)
Lines 1-4 Link Here
1
1
/*******************************************************************************
2
 * Copyright (c) 2009 Standards for Technology for Automotive Retail and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     David Carver (STAR) - initial API and implementation
10
 *     Jesper Steen Moeller - bug 282096 - special case for a test which works
11
 *                                         differently in XPath2 than in XQuery
12
 *******************************************************************************/
13
 
2
package org.eclipse.wst.xml.xpath2.processor.testsuite.functions;
14
package org.eclipse.wst.xml.xpath2.processor.testsuite.functions;
3
15
4
import java.io.IOException;
16
import java.io.IOException;
Lines 12-30 Link Here
12
      
24
      
13
      
25
      
14
public class NormalizeUnicodeFuncTest extends AbstractPsychoPathTest {
26
public class NormalizeUnicodeFuncTest extends AbstractPsychoPathTest {
15
16
	@Override
17
	public String extractXPathExpression(String xqFile, String inputFile) {
18
		String body = super.extractXPathExpression(xqFile, inputFile);
19
		try {
20
			body = resolveCharacterReferences(body);
21
		} catch (DOMLoaderException e) {
22
			e.printStackTrace();
23
		} catch (IOException e) {
24
			e.printStackTrace();
25
		}
26
		return body;
27
	}
28
	
27
	
29
   //Test normalize-unicode with simple text input.
28
   //Test normalize-unicode with simple text input.
30
   public void test_fn_normalize_unicode1args_1() throws Exception {
29
   public void test_fn_normalize_unicode1args_1() throws Exception {
(-)src/org/eclipse/wst/xml/xpath2/processor/testsuite/core/LiteralsTest.java (-2 / +4 lines)
Lines 7-12 Link Here
7
 * 
7
 * 
8
 * Contributors:
8
 * Contributors:
9
 *     David Carver (STAR) - initial API and implementation
9
 *     David Carver (STAR) - initial API and implementation
10
 *     Jesper Steen Moeller - bug 282096 - special case for a test which works
11
 *                                         differently in XPath2 than in XQuery
10
 *******************************************************************************/
12
 *******************************************************************************/
11
13
12
package org.eclipse.wst.xml.xpath2.processor.testsuite.core;
14
package org.eclipse.wst.xml.xpath2.processor.testsuite.core;
Lines 2013-2019 Link Here
2013
      String inputFile = "/TestSources/emptydoc.xml";
2015
      String inputFile = "/TestSources/emptydoc.xml";
2014
      String xqFile = "/Queries/XQuery/Expressions/PrimaryExpr/Literals/Literals057.xq";
2016
      String xqFile = "/Queries/XQuery/Expressions/PrimaryExpr/Literals/Literals057.xq";
2015
      String resultFile = "/ExpectedTestResults/Expressions/PrimaryExpr/Literals/Literals057.txt";
2017
      String resultFile = "/ExpectedTestResults/Expressions/PrimaryExpr/Literals/Literals057.txt";
2016
      String expectedResult = getExpectedResult(resultFile);
2018
      String expectedResult = getExpectedResultNoEscape(resultFile);
2017
      URL fileURL = bundle.getEntry(inputFile);
2019
      URL fileURL = bundle.getEntry(inputFile);
2018
      loadDOMDocument(fileURL);
2020
      loadDOMDocument(fileURL);
2019
      
2021
      
Lines 2022-2028 Link Here
2022
2024
2023
      DynamicContext dc = setupDynamicContext(schema);
2025
      DynamicContext dc = setupDynamicContext(schema);
2024
2026
2025
      String xpath = extractXPathExpression(xqFile, inputFile);
2027
      String xpath = extractXPathExpressionNoEscape(xqFile, inputFile);
2026
      String actual = null;
2028
      String actual = null;
2027
      try {
2029
      try {
2028
	   	  XPath path = compileXPath(dc, xpath);
2030
	   	  XPath path = compileXPath(dc, xpath);
(-)src/org/eclipse/wst/xml/xpath2/processor/internal/function/FnTokenize.java (-5 / +2 lines)
Lines 7-23 Link Here
7
 *
7
 *
8
 * Contributors:
8
 * Contributors:
9
 *     Andrea Bittau - initial API and implementation from the PsychoPath XPath 2.0 
9
 *     Andrea Bittau - initial API and implementation from the PsychoPath XPath 2.0 
10
 *     Jesper Steen Moeller - bug 282096 - clean up string storage
10
 *******************************************************************************/
11
 *******************************************************************************/
11
12
12
package org.eclipse.wst.xml.xpath2.processor.internal.function;
13
package org.eclipse.wst.xml.xpath2.processor.internal.function;
13
14
14
import org.apache.commons.lang.StringEscapeUtils;
15
import org.eclipse.wst.xml.xpath2.processor.DynamicError;
15
import org.eclipse.wst.xml.xpath2.processor.DynamicError;
16
import org.eclipse.wst.xml.xpath2.processor.ResultSequence;
16
import org.eclipse.wst.xml.xpath2.processor.ResultSequence;
17
import org.eclipse.wst.xml.xpath2.processor.ResultSequenceFactory;
17
import org.eclipse.wst.xml.xpath2.processor.ResultSequenceFactory;
18
import org.eclipse.wst.xml.xpath2.processor.internal.*;
18
import org.eclipse.wst.xml.xpath2.processor.internal.*;
19
import org.eclipse.wst.xml.xpath2.processor.internal.types.*;
19
import org.eclipse.wst.xml.xpath2.processor.internal.types.*;
20
import org.eclipse.wst.xml.xpath2.processor.internal.utils.SurrogateUtils;
21
20
22
import java.util.*;
21
import java.util.*;
23
import java.util.regex.*;
22
import java.util.regex.*;
Lines 71-78 Link Here
71
		String str1 = "";
70
		String str1 = "";
72
		if (!arg1.empty()) {
71
		if (!arg1.empty()) {
73
			str1 = ((XSString) arg1.first()).value();
72
			str1 = ((XSString) arg1.first()).value();
74
			str1 = SurrogateUtils.decodeXML(str1);
75
			str1 = StringEscapeUtils.unescapeXml(str1);
76
		}
73
		}
77
74
78
		ResultSequence arg2 = (ResultSequence) argiter.next();
75
		ResultSequence arg2 = (ResultSequence) argiter.next();
Lines 92-98 Link Here
92
			ArrayList<String> ret = tokenize(pattern, flags, str1);
89
			ArrayList<String> ret = tokenize(pattern, flags, str1);
93
90
94
			for(String token : ret) {
91
			for(String token : ret) {
95
				rs.add(new XSString(StringEscapeUtils.escapeXml(token)));
92
				rs.add(new XSString(token));
96
			}
93
			}
97
		} catch (PatternSyntaxException err) {
94
		} catch (PatternSyntaxException err) {
98
			throw DynamicError.regex_error(null);
95
			throw DynamicError.regex_error(null);
(-)src/org/eclipse/wst/xml/xpath2/processor/internal/function/FnStringLength.java (-4 / +2 lines)
Lines 11-28 Link Here
11
 *     Mukul Gandhi - bug 274805 - improvements to xs:integer data type  
11
 *     Mukul Gandhi - bug 274805 - improvements to xs:integer data type  
12
 *     Jesper Steen Moeller - bug 285145 - implement full arity checking
12
 *     Jesper Steen Moeller - bug 285145 - implement full arity checking
13
 *     David Carver - bug 282096 - improvements for surrogate handling 
13
 *     David Carver - bug 282096 - improvements for surrogate handling 
14
 *     Jesper Steen Moeller - bug 282096 - clean up string storage
14
 *******************************************************************************/
15
 *******************************************************************************/
15
16
16
package org.eclipse.wst.xml.xpath2.processor.internal.function;
17
package org.eclipse.wst.xml.xpath2.processor.internal.function;
17
18
18
import org.apache.commons.lang.StringEscapeUtils;
19
import org.eclipse.wst.xml.xpath2.processor.DynamicContext;
19
import org.eclipse.wst.xml.xpath2.processor.DynamicContext;
20
import org.eclipse.wst.xml.xpath2.processor.DynamicError;
20
import org.eclipse.wst.xml.xpath2.processor.DynamicError;
21
import org.eclipse.wst.xml.xpath2.processor.ResultSequence;
21
import org.eclipse.wst.xml.xpath2.processor.ResultSequence;
22
import org.eclipse.wst.xml.xpath2.processor.ResultSequenceFactory;
22
import org.eclipse.wst.xml.xpath2.processor.ResultSequenceFactory;
23
import org.eclipse.wst.xml.xpath2.processor.internal.*;
23
import org.eclipse.wst.xml.xpath2.processor.internal.*;
24
import org.eclipse.wst.xml.xpath2.processor.internal.types.*;
24
import org.eclipse.wst.xml.xpath2.processor.internal.types.*;
25
import org.eclipse.wst.xml.xpath2.processor.internal.utils.SurrogateUtils;
26
25
27
import java.math.BigInteger;
26
import java.math.BigInteger;
28
import java.util.*;
27
import java.util.*;
Lines 98-107 Link Here
98
		}
97
		}
99
98
100
		String str = ((XSString) arg1.first()).value();
99
		String str = ((XSString) arg1.first()).value();
101
		str = SurrogateUtils.decodeXML(str);
102
100
103
		ResultSequence rs = ResultSequenceFactory.create_new();
101
		ResultSequence rs = ResultSequenceFactory.create_new();
104
		rs.add(new XSInteger(BigInteger.valueOf(str.length())));
102
		rs.add(new XSInteger(BigInteger.valueOf(str.codePointCount(0, str.length()))));
105
103
106
		return rs;
104
		return rs;
107
	}
105
	}
(-)src/org/eclipse/wst/xml/xpath2/processor/internal/function/FnTranslate.java (-26 / +49 lines)
Lines 7-23 Link Here
7
 *
7
 *
8
 * Contributors:
8
 * Contributors:
9
 *     Andrea Bittau - initial API and implementation from the PsychoPath XPath 2.0 
9
 *     Andrea Bittau - initial API and implementation from the PsychoPath XPath 2.0 
10
 *     Jesper Steen Moeller - bug 282096 - clean up string storage and make
11
 *                                         translate function surrogate aware
10
 *******************************************************************************/
12
 *******************************************************************************/
11
13
12
package org.eclipse.wst.xml.xpath2.processor.internal.function;
14
package org.eclipse.wst.xml.xpath2.processor.internal.function;
13
15
14
import org.apache.commons.lang.StringEscapeUtils;
15
import org.eclipse.wst.xml.xpath2.processor.DynamicError;
16
import org.eclipse.wst.xml.xpath2.processor.DynamicError;
16
import org.eclipse.wst.xml.xpath2.processor.ResultSequence;
17
import org.eclipse.wst.xml.xpath2.processor.ResultSequence;
17
import org.eclipse.wst.xml.xpath2.processor.ResultSequenceFactory;
18
import org.eclipse.wst.xml.xpath2.processor.ResultSequenceFactory;
18
import org.eclipse.wst.xml.xpath2.processor.internal.*;
19
import org.eclipse.wst.xml.xpath2.processor.internal.*;
19
import org.eclipse.wst.xml.xpath2.processor.internal.types.*;
20
import org.eclipse.wst.xml.xpath2.processor.internal.types.*;
20
import org.eclipse.wst.xml.xpath2.processor.internal.utils.SurrogateUtils;
21
import org.eclipse.wst.xml.xpath2.processor.internal.utils.CodePointIterator;
22
import org.eclipse.wst.xml.xpath2.processor.internal.utils.StringCodePointIterator;
21
23
22
import java.util.*;
24
import java.util.*;
23
25
Lines 110-149 Link Here
110
		}
112
		}
111
113
112
		String str = ((XSString) arg1.first()).value();
114
		String str = ((XSString) arg1.first()).value();
113
		str = SurrogateUtils.decodeXML(str);
114
		String mapstr = ((XSString) arg2.first()).value();
115
		String mapstr = ((XSString) arg2.first()).value();
115
		mapstr = SurrogateUtils.decodeXML(mapstr);
116
		String transstr = ((XSString) arg3.first()).value();
116
		String transstr = ((XSString) arg3.first()).value();
117
		transstr = SurrogateUtils.decodeXML(transstr);
118
117
119
		String result = new String(str);
118
		Map<Integer, Integer> replacements = buildReplacementMap(mapstr, transstr);
120
119
		
121
		// ok the spec says that first occurence decides how to change
120
		StringBuffer sb = new StringBuffer(str.length());
122
		// it... 
121
		CodePointIterator strIter = new StringCodePointIterator(str);
123
		Map repmap = new Hashtable(256);
122
		for (int input = strIter.current(); input != CodePointIterator.DONE; input = strIter.next()) {
124
		for (int i = 0; i < mapstr.length(); i++) {
123
			Integer inputCodepoint = Integer.valueOf(input);
125
			String replace = "";
124
			if (replacements.containsKey(inputCodepoint)) {
126
			String chartofind = "" + mapstr.charAt(i);
125
				Integer replaceWith = (Integer)replacements.get(inputCodepoint);
127
126
				if (replaceWith != null) {
128
			if (transstr.length() > i)
127
					sb.appendCodePoint(replaceWith.intValue());
129
				replace += transstr.charAt(i);
128
				}					
130
129
			} else {
131
			if (repmap.containsKey(chartofind))
130
				sb.appendCodePoint(input);
132
				replace = (String) repmap.get(chartofind);
131
			}
133
134
			else
135
				repmap.put(chartofind, replace);
136
137
			result = result.replaceAll(chartofind, replace);
138
		}
132
		}
139
		
133
		
140
		result = StringEscapeUtils.escapeXml(result);
134
		rs.add(new XSString(sb.toString()));
141
		rs.add(new XSString(result));
142
135
143
		return rs;
136
		return rs;
144
	}
137
	}
145
138
146
	/**
139
	/**
140
	 * Build a replacement map from the mapstr and the transstr for translation. The function returns a Map<Integer, Integer> mapping each codepoint
141
	 * mentioned in the mapstr into the corresponding codepoint in transstr, or null if there is no matching mapping in transstr.
142
	 * 
143
	 * @param mapstr The "mapping from" string
144
	 * @param transstr The "mapping into" string
145
	 * @return A map which maps input codepoint to output codepoint (or null)
146
	 */
147
	private static Map<Integer, Integer> buildReplacementMap(String mapstr, String transstr) {
148
		// Build mapping (map from codepoint -> codepoint)		
149
		Map<Integer, Integer> replacements = new HashMap<Integer, Integer>(mapstr.length() * 4);
150
151
		CodePointIterator mapIter = new StringCodePointIterator(mapstr);
152
		CodePointIterator transIter = new StringCodePointIterator(transstr);
153
		// Iterate through both mapIter and transIter and produce the mapping
154
		int mapFrom = mapIter.current();
155
		int mapTo = transIter.current();
156
		while (mapFrom != CodePointIterator.DONE) {
157
			Integer codepointFrom = Integer.valueOf(mapFrom);
158
			if (! replacements.containsKey(codepointFrom)) {
159
				// only overwrite if it doesn't exist already
160
				Integer replacement = mapTo != CodePointIterator.DONE ? Integer.valueOf(mapTo) : null;
161
				replacements.put(codepointFrom, replacement);
162
			}
163
			mapFrom = mapIter.next();
164
			mapTo = transIter.next();	
165
		}
166
		return replacements;
167
	}
168
169
	/**
147
	 * Calculate the expected arguments.
170
	 * Calculate the expected arguments.
148
	 * 
171
	 * 
149
	 * @return The expected arguments.
172
	 * @return The expected arguments.
(-)src/org/eclipse/wst/xml/xpath2/processor/internal/function/FnCodepointsToString.java (-2 / +1 lines)
Lines 9-19 Link Here
9
 *     Andrea Bittau - initial API and implementation from the PsychoPath XPath 2.0
9
 *     Andrea Bittau - initial API and implementation from the PsychoPath XPath 2.0
10
 *     Mukul Gandhi - improvements to the function implementation
10
 *     Mukul Gandhi - improvements to the function implementation
11
 *     David Carver - bug 282096 - improvements for surrogate handling 
11
 *     David Carver - bug 282096 - improvements for surrogate handling 
12
 *     Jesper Steen Moeller - bug 282096 - clean up string storage
12
 *******************************************************************************/
13
 *******************************************************************************/
13
14
14
package org.eclipse.wst.xml.xpath2.processor.internal.function;
15
package org.eclipse.wst.xml.xpath2.processor.internal.function;
15
16
16
import org.apache.commons.lang.StringEscapeUtils;
17
import org.eclipse.wst.xml.xpath2.processor.DynamicError;
17
import org.eclipse.wst.xml.xpath2.processor.DynamicError;
18
import org.eclipse.wst.xml.xpath2.processor.ResultSequence;
18
import org.eclipse.wst.xml.xpath2.processor.ResultSequence;
19
import org.eclipse.wst.xml.xpath2.processor.ResultSequenceFactory;
19
import org.eclipse.wst.xml.xpath2.processor.ResultSequenceFactory;
Lines 83-89 Link Here
83
		// "new String(int[] codePoints, int offset, int count)" is a facility
83
		// "new String(int[] codePoints, int offset, int count)" is a facility
84
		// introduced in Java 1.5
84
		// introduced in Java 1.5
85
		String str = new String(codePointArray, 0, codePointArray.length);
85
		String str = new String(codePointArray, 0, codePointArray.length);
86
		str = StringEscapeUtils.escapeXml(str);
87
		rs.add(new XSString(str));
86
		rs.add(new XSString(str));
88
		
87
		
89
		return rs;
88
		return rs;
(-)src/org/eclipse/wst/xml/xpath2/processor/internal/function/FnLowerCase.java (-4 / +2 lines)
Lines 8-24 Link Here
8
 * Contributors:
8
 * Contributors:
9
 *     Andrea Bittau - initial API and implementation from the PsychoPath XPath 2.0
9
 *     Andrea Bittau - initial API and implementation from the PsychoPath XPath 2.0
10
 *     David Carver - bug 282096 - improvements for surrogate handling  
10
 *     David Carver - bug 282096 - improvements for surrogate handling  
11
 *     Jesper Steen Moeller - bug 282096 - clean up string storage
11
 *******************************************************************************/
12
 *******************************************************************************/
12
13
13
package org.eclipse.wst.xml.xpath2.processor.internal.function;
14
package org.eclipse.wst.xml.xpath2.processor.internal.function;
14
15
15
import org.apache.commons.lang.StringEscapeUtils;
16
import org.eclipse.wst.xml.xpath2.processor.DynamicError;
16
import org.eclipse.wst.xml.xpath2.processor.DynamicError;
17
import org.eclipse.wst.xml.xpath2.processor.ResultSequence;
17
import org.eclipse.wst.xml.xpath2.processor.ResultSequence;
18
import org.eclipse.wst.xml.xpath2.processor.ResultSequenceFactory;
18
import org.eclipse.wst.xml.xpath2.processor.ResultSequenceFactory;
19
import org.eclipse.wst.xml.xpath2.processor.internal.*;
19
import org.eclipse.wst.xml.xpath2.processor.internal.*;
20
import org.eclipse.wst.xml.xpath2.processor.internal.types.*;
20
import org.eclipse.wst.xml.xpath2.processor.internal.types.*;
21
import org.eclipse.wst.xml.xpath2.processor.internal.utils.SurrogateUtils;
22
21
23
import java.util.*;
22
import java.util.*;
24
23
Lines 89-97 Link Here
89
		}
88
		}
90
89
91
		String str = ((XSString) arg1.first()).value();
90
		String str = ((XSString) arg1.first()).value();
92
		str = SurrogateUtils.decodeXML(str);
93
91
94
		rs.add(new XSString(StringEscapeUtils.escapeXml(str.toLowerCase())));
92
		rs.add(new XSString(str.toLowerCase()));
95
93
96
		return rs;
94
		return rs;
97
	}
95
	}
(-)src/org/eclipse/wst/xml/xpath2/processor/internal/function/FnSubstring.java (-60 / +27 lines)
Lines 10-26 Link Here
10
 *     Mukul Gandhi - bug 273795 - improvements to function, substring
10
 *     Mukul Gandhi - bug 273795 - improvements to function, substring
11
 *     Jesper Steen Moeller - bug 285145 - implement full arity checking
11
 *     Jesper Steen Moeller - bug 285145 - implement full arity checking
12
 *     David Carver - bug 282096 - improvements for surrogate handling 
12
 *     David Carver - bug 282096 - improvements for surrogate handling 
13
 *     Jesper Steen Moeller - bug 282096 - reimplemented to be surrogate sensitive
13
 *******************************************************************************/
14
 *******************************************************************************/
14
15
15
package org.eclipse.wst.xml.xpath2.processor.internal.function;
16
package org.eclipse.wst.xml.xpath2.processor.internal.function;
16
17
17
import org.apache.commons.lang.StringEscapeUtils;
18
import org.eclipse.wst.xml.xpath2.processor.DynamicError;
18
import org.eclipse.wst.xml.xpath2.processor.DynamicError;
19
import org.eclipse.wst.xml.xpath2.processor.ResultSequence;
19
import org.eclipse.wst.xml.xpath2.processor.ResultSequence;
20
import org.eclipse.wst.xml.xpath2.processor.ResultSequenceFactory;
20
import org.eclipse.wst.xml.xpath2.processor.ResultSequenceFactory;
21
import org.eclipse.wst.xml.xpath2.processor.internal.*;
21
import org.eclipse.wst.xml.xpath2.processor.internal.*;
22
import org.eclipse.wst.xml.xpath2.processor.internal.types.*;
22
import org.eclipse.wst.xml.xpath2.processor.internal.types.*;
23
import org.eclipse.wst.xml.xpath2.processor.internal.utils.SurrogateUtils;
23
import org.eclipse.wst.xml.xpath2.processor.internal.utils.CodePointIterator;
24
import org.eclipse.wst.xml.xpath2.processor.internal.utils.StringCodePointIterator;
24
25
25
import java.util.*;
26
import java.util.*;
26
27
Lines 100-175 Link Here
100
		}
101
		}
101
102
102
		String str = ((XSString) stringArg.first()).value();
103
		String str = ((XSString) stringArg.first()).value();
103
		str = SurrogateUtils.decodeXML(str);
104
		double dstart = ((XSDouble) startPosArg.first()).double_value();
104
		double dstart = ((XSDouble) startPosArg.first()).double_value();
105
		
105
		
106
		if (Double.NaN == dstart) {
106
		// is start is NaN, no chars are returned
107
		if (Double.NaN == dstart || Double.NEGATIVE_INFINITY == dstart) {
107
			return emptyString(rs);
108
			return emptyString(rs);
108
		}
109
		}
109
110
		long istart = Math.round(dstart);
110
		int start = (int) Math.round(dstart);
111
112
		if (isStartOutOfBounds(str, start)) {
113
		  return emptyString(rs);
114
		}
115
		
111
		
116
		start = adjustStartPosition(start);
112
		long ilength = Long.MAX_VALUE;
117
118
		if (lengthArg != null) {
113
		if (lengthArg != null) {
119
		  return substringLength(rs, lengthArg, dstart, start, str);
114
			double dlength = ((XSDouble) lengthArg.first()).double_value();
115
			if (Double.NaN == dlength)
116
				return emptyString(rs);
117
			// Switch to the rounded kind
118
			ilength = Math.round(dlength);
119
			if (ilength <= 0)
120
				return emptyString(rs);
120
		}
121
		}
121
		
122
		
122
		rs.add(new XSString(StringEscapeUtils.escapeXml(str.substring(start))));
123
		
123
124
		// could guess too short in cases supplementary chars 
124
		return rs;
125
		StringBuilder sb = new StringBuilder((int) Math.min(str.length(), ilength));
125
	}
126
	
127
	private static ResultSequence substringLength(ResultSequence rs, ResultSequence lengthArg, double dstart, int start, String str) {
128
		  int length = adjustLength(lengthArg, dstart, start);
129
		  int endpos = start + length;
130
		  if (isEndPosOutOfBounds(endpos) || isStartOutOfBounds(str, endpos)) {
131
			  return emptyString(rs);
132
		  }
133
		 
134
		  if (start == 0 && endpos == 0) {
135
			  rs.add(new XSString(StringEscapeUtils.escapeXml(str.substring(start))));
136
		  } else {
137
			  rs.add(new XSString(StringEscapeUtils.escapeXml(str.substring(start, endpos))));
138
		  }
139
		  return rs;
140
	}
141
142
	private static boolean isEndPosOutOfBounds(int endpos) {
143
		return endpos < 0;
144
	}
145
146
	private static int adjustLength(ResultSequence arg3, double dstart,
147
			int start) {
148
		double dlength = ((XSDouble) arg3.first()).double_value();
149
		  int length = (int) Math.round(dlength);
150
		  if (dstart < 0) {
151
			  length = (int)( dlength - (Math.abs(dstart) + 1));
152
		  } else if (dstart == 0) {
153
			  length = length - 1;
154
		  } else if (isEndPosOutOfBounds(length)) {
155
			  length = start - Math.abs(length);
156
		  }
157
		return length;
158
	}
159
126
160
	private static int adjustStartPosition(int start) {
127
		// This looks like an inefficient way to iterate, but due to surrogate handling,
161
		if (start <= 0) {
128
		// string indexes are no good here. Welcome to UTF-16!
162
			start = 0;
129
		
163
		} else {
130
		CodePointIterator strIter = new StringCodePointIterator(str);
164
			start = start - 1;
131
		for (long p = 1; strIter.current() != CodePointIterator.DONE; ++p, strIter.next()) {
132
			if (istart <= p && p - istart < ilength)
133
				sb.appendCodePoint(strIter.current());
165
		}
134
		}
166
		return start;
135
		rs.add(new XSString(sb.toString()));
167
	}
168
136
169
	private static boolean isStartOutOfBounds(String str, int start) {
137
		return rs;
170
		return start > str.length();
171
	}
138
	}
172
139
	
173
	private static ResultSequence emptyString(ResultSequence rs) {
140
	private static ResultSequence emptyString(ResultSequence rs) {
174
		rs.add(new XSString(""));
141
		rs.add(new XSString(""));
175
		return rs;
142
		return rs;
(-)src/org/eclipse/wst/xml/xpath2/processor/internal/function/FnSubstringAfter.java (-5 / +2 lines)
Lines 8-24 Link Here
8
 * Contributors:
8
 * Contributors:
9
 *     Andrea Bittau - initial API and implementation from the PsychoPath XPath 2.0
9
 *     Andrea Bittau - initial API and implementation from the PsychoPath XPath 2.0
10
 *     David Carver - bug 282096 - improvements for surrogate handling  
10
 *     David Carver - bug 282096 - improvements for surrogate handling  
11
 *     Jesper Steen Moeller - bug 282096 - clean up string storage
11
 *******************************************************************************/
12
 *******************************************************************************/
12
13
13
package org.eclipse.wst.xml.xpath2.processor.internal.function;
14
package org.eclipse.wst.xml.xpath2.processor.internal.function;
14
15
15
import org.apache.commons.lang.StringEscapeUtils;
16
import org.eclipse.wst.xml.xpath2.processor.DynamicError;
16
import org.eclipse.wst.xml.xpath2.processor.DynamicError;
17
import org.eclipse.wst.xml.xpath2.processor.ResultSequence;
17
import org.eclipse.wst.xml.xpath2.processor.ResultSequence;
18
import org.eclipse.wst.xml.xpath2.processor.ResultSequenceFactory;
18
import org.eclipse.wst.xml.xpath2.processor.ResultSequenceFactory;
19
import org.eclipse.wst.xml.xpath2.processor.internal.*;
19
import org.eclipse.wst.xml.xpath2.processor.internal.*;
20
import org.eclipse.wst.xml.xpath2.processor.internal.types.*;
20
import org.eclipse.wst.xml.xpath2.processor.internal.types.*;
21
import org.eclipse.wst.xml.xpath2.processor.internal.utils.SurrogateUtils;
22
21
23
import java.util.*;
22
import java.util.*;
24
23
Lines 74-86 Link Here
74
		String str2 = "";
73
		String str2 = "";
75
		if (!arg1.empty()) {
74
		if (!arg1.empty()) {
76
			str1 = ((XSString) arg1.first()).value();
75
			str1 = ((XSString) arg1.first()).value();
77
			str1 = SurrogateUtils.decodeXML(str1);
78
		}
76
		}
79
77
80
		ResultSequence arg2 = (ResultSequence) argiter.next();
78
		ResultSequence arg2 = (ResultSequence) argiter.next();
81
		if (!arg2.empty()) {
79
		if (!arg2.empty()) {
82
			str2 = ((XSString) arg2.first()).value();
80
			str2 = ((XSString) arg2.first()).value();
83
			str2 = SurrogateUtils.decodeXML(str2);
84
		}
81
		}
85
82
86
		int str1len = str1.length();
83
		int str1len = str1.length();
Lines 104-110 Link Here
104
			result = str1.substring(index, str1len);
101
			result = str1.substring(index, str1len);
105
		}
102
		}
106
103
107
		rs.add(new XSString(StringEscapeUtils.escapeXml(result)));
104
		rs.add(new XSString(result));
108
105
109
		return rs;
106
		return rs;
110
	}
107
	}
(-)src/org/eclipse/wst/xml/xpath2/processor/internal/function/FnMatches.java (-5 / +1 lines)
Lines 9-25 Link Here
9
 *     Andrea Bittau - initial API and implementation from the PsychoPath XPath 2.0
9
 *     Andrea Bittau - initial API and implementation from the PsychoPath XPath 2.0
10
 *     David Carver - bug 282096 - improvements for surrogate handling
10
 *     David Carver - bug 282096 - improvements for surrogate handling
11
 *     David Carver - bug 262765 - improvements to Regular Expression   
11
 *     David Carver - bug 262765 - improvements to Regular Expression   
12
 *     Jesper Steen Moeller - bug 282096 - clean up string storage
12
 *******************************************************************************/
13
 *******************************************************************************/
13
14
14
package org.eclipse.wst.xml.xpath2.processor.internal.function;
15
package org.eclipse.wst.xml.xpath2.processor.internal.function;
15
16
16
import org.apache.commons.lang.StringEscapeUtils;
17
import org.eclipse.wst.xml.xpath2.processor.DynamicError;
17
import org.eclipse.wst.xml.xpath2.processor.DynamicError;
18
import org.eclipse.wst.xml.xpath2.processor.ResultSequence;
18
import org.eclipse.wst.xml.xpath2.processor.ResultSequence;
19
import org.eclipse.wst.xml.xpath2.processor.ResultSequenceFactory;
19
import org.eclipse.wst.xml.xpath2.processor.ResultSequenceFactory;
20
import org.eclipse.wst.xml.xpath2.processor.internal.*;
20
import org.eclipse.wst.xml.xpath2.processor.internal.*;
21
import org.eclipse.wst.xml.xpath2.processor.internal.types.*;
21
import org.eclipse.wst.xml.xpath2.processor.internal.types.*;
22
import org.eclipse.wst.xml.xpath2.processor.internal.utils.SurrogateUtils;
23
22
24
import java.util.*;
23
import java.util.*;
25
import java.util.regex.*;
24
import java.util.regex.*;
Lines 73-85 Link Here
73
		String str1 = "";
72
		String str1 = "";
74
		if (!arg1.empty()) {
73
		if (!arg1.empty()) {
75
			str1 = ((XSString) arg1.first()).value();
74
			str1 = ((XSString) arg1.first()).value();
76
			str1 = SurrogateUtils.decodeXML(str1);
77
			str1 = StringEscapeUtils.unescapeXml(str1);
78
		}
75
		}
79
76
80
		ResultSequence arg2 = (ResultSequence) argiter.next();
77
		ResultSequence arg2 = (ResultSequence) argiter.next();
81
		String pattern = ((XSString) arg2.first()).value();
78
		String pattern = ((XSString) arg2.first()).value();
82
		pattern = SurrogateUtils.decodeXML(pattern);
83
		String flags = null;
79
		String flags = null;
84
80
85
		if (argiter.hasNext()) {
81
		if (argiter.hasNext()) {
(-)src/org/eclipse/wst/xml/xpath2/processor/internal/function/FnStringToCodepoints.java (-7 / +7 lines)
Lines 9-14 Link Here
9
 *     Andrea Bittau - initial API and implementation from the PsychoPath XPath 2.0
9
 *     Andrea Bittau - initial API and implementation from the PsychoPath XPath 2.0
10
 *     Mukul Gandhi - bug 280554 - improvements to the function implementation
10
 *     Mukul Gandhi - bug 280554 - improvements to the function implementation
11
 *     David Carver - bug 282096 - improvements for surrogate handling  
11
 *     David Carver - bug 282096 - improvements for surrogate handling  
12
 *     Jesper Steen Moeller - bug 282096 - clean up string storage and fix surrogate handling
12
 *******************************************************************************/
13
 *******************************************************************************/
13
14
14
package org.eclipse.wst.xml.xpath2.processor.internal.function;
15
package org.eclipse.wst.xml.xpath2.processor.internal.function;
Lines 18-24 Link Here
18
import org.eclipse.wst.xml.xpath2.processor.ResultSequenceFactory;
19
import org.eclipse.wst.xml.xpath2.processor.ResultSequenceFactory;
19
import org.eclipse.wst.xml.xpath2.processor.internal.*;
20
import org.eclipse.wst.xml.xpath2.processor.internal.*;
20
import org.eclipse.wst.xml.xpath2.processor.internal.types.*;
21
import org.eclipse.wst.xml.xpath2.processor.internal.types.*;
21
import org.eclipse.wst.xml.xpath2.processor.internal.utils.SurrogateUtils;
22
import org.eclipse.wst.xml.xpath2.processor.internal.utils.CodePointIterator;
23
import org.eclipse.wst.xml.xpath2.processor.internal.utils.StringCodePointIterator;
22
24
23
import java.math.BigInteger;
25
import java.math.BigInteger;
24
import java.util.*;
26
import java.util.*;
Lines 71-83 Link Here
71
		   return rs;
73
		   return rs;
72
74
73
		XSString xstr = (XSString) arg1.first();
75
		XSString xstr = (XSString) arg1.first();
74
		String str = xstr.value();
75
		str = SurrogateUtils.decodeXML(str);
76
76
77
		for (int i = 0; i < str.length(); i++) {
77
		CodePointIterator cpi = new StringCodePointIterator(xstr.value());
78
			// Character.codePointAt API, is introduced in Java 1.5 
78
		
79
            int codePointValue = Character.codePointAt(str, i);
79
		for (int codePoint = cpi.current(); codePoint != CodePointIterator.DONE; codePoint = cpi.next()) {
80
			rs.add(new XSInteger(BigInteger.valueOf(codePointValue)));
80
           	rs.add(new XSInteger(BigInteger.valueOf(codePoint)));
81
		}
81
		}
82
82
83
		return rs;
83
		return rs;
(-)src/org/eclipse/wst/xml/xpath2/processor/internal/function/FnSubstringBefore.java (-5 / +2 lines)
Lines 8-24 Link Here
8
 * Contributors:
8
 * Contributors:
9
 *     Andrea Bittau - initial API and implementation from the PsychoPath XPath 2.0
9
 *     Andrea Bittau - initial API and implementation from the PsychoPath XPath 2.0
10
 *     David Carver - bug 282096 - improvements for surrogate handling  
10
 *     David Carver - bug 282096 - improvements for surrogate handling  
11
 *     Jesper Steen Moeller - bug 282096 - clean up string storage
11
 *******************************************************************************/
12
 *******************************************************************************/
12
13
13
package org.eclipse.wst.xml.xpath2.processor.internal.function;
14
package org.eclipse.wst.xml.xpath2.processor.internal.function;
14
15
15
import org.apache.commons.lang.StringEscapeUtils;
16
import org.eclipse.wst.xml.xpath2.processor.DynamicError;
16
import org.eclipse.wst.xml.xpath2.processor.DynamicError;
17
import org.eclipse.wst.xml.xpath2.processor.ResultSequence;
17
import org.eclipse.wst.xml.xpath2.processor.ResultSequence;
18
import org.eclipse.wst.xml.xpath2.processor.ResultSequenceFactory;
18
import org.eclipse.wst.xml.xpath2.processor.ResultSequenceFactory;
19
import org.eclipse.wst.xml.xpath2.processor.internal.*;
19
import org.eclipse.wst.xml.xpath2.processor.internal.*;
20
import org.eclipse.wst.xml.xpath2.processor.internal.types.*;
20
import org.eclipse.wst.xml.xpath2.processor.internal.types.*;
21
import org.eclipse.wst.xml.xpath2.processor.internal.utils.SurrogateUtils;
22
21
23
import java.util.*;
22
import java.util.*;
24
23
Lines 74-86 Link Here
74
		String str2 = "";
73
		String str2 = "";
75
		if (!arg1.empty()) {
74
		if (!arg1.empty()) {
76
			str1 = ((XSString) arg1.first()).value();
75
			str1 = ((XSString) arg1.first()).value();
77
			str1 = SurrogateUtils.decodeXML(str1);
78
		}
76
		}
79
77
80
		ResultSequence arg2 = (ResultSequence) argiter.next();
78
		ResultSequence arg2 = (ResultSequence) argiter.next();
81
		if (!arg2.empty()) {
79
		if (!arg2.empty()) {
82
			str2 = ((XSString) arg2.first()).value();
80
			str2 = ((XSString) arg2.first()).value();
83
			str2 = SurrogateUtils.decodeXML(str2);
84
		}
81
		}
85
82
86
		int str1len = str1.length();
83
		int str1len = str1.length();
Lines 98-104 Link Here
98
		}
95
		}
99
96
100
		
97
		
101
		rs.add(new XSString(StringEscapeUtils.escapeXml(str1.substring(0, index))));
98
		rs.add(new XSString(str1.substring(0, index)));
102
99
103
		return rs;
100
		return rs;
104
	}
101
	}
(-)src/org/eclipse/wst/xml/xpath2/processor/internal/utils/SurrogateUtils.java (-34 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Standards for Technology in Automotive Retail and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     David Carver (STAR) - bug 282096 - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.wst.xml.xpath2.processor.internal.utils;
12
13
public class SurrogateUtils {
14
15
	/**
16
	 * This class will decode a surrogate entity into it's string representation
17
	 * @param str
18
	 * @return The decoded string
19
	 * @since 1.1
20
	 */
21
	public static String decodeXML(String str) {
22
		String decodeString = str;
23
		while (decodeString.contains("&#x1")) {
24
			int startpos = decodeString.indexOf("&#x1");
25
			String starthex = decodeString.substring(startpos);
26
			int semipos = starthex.indexOf(';');
27
			String hexValue = starthex.substring(4, semipos);
28
			int i = Integer.parseInt(hexValue, 16);
29
			char c = (char)i;
30
			decodeString = decodeString.replaceAll("&#x1" + hexValue + ";", "" + c);
31
		}
32
		return decodeString;
33
	}
34
}
(-)src/org/eclipse/wst/xml/xpath2/processor/internal/utils/CodePointIterator.java (+75 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Jesper Steen Moeller and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Jesper Steen Moeller - bug 282096 - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.wst.xml.xpath2.processor.internal.utils;
13
14
public interface CodePointIterator extends Cloneable
15
{
16
    /**
17
     * Sentinel value returned from iterator when the end is reached.
18
     * The value is -1 which will never be a valid codepoint.
19
     */
20
    public static final int DONE = -1;
21
22
    /**
23
     * Resets the position to 0 and returns the first code point.
24
     * @return the first code point in the text, or DONE if the text is empty
25
     */
26
    public int first();
27
28
    /**
29
     * Sets the position to the last possible position (or 0 if the text is empty)
30
     * and returns the code point at that position.
31
     * @return the last code point in the text, or DONE if the text is empty
32
     * @see #getEndIndex()
33
     */
34
    public int last();
35
36
    /**
37
     * Gets the code point at the current position (as returned by getIndex()).
38
     * @return the code point at the current position or DONE if the current
39
     * position is off the end of the text.
40
     * @see #getIndex()
41
     */
42
    public int current();
43
44
    /**
45
     * Increments the iterator's code point index by one and returns the code point
46
     * at the new index.  If the resulting index is at the end of the string, the
47
     * index is not incremented, and DONE is returned.
48
     * @return the code point at the new position or DONE if the new
49
     * position is after the text range.
50
     */
51
    public int next();
52
53
    /**
54
     * Decrements the iterator's index by one and returns the character
55
     * at the new index. If the current index is 0, the index
56
     * remains at 0 and a value of DONE is returned.
57
     *
58
     * @return the code point at the new position (or DONE if the current
59
     * position is 0)
60
     */
61
    public int previous();
62
63
    /**
64
     * Returns the current index (as a codepoint, not a string index).
65
     * @return the current index.
66
     */
67
    public int getIndex();
68
69
    /**
70
     * Create a copy of this code point iterator
71
     * @return A copy of this
72
     */
73
    public Object clone();
74
75
}
(-)src/org/eclipse/wst/xml/xpath2/processor/internal/utils/StringCodePointIterator.java (+188 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Jesper Steen Moeller and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Jesper Steen Moeller - bug 282096 - initial API and implementation
10
 *******************************************************************************/
11
 
12
package org.eclipse.wst.xml.xpath2.processor.internal.utils;
13
14
public final class StringCodePointIterator implements CodePointIterator
15
{
16
    private String text;
17
    private int end;
18
    // invariant: 0 <= pos <= end
19
    private int pos;
20
	private int cpPos;
21
22
    /**
23
     * Constructs an iterator with an initial index of 0.
24
     */
25
    public StringCodePointIterator(String text)
26
    {
27
        if (text == null)
28
            throw new NullPointerException();
29
        
30
        this.text = text;
31
        this.end = text.length();
32
        if (end > 0 && Character.isHighSurrogate(text.charAt(end-1)))
33
            throw new IllegalArgumentException("Invalid UTF-16 sequence ending with a high surrogate");
34
       
35
        this.pos = 0;
36
        this.cpPos = 0;
37
    }
38
39
    /**
40
     * Reset this iterator to point to a new string.  This package-visible
41
     * method is used by other java.text classes that want to avoid allocating
42
     * new StringCodePointIterator objects every time their setText method
43
     * is called.
44
     *
45
     * @param  text   The String to be iterated over
46
     * @since 1.2
47
     */
48
    public void setText(String text) {
49
        if (text == null)
50
            throw new NullPointerException();
51
        this.text = text;
52
        this.end = text.length();
53
        this.pos = 0;
54
        this.cpPos = 0;
55
    }
56
57
    /**
58
     * Implements CodePointIterator.first() for String.
59
     * @see CodePointIterator#first
60
     */
61
    public int first()
62
    {
63
        pos = 0;
64
        cpPos = 0;
65
        return current();
66
    }
67
68
    /**
69
     * Implements CodePointIterator.last() for String.
70
     * @see CodePointIterator#last
71
     */
72
    public int last()
73
    {
74
        pos = end;
75
        cpPos = Character.codePointCount(text, 0, pos);
76
        return previous();
77
     }
78
79
    /**
80
     * Implements CodePointIterator.current() for String.
81
     * @see CodePointIterator#current
82
     */
83
    public int current()
84
    {
85
        if (pos < end) {
86
            char ch1 =  text.charAt(pos);
87
            if (Character.isHighSurrogate(ch1)) return Character.toCodePoint(ch1, text.charAt(pos+1));
88
            return ch1;
89
        }
90
        else {
91
            return DONE;
92
        }
93
    }
94
95
    /**
96
     * Implements CodePointIterator.next() for String.
97
     * @see CodePointIterator#next
98
     */
99
    public int next()
100
    {
101
        if (pos < end - 1) {
102
            pos++;
103
            if (Character.isLowSurrogate(text.charAt(pos))) pos++;
104
            cpPos++;
105
            return current();
106
        }
107
        else {
108
        	pos = end;
109
            return DONE;
110
        }
111
    }
112
113
    /**
114
     * Implements CodePointIterator.previous() for String.
115
     * @see CodePointIterator#previous
116
     */
117
    public int previous()
118
    {
119
        if (pos > 0) {
120
            pos--;
121
            if (Character.isLowSurrogate(text.charAt(pos))) pos--; 
122
            cpPos--;
123
            return current();
124
        }
125
        else {
126
            return DONE;
127
        }
128
    }
129
130
    /**
131
     * Implements CodePointIterator.getIndex() for String.
132
     * @see CodePointIterator#getIndex
133
     */
134
    public int getIndex()
135
    {
136
        return cpPos;
137
    }
138
139
    /**
140
     * Compares the equality of two StringCodePointIterator objects.
141
     * @param obj the StringCodePointIterator object to be compared with.
142
     * @return true if the given obj is the same as this
143
     * StringCodePointIterator object; false otherwise.
144
     */
145
    public boolean equals(Object obj)
146
    {
147
        if (this == obj)
148
            return true;
149
        if (!(obj instanceof StringCodePointIterator))
150
            return false;
151
152
        StringCodePointIterator that = (StringCodePointIterator) obj;
153
154
        if (hashCode() != that.hashCode())
155
            return false;
156
        if (!text.equals(that.text))
157
            return false;
158
        if (pos != that.pos || end != that.end)
159
            return false;
160
        return true;
161
    }
162
163
    /**
164
     * Computes a hashcode for this iterator.
165
     * @return A hash code
166
     */
167
    public int hashCode()
168
    {
169
        return text.hashCode() ^ pos ^ end;
170
    }
171
172
    /**
173
     * Creates a copy of this iterator.
174
     * @return A copy of this
175
     */
176
    public Object clone()
177
    {
178
        try {
179
            StringCodePointIterator other
180
            = (StringCodePointIterator) super.clone();
181
            return other;
182
        }
183
        catch (CloneNotSupportedException e) {
184
            throw new InternalError();
185
        }
186
    }
187
188
}

Return to bug 282096