00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "value.h"
00024 #include "object.h"
00025 #include "types.h"
00026 #include "interpreter.h"
00027 #include "operations.h"
00028 #include "regexp.h"
00029 #include "regexp_object.h"
00030 #include "string_object.h"
00031 #include "error_object.h"
00032 #include <stdio.h>
00033 #include "string_object.lut.h"
00034
00035 #ifdef HAVE_STDINT_H
00036 #include <stdint.h>
00037 #endif
00038 #ifdef HAVE_SYS_TYPES_H
00039 #include <sys/types.h>
00040 #endif
00041 #ifdef HAVE_SYS_BITYPES_H
00042 #include <sys/bitypes.h>
00043 #endif
00044
00045 using namespace KJS;
00046
00047
00048
00049 const ClassInfo StringInstanceImp::info = {"String", 0, 0, 0};
00050
00051 StringInstanceImp::StringInstanceImp(ObjectImp *proto)
00052 : ObjectImp(proto)
00053 {
00054 setInternalValue(String(""));
00055 }
00056
00057 StringInstanceImp::StringInstanceImp(ObjectImp *proto, const UString &string)
00058 : ObjectImp(proto)
00059 {
00060 setInternalValue(String(string));
00061 }
00062
00063 Value StringInstanceImp::get(ExecState *exec, const Identifier &propertyName) const
00064 {
00065 if (propertyName == lengthPropertyName)
00066 return Number(internalValue().toString(exec).size());
00067
00068 bool ok;
00069 const unsigned index = propertyName.toArrayIndex(&ok);
00070 if (ok) {
00071 const UString s = internalValue().toString(exec);
00072 const unsigned length = s.size();
00073 if (index < length) {
00074 const UChar c = s[index];
00075 return String(UString(&c, 1));
00076 }
00077 }
00078
00079 return ObjectImp::get(exec, propertyName);
00080 }
00081
00082 void StringInstanceImp::put(ExecState *exec, const Identifier &propertyName, const Value &value, int attr)
00083 {
00084 if (propertyName == lengthPropertyName)
00085 return;
00086 ObjectImp::put(exec, propertyName, value, attr);
00087 }
00088
00089 bool StringInstanceImp::hasProperty(ExecState *exec, const Identifier &propertyName) const
00090 {
00091 if (propertyName == lengthPropertyName)
00092 return true;
00093
00094 bool ok;
00095 unsigned index = propertyName.toULong(&ok);
00096 if (ok && index < (unsigned)internalValue().toString(exec).size())
00097 return true;
00098
00099 return ObjectImp::hasProperty(exec, propertyName);
00100 }
00101
00102 bool StringInstanceImp::deleteProperty(ExecState *exec, const Identifier &propertyName)
00103 {
00104 if (propertyName == lengthPropertyName)
00105 return false;
00106
00107 bool ok;
00108 unsigned index = propertyName.toULong(&ok);
00109 if (ok && index < (unsigned)internalValue().toString(exec).size())
00110 return false;
00111
00112 return ObjectImp::deleteProperty(exec, propertyName);
00113 }
00114
00115 ReferenceList StringInstanceImp::propList(ExecState *exec, bool recursive)
00116 {
00117 ReferenceList properties = ObjectImp::propList(exec,recursive);
00118
00119 UString str = internalValue().toString(exec);
00120 for (int i = 0; i < str.size(); i++)
00121 if (!ObjectImp::hasProperty(exec,Identifier::from(i)))
00122 properties.append(Reference(this, i));
00123
00124 return properties;
00125 }
00126
00127
00128 const ClassInfo StringPrototypeImp::info = {"String", &StringInstanceImp::info, &stringTable, 0};
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169 StringPrototypeImp::StringPrototypeImp(ExecState * ,
00170 ObjectPrototypeImp *objProto)
00171 : StringInstanceImp(objProto)
00172 {
00173 Value protect(this);
00174
00175 putDirect(lengthPropertyName, NumberImp::zero(), DontDelete|ReadOnly|DontEnum);
00176
00177 }
00178
00179 Value StringPrototypeImp::get(ExecState *exec, const Identifier &propertyName) const
00180 {
00181 return lookupGetFunction<StringProtoFuncImp, StringInstanceImp>( exec, propertyName, &stringTable, this );
00182 }
00183
00184
00185
00186 StringProtoFuncImp::StringProtoFuncImp(ExecState *exec, int i, int len)
00187 : InternalFunctionImp(
00188 static_cast<FunctionPrototypeImp*>(exec->lexicalInterpreter()->builtinFunctionPrototype().imp())
00189 ), id(i)
00190 {
00191 Value protect(this);
00192 putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);
00193 }
00194
00195 bool StringProtoFuncImp::implementsCall() const
00196 {
00197 return true;
00198 }
00199
00200
00201 Value StringProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &args)
00202 {
00203 Value result;
00204
00205
00206 if (id == ToString || id == ValueOf) {
00207 KJS_CHECK_THIS( StringInstanceImp, thisObj );
00208
00209 return String(thisObj.internalValue().toString(exec));
00210 }
00211
00212 int n, m;
00213 UString u2, u3;
00214 double dpos;
00215 int pos, p0, i;
00216 double d = 0.0;
00217
00218 UString s = thisObj.toString(exec);
00219
00220 int len = s.size();
00221 Value a0 = args[0];
00222 Value a1 = args[1];
00223
00224 switch (id) {
00225 case ToString:
00226 case ValueOf:
00227
00228 break;
00229 case CharAt:
00230 pos = a0.type() == UndefinedType ? 0 : a0.toInteger(exec);
00231 if (pos < 0 || pos >= len)
00232 s = "";
00233 else
00234 s = s.substr(pos, 1);
00235 result = String(s);
00236 break;
00237 case CharCodeAt:
00238 pos = a0.type() == UndefinedType ? 0 : a0.toInteger(exec);
00239 if (pos < 0 || pos >= len)
00240 d = NaN;
00241 else {
00242 UChar c = s[pos];
00243 d = (c.high() << 8) + c.low();
00244 }
00245 result = Number(d);
00246 break;
00247 case Concat: {
00248 ListIterator it = args.begin();
00249 for ( ; it != args.end() ; ++it) {
00250 s += it->dispatchToString(exec);
00251 }
00252 result = String(s);
00253 break;
00254 }
00255 case IndexOf:
00256 u2 = a0.toString(exec);
00257 if (a1.type() == UndefinedType)
00258 pos = 0;
00259 else
00260 pos = a1.toInteger(exec);
00261 d = s.find(u2, pos);
00262 result = Number(d);
00263 break;
00264 case LastIndexOf:
00265 u2 = a0.toString(exec);
00266 d = a1.toNumber(exec);
00267 if (a1.type() == UndefinedType || KJS::isNaN(d))
00268 dpos = len;
00269 else {
00270 dpos = d;
00271 if (dpos < 0)
00272 dpos = 0;
00273 else if (dpos > len)
00274 dpos = len;
00275 }
00276 result = Number(s.rfind(u2, int(dpos)));
00277 break;
00278 case Match:
00279 case Search: {
00280 RegExp *reg, *tmpReg = 0;
00281 RegExpImp *imp = 0;
00282 if (a0.isA(ObjectType) && a0.toObject(exec).inherits(&RegExpImp::info))
00283 {
00284 imp = static_cast<RegExpImp *>( a0.toObject(exec).imp() );
00285 reg = imp->regExp();
00286 }
00287 else
00288 {
00289
00290
00291
00292
00293 reg = tmpReg = new RegExp(a0.toString(exec), RegExp::None);
00294 }
00295 RegExpObjectImp* regExpObj = static_cast<RegExpObjectImp*>(exec->interpreter()->builtinRegExp().imp());
00296 int **ovector = regExpObj->registerRegexp(reg, s);
00297 reg->prepareMatch(s);
00298 UString mstr = reg->match(s, -1, &pos, ovector);
00299 if (id == Search) {
00300 result = Number(pos);
00301 } else {
00302 if (mstr.isNull()) {
00303 result = Null();
00304 } else if ((reg->flags() & RegExp::Global) == 0) {
00305
00306 regExpObj->setSubPatterns(reg->subPatterns());
00307 result = regExpObj->arrayOfMatches(exec,mstr);
00308 } else {
00309
00310 List list;
00311 while (pos >= 0) {
00312 list.append(String(mstr));
00313 pos += mstr.isEmpty() ? 1 : mstr.size();
00314 delete [] *ovector;
00315 mstr = reg->match(s, pos, &pos, ovector);
00316 }
00317 result = exec->lexicalInterpreter()->builtinArray().construct(exec, list);
00318 }
00319 }
00320 reg->doneMatch();
00321 delete tmpReg;
00322 break;
00323 }
00324 case Replace:
00325 if (a0.type() == ObjectType && a0.toObject(exec).inherits(&RegExpImp::info)) {
00326 RegExpImp* imp = static_cast<RegExpImp *>( a0.toObject(exec).imp() );
00327 RegExp *reg = imp->regExp();
00328 bool global = false;
00329 Value tmp = imp->get(exec,"global");
00330 if (tmp.type() != UndefinedType && tmp.toBoolean(exec) == true)
00331 global = true;
00332
00333 RegExpObjectImp* regExpObj = static_cast<RegExpObjectImp*>(exec->lexicalInterpreter()->builtinRegExp().imp());
00334 int lastIndex = 0;
00335 Object o1;
00336
00337 if ( a1.type() == ObjectType && a1.toObject(exec).implementsCall() )
00338 o1 = a1.toObject(exec);
00339 else
00340 u3 = a1.toString(exec);
00341
00342 UString out;
00343
00344
00345 reg->prepareMatch(s);
00346 do {
00347 int **ovector = regExpObj->registerRegexp( reg, s );
00348 UString mstr = reg->match(s, lastIndex, &pos, ovector);
00349 regExpObj->setSubPatterns(reg->subPatterns());
00350 if (pos == -1)
00351 break;
00352
00353 len = mstr.size();
00354
00355 UString rstr;
00356
00357 if (!o1.isValid())
00358 {
00359 rstr = u3;
00360 bool ok;
00361
00362 for (int i = 0; (i = rstr.find(UString("$"), i)) != -1; i++) {
00363 if (i+1<rstr.size() && rstr[i+1] == '$') {
00364 rstr = rstr.substr(0,i) + "$" + rstr.substr(i+2);
00365 continue;
00366 }
00367
00368 unsigned long pos = rstr.substr(i+1,1).toULong(&ok, false );
00369 if (ok && pos <= (unsigned)reg->subPatterns()) {
00370 rstr = rstr.substr(0,i)
00371 + s.substr((*ovector)[2*pos],
00372 (*ovector)[2*pos+1]-(*ovector)[2*pos])
00373 + rstr.substr(i+2);
00374 i += (*ovector)[2*pos+1]-(*ovector)[2*pos] - 1;
00375 }
00376 }
00377 } else
00378 {
00379 List l;
00380 l.append(String(mstr));
00381
00382 for ( unsigned int sub = 1; sub <= reg->subPatterns() ; ++sub )
00383 l.append( String( s.substr((*ovector)[2*sub],
00384 (*ovector)[2*sub+1]-(*ovector)[2*sub]) ) );
00385 l.append(Number(pos));
00386 l.append(String(s));
00387 Object thisObj = exec->interpreter()->globalObject();
00388 rstr = o1.call( exec, thisObj, l ).toString(exec);
00389 }
00390
00391
00392
00393 if (pos != lastIndex)
00394 out += s.substr(lastIndex, pos - lastIndex);
00395
00396
00397 out += rstr;
00398
00399 lastIndex = pos + len;
00400 } while (global);
00401
00402
00403 if (lastIndex == 0 && out.size() == 0)
00404 out = s;
00405 else
00406 out += s.substr(lastIndex, s.size() - lastIndex);
00407
00408 reg->doneMatch();
00409
00410 result = String(out);
00411 } else {
00412 u2 = a0.toString(exec);
00413 pos = s.find(u2);
00414 len = u2.size();
00415
00416 if (pos == -1)
00417 result = String(s);
00418 else {
00419 u3 = s.substr(0, pos) + a1.toString(exec) +
00420 s.substr(pos + len);
00421 result = String(u3);
00422 }
00423 }
00424 break;
00425 case Slice:
00426 {
00427
00428 int begin = args[0].toUInt32(exec);
00429 int end = len;
00430 if (args[1].type() != UndefinedType) {
00431 end = args[1].toInteger(exec);
00432 }
00433 int from = begin < 0 ? len + begin : begin;
00434 int to = end < 0 ? len + end : end;
00435 if (to > from && to > 0 && from < len) {
00436 if (from < 0) {
00437 from = 0;
00438 }
00439 if (to > len) {
00440 to = len;
00441 }
00442 result = String(s.substr(from, to - from));
00443 } else {
00444 result = String("");
00445 }
00446 break;
00447 }
00448 case Split: {
00449 Object constructor = exec->lexicalInterpreter()->builtinArray();
00450 Object res = Object::dynamicCast(constructor.construct(exec,List::empty()));
00451 result = res;
00452 i = p0 = 0;
00453 uint32_t limit = (a1.type() != UndefinedType) ? a1.toUInt32(exec) : 0xFFFFFFFFU;
00454 if (a0.type() == ObjectType && Object::dynamicCast(a0).inherits(&RegExpImp::info)) {
00455 Object obj0 = Object::dynamicCast(a0);
00456 RegExp reg(obj0.get(exec,"source").toString(exec));
00457 reg.prepareMatch(s);
00458 if (s.isEmpty() && !reg.match(s, 0).isNull()) {
00459
00460 reg.doneMatch();
00461 res.put(exec, lengthPropertyName, Number(0), DontDelete|ReadOnly|DontEnum);
00462 break;
00463 }
00464 pos = 0;
00465 while (static_cast<uint32_t>(i) != limit && pos < s.size()) {
00466
00467 int mpos;
00468 int *ovector = 0L;
00469 UString mstr = reg.match(s, pos, &mpos, &ovector);
00470 delete [] ovector; ovector = 0L;
00471 if (mpos < 0)
00472 break;
00473 pos = mpos + (mstr.isEmpty() ? 1 : mstr.size());
00474 if (mpos != p0 || !mstr.isEmpty()) {
00475 res.put(exec,i, String(s.substr(p0, mpos-p0)));
00476 p0 = mpos + mstr.size();
00477 i++;
00478 }
00479 }
00480 reg.doneMatch();
00481 } else {
00482 u2 = a0.toString(exec);
00483 if (u2.isEmpty()) {
00484 if (s.isEmpty()) {
00485
00486 put(exec,lengthPropertyName, Number(0));
00487 break;
00488 } else {
00489 while (static_cast<uint32_t>(i) != limit && i < s.size()-1)
00490 res.put(exec,i++, String(s.substr(p0++, 1)));
00491 }
00492 } else {
00493 while (static_cast<uint32_t>(i) != limit && (pos = s.find(u2, p0)) >= 0) {
00494 res.put(exec,i, String(s.substr(p0, pos-p0)));
00495 p0 = pos + u2.size();
00496 i++;
00497 }
00498 }
00499 }
00500
00501 if (static_cast<uint32_t>(i) != limit)
00502 res.put(exec,i++, String(s.substr(p0)));
00503 res.put(exec,lengthPropertyName, Number(i));
00504 }
00505 break;
00506 case Substr: {
00507 n = a0.toInteger(exec);
00508 m = a1.toInteger(exec);
00509 int d, d2;
00510 if (n >= 0)
00511 d = n;
00512 else
00513 d = maxInt(len + n, 0);
00514 if (a1.type() == UndefinedType)
00515 d2 = len - d;
00516 else
00517 d2 = minInt(maxInt(m, 0), len - d);
00518 result = String(s.substr(d, d2));
00519 break;
00520 }
00521 case Substring: {
00522 double start = a0.toNumber(exec);
00523 double end = a1.toNumber(exec);
00524 if (KJS::isNaN(start))
00525 start = 0;
00526 if (KJS::isNaN(end))
00527 end = 0;
00528 if (start < 0)
00529 start = 0;
00530 if (end < 0)
00531 end = 0;
00532 if (start > len)
00533 start = len;
00534 if (end > len)
00535 end = len;
00536 if (a1.type() == UndefinedType)
00537 end = len;
00538 if (start > end) {
00539 double temp = end;
00540 end = start;
00541 start = temp;
00542 }
00543 result = String(s.substr((int)start, (int)end-(int)start));
00544 }
00545 break;
00546 case ToLowerCase:
00547 case ToLocaleLowerCase:
00548 for (i = 0; i < len; i++)
00549 s[i] = s[i].toLower();
00550 result = String(s);
00551 break;
00552 case ToUpperCase:
00553 case ToLocaleUpperCase:
00554 for (i = 0; i < len; i++)
00555 s[i] = s[i].toUpper();
00556 result = String(s);
00557 break;
00558 #ifndef KJS_PURE_ECMA
00559 case Big:
00560 result = String("<big>" + s + "</big>");
00561 break;
00562 case Small:
00563 result = String("<small>" + s + "</small>");
00564 break;
00565 case Blink:
00566 result = String("<blink>" + s + "</blink>");
00567 break;
00568 case Bold:
00569 result = String("<b>" + s + "</b>");
00570 break;
00571 case Fixed:
00572 result = String("<tt>" + s + "</tt>");
00573 break;
00574 case Italics:
00575 result = String("<i>" + s + "</i>");
00576 break;
00577 case Strike:
00578 result = String("<strike>" + s + "</strike>");
00579 break;
00580 case Sub:
00581 result = String("<sub>" + s + "</sub>");
00582 break;
00583 case Sup:
00584 result = String("<sup>" + s + "</sup>");
00585 break;
00586 case Fontcolor:
00587 result = String("<font color=\"" + a0.toString(exec) + "\">" + s + "</font>");
00588 break;
00589 case Fontsize:
00590 result = String("<font size=\"" + a0.toString(exec) + "\">" + s + "</font>");
00591 break;
00592 case Anchor:
00593 result = String("<a name=\"" + a0.toString(exec) + "\">" + s + "</a>");
00594 break;
00595 case Link:
00596 result = String("<a href=\"" + a0.toString(exec) + "\">" + s + "</a>");
00597 break;
00598 #endif
00599 }
00600
00601 return result;
00602 }
00603
00604
00605
00606 StringObjectImp::StringObjectImp(ExecState *exec,
00607 FunctionPrototypeImp *funcProto,
00608 StringPrototypeImp *stringProto)
00609 : InternalFunctionImp(funcProto)
00610 {
00611 Value protect(this);
00612
00613 putDirect(prototypePropertyName, stringProto, DontEnum|DontDelete|ReadOnly);
00614
00615 putDirect("fromCharCode", new StringObjectFuncImp(exec,funcProto), DontEnum);
00616
00617
00618 putDirect(lengthPropertyName, NumberImp::one(), ReadOnly|DontDelete|DontEnum);
00619 }
00620
00621
00622 bool StringObjectImp::implementsConstruct() const
00623 {
00624 return true;
00625 }
00626
00627
00628 Object StringObjectImp::construct(ExecState *exec, const List &args)
00629 {
00630 ObjectImp *proto = exec->lexicalInterpreter()->builtinStringPrototype().imp();
00631 if (args.size() == 0)
00632 return Object(new StringInstanceImp(proto));
00633 return Object(new StringInstanceImp(proto, args.begin()->dispatchToString(exec)));
00634 }
00635
00636 bool StringObjectImp::implementsCall() const
00637 {
00638 return true;
00639 }
00640
00641
00642 Value StringObjectImp::call(ExecState *exec, Object &, const List &args)
00643 {
00644 if (args.isEmpty())
00645 return String("");
00646 else {
00647 Value v = args[0];
00648 return String(v.toString(exec));
00649 }
00650 }
00651
00652
00653
00654
00655 StringObjectFuncImp::StringObjectFuncImp(ExecState* , FunctionPrototypeImp *funcProto)
00656 : InternalFunctionImp(funcProto)
00657 {
00658 Value protect(this);
00659 putDirect(lengthPropertyName, NumberImp::one(), DontDelete|ReadOnly|DontEnum);
00660 }
00661
00662 bool StringObjectFuncImp::implementsCall() const
00663 {
00664 return true;
00665 }
00666
00667 Value StringObjectFuncImp::call(ExecState *exec, Object &, const List &args)
00668 {
00669 UString s;
00670 if (args.size()) {
00671 UChar *buf = new UChar[args.size()];
00672 UChar *p = buf;
00673 ListIterator it = args.begin();
00674 while (it != args.end()) {
00675 unsigned short u = it->toUInt16(exec);
00676 *p++ = UChar(u);
00677 it++;
00678 }
00679 s = UString(buf, args.size(), false);
00680 } else
00681 s = "";
00682
00683 return String(s);
00684 }