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