KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > es > NativeString


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  * Free SoftwareFoundation, Inc.
23  * 59 Temple Place, Suite 330
24  * Boston, MA 02111-1307 USA
25  *
26  * @author Scott Ferguson
27  */

28
29 package com.caucho.es;
30
31 import com.caucho.util.CharBuffer;
32 import com.caucho.util.IntArray;
33
34 /**
35  * JavaScript object
36  */

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   // js1.2
52
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   // caucho
60
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 JavaDoc name, int n, int len)
71   {
72     super(name, len);
73
74     this.n = n;
75   }
76
77   /**
78    * Creates the native String object
79    */

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     // js1.2
107
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     // caucho extensions
115
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 JavaDoc 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 JavaDoc
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 JavaDoc 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 JavaDoc
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 JavaDoc
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 JavaDoc
254   {
255     StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
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 JavaDoc
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 JavaDoc
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 JavaDoc
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 JavaDoc
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 JavaDoc escapeRegexp(String JavaDoc 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 JavaDoc
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 JavaDoc();
363       
364       // splitter = (ESRegexp) eval.getArg(0);
365
}
366     else {
367       String JavaDoc arg = eval.getArg(0).toString();
368
369       String JavaDoc []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       /*
376       if (arg.length() == 1 && arg.charAt(0) == ' ') {
377     splitter = new ESRegexp("\\s", "g");
378       } else
379     splitter = new ESRegexp(escapeRegexp(arg), "g");
380       */

381     }
382
383     return array;
384   }
385
386   private ESBase substring(Call eval, int length) throws Throwable JavaDoc
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 JavaDoc
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 JavaDoc
429   {
430     /*
431     if (length == 0)
432       return esNull;
433     
434     Global resin = Global.getGlobalProto();
435     ESString string = eval.getArg(-1).toStr();
436
437     ESBase arg = eval.getArg(0);
438     ESRegexp regexp;
439
440     if (arg instanceof ESRegexp)
441       regexp = (ESRegexp) arg;
442     else if (length > 1)
443       regexp = new ESRegexp(arg.toStr(), eval.getArg(1).toStr());
444     else
445       regexp = new ESRegexp(arg.toStr(), ESString.NULL);
446
447     IntArray results = new IntArray();
448
449     resin.getRegexp().setRegexp(regexp);
450     regexp.setLastIndex(0);
451     if (! regexp.exec(string))
452       return esNull;
453
454     ESArray array = resin.createArray();
455
456     if (! regexp.regexp.isGlobal()) {
457       for (int i = 0; i < regexp.regexp.length(); i++) {
458     array.setProperty(i, string.substring(regexp.regexp.getBegin(i),
459                           regexp.regexp.getEnd(i)));
460       }
461
462       return array;
463     }
464
465     int i = 0;
466     do {
467       array.setProperty(i, string.substring(regexp.regexp.getBegin(0),
468                         regexp.regexp.getEnd(0)));
469       i++;
470     } while (regexp.exec(string));
471
472     return array;
473     */

474     return esNull;
475   }
476
477   private void replaceFun(CharBuffer result, String JavaDoc pattern,
478               ESRegexp regexp, ESBase fun)
479     throws Throwable JavaDoc
480   {
481     /*
482     Call call = Global.getGlobalProto().getCall();
483
484     call.top = 1;
485     call.setThis(regexp);
486     for (int i = 0; i < regexp.regexp.length(); i++) {
487       int begin = regexp.regexp.getBegin(i);
488       int end = regexp.regexp.getEnd(i);
489       call.setArg(i, ESString.create(pattern.substring(begin, end)));
490     }
491
492     ESBase value = fun.call(call, regexp.regexp.length());
493
494     Global.getGlobalProto().freeCall(call);
495
496     String string = value.toStr().toString();
497
498     result.append(string);
499     */

500   }
501
502   /*
503   private void replaceString(CharBuffer result, String pattern,
504                  Pattern regexp, String replacement)
505     throws Throwable
506   {
507     int len = replacement.length();
508
509     for (int i = 0; i < len; i++) {
510       char ch = replacement.charAt(i);
511       
512       if (ch == '$' && i + 1 < len) {
513     i++;
514     ch = replacement.charAt(i);
515
516     if (ch >= '0' && ch <= '9') {
517       int index = ch - '0';
518
519       if (index < regexp.length()) {
520         int begin = regexp.getBegin(index);
521         int end = regexp.getEnd(index);
522         result.append(pattern.substring(begin, end));
523       }
524     } else if (ch == '$')
525       result.append('$');
526     else if (ch == '&') {
527       int begin = regexp.getBegin(0);
528       int end = regexp.getEnd(0);
529       result.append(pattern.substring(begin, end));
530     } else if (ch == '+') {
531       int begin = regexp.getBegin(regexp.length() - 1);
532       int end = regexp.getEnd(regexp.length() - 1);
533       result.append(pattern.substring(begin, end));
534     } else if (ch == '`') {
535       int begin = 0;
536       int end = regexp.getBegin(0);
537       result.append(pattern.substring(begin, end));
538     } else if (ch == '\'') {
539       int begin = regexp.getEnd(0);
540       int end = pattern.length();
541       result.append(pattern.substring(begin, end));
542     } else {
543       result.append('$');
544       result.append(ch);
545     }
546       } else {
547     result.append(ch);
548       }
549     }
550   }
551   */

552
553   private ESBase replace(Call eval, int length) throws Throwable JavaDoc
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 JavaDoc pattern = string.toString();
571
572     ESBase replace = null;
573     String JavaDoc stringPattern = null;
574     if (length > 1)
575       replace = eval.getArg(1);
576
577     /* XXX: convert to java.util.regex
578     int last = 0;
579     CharBuffer result = new CharBuffer();
580     resin.getRegexp().setRegexp(regexp);
581     if (regexp.regexp.isGlobal())
582       regexp.setLastIndex(0);
583     while (regexp.exec(string)) {
584       result.append(pattern.substring(last, regexp.regexp.getBegin(0)));
585       last = regexp.regexp.getEnd(0);
586
587       if (replace instanceof ESClosure) {
588     replaceFun(result, pattern, regexp, replace);
589       } else {
590     if (stringPattern == null)
591       stringPattern = replace == null ? "" : replace.toString();
592
593     replaceString(result, pattern, regexp.regexp, stringPattern);
594       }
595
596       if (! regexp.regexp.isGlobal())
597     break;
598
599     }
600         result.append(pattern.substring(last));
601
602     return ESString.create(result);
603     */

604
605     return null;
606   }
607
608   private ESBase search(Call eval, int length) throws Throwable JavaDoc
609   {
610     if (length == 0)
611       return ESNumber.create(-1);
612     
613     return ESNumber.create(-1);
614
615     /* XXX: convert to java.util.regex
616     ESString string = eval.getArg(-1).toStr();
617
618     ESBase arg = eval.getArg(0);
619     ESRegexp regexp;
620
621     if (arg instanceof ESRegexp)
622       regexp = (ESRegexp) arg;
623     else if (length > 1)
624       regexp = new ESRegexp(arg.toStr(), eval.getArg(1).toStr());
625     else
626       regexp = new ESRegexp(arg.toStr(), ESString.NULL);
627
628     Global.getGlobalProto().getRegexp().setRegexp(regexp);
629     if (! regexp.exec(string, false))
630       return ESNumber.create(-1);
631     else
632       return ESNumber.create(regexp.regexp.getBegin(0));
633     */

634   }
635
636   private ESBase slice(Call eval, int length) throws Throwable JavaDoc
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 JavaDoc
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 JavaDoc
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