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
00170 StringPrototypeImp::StringPrototypeImp(ExecState * ,
00171 ObjectPrototypeImp *objProto)
00172 : StringInstanceImp(objProto)
00173 {
00174 Value protect(this);
00175
00176 putDirect(lengthPropertyName, NumberImp::zero(), DontDelete|ReadOnly|DontEnum);
00177
00178 }
00179
00180 Value StringPrototypeImp::get(ExecState *exec, const Identifier &propertyName) const
00181 {
00182 return lookupGetFunction<StringProtoFuncImp, StringInstanceImp>( exec, propertyName, &stringTable, this );
00183 }
00184
00185
00186
00187 StringProtoFuncImp::StringProtoFuncImp(ExecState *exec, int i, int len)
00188 : InternalFunctionImp(
00189 static_cast<FunctionPrototypeImp*>(exec->lexicalInterpreter()->builtinFunctionPrototype().imp())
00190 ), id(i)
00191 {
00192 Value protect(this);
00193 putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);
00194 }
00195
00196 bool StringProtoFuncImp::implementsCall() const
00197 {
00198 return true;
00199 }
00200
00201
00202 static inline int localeCompare(const UString &a, const UString &b)
00203 {
00204
00205 return compare(a, b);
00206 }
00207
00208
00209 Value StringProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &args)
00210 {
00211 Value result;
00212
00213
00214 if (id == ToString || id == ValueOf) {
00215 KJS_CHECK_THIS( StringInstanceImp, thisObj );
00216
00217 return String(thisObj.internalValue().toString(exec));
00218 }
00219
00220 int n, m;
00221 UString u2, u3;
00222 double dpos;
00223 int pos, p0, i;
00224 double d = 0.0;
00225
00226 UString s = thisObj.toString(exec);
00227
00228 int len = s.size();
00229 Value a0 = args[0];
00230 Value a1 = args[1];
00231
00232 switch (id) {
00233 case ToString:
00234 case ValueOf:
00235
00236 break;
00237 case CharAt:
00238 pos = a0.type() == UndefinedType ? 0 : a0.toInteger(exec);
00239 if (pos < 0 || pos >= len)
00240 s = "";
00241 else
00242 s = s.substr(pos, 1);
00243 result = String(s);
00244 break;
00245 case CharCodeAt:
00246 pos = a0.type() == UndefinedType ? 0 : a0.toInteger(exec);
00247 if (pos < 0 || pos >= len)
00248 d = NaN;
00249 else {
00250 UChar c = s[pos];
00251 d = (c.high() << 8) + c.low();
00252 }
00253 result = Number(d);
00254 break;
00255 case Concat: {
00256 ListIterator it = args.begin();
00257 for ( ; it != args.end() ; ++it) {
00258 s += it->dispatchToString(exec);
00259 }
00260 result = String(s);
00261 break;
00262 }
00263 case IndexOf:
00264 u2 = a0.toString(exec);
00265 if (a1.type() == UndefinedType)
00266 pos = 0;
00267 else
00268 pos = a1.toInteger(exec);
00269 d = s.find(u2, pos);
00270 result = Number(d);
00271 break;
00272 case LastIndexOf:
00273 u2 = a0.toString(exec);
00274 d = a1.toNumber(exec);
00275 if (a1.type() == UndefinedType || KJS::isNaN(d))
00276 dpos = len;
00277 else {
00278 dpos = d;
00279 if (dpos < 0)
00280 dpos = 0;
00281 else if (dpos > len)
00282 dpos = len;
00283 }
00284 result = Number(s.rfind(u2, int(dpos)));
00285 break;
00286 case Match:
00287 case Search: {
00288 RegExp *reg, *tmpReg = 0;
00289 RegExpImp *imp = 0;
00290 if (a0.isA(ObjectType) && a0.toObject(exec).inherits(&RegExpImp::info))
00291 {
00292 imp = static_cast<RegExpImp *>( a0.toObject(exec).imp() );
00293 reg = imp->regExp();
00294 }
00295 else
00296 {
00297
00298
00299
00300
00301 reg = tmpReg = new RegExp(a0.toString(exec), RegExp::None);
00302 }
00303 if (!reg->isValid()) {
00304 delete tmpReg;
00305 Object err = Error::create(exec, SyntaxError,
00306 "Invalid regular expression");
00307 exec->setException(err);
00308 return err;
00309 }
00310 RegExpObjectImp* regExpObj = static_cast<RegExpObjectImp*>(exec->interpreter()->builtinRegExp().imp());
00311 int **ovector = regExpObj->registerRegexp(reg, s);
00312 reg->prepareMatch(s);
00313 UString mstr = reg->match(s, -1, &pos, ovector);
00314 if (id == Search) {
00315 result = Number(pos);
00316 } else {
00317 if (mstr.isNull()) {
00318 result = Null();
00319 } else if ((reg->flags() & RegExp::Global) == 0) {
00320
00321 regExpObj->setSubPatterns(reg->subPatterns());
00322 result = regExpObj->arrayOfMatches(exec,mstr);
00323 } else {
00324
00325 List list;
00326 while (pos >= 0) {
00327 list.append(String(mstr));
00328 pos += mstr.isEmpty() ? 1 : mstr.size();
00329 delete [] *ovector;
00330 mstr = reg->match(s, pos, &pos, ovector);
00331 }
00332 result = exec->lexicalInterpreter()->builtinArray().construct(exec, list);
00333 }
00334 }
00335 reg->doneMatch();
00336 delete tmpReg;
00337 break;
00338 }
00339 case Replace:
00340 if (a0.type() == ObjectType && a0.toObject(exec).inherits(&RegExpImp::info)) {
00341 RegExpImp* imp = static_cast<RegExpImp *>( a0.toObject(exec).imp() );
00342 RegExp *reg = imp->regExp();
00343 bool global = false;
00344 Value tmp = imp->get(exec,"global");
00345 if (tmp.type() != UndefinedType && tmp.toBoolean(exec) == true)
00346 global = true;
00347
00348 RegExpObjectImp* regExpObj = static_cast<RegExpObjectImp*>(exec->lexicalInterpreter()->builtinRegExp().imp());
00349 int lastIndex = 0;
00350 Object o1;
00351
00352 if ( a1.type() == ObjectType && a1.toObject(exec).implementsCall() )
00353 o1 = a1.toObject(exec);
00354 else
00355 u3 = a1.toString(exec);
00356
00357 UString out;
00358
00359
00360 reg->prepareMatch(s);
00361 do {
00362 int **ovector = regExpObj->registerRegexp( reg, s );
00363 UString mstr = reg->match(s, lastIndex, &pos, ovector);
00364 regExpObj->setSubPatterns(reg->subPatterns());
00365 if (pos == -1)
00366 break;
00367
00368 len = mstr.size();
00369
00370 UString rstr;
00371
00372 if (!o1.isValid())
00373 {
00374 rstr = u3;
00375 bool ok;
00376
00377 for (int i = 0; (i = rstr.find(UString("$"), i)) != -1; i++) {
00378 if (i+1<rstr.size() && rstr[i+1] == '$') {
00379 rstr = rstr.substr(0,i) + "$" + rstr.substr(i+2);
00380 continue;
00381 }
00382
00383 unsigned long pos = rstr.substr(i+1,1).toULong(&ok, false );
00384 if (ok && pos <= (unsigned)reg->subPatterns()) {
00385 rstr = rstr.substr(0,i)
00386 + s.substr((*ovector)[2*pos],
00387 (*ovector)[2*pos+1]-(*ovector)[2*pos])
00388 + rstr.substr(i+2);
00389 i += (*ovector)[2*pos+1]-(*ovector)[2*pos] - 1;
00390 }
00391 }
00392 } else
00393 {
00394 List l;
00395 l.append(String(mstr));
00396
00397 for ( unsigned int sub = 1; sub <= reg->subPatterns() ; ++sub )
00398 l.append( String( s.substr((*ovector)[2*sub],
00399 (*ovector)[2*sub+1]-(*ovector)[2*sub]) ) );
00400 l.append(Number(pos));
00401 l.append(String(s));
00402 Object thisObj = exec->interpreter()->globalObject();
00403 rstr = o1.call( exec, thisObj, l ).toString(exec);
00404 }
00405
00406
00407
00408 if (pos != lastIndex)
00409 out += s.substr(lastIndex, pos - lastIndex);
00410
00411
00412 out += rstr;
00413
00414 lastIndex = pos + len;
00415 } while (global);
00416
00417
00418 if (lastIndex == 0 && out.size() == 0)
00419 out = s;
00420 else
00421 out += s.substr(lastIndex, s.size() - lastIndex);
00422
00423 reg->doneMatch();
00424
00425 result = String(out);
00426 } else {
00427 u2 = a0.toString(exec);
00428 pos = s.find(u2);
00429 len = u2.size();
00430
00431 if (pos == -1)
00432 result = String(s);
00433 else {
00434 u3 = s.substr(0, pos) + a1.toString(exec) +
00435 s.substr(pos + len);
00436 result = String(u3);
00437 }
00438 }
00439 break;
00440 case Slice:
00441 {
00442
00443 int begin = args[0].toUInt32(exec);
00444 int end = len;
00445 if (args[1].type() != UndefinedType) {
00446 end = args[1].toInteger(exec);
00447 }
00448 int from = begin < 0 ? len + begin : begin;
00449 int to = end < 0 ? len + end : end;
00450 if (to > from && to > 0 && from < len) {
00451 if (from < 0) {
00452 from = 0;
00453 }
00454 if (to > len) {
00455 to = len;
00456 }
00457 result = String(s.substr(from, to - from));
00458 } else {
00459 result = String("");
00460 }
00461 break;
00462 }
00463 case Split: {
00464 Object constructor = exec->lexicalInterpreter()->builtinArray();
00465 Object res = Object::dynamicCast(constructor.construct(exec,List::empty()));
00466 result = res;
00467 i = p0 = 0;
00468 uint32_t limit = (a1.type() != UndefinedType) ? a1.toUInt32(exec) : 0xFFFFFFFFU;
00469 if (a0.type() == ObjectType && Object::dynamicCast(a0).inherits(&RegExpImp::info)) {
00470 Object obj0 = Object::dynamicCast(a0);
00471 RegExp reg(obj0.get(exec,"source").toString(exec));
00472 reg.prepareMatch(s);
00473 if (s.isEmpty() && !reg.match(s, 0).isNull()) {
00474
00475 reg.doneMatch();
00476 res.put(exec, lengthPropertyName, Number(0), DontDelete|ReadOnly|DontEnum);
00477 break;
00478 }
00479 pos = 0;
00480 while (static_cast<uint32_t>(i) != limit && pos < s.size()) {
00481
00482 int mpos;
00483 int *ovector = 0L;
00484 UString mstr = reg.match(s, pos, &mpos, &ovector);
00485 delete [] ovector; ovector = 0L;
00486 if (mpos < 0)
00487 break;
00488 pos = mpos + (mstr.isEmpty() ? 1 : mstr.size());
00489 if (mpos != p0 || !mstr.isEmpty()) {
00490 res.put(exec,i, String(s.substr(p0, mpos-p0)));
00491 p0 = mpos + mstr.size();
00492 i++;
00493 }
00494 }
00495 reg.doneMatch();
00496 } else {
00497 u2 = a0.toString(exec);
00498 if (u2.isEmpty()) {
00499 if (s.isEmpty()) {
00500
00501 put(exec,lengthPropertyName, Number(0));
00502 break;
00503 } else {
00504 while (static_cast<uint32_t>(i) != limit && i < s.size()-1)
00505 res.put(exec,i++, String(s.substr(p0++, 1)));
00506 }
00507 } else {
00508 while (static_cast<uint32_t>(i) != limit && (pos = s.find(u2, p0)) >= 0) {
00509 res.put(exec,i, String(s.substr(p0, pos-p0)));
00510 p0 = pos + u2.size();
00511 i++;
00512 }
00513 }
00514 }
00515
00516 if (static_cast<uint32_t>(i) != limit)
00517 res.put(exec,i++, String(s.substr(p0)));
00518 res.put(exec,lengthPropertyName, Number(i));
00519 }
00520 break;
00521 case Substr: {
00522 n = a0.toInteger(exec);
00523 m = a1.toInteger(exec);
00524 int d, d2;
00525 if (n >= 0)
00526 d = n;
00527 else
00528 d = maxInt(len + n, 0);
00529 if (a1.type() == UndefinedType)
00530 d2 = len - d;
00531 else
00532 d2 = minInt(maxInt(m, 0), len - d);
00533 result = String(s.substr(d, d2));
00534 break;
00535 }
00536 case Substring: {
00537 double start = a0.toNumber(exec);
00538 double end = a1.toNumber(exec);
00539 if (KJS::isNaN(start))
00540 start = 0;
00541 if (KJS::isNaN(end))
00542 end = 0;
00543 if (start < 0)
00544 start = 0;
00545 if (end < 0)
00546 end = 0;
00547 if (start > len)
00548 start = len;
00549 if (end > len)
00550 end = len;
00551 if (a1.type() == UndefinedType)
00552 end = len;
00553 if (start > end) {
00554 double temp = end;
00555 end = start;
00556 start = temp;
00557 }
00558 result = String(s.substr((int)start, (int)end-(int)start));
00559 }
00560 break;
00561 case ToLowerCase:
00562 case ToLocaleLowerCase:
00563 for (i = 0; i < len; i++)
00564 s[i] = s[i].toLower();
00565 result = String(s);
00566 break;
00567 case ToUpperCase:
00568 case ToLocaleUpperCase:
00569 for (i = 0; i < len; i++)
00570 s[i] = s[i].toUpper();
00571 result = String(s);
00572 break;
00573 case LocaleCompare:
00574 return Number(localeCompare(s, a0.toString(exec)));
00575 #ifndef KJS_PURE_ECMA
00576 case Big:
00577 result = String("<big>" + s + "</big>");
00578 break;
00579 case Small:
00580 result = String("<small>" + s + "</small>");
00581 break;
00582 case Blink:
00583 result = String("<blink>" + s + "</blink>");
00584 break;
00585 case Bold:
00586 result = String("<b>" + s + "</b>");
00587 break;
00588 case Fixed:
00589 result = String("<tt>" + s + "</tt>");
00590 break;
00591 case Italics:
00592 result = String("<i>" + s + "</i>");
00593 break;
00594 case Strike:
00595 result = String("<strike>" + s + "</strike>");
00596 break;
00597 case Sub:
00598 result = String("<sub>" + s + "</sub>");
00599 break;
00600 case Sup:
00601 result = String("<sup>" + s + "</sup>");
00602 break;
00603 case Fontcolor:
00604 result = String("<font color=\"" + a0.toString(exec) + "\">" + s + "</font>");
00605 break;
00606 case Fontsize:
00607 result = String("<font size=\"" + a0.toString(exec) + "\">" + s + "</font>");
00608 break;
00609 case Anchor:
00610 result = String("<a name=\"" + a0.toString(exec) + "\">" + s + "</a>");
00611 break;
00612 case Link:
00613 result = String("<a href=\"" + a0.toString(exec) + "\">" + s + "</a>");
00614 break;
00615 #endif
00616 }
00617
00618 return result;
00619 }
00620
00621
00622
00623 StringObjectImp::StringObjectImp(ExecState *exec,
00624 FunctionPrototypeImp *funcProto,
00625 StringPrototypeImp *stringProto)
00626 : InternalFunctionImp(funcProto)
00627 {
00628 Value protect(this);
00629
00630 putDirect(prototypePropertyName, stringProto, DontEnum|DontDelete|ReadOnly);
00631
00632 putDirect("fromCharCode", new StringObjectFuncImp(exec,funcProto), DontEnum);
00633
00634
00635 putDirect(lengthPropertyName, NumberImp::one(), ReadOnly|DontDelete|DontEnum);
00636 }
00637
00638
00639 bool StringObjectImp::implementsConstruct() const
00640 {
00641 return true;
00642 }
00643
00644
00645 Object StringObjectImp::construct(ExecState *exec, const List &args)
00646 {
00647 ObjectImp *proto = exec->lexicalInterpreter()->builtinStringPrototype().imp();
00648 if (args.size() == 0)
00649 return Object(new StringInstanceImp(proto));
00650 return Object(new StringInstanceImp(proto, args.begin()->dispatchToString(exec)));
00651 }
00652
00653 bool StringObjectImp::implementsCall() const
00654 {
00655 return true;
00656 }
00657
00658
00659 Value StringObjectImp::call(ExecState *exec, Object &, const List &args)
00660 {
00661 if (args.isEmpty())
00662 return String("");
00663 else {
00664 Value v = args[0];
00665 return String(v.toString(exec));
00666 }
00667 }
00668
00669
00670
00671
00672 StringObjectFuncImp::StringObjectFuncImp(ExecState* , FunctionPrototypeImp *funcProto)
00673 : InternalFunctionImp(funcProto)
00674 {
00675 Value protect(this);
00676 putDirect(lengthPropertyName, NumberImp::one(), DontDelete|ReadOnly|DontEnum);
00677 }
00678
00679 bool StringObjectFuncImp::implementsCall() const
00680 {
00681 return true;
00682 }
00683
00684 Value StringObjectFuncImp::call(ExecState *exec, Object &, const List &args)
00685 {
00686 UString s;
00687 if (args.size()) {
00688 UChar *buf = new UChar[args.size()];
00689 UChar *p = buf;
00690 ListIterator it = args.begin();
00691 while (it != args.end()) {
00692 unsigned short u = it->toUInt16(exec);
00693 *p++ = UChar(u);
00694 it++;
00695 }
00696 s = UString(buf, args.size(), false);
00697 } else
00698 s = "";
00699
00700 return String(s);
00701 }