|
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; |