1 28 29 package com.caucho.es; 30 31 import com.caucho.util.CharBuffer; 32 import com.caucho.util.IntArray; 33 34 37 class NativeString extends Native { 38 static final int NEW = 1; 39 static final int TO_STRING = NEW + 1; 40 static final int FROM_CHAR_CODE = TO_STRING + 1; 41 static final int VALUE_OF = FROM_CHAR_CODE + 1; 42 static final int CHAR_AT = VALUE_OF + 1; 43 static final int CHAR_CODE_AT = CHAR_AT + 1; 44 static final int INDEX_OF = CHAR_CODE_AT + 1; 45 static final int LAST_INDEX_OF = INDEX_OF + 1; 46 static final int SPLIT = LAST_INDEX_OF + 1; 47 static final int SUBSTRING = SPLIT + 1; 48 static final int TO_UPPER_CASE = SUBSTRING + 1; 49 static final int TO_LOWER_CASE = TO_UPPER_CASE + 1; 50 51 static final int CONCAT = TO_LOWER_CASE + 1; 53 static final int MATCH = CONCAT + 1; 54 static final int REPLACE = MATCH + 1; 55 static final int SEARCH = REPLACE + 1; 56 static final int SLICE = SEARCH + 1; 57 static final int SUBSTR = SLICE + 1; 58 59 static final int PRINTF = SUBSTR + 1; 61 static final int CONTAINS = PRINTF + 1; 62 static final int STARTS_WITH = CONTAINS + 1; 63 static final int ENDS_WITH = STARTS_WITH + 1; 64 static final int GET_BYTES = ENDS_WITH + 1; 65 66 static final int REPLACE_WS = 0; 67 static final int REPLACE_DIGIT = REPLACE_WS + 1; 68 static final int REPLACE_ID = REPLACE_DIGIT + 1; 69 70 private NativeString(String name, int n, int len) 71 { 72 super(name, len); 73 74 this.n = n; 75 } 76 77 80 static ESObject create(Global resin) 81 { 82 NativeString nativeString = new NativeString("String", NEW, 1); 83 ESObject stringProto = new ESWrapper("String", resin.objProto, 84 ESString.NULL); 85 NativeWrapper string; 86 string = new NativeWrapper(resin, nativeString, 87 stringProto, ESThunk.STRING_THUNK); 88 resin.stringProto = stringProto; 89 90 stringProto.put("length", ESNumber.create(0), 91 DONT_ENUM|DONT_DELETE|READ_ONLY); 92 93 put(stringProto, "valueOf", VALUE_OF, 0); 94 put(stringProto, "toString", TO_STRING, 0); 95 put(stringProto, "charAt", CHAR_AT, 1); 96 put(stringProto, "charCodeAt", CHAR_CODE_AT, 1); 97 put(stringProto, "indexOf", INDEX_OF, 2); 98 put(stringProto, "lastIndexOf", LAST_INDEX_OF, 2); 99 put(stringProto, "split", SPLIT, 1); 100 put(stringProto, "substring", SUBSTRING, 2); 101 put(stringProto, "toUpperCase", TO_UPPER_CASE, 0); 102 put(stringProto, "toLowerCase", TO_LOWER_CASE, 0); 103 104 put(string, "fromCharCode", FROM_CHAR_CODE, 0); 105 106 put(stringProto, "concat", CONCAT, 1); 108 put(stringProto, "match", MATCH, 1); 109 put(stringProto, "replace", REPLACE, 2); 110 put(stringProto, "search", SEARCH, 1); 111 put(stringProto, "slice", SLICE, 2); 112 put(stringProto, "substr", SUBSTR, 2); 113 114 put(string, "printf", PRINTF, 1); 116 put(stringProto, "contains", CONTAINS, 1); 117 put(stringProto, "startsWith", STARTS_WITH, 1); 118 put(stringProto, "endsWith", ENDS_WITH, 1); 119 put(stringProto, "getBytes", GET_BYTES, 1); 120 121 stringProto.setClean(); 122 string.setClean(); 123 124 return string; 125 } 126 127 private static void put(ESObject obj, String name, int n, int len) 128 { 129 ESId id = ESId.intern(name); 130 131 obj.put(id, new NativeString(name, n, len), DONT_ENUM); 132 } 133 134 public ESBase call(Call eval, int length) throws Throwable 135 { 136 switch (n) { 137 case NEW: 138 if (length == 0) 139 return ESString.create(""); 140 else 141 return eval.getArg(0).toStr(); 142 143 case FROM_CHAR_CODE: 144 return fromCharCode(eval, length); 145 146 case VALUE_OF: 147 case TO_STRING: 148 try { 149 return (ESBase) ((ESWrapper) eval.getArg(-1)).value; 150 } catch (ClassCastException e) { 151 if (eval.getArg(-1) instanceof ESString) 152 return eval.getArg(-1); 153 154 if (eval.getArg(-1) instanceof ESThunk) 155 return (ESBase) ((ESWrapper) ((ESThunk) eval.getArg(-1)).getObject()).value; 156 157 throw new ESException("toString expects string object"); 158 } 159 160 case CHAR_AT: 161 return charAt(eval, length); 162 163 case CHAR_CODE_AT: 164 return charCodeAt(eval, length); 165 166 case INDEX_OF: 167 return indexOf(eval, length); 168 169 case LAST_INDEX_OF: 170 return lastIndexOf(eval, length); 171 172 case SPLIT: 173 return split(eval, length); 174 175 case SUBSTRING: 176 return substring(eval, length); 177 178 case TO_UPPER_CASE: 179 return eval.getArg(-1).toStr().toUpperCase(); 180 181 case TO_LOWER_CASE: 182 return eval.getArg(-1).toStr().toLowerCase(); 183 184 case CONCAT: 185 return concat(eval, length); 186 187 case MATCH: 188 return match(eval, length); 189 190 case REPLACE: 191 return replace(eval, length); 192 193 case SEARCH: 194 return search(eval, length); 195 196 case SLICE: 197 return slice(eval, length); 198 199 case SUBSTR: 200 return substr(eval, length); 201 202 case PRINTF: 203 return printf(eval, length); 204 205 case CONTAINS: 206 if (length < 1) 207 return ESBoolean.FALSE; 208 else 209 return eval.getArg(-1).toStr().contains(eval.getArg(0)); 210 211 case STARTS_WITH: 212 if (length < 1) 213 return ESBoolean.FALSE; 214 else 215 return eval.getArg(-1).toStr().startsWith(eval.getArg(0)); 216 217 case ENDS_WITH: 218 if (length < 1) 219 return ESBoolean.FALSE; 220 else 221 return eval.getArg(-1).toStr().endsWith(eval.getArg(0)); 222 223 case GET_BYTES: 224 if (length < 1) 225 return eval.wrap(eval.getArgString(-1, length).getBytes()); 226 else 227 return eval.wrap(eval.getArgString(-1, length).getBytes(eval.getArgString(0, length))); 228 229 default: 230 throw new ESException("Unknown object function"); 231 } 232 } 233 234 public ESBase construct(Call eval, int length) throws Throwable 235 { 236 if (n != NEW) 237 throw new ESException("Unknown object function"); 238 239 return (ESObject) create(eval, length); 240 } 241 242 private ESBase create(Call eval, int length) throws Throwable 243 { 244 ESBase value; 245 if (length == 0) 246 value = ESString.create(""); 247 else 248 value = eval.getArg(0).toStr(); 249 250 return value.toObject(); 251 } 252 253 private ESBase fromCharCode(Call eval, int length) throws Throwable 254 { 255 StringBuffer sbuf = new StringBuffer (); 256 257 for (int i = 0; i < length; i++) { 258 int value = eval.getArg(i).toInt32() & 0xffff; 259 260 sbuf.append((char) value); 261 } 262 263 return ESString.create(sbuf.toString()); 264 } 265 266 private ESBase charAt(Call eval, int length) throws Throwable 267 { 268 ESString string = eval.getArg(-1).toStr(); 269 270 if (length == 0) 271 return ESString.create(""); 272 273 int value = (int) eval.getArg(0).toNum(); 274 275 if (value < 0 || value >= string.length()) 276 return ESString.create(""); 277 else 278 return ESString.create("" + (char) string.charAt(value)); 279 } 280 281 private ESBase charCodeAt(Call eval, int length) throws Throwable 282 { 283 ESString string = eval.getArg(-1).toStr(); 284 285 if (length == 0) 286 return ESNumber.NaN; 287 288 int value = (int) eval.getArg(0).toNum(); 289 290 if (value < 0 || value >= string.length()) 291 return ESNumber.NaN; 292 else 293 return ESNumber.create(string.charAt(value)); 294 } 295 296 private ESBase indexOf(Call eval, int length) throws Throwable 297 { 298 ESString string = eval.getArg(-1).toStr(); 299 300 if (length == 0) 301 return ESNumber.create(-1); 302 303 int pos = 0; 304 if (length > 1) 305 pos = (int) eval.getArg(1).toNum(); 306 307 ESString test = eval.getArg(0).toStr(); 308 309 return ESNumber.create(string.indexOf(test, pos)); 310 } 311 312 private ESBase lastIndexOf(Call eval, int length) throws Throwable 313 { 314 ESString string = eval.getArg(-1).toStr(); 315 316 if (length == 0) 317 return ESNumber.create(-1); 318 319 int pos = string.length() + 1; 320 if (length > 1) 321 pos = (int) eval.getArg(1).toNum(); 322 323 ESString test = eval.getArg(0).toStr(); 324 325 return ESNumber.create(string.lastIndexOf(test, pos)); 326 } 327 328 private String escapeRegexp(String arg) 329 { 330 CharBuffer cb = new CharBuffer(); 331 332 for (int i = 0; i < arg.length(); i++) { 333 int ch; 334 switch ((ch = arg.charAt(i))) { 335 case '\\': case '-': case '[': case ']': case '(': case ')': 336 case '$': case '^': case '|': case '?': case '*': case '{': 337 case '}': case '.': 338 cb.append('\\'); 339 cb.append((char) ch); 340 break; 341 342 default: 343 cb.append((char) ch); 344 } 345 } 346 347 return cb.toString(); 348 } 349 350 private ESBase split(Call eval, int length) throws Throwable 351 { 352 Global resin = Global.getGlobalProto(); 353 ESString string = eval.getArg(-1).toStr(); 354 355 ESArray array = resin.createArray(); 356 357 if (length == 0) { 358 array.setProperty(0, string); 359 return array; 360 } 361 else if (eval.getArg(0) instanceof ESRegexp) { 362 throw new UnsupportedOperationException (); 363 364 } 366 else { 367 String arg = eval.getArg(0).toString(); 368 369 String []values = string.toString().split(arg); 370 371 for (int i = 0; i < values.length; i++) { 372 array.setProperty(i, ESString.create(values[i])); 373 } 374 375 381 } 382 383 return array; 384 } 385 386 private ESBase substring(Call eval, int length) throws Throwable 387 { 388 ESString string = eval.getArg(-1).toStr(); 389 390 if (length == 0) 391 return string; 392 393 int start = (int) eval.getArg(0).toNum(); 394 int end = string.length(); 395 396 if (length > 1) 397 end = (int) eval.getArg(1).toNum(); 398 399 if (start < 0) 400 start = 0; 401 if (end > string.length()) 402 end = string.length(); 403 if (start > end) 404 return string.substring(end, start); 405 else 406 return string.substring(start, end); 407 } 408 409 private ESBase concat(Call eval, int length) throws Throwable 410 { 411 ESString string = eval.getArg(-1).toStr(); 412 413 if (length == 0) 414 return string; 415 416 CharBuffer cb = new CharBuffer(); 417 cb.append(string.toString()); 418 419 for (int i = 0; i < length; i++) { 420 ESString next = eval.getArg(i).toStr(); 421 422 cb.append(next.toString()); 423 } 424 425 return ESString.create(cb); 426 } 427 428 private ESBase match(Call eval, int length) throws Throwable 429 { 430 474 return esNull; 475 } 476 477 private void replaceFun(CharBuffer result, String pattern, 478 ESRegexp regexp, ESBase fun) 479 throws Throwable 480 { 481 500 } 501 502 552 553 private ESBase replace(Call eval, int length) throws Throwable 554 { 555 ESString string = eval.getArg(-1).toStr(); 556 557 if (length < 1) 558 return string; 559 560 Global resin = Global.getGlobalProto(); 561 ESBase arg = eval.getArg(0); 562 ESRegexp regexp; 563 564 if (arg instanceof ESRegexp) 565 regexp = (ESRegexp) arg; 566 else 567 regexp = new ESRegexp(arg.toStr(), ESString.NULL); 568 569 IntArray results = new IntArray(); 570 String pattern = string.toString(); 571 572 ESBase replace = null; 573 String stringPattern = null; 574 if (length > 1) 575 replace = eval.getArg(1); 576 577 604 605 return null; 606 } 607 608 private ESBase search(Call eval, int length) throws Throwable 609 { 610 if (length == 0) 611 return ESNumber.create(-1); 612 613 return ESNumber.create(-1); 614 615 634 } 635 636 private ESBase slice(Call eval, int length) throws Throwable 637 { 638 ESString string = eval.getArg(-1).toStr(); 639 640 if (length == 0) 641 return string; 642 643 int start = (int) eval.getArg(0).toNum(); 644 int end = string.length(); 645 646 if (length > 1) 647 end = (int) eval.getArg(1).toNum(); 648 649 if (start < 0) 650 start += string.length(); 651 if (end < 0) 652 end += string.length(); 653 654 if (start < 0) 655 start = 0; 656 if (start > string.length()) 657 start = string.length(); 658 659 if (end < 0) 660 end = 0; 661 if (end > string.length()) 662 end = string.length(); 663 664 if (start <= end) 665 return string.substring(start, end); 666 else 667 return ESString.NULL; 668 } 669 670 private ESBase substr(Call eval, int length) throws Throwable 671 { 672 ESString string = eval.getArg(-1).toStr(); 673 674 if (length == 0) 675 return string; 676 677 int start = (int) eval.getArg(0).toNum(); 678 int len = string.length(); 679 680 if (length > 1) 681 len = (int) eval.getArg(1).toNum(); 682 683 if (start < 0) 684 start += string.length(); 685 686 if (start < 0) 687 start = 0; 688 if (start > string.length()) 689 start = string.length(); 690 691 if (len <= 0) 692 return ESString.NULL; 693 694 int end = start + len; 695 696 if (end > string.length()) 697 end = string.length(); 698 699 return string.substring(start, end); 700 } 701 702 private ESBase printf(Call eval, int length) throws Throwable 703 { 704 if (length == 0) 705 return ESString.NULL; 706 707 ESString format = eval.getArg(0).toStr(); 708 CharBuffer cb = new CharBuffer(); 709 710 Printf.printf(cb, format, eval, length); 711 712 return ESString.create(cb.toString()); 713 } 714 } 715 | Popular Tags |