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 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->lexicalInterpreter()->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->lexicalInterpreter()->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 int end = len;
00409 if (args[1].type() != UndefinedType) {
00410 end = args[1].toInteger(exec);
00411 }
00412 int from = begin < 0 ? len + begin : begin;
00413 int to = end < 0 ? len + end : end;
00414 if (to > from && to > 0 && from < len) {
00415 if (from < 0) {
00416 from = 0;
00417 }
00418 if (to > len) {
00419 to = len;
00420 }
00421 result = String(s.substr(from, to - from));
00422 } else {
00423 result = String("");
00424 }
00425 break;
00426 }
00427 case Split: {
00428 Object constructor = exec->lexicalInterpreter()->builtinArray();
00429 Object res = Object::dynamicCast(constructor.construct(exec,List::empty()));
00430 result = res;
00431 i = p0 = 0;
00432 uint32_t limit = (a1.type() != UndefinedType) ? a1.toUInt32(exec) : 0xFFFFFFFFU;
00433 if (a0.type() == ObjectType && Object::dynamicCast(a0).inherits(&RegExpImp::info)) {
00434 Object obj0 = Object::dynamicCast(a0);
00435 RegExp reg(obj0.get(exec,"source").toString(exec));
00436 if (s.isEmpty() && !reg.match(s, 0).isNull()) {
00437
00438 res.put(exec, lengthPropertyName, Number(0), DontDelete|ReadOnly|DontEnum);
00439 break;
00440 }
00441 pos = 0;
00442 while (static_cast<uint32_t>(i) != limit && pos < s.size()) {
00443
00444 int mpos;
00445 int *ovector = 0L;
00446 UString mstr = reg.match(s, pos, &mpos, &ovector);
00447 delete [] ovector; ovector = 0L;
00448 if (mpos < 0)
00449 break;
00450 pos = mpos + (mstr.isEmpty() ? 1 : mstr.size());
00451 if (mpos != p0 || !mstr.isEmpty()) {
00452 res.put(exec,i, String(s.substr(p0, mpos-p0)));
00453 p0 = mpos + mstr.size();
00454 i++;
00455 }
00456 }
00457 } else {
00458 u2 = a0.toString(exec);
00459 if (u2.isEmpty()) {
00460 if (s.isEmpty()) {
00461
00462 put(exec,lengthPropertyName, Number(0));
00463 break;
00464 } else {
00465 while (static_cast<uint32_t>(i) != limit && i < s.size()-1)
00466 res.put(exec,i++, String(s.substr(p0++, 1)));
00467 }
00468 } else {
00469 while (static_cast<uint32_t>(i) != limit && (pos = s.find(u2, p0)) >= 0) {
00470 res.put(exec,i, String(s.substr(p0, pos-p0)));
00471 p0 = pos + u2.size();
00472 i++;
00473 }
00474 }
00475 }
00476
00477 if (static_cast<uint32_t>(i) != limit)
00478 res.put(exec,i++, String(s.substr(p0)));
00479 res.put(exec,lengthPropertyName, Number(i));
00480 }
00481 break;
00482 case Substr: {
00483 n = a0.toInteger(exec);
00484 m = a1.toInteger(exec);
00485 int d, d2;
00486 if (n >= 0)
00487 d = n;
00488 else
00489 d = maxInt(len + n, 0);
00490 if (a1.type() == UndefinedType)
00491 d2 = len - d;
00492 else
00493 d2 = minInt(maxInt(m, 0), len - d);
00494 result = String(s.substr(d, d2));
00495 break;
00496 }
00497 case Substring: {
00498 double start = a0.toNumber(exec);
00499 double end = a1.toNumber(exec);
00500 if (KJS::isNaN(start))
00501 start = 0;
00502 if (KJS::isNaN(end))
00503 end = 0;
00504 if (start < 0)
00505 start = 0;
00506 if (end < 0)
00507 end = 0;
00508 if (start > len)
00509 start = len;
00510 if (end > len)
00511 end = len;
00512 if (a1.type() == UndefinedType)
00513 end = len;
00514 if (start > end) {
00515 double temp = end;
00516 end = start;
00517 start = temp;
00518 }
00519 result = String(s.substr((int)start, (int)end-(int)start));
00520 }
00521 break;
00522 case ToLowerCase:
00523 case ToLocaleLowerCase:
00524 for (i = 0; i < len; i++)
00525 s[i] = s[i].toLower();
00526 result = String(s);
00527 break;
00528 case ToUpperCase:
00529 case ToLocaleUpperCase:
00530 for (i = 0; i < len; i++)
00531 s[i] = s[i].toUpper();
00532 result = String(s);
00533 break;
00534 #ifndef KJS_PURE_ECMA
00535 case Big:
00536 result = String("<big>" + s + "</big>");
00537 break;
00538 case Small:
00539 result = String("<small>" + s + "</small>");
00540 break;
00541 case Blink:
00542 result = String("<blink>" + s + "</blink>");
00543 break;
00544 case Bold:
00545 result = String("<b>" + s + "</b>");
00546 break;
00547 case Fixed:
00548 result = String("<tt>" + s + "</tt>");
00549 break;
00550 case Italics:
00551 result = String("<i>" + s + "</i>");
00552 break;
00553 case Strike:
00554 result = String("<strike>" + s + "</strike>");
00555 break;
00556 case Sub:
00557 result = String("<sub>" + s + "</sub>");
00558 break;
00559 case Sup:
00560 result = String("<sup>" + s + "</sup>");
00561 break;
00562 case Fontcolor:
00563 result = String("<font color=\"" + a0.toString(exec) + "\">" + s + "</font>");
00564 break;
00565 case Fontsize:
00566 result = String("<font size=\"" + a0.toString(exec) + "\">" + s + "</font>");
00567 break;
00568 case Anchor:
00569 result = String("<a name=\"" + a0.toString(exec) + "\">" + s + "</a>");
00570 break;
00571 case Link:
00572 result = String("<a href=\"" + a0.toString(exec) + "\">" + s + "</a>");
00573 break;
00574 #endif
00575 }
00576
00577 return result;
00578 }
00579
00580
00581
00582 StringObjectImp::StringObjectImp(ExecState *exec,
00583 FunctionPrototypeImp *funcProto,
00584 StringPrototypeImp *stringProto)
00585 : InternalFunctionImp(funcProto)
00586 {
00587 Value protect(this);
00588
00589 putDirect(prototypePropertyName, stringProto, DontEnum|DontDelete|ReadOnly);
00590
00591 putDirect("fromCharCode", new StringObjectFuncImp(exec,funcProto), DontEnum);
00592
00593
00594 putDirect(lengthPropertyName, NumberImp::one(), ReadOnly|DontDelete|DontEnum);
00595 }
00596
00597
00598 bool StringObjectImp::implementsConstruct() const
00599 {
00600 return true;
00601 }
00602
00603
00604 Object StringObjectImp::construct(ExecState *exec, const List &args)
00605 {
00606 ObjectImp *proto = exec->lexicalInterpreter()->builtinStringPrototype().imp();
00607 if (args.size() == 0)
00608 return Object(new StringInstanceImp(proto));
00609 return Object(new StringInstanceImp(proto, args.begin()->dispatchToString(exec)));
00610 }
00611
00612 bool StringObjectImp::implementsCall() const
00613 {
00614 return true;
00615 }
00616
00617
00618 Value StringObjectImp::call(ExecState *exec, Object &, const List &args)
00619 {
00620 if (args.isEmpty())
00621 return String("");
00622 else {
00623 Value v = args[0];
00624 return String(v.toString(exec));
00625 }
00626 }
00627
00628
00629
00630
00631 StringObjectFuncImp::StringObjectFuncImp(ExecState* , FunctionPrototypeImp *funcProto)
00632 : InternalFunctionImp(funcProto)
00633 {
00634 Value protect(this);
00635 putDirect(lengthPropertyName, NumberImp::one(), DontDelete|ReadOnly|DontEnum);
00636 }
00637
00638 bool StringObjectFuncImp::implementsCall() const
00639 {
00640 return true;
00641 }
00642
00643 Value StringObjectFuncImp::call(ExecState *exec, Object &, const List &args)
00644 {
00645 UString s;
00646 if (args.size()) {
00647 UChar *buf = new UChar[args.size()];
00648 UChar *p = buf;
00649 ListIterator it = args.begin();
00650 while (it != args.end()) {
00651 unsigned short u = it->toUInt16(exec);
00652 *p++ = UChar(u);
00653 it++;
00654 }
00655 s = UString(buf, args.size(), false);
00656 } else
00657 s = "";
00658
00659 return String(s);
00660 }