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->interpreter()->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 UString mstr = reg->match(s, -1, &pos, ovector);
00298 if (id == Search) {
00299 result = Number(pos);
00300 } else {
00301 if (mstr.isNull()) {
00302 result = Null();
00303 } else if ((reg->flags() & RegExp::Global) == 0) {
00304
00305 regExpObj->setSubPatterns(reg->subPatterns());
00306 result = regExpObj->arrayOfMatches(exec,mstr);
00307 } else {
00308
00309 List list;
00310 while (pos >= 0) {
00311 list.append(String(mstr));
00312 pos += mstr.isEmpty() ? 1 : mstr.size();
00313 delete [] *ovector;
00314 mstr = reg->match(s, pos, &pos, ovector);
00315 }
00316 result = exec->interpreter()->builtinArray().construct(exec, list);
00317 }
00318 }
00319 delete tmpReg;
00320 break;
00321 }
00322 case Replace:
00323 if (a0.type() == ObjectType && a0.toObject(exec).inherits(&RegExpImp::info)) {
00324 RegExpImp* imp = static_cast<RegExpImp *>( a0.toObject(exec).imp() );
00325 RegExp *reg = imp->regExp();
00326 bool global = false;
00327 Value tmp = imp->get(exec,"global");
00328 if (tmp.type() != UndefinedType && tmp.toBoolean(exec) == true)
00329 global = true;
00330
00331 RegExpObjectImp* regExpObj = static_cast<RegExpObjectImp*>(exec->interpreter()->builtinRegExp().imp());
00332 int lastIndex = 0;
00333 Object o1;
00334
00335 if ( a1.type() == ObjectType && a1.toObject(exec).implementsCall() )
00336 o1 = a1.toObject(exec);
00337 else
00338 u3 = a1.toString(exec);
00339
00340
00341 do {
00342 int **ovector = regExpObj->registerRegexp( reg, s );
00343 UString mstr = reg->match(s, lastIndex, &pos, ovector);
00344 regExpObj->setSubPatterns(reg->subPatterns());
00345 if (pos == -1)
00346 break;
00347 len = mstr.size();
00348
00349 UString rstr;
00350
00351 if (!o1.isValid())
00352 {
00353 rstr = u3;
00354 bool ok;
00355
00356 for (int i = 0; (i = rstr.find(UString("$"), i)) != -1; i++) {
00357 if (i+1<rstr.size() && rstr[i+1] == '$') {
00358 rstr = rstr.substr(0,i) + "$" + rstr.substr(i+2);
00359 continue;
00360 }
00361
00362 unsigned long pos = rstr.substr(i+1,1).toULong(&ok, false );
00363 if (ok && pos <= (unsigned)reg->subPatterns()) {
00364 rstr = rstr.substr(0,i)
00365 + s.substr((*ovector)[2*pos],
00366 (*ovector)[2*pos+1]-(*ovector)[2*pos])
00367 + rstr.substr(i+2);
00368 i += (*ovector)[2*pos+1]-(*ovector)[2*pos] - 1;
00369 }
00370 }
00371 } else
00372 {
00373 List l;
00374 l.append(String(mstr));
00375
00376 for ( unsigned int sub = 1; sub <= reg->subPatterns() ; ++sub )
00377 l.append( String( s.substr((*ovector)[2*sub],
00378 (*ovector)[2*sub+1]-(*ovector)[2*sub]) ) );
00379 l.append(Number(pos));
00380 l.append(String(s));
00381 Object thisObj = exec->interpreter()->globalObject();
00382 rstr = o1.call( exec, thisObj, l ).toString(exec);
00383 }
00384 lastIndex = pos + rstr.size();
00385 s = s.substr(0, pos) + rstr + s.substr(pos + len);
00386
00387 } while (global);
00388
00389 result = String(s);
00390 } else {
00391 u2 = a0.toString(exec);
00392 pos = s.find(u2);
00393 len = u2.size();
00394
00395 if (pos == -1)
00396 result = String(s);
00397 else {
00398 u3 = s.substr(0, pos) + a1.toString(exec) +
00399 s.substr(pos + len);
00400 result = String(u3);
00401 }
00402 }
00403 break;
00404 case Slice:
00405 {
00406
00407 int begin = args[0].toUInt32(exec);
00408 if (begin < 0)
00409 begin = maxInt(begin + len, 0);
00410 else
00411 begin = minInt(begin, len);
00412 int end = len;
00413 if (args[1].type() != UndefinedType) {
00414 end = args[1].toInteger(exec);
00415 if (end < 0)
00416 end = maxInt(len + end, 0);
00417 else
00418 end = minInt(end, len);
00419 }
00420
00421 result = String(s.substr(begin, end-begin));
00422 break;
00423 }
00424 case Split: {
00425 Object constructor = exec->interpreter()->builtinArray();
00426 Object res = Object::dynamicCast(constructor.construct(exec,List::empty()));
00427 result = res;
00428 i = p0 = 0;
00429 uint32_t limit = (a1.type() != UndefinedType) ? a1.toUInt32(exec) : 0xFFFFFFFFU;
00430 if (a0.type() == ObjectType && Object::dynamicCast(a0).inherits(&RegExpImp::info)) {
00431 Object obj0 = Object::dynamicCast(a0);
00432 RegExp reg(obj0.get(exec,"source").toString(exec));
00433 if (s.isEmpty() && !reg.match(s, 0).isNull()) {
00434
00435 res.put(exec, lengthPropertyName, Number(0), DontDelete|ReadOnly|DontEnum);
00436 break;
00437 }
00438 pos = 0;
00439 while (static_cast<uint32_t>(i) != limit && pos < s.size()) {
00440
00441 int mpos;
00442 int *ovector = 0L;
00443 UString mstr = reg.match(s, pos, &mpos, &ovector);
00444 delete [] ovector; ovector = 0L;
00445 if (mpos < 0)
00446 break;
00447 pos = mpos + (mstr.isEmpty() ? 1 : mstr.size());
00448 if (mpos != p0 || !mstr.isEmpty()) {
00449 res.put(exec,i, String(s.substr(p0, mpos-p0)));
00450 p0 = mpos + mstr.size();
00451 i++;
00452 }
00453 }
00454 } else {
00455 u2 = a0.toString(exec);
00456 if (u2.isEmpty()) {
00457 if (s.isEmpty()) {
00458
00459 put(exec,lengthPropertyName, Number(0));
00460 break;
00461 } else {
00462 while (static_cast<uint32_t>(i) != limit && i < s.size()-1)
00463 res.put(exec,i++, String(s.substr(p0++, 1)));
00464 }
00465 } else {
00466 while (static_cast<uint32_t>(i) != limit && (pos = s.find(u2, p0)) >= 0) {
00467 res.put(exec,i, String(s.substr(p0, pos-p0)));
00468 p0 = pos + u2.size();
00469 i++;
00470 }
00471 }
00472 }
00473
00474 if (static_cast<uint32_t>(i) != limit)
00475 res.put(exec,i++, String(s.substr(p0)));
00476 res.put(exec,lengthPropertyName, Number(i));
00477 }
00478 break;
00479 case Substr: {
00480 n = a0.toInteger(exec);
00481 m = a1.toInteger(exec);
00482 int d, d2;
00483 if (n >= 0)
00484 d = n;
00485 else
00486 d = maxInt(len + n, 0);
00487 if (a1.type() == UndefinedType)
00488 d2 = len - d;
00489 else
00490 d2 = minInt(maxInt(m, 0), len - d);
00491 result = String(s.substr(d, d2));
00492 break;
00493 }
00494 case Substring: {
00495 double start = a0.toNumber(exec);
00496 double end = a1.toNumber(exec);
00497 if (KJS::isNaN(start))
00498 start = 0;
00499 if (KJS::isNaN(end))
00500 end = 0;
00501 if (start < 0)
00502 start = 0;
00503 if (end < 0)
00504 end = 0;
00505 if (start > len)
00506 start = len;
00507 if (end > len)
00508 end = len;
00509 if (a1.type() == UndefinedType)
00510 end = len;
00511 if (start > end) {
00512 double temp = end;
00513 end = start;
00514 start = temp;
00515 }
00516 result = String(s.substr((int)start, (int)end-(int)start));
00517 }
00518 break;
00519 case ToLowerCase:
00520 case ToLocaleLowerCase:
00521 for (i = 0; i < len; i++)
00522 s[i] = s[i].toLower();
00523 result = String(s);
00524 break;
00525 case ToUpperCase:
00526 case ToLocaleUpperCase:
00527 for (i = 0; i < len; i++)
00528 s[i] = s[i].toUpper();
00529 result = String(s);
00530 break;
00531 #ifndef KJS_PURE_ECMA
00532 case Big:
00533 result = String("<big>" + s + "</big>");
00534 break;
00535 case Small:
00536 result = String("<small>" + s + "</small>");
00537 break;
00538 case Blink:
00539 result = String("<blink>" + s + "</blink>");
00540 break;
00541 case Bold:
00542 result = String("<b>" + s + "</b>");
00543 break;
00544 case Fixed:
00545 result = String("<tt>" + s + "</tt>");
00546 break;
00547 case Italics:
00548 result = String("<i>" + s + "</i>");
00549 break;
00550 case Strike:
00551 result = String("<strike>" + s + "</strike>");
00552 break;
00553 case Sub:
00554 result = String("<sub>" + s + "</sub>");
00555 break;
00556 case Sup:
00557 result = String("<sup>" + s + "</sup>");
00558 break;
00559 case Fontcolor:
00560 result = String("<font color=\"" + a0.toString(exec) + "\">" + s + "</font>");
00561 break;
00562 case Fontsize:
00563 result = String("<font size=\"" + a0.toString(exec) + "\">" + s + "</font>");
00564 break;
00565 case Anchor:
00566 result = String("<a name=\"" + a0.toString(exec) + "\">" + s + "</a>");
00567 break;
00568 case Link:
00569 result = String("<a href=\"" + a0.toString(exec) + "\">" + s + "</a>");
00570 break;
00571 #endif
00572 }
00573
00574 return result;
00575 }
00576
00577
00578
00579 StringObjectImp::StringObjectImp(ExecState *exec,
00580 FunctionPrototypeImp *funcProto,
00581 StringPrototypeImp *stringProto)
00582 : InternalFunctionImp(funcProto)
00583 {
00584 Value protect(this);
00585
00586 putDirect(prototypePropertyName, stringProto, DontEnum|DontDelete|ReadOnly);
00587
00588 putDirect("fromCharCode", new StringObjectFuncImp(exec,funcProto), DontEnum);
00589
00590
00591 putDirect(lengthPropertyName, NumberImp::one(), ReadOnly|DontDelete|DontEnum);
00592 }
00593
00594
00595 bool StringObjectImp::implementsConstruct() const
00596 {
00597 return true;
00598 }
00599
00600
00601 Object StringObjectImp::construct(ExecState *exec, const List &args)
00602 {
00603 ObjectImp *proto = exec->interpreter()->builtinStringPrototype().imp();
00604 if (args.size() == 0)
00605 return Object(new StringInstanceImp(proto));
00606 return Object(new StringInstanceImp(proto, args.begin()->dispatchToString(exec)));
00607 }
00608
00609 bool StringObjectImp::implementsCall() const
00610 {
00611 return true;
00612 }
00613
00614
00615 Value StringObjectImp::call(ExecState *exec, Object &, const List &args)
00616 {
00617 if (args.isEmpty())
00618 return String("");
00619 else {
00620 Value v = args[0];
00621 return String(v.toString(exec));
00622 }
00623 }
00624
00625
00626
00627
00628 StringObjectFuncImp::StringObjectFuncImp(ExecState* , FunctionPrototypeImp *funcProto)
00629 : InternalFunctionImp(funcProto)
00630 {
00631 Value protect(this);
00632 putDirect(lengthPropertyName, NumberImp::one(), DontDelete|ReadOnly|DontEnum);
00633 }
00634
00635 bool StringObjectFuncImp::implementsCall() const
00636 {
00637 return true;
00638 }
00639
00640 Value StringObjectFuncImp::call(ExecState *exec, Object &, const List &args)
00641 {
00642 UString s;
00643 if (args.size()) {
00644 UChar *buf = new UChar[args.size()];
00645 UChar *p = buf;
00646 ListIterator it = args.begin();
00647 while (it != args.end()) {
00648 unsigned short u = it->toUInt16(exec);
00649 *p++ = UChar(u);
00650 it++;
00651 }
00652 s = UString(buf, args.size(), false);
00653 } else
00654 s = "";
00655
00656 return String(s);
00657 }