00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #include "avmplus.h"
00040
00041 namespace avmplus
00042 {
00043 #undef DEBUG_EARLY_BINDING
00044
00045
00046
00047
00048 BEGIN_NATIVE_MAP(Toplevel)
00049 NATIVE_METHOD_FLAGS(escape, Toplevel::escape, 0)
00050 NATIVE_METHOD_FLAGS(unescape, Toplevel::unescape, 0)
00051 NATIVE_METHOD_FLAGS(decodeURI, Toplevel::decodeURI, 0)
00052 NATIVE_METHOD_FLAGS(decodeURIComponent, Toplevel::decodeURIComponent, 0)
00053 NATIVE_METHOD_FLAGS(encodeURI, Toplevel::encodeURI, 0)
00054 NATIVE_METHOD_FLAGS(encodeURIComponent, Toplevel::encodeURIComponent, 0)
00055 NATIVE_METHOD_FLAGS(isNaN, Toplevel::isNaN, 0)
00056 NATIVE_METHOD_FLAGS(isFinite, Toplevel::isFinite, 0)
00057 NATIVE_METHOD_FLAGS(parseInt, Toplevel::parseInt, 0)
00058 NATIVE_METHOD_FLAGS(parseFloat, Toplevel::parseFloat, 0)
00059 NATIVE_METHOD(isXMLName, Toplevel::isXMLName)
00060 END_NATIVE_MAP()
00061
00062
00063 Toplevel::Toplevel(VTable* cvtable, ScriptObject* delegate)
00064 : ScriptObject(cvtable, delegate)
00065 {
00066 builtinClasses = (ClassClosure**) core()->GetGC()->Alloc(sizeof(ClassClosure*) * core()->builtinPool->cinits.capacity(), MMgc::GC::kZero | MMgc::GC::kContainsPointers);
00067 }
00068
00069 Toplevel::~Toplevel()
00070 {
00071 }
00072
00073 ClassClosure* Toplevel::resolveBuiltinClass(int class_id)
00074 {
00075 Traits *traits = core()->builtinPool->cinits[class_id]->declaringTraits->itraits;
00076 Multiname qname(traits->ns, traits->name);
00077 ScriptObject *container = vtable->init->finddef(&qname);
00078
00079 Atom classAtom = getproperty(container->atom(), &qname, container->vtable);
00080 ClassClosure *cc = (ClassClosure*)AvmCore::atomToScriptObject(classAtom);
00081
00082 WBRC(core()->GetGC(), builtinClasses, &builtinClasses[class_id], cc);
00083 return cc;
00084 }
00085
00086 ScriptObject* Toplevel::toPrototype(Atom atom)
00087 {
00088 if (!AvmCore::isNullOrUndefined(atom))
00089 {
00090 switch (atom&7)
00091 {
00092 default:
00093
00094 case kNamespaceType:
00095 return namespaceClass->prototype;
00096
00097 case kStringType:
00098 return stringClass->prototype;
00099
00100 case kObjectType:
00101 return AvmCore::atomToScriptObject(atom)->getDelegate();
00102
00103 case kDoubleType:
00104 case kIntegerType:
00105
00106 return numberClass->prototype;
00107
00108 case kBooleanType:
00109 return booleanClass->prototype;
00110 }
00111 }
00112 else
00113 {
00114
00115 throwTypeError(
00116 (atom == undefinedAtom) ? kConvertUndefinedToObjectError :
00117 kConvertNullToObjectError);
00118 return NULL;
00119 }
00120 }
00121
00122
00123 VTable* Toplevel::toVTable(Atom atom)
00124 {
00125 if (!AvmCore::isNullOrUndefined(atom))
00126 {
00127 switch (atom&7)
00128 {
00129 case kObjectType:
00130 return AvmCore::atomToScriptObject(atom)->vtable;
00131 case kNamespaceType:
00132 return namespaceClass->ivtable();
00133 case kStringType:
00134 return stringClass->ivtable();
00135 case kBooleanType:
00136 return booleanClass->ivtable();
00137 case kIntegerType:
00138 case kDoubleType:
00139
00140 return numberClass->ivtable();
00141 }
00142 }
00143 else
00144 {
00145
00146 throwTypeError(
00147 (atom == undefinedAtom) ? kConvertUndefinedToObjectError :
00148 kConvertNullToObjectError);
00149 }
00150 return NULL;
00151 }
00152
00153
00154 Traits* Toplevel::toTraits(Atom atom)
00155 {
00156 if (!AvmCore::isNullOrUndefined(atom))
00157 {
00158 switch (atom&7)
00159 {
00160 case kObjectType:
00161 return AvmCore::atomToScriptObject(atom)->traits();
00162 case kNamespaceType:
00163 return core()->traits.namespace_itraits;
00164 case kStringType:
00165 return core()->traits.string_itraits;
00166 case kBooleanType:
00167 return core()->traits.boolean_itraits;
00168 case kIntegerType:
00169 case kDoubleType:
00170
00171 return core()->traits.number_itraits;
00172 }
00173 }
00174 else
00175 {
00176
00177 ErrorClass *error = typeErrorClass();
00178 if( error )
00179 error->throwError(
00180 (atom == undefinedAtom) ? kConvertUndefinedToObjectError :
00181 kConvertNullToObjectError);
00182 else
00183 throwVerifyError(kCorruptABCError);
00184 }
00185 return NULL;
00186 }
00187
00195 Atom Toplevel::op_call(Atom method, int argc, Atom* atomv)
00196 {
00197 if (!AvmCore::isObject(method))
00198 {
00199 Multiname name(core()->publicNamespace, core()->constantString("value"));
00200 throwTypeError(kCallOfNonFunctionError, core()->toErrorString(&name));
00201 }
00202 return AvmCore::atomToScriptObject(method)->call(argc, atomv);
00203 }
00204
00212 Atom Toplevel::op_construct(Atom ctor, int argc, Atom* atomv)
00213 {
00214 if (!AvmCore::isObject(ctor))
00215 {
00216 throwTypeError(kConstructOfNonFunctionError);
00217 }
00218
00219 ScriptObject *ct = AvmCore::atomToScriptObject(ctor);
00220 Atom val = ct->construct(argc, atomv);
00221 return val;
00222 }
00223
00230 Atom Toplevel::op_applytype(Atom factory, int argc, Atom* atomv)
00231 {
00232 if (!AvmCore::isObject(factory))
00233 {
00234 throwTypeError(kTypeAppOfNonParamType);
00235 }
00236 return AvmCore::atomToScriptObject(factory)->applyTypeArgs(argc, atomv);
00237 }
00238
00239
00240 QNameObject* Toplevel::ToAttributeName(Atom attributeName)
00241 {
00242 if (!AvmCore::isNullOrUndefined(attributeName))
00243 {
00244 AvmCore* core = this->core();
00245 switch (attributeName&7)
00246 {
00247 case kNamespaceType:
00248 attributeName = AvmCore::atomToNamespace(attributeName)->getURI()->atom();
00249 break;
00250 case kObjectType:
00251
00252
00253
00254
00255
00256
00257
00258 if (core->isQName(attributeName))
00259 {
00260 QNameObject *q = core->atomToQName (attributeName);
00261 if (q->isAttr())
00262 return q;
00263 else
00264 return new (core->GetGC(), qnameClass()->ivtable()->getExtraSize()) QNameObject(qnameClass(), attributeName, true);
00265 }
00266 else
00267 {
00268 attributeName = core->string(attributeName)->atom();
00269 break;
00270 }
00271 break;
00272 case kStringType:
00273 {
00274 break;
00275 }
00276 case kBooleanType:
00277 case kIntegerType:
00278 case kDoubleType:
00279 default:
00280 throwTypeError(kConvertUndefinedToObjectError);
00281 }
00282
00283 return new (core->GetGC(), qnameClass()->ivtable()->getExtraSize()) QNameObject(qnameClass(), attributeName, true);
00284 }
00285 else
00286 {
00287 throwTypeError(kConvertUndefinedToObjectError);
00288 return NULL;
00289 }
00290 }
00291
00292
00293
00294
00295
00296 void Toplevel::ToXMLName (const Atom p, Multiname& m)
00297 {
00298 Stringp s = 0;
00299 AvmCore* core = this->core();
00300
00301 if (!AvmCore::isNullOrUndefined(p))
00302 {
00303 switch (p & 7)
00304 {
00305 case kNamespaceType:
00306 s = AvmCore::atomToNamespace(p)->getURI();
00307 break;
00308 case kObjectType:
00309 {
00310
00311
00312
00313
00314
00315
00316 if (core->isQName(p))
00317 {
00318 QNameObject *q = core->atomToQName (p);
00319
00320 m.setAttr(q->isAttr() ? true : false);
00321 m.setNamespace(core->newNamespace (q->getURI()));
00322 Stringp name = q->getLocalName();
00323 if (name == core->kAsterisk)
00324 {
00325 m.setAnyName();
00326 }
00327 else
00328 {
00329 m.setName(name);
00330 }
00331 return;
00332 }
00333 else
00334 {
00335 s = core->string(p);
00336 break;
00337 }
00338 }
00339 case kIntegerType:
00340 case kDoubleType:
00341 case kStringType:
00342 case kBooleanType:
00343 {
00344 s = core->string(p);
00345 break;
00346 }
00347 }
00348 }
00349 else
00350 {
00351 throwTypeError(kConvertUndefinedToObjectError);
00352 return;
00353 }
00354
00355
00356 AvmAssert (s != 0);
00357
00358
00359
00360
00361 if ((*s)[0] == '@')
00362 {
00363
00364 Stringp news = new (core->GetGC()) String(s, 1, s->length() - 1);
00365 m.setName(core->internString(news));
00366 m.setAttr();
00367 }
00368 else
00369 {
00370 m.setName(core->internString(s));
00371 }
00372
00373 if (m.getName() == core->kAsterisk)
00374 {
00375 m.setAnyName();
00376 }
00377
00378 m.setNamespace(core->publicNamespace);
00379 }
00380
00381 void Toplevel::CoerceE4XMultiname (const Multiname *m, Multiname &out) const
00382 {
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394 AvmAssert(!m->isRuntime());
00395
00396 AvmCore *core = this->core();
00397
00398 if (m->isQName())
00399 {
00400 AvmAssert(m->namespaceCount() == 1);
00401 out.setNamespace(m);
00402 out.setQName();
00403 }
00404 else
00405 {
00406
00407 if (m->isAnyNamespace())
00408 {
00409 out.setAnyNamespace();
00410 }
00411 else
00412 {
00413
00414 Namespace *defaultNs = toplevel()->getDefaultNamespace();
00415 bool bMatch = false;
00416 for (int i=0, n=m->namespaceCount(); i < n; i++)
00417 {
00418 Namespace *ns = m->getNamespace(i);
00419 if (ns && ns->getPrefix() == defaultNs->getPrefix() &&
00420 ns->getURI() == defaultNs->getURI() &&
00421 ns->getType() == defaultNs->getType())
00422 {
00423 bMatch = true;
00424 break;
00425 }
00426 }
00427
00428
00429
00430 if (!bMatch)
00431 {
00432 int newNameCount = m->namespaceCount() + 1;
00433 NamespaceSet *nsset = core->newNamespaceSet(newNameCount);
00434 for (int i=0, n=m->namespaceCount(); i < n; i++)
00435 {
00436 nsset->namespaces[i] = m->getNamespace(i);
00437 }
00438
00439
00440 nsset->namespaces[newNameCount-1] = toplevel()->getDefaultNamespace();
00441 out.setNsset(nsset);
00442 }
00443 else
00444 {
00445 if (m->namespaceCount() > 1)
00446 out.setNsset(m->getNsset());
00447 else
00448 out.setNamespace (m->getNamespace());
00449 }
00450 }
00451 }
00452
00453 out.setAttr(m->isAttr() ? true : false);
00454
00455 if (m->isAnyName())
00456 {
00457 out.setAnyName();
00458 }
00459 else
00460 {
00461 Stringp s = m->getName();
00462 if ((s->length() == 1) && ((*s)[0] == '*'))
00463 {
00464
00465 out.setAnyName();
00466 }
00467 else if ((s->length() >= 1) && ((*s)[0] == '@'))
00468 {
00469
00470
00471
00472 if (!out.isAttr())
00473 {
00474
00475 if ((s->length() == 2) && ((*s)[1] == '*'))
00476 out.setAnyName();
00477 else
00478 out.setName(core->internString (new (core->GetGC()) String(s, 1, s->length()-1)));
00479 out.setAttr();
00480 }
00481 else
00482 {
00483 if (m->isAnyName())
00484 out.setAnyName();
00485 else
00486 out.setName(m->getName());
00487 }
00488 }
00489 else
00490 {
00491 if (m->isAnyName())
00492 out.setAnyName();
00493 else
00494 out.setName(m->getName());
00495 }
00496 }
00497 }
00498
00499 Atom Toplevel::callproperty(Atom base, const Multiname* multiname, int argc, Atom* atomv, VTable* vtable)
00500 {
00501 Binding b = getBinding(vtable->traits, multiname);
00502 switch (b&7)
00503 {
00504 case BIND_METHOD:
00505 {
00506 #ifdef DEBUG_EARLY_BINDING
00507 core()->console << "callproperty method " << vtable->traits << " " << multiname->getName() << "\n";
00508 #endif
00509
00510 atomv[0] = base;
00511 MethodEnv* method = vtable->methods[AvmCore::bindingToMethodId(b)];
00512 AvmAssert(method != NULL);
00513 return method->coerceEnter(argc, atomv);
00514 }
00515 case BIND_VAR:
00516 case BIND_CONST:
00517 {
00518 #ifdef DEBUG_EARLY_BINDING
00519 core()->console << "callproperty slot " << vtable->traits << " " << multiname->getName() << "\n";
00520 #endif
00521 Atom method = AvmCore::atomToScriptObject(base)->getSlotAtom(AvmCore::bindingToSlotId(b));
00522 return op_call(method, argc, atomv);
00523 }
00524 case BIND_GET:
00525 case BIND_GETSET:
00526 {
00527 #ifdef DEBUG_EARLY_BINDING
00528 core()->console << "callproperty getter " << vtable->traits << " " << multiname->getName() << "\n";
00529 #endif
00530
00531 int m = AvmCore::bindingToGetterId(b);
00532 MethodEnv *f = vtable->methods[m];
00533 Atom method = f->coerceEnter(base);
00534 return op_call(method, argc, atomv);
00535 }
00536 case BIND_SET:
00537 {
00538 #ifdef DEBUG_EARLY_BINDING
00539 core()->console << "callproperty setter " << vtable->traits << " " << multiname->getName() << "\n";
00540 #endif
00541
00542 throwReferenceError(kWriteOnlyError, multiname, vtable->traits);
00543 }
00544 default:
00545 #ifdef DEBUG_EARLY_BINDING
00546 core()->console << "callproperty dynamic " << vtable->traits << " " << multiname->getName() << "\n";
00547 #endif
00548 if (AvmCore::isObject(base))
00549 {
00550 return AvmCore::atomToScriptObject(base)->callProperty(multiname, argc, atomv);
00551 }
00552 else
00553 {
00554
00555
00556 ScriptObject* proto = toPrototype(base);
00557 Atom method = proto->getMultinameProperty(multiname);
00558 return op_call(method, argc, atomv);
00559 }
00560 }
00561 }
00562
00563 Atom Toplevel::constructprop(const Multiname* multiname, int argc, Atom* atomv, VTable* vtable)
00564 {
00565 Binding b = getBinding(vtable->traits, multiname);
00566 Atom obj = atomv[0];
00567 AvmCore* core = this->core();
00568 switch (b&7)
00569 {
00570 case BIND_METHOD:
00571 {
00572
00573 MethodEnv* env = vtable->methods[AvmCore::bindingToMethodId(b)];
00574 throwTypeError(kCannotCallMethodAsConstructor, core->toErrorString((AbstractFunction*)env->method));
00575 }
00576 case BIND_VAR:
00577 case BIND_CONST:
00578 {
00579 #ifdef DEBUG_EARLY_BINDING
00580 core->console << "constructprop slot " << vtable->traits << " " << multiname->getName() << "\n";
00581 #endif
00582 Atom ctor = AvmCore::atomToScriptObject(obj)->getSlotAtom(AvmCore::bindingToSlotId(b));
00583 if (!core->istype(ctor, CLASS_TYPE) && !core->istype(ctor, FUNCTION_TYPE))
00584 throwTypeError(kNotConstructorError, core->toErrorString(multiname));
00585 return op_construct(ctor, argc, atomv);
00586 }
00587 case BIND_GET:
00588 case BIND_GETSET:
00589 {
00590 #ifdef DEBUG_EARLY_BINDING
00591 core()->console << "constructprop getter " << vtable->traits << " " << multiname->getName() << "\n";
00592 #endif
00593
00594 int m = AvmCore::bindingToGetterId(b);
00595 MethodEnv *f = vtable->methods[m];
00596 Atom ctor = f->coerceEnter(obj);
00597 return op_construct(ctor, argc, atomv);
00598 }
00599 case BIND_SET:
00600 {
00601 #ifdef DEBUG_EARLY_BINDING
00602 core()->console << "constructprop setter " << vtable->traits << " " << multiname->getName() << "\n";
00603 #endif
00604
00605 throwReferenceError(kWriteOnlyError, multiname, vtable->traits);
00606 }
00607 default:
00608 #ifdef DEBUG_EARLY_BINDING
00609 core()->console << "constructprop dynamic " << vtable->traits << " " << multiname->getName() << "\n";
00610 #endif
00611 if ((obj&7)==kObjectType)
00612 {
00613 return AvmCore::atomToScriptObject(obj)->constructProperty(multiname, argc, atomv);
00614 }
00615 else
00616 {
00617
00618
00619 ScriptObject* proto = toPrototype(obj);
00620 Atom ctor = proto->getMultinameProperty(multiname);
00621 return op_construct(ctor, argc, atomv);
00622 }
00623 }
00624 }
00625
00626 Atom Toplevel::instanceof(Atom atom, Atom ctor)
00627 {
00628 AvmCore* core = this->core();
00629 if ((ctor&7) != kObjectType ||
00630 !core->istype(ctor, core->traits.function_itraits) &&
00631 !core->istype(ctor, core->traits.class_itraits))
00632 {
00633 throwTypeError(kCantUseInstanceofOnNonObjectError);
00634 }
00635
00636 if (AvmCore::isNull(atom))
00637 return falseAtom;
00638
00639 ClassClosure* c = (ClassClosure*)AvmCore::atomToScriptObject(ctor);
00640
00641 ScriptObject *proto = c->prototype;
00642 ScriptObject *o = toPrototype(atom);
00643
00644 for (; o != NULL; o = o->getDelegate())
00645 {
00646 if (o == proto)
00647 return trueAtom;
00648 }
00649
00650 return falseAtom;
00651 }
00652
00653
00658 Atom Toplevel::coerce(Atom atom, Traits* expected) const
00659 {
00660 Traits* actual;
00661 AvmCore* core = this->core();
00662
00663
00664 if (expected == NULL)
00665 return atom;
00666 if (expected == BOOLEAN_TYPE)
00667 return core->booleanAtom(atom);
00668 if (expected == NUMBER_TYPE)
00669 return core->numberAtom(atom);
00670 if ((expected == STRING_TYPE))
00671 return AvmCore::isNullOrUndefined(atom) ? 0|kStringType : core->string(atom)->atom();
00672 if (expected == INT_TYPE)
00673 return core->intAtom(atom);
00674 if (expected == UINT_TYPE)
00675 return core->uintAtom(atom);
00676 if (expected == OBJECT_TYPE)
00677 return atom == undefinedAtom ? nullObjectAtom : atom;
00678
00679 if (AvmCore::isNullOrUndefined(atom))
00680 return expected == VOID_TYPE ? undefinedAtom : nullObjectAtom;
00681
00682 switch (atom&7)
00683 {
00684 case kStringType:
00685 actual = STRING_TYPE;
00686 break;
00687
00688 case kBooleanType:
00689 actual = BOOLEAN_TYPE;
00690 break;
00691
00692 case kDoubleType:
00693 actual = NUMBER_TYPE;
00694 break;
00695
00696 case kIntegerType:
00697 actual = INT_TYPE;
00698 break;
00699
00700 case kNamespaceType:
00701 actual = NAMESPACE_TYPE;
00702 break;
00703
00704 case kObjectType:
00705 actual = AvmCore::atomToScriptObject(atom)->traits();
00706 break;
00707
00708 default:
00709
00710 AvmAssert(false);
00711 return false;
00712 }
00713
00714 if (actual->containsInterface(expected))
00715 {
00716 return atom;
00717 }
00718 else
00719 {
00720
00721 #ifdef AVMPLUS_VERBOSE
00722
00723 #endif
00724 throwTypeError(kCheckTypeFailedError, core->atomToErrorString(atom), core->toErrorString(expected));
00725 return atom;
00726 }
00727 }
00728
00729 void Toplevel::coerceobj(ScriptObject* obj, Traits* expected) const
00730 {
00731 if (obj && !obj->traits()->containsInterface(expected))
00732 {
00733
00734 #ifdef DEBUGGER
00735
00736 #endif
00737 throwTypeError(kCheckTypeFailedError, core()->atomToErrorString(obj->atom()), core()->toErrorString(expected));
00738 }
00739 }
00740
00741 Atom Toplevel::add2(Atom lhs, Atom rhs)
00742 {
00743 AvmCore* core = this->core();
00744
00745
00746 if (AvmCore::isNumber(lhs) && AvmCore::isNumber(rhs))
00747 {
00748
00749
00750
00751 return core->doubleToAtom(core->number(lhs) + core->number(rhs));
00752 }
00753 else if (AvmCore::isString(lhs) || AvmCore::isString(rhs) || core->isDate(lhs) || core->isDate(rhs))
00754 {
00755 return core->concatStrings(core->string(lhs), core->string(rhs))->atom();
00756 }
00757
00758
00759
00760
00761
00762
00763 if (core->isObject (lhs) && core->isObject (rhs) &&
00764 (core->isXML(lhs) || core->isXMLList(lhs))
00765 && (core->isXML(rhs) || core->isXMLList (rhs)))
00766 {
00767 XMLListObject *l = new (core->GetGC()) XMLListObject(xmlListClass());
00768 l->_append (lhs);
00769 l->_append (rhs);
00770 return l->atom();
00771 }
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791 Atom lhs_asPrimVal = core->primitive(lhs);
00792 Atom rhs_asPrimVal = core->primitive(rhs);
00793
00794 if (AvmCore::isString(lhs_asPrimVal) || AvmCore::isString(rhs_asPrimVal))
00795 {
00796 return core->concatStrings(core->string(lhs_asPrimVal), core->string(rhs_asPrimVal))->atom();
00797 }
00798 else
00799 {
00800 return core->doubleToAtom(core->number(lhs_asPrimVal) + core->number(rhs_asPrimVal));
00801 }
00802 }
00803
00804 Atom Toplevel::getproperty(Atom obj, const Multiname* multiname, VTable* vtable)
00805 {
00806 Binding b = getBinding(vtable->traits, multiname);
00807 AvmCore* core = this->core();
00808 switch (b&7)
00809 {
00810 case BIND_METHOD:
00811 {
00812 #ifdef DEBUG_EARLY_BINDING
00813 core->console << "getproperty method " << vtable->traits << " " << multiname->getName() << "\n";
00814 #endif
00815 if (multiname->contains(core->publicNamespace) && isXmlBase(obj))
00816 {
00817
00818 ScriptObject* so = AvmCore::atomToScriptObject(obj);
00819 return so->getMultinameProperty(multiname);
00820 }
00821
00822 MethodEnv *m = vtable->methods[AvmCore::bindingToMethodId(b)];
00823 return methodClosureClass->create(m, obj)->atom();
00824 }
00825
00826 case BIND_VAR:
00827 case BIND_CONST:
00828 {
00829 #ifdef DEBUG_EARLY_BINDING
00830 core->console << "getproperty slot " << vtable->traits << " " << multiname->getName() << "\n";
00831 #endif
00832 int slot = AvmCore::bindingToSlotId(b);
00833 return AvmCore::atomToScriptObject(obj)->getSlotAtom(slot);
00834 }
00835
00836 case BIND_NONE:
00837 #ifdef DEBUG_EARLY_BINDING
00838 core->console << "getproperty dynamic " << vtable->traits << " " << multiname->getName() << "\n";
00839 #endif
00840 if ((obj&7) == kObjectType)
00841 {
00842
00843
00844 return AvmCore::atomToScriptObject(obj)->getMultinameProperty(multiname);
00845 }
00846 else
00847 {
00848
00849
00850
00851
00852 ScriptObject* delegate = toPrototype(obj);
00853 if (delegate->isValidDynamicName(multiname))
00854 {
00855 return delegate->ScriptObject::getStringPropertyFromProtoChain(multiname->getName(), delegate, toTraits(obj));
00856 }
00857 else
00858 {
00859 throwReferenceError(kReadSealedError, multiname, toTraits(obj));
00860 return undefinedAtom;
00861 }
00862 }
00863
00864 case BIND_GET:
00865 case BIND_GETSET:
00866 {
00867 #ifdef DEBUG_EARLY_BINDING
00868 core->console << "getproperty getter " << vtable->traits << " " << multiname->getName() << "\n";
00869 #endif
00870
00871 int m = AvmCore::bindingToGetterId(b);
00872 MethodEnv *f = vtable->methods[m];
00873 return f->coerceEnter(obj);
00874 }
00875 case BIND_SET:
00876 {
00877 #ifdef DEBUG_EARLY_BINDING
00878 core->console << "getproperty setter " << vtable->traits << " " << multiname->getName() << "\n";
00879 #endif
00880
00881 throwReferenceError(kWriteOnlyError, multiname, vtable->traits);
00882 }
00883
00884 default:
00885
00886 AvmAssert(false);
00887 return undefinedAtom;
00888 }
00889 }
00890
00891 void Toplevel::setproperty(Atom obj, const Multiname* multiname, Atom value, VTable* vtable) const
00892 {
00893 Binding b = getBinding(vtable->traits, multiname);
00894 setproperty_b(obj,multiname,value,vtable,b);
00895 }
00896
00897 void Toplevel::setproperty_b(Atom obj, const Multiname* multiname, Atom value, VTable* vtable, Binding b) const
00898 {
00899 switch (b&7)
00900 {
00901 case BIND_METHOD:
00902 {
00903 #ifdef DEBUG_EARLY_BINDING
00904 core()->console << "setproperty method " << vtable->traits << " " << multiname->getName() << "\n";
00905 #endif
00906 if (multiname->contains(core()->publicNamespace) && isXmlBase(obj))
00907 {
00908
00909 ScriptObject* so = AvmCore::atomToScriptObject(obj);
00910 so->setMultinameProperty(multiname, value);
00911 return;
00912 }
00913
00914 throwReferenceError(kCannotAssignToMethodError, multiname, vtable->traits);
00915 }
00916
00917 case BIND_CONST:
00918 {
00919
00920 throwReferenceError(kConstWriteError, multiname, vtable->traits);
00921 return;
00922 }
00923 case BIND_VAR:
00924 {
00925 #ifdef DEBUG_EARLY_BINDING
00926 core()->console << "setproperty slot " << vtable->traits << " " << multiname->getName() << "\n";
00927 #endif
00928 int slot = AvmCore::bindingToSlotId(b);
00929 AvmCore::atomToScriptObject(obj)->setSlotAtom(slot,
00930 coerce(value, vtable->traits->getSlotTraits(slot)));
00931 return;
00932 }
00933
00934 case BIND_SET:
00935 case BIND_GETSET:
00936 {
00937 #ifdef DEBUG_EARLY_BINDING
00938 core()->console << "setproperty setter " << vtable->traits << " " << multiname->getName() << "\n";
00939 #endif
00940
00941 uint32 m = AvmCore::bindingToSetterId(b);
00942 AvmAssert(m < vtable->traits->methodCount);
00943 MethodEnv* method = vtable->methods[m];
00944 Atom atomv_out[2] = { obj, value };
00945 method->coerceEnter(1, atomv_out);
00946 return;
00947 }
00948 case BIND_GET:
00949 {
00950 #ifdef DEBUG_EARLY_BINDING
00951 core()->console << "setproperty getter " << vtable->traits << " " << multiname->getName() << "\n";
00952 #endif
00953 throwReferenceError(kConstWriteError, multiname, vtable->traits);
00954 return;
00955 }
00956
00957 case BIND_NONE:
00958 {
00959 #ifdef DEBUG_EARLY_BINDING
00960 core()->console << "setproperty dynamic " << vtable->traits << " " << multiname->getName() << "\n";
00961 #endif
00962 if (AvmCore::isObject(obj))
00963 {
00964 AvmCore::atomToScriptObject(obj)->setMultinameProperty(multiname, value);
00965 }
00966 else
00967 {
00968
00969
00970
00971
00972 throwReferenceError(kWriteSealedError, multiname, vtable->traits);
00973 }
00974 return;
00975 }
00976
00977 default:
00978
00979 AvmAssert(false);
00980 }
00981 }
00982
00983
00984 Namespace* Toplevel::getDefaultNamespace()
00985 {
00986
00987
00988
00989
00990 AvmCore* core = this->core();
00991 #ifdef _DEBUG
00992 AvmAssert(!core->dxnsAddr || (uintptr)(*core->dxnsAddr) != 0xcccccccc);
00993 #endif
00994 if (!core->dxnsAddr || !(*core->dxnsAddr))
00995 throwTypeError(kNoDefaultNamespaceError);
00996 return *core->dxnsAddr;
00997 }
00998
01004 Binding Toplevel::getBinding(Traits* traits, const Multiname* ref) const
01005 {
01006 Binding b = BIND_NONE;
01007 if (traits && ref->isBinding())
01008 {
01009 if (!ref->isNsset())
01010 {
01011 b = traits->findBinding(ref->getName(), ref->getNamespace());
01012 }
01013 else
01014 {
01015 b = traits->findBinding(ref->getName(), ref->getNsset());
01016 if (b == BIND_AMBIGUOUS)
01017 {
01018
01019 throwTypeError(
01020 kAmbiguousBindingError, core()->toErrorString(ref));
01021 }
01022 }
01023 }
01024 return b;
01025 }
01026
01027 Stringp Toplevel::decodeURI(Stringp uri)
01028 {
01029 AvmCore* core = this->core();
01030 if (!uri) uri = core->knull;
01031 Stringp out = decode(uri, false);
01032 if (!out) {
01033 toplevel()->uriErrorClass()->throwError(kInvalidURIError, core->toErrorString("decodeURI"));
01034 }
01035 return out;
01036 }
01037
01038 Stringp Toplevel::decodeURIComponent(Stringp uri)
01039 {
01040 AvmCore* core = this->core();
01041 if (!uri) uri = core->knull;
01042 Stringp out = decode(uri, true);
01043 if (!out) {
01044 toplevel()->uriErrorClass()->throwError(kInvalidURIError, core->toErrorString("decodeURIComponent"));
01045 }
01046 return out;
01047 }
01048
01049 Stringp Toplevel::encodeURI(Stringp uri)
01050 {
01051 AvmCore* core = this->core();
01052 if (!uri) uri = core->knull;
01053 Stringp out = encode(uri, false);
01054 if (!out) {
01055 toplevel()->uriErrorClass()->throwError(kInvalidURIError, core->toErrorString("encodeURI"));
01056 }
01057 return out;
01058 }
01059
01060 Stringp Toplevel::encodeURIComponent(Stringp uri)
01061 {
01062 AvmCore* core = this->core();
01063 if (!uri) uri = core->knull;
01064 Stringp out = encode(uri, true);
01065 if (!out) {
01066 toplevel()->uriErrorClass()->throwError(kInvalidURIError, core->toErrorString("encodeURIComponent"));
01067 }
01068 return out;
01069 }
01070
01071 bool Toplevel::isNaN(double n)
01072 {
01073 return MathUtils::isNaN(n);
01074 }
01075
01088 bool Toplevel::isFinite(double d)
01089 {
01090 return !(MathUtils::isInfinite(d)||MathUtils::isNaN(d));
01091 }
01092
01093 double Toplevel::parseInt(Stringp in, int radix)
01094 {
01095 AvmCore* core = this->core();
01096 if (!in) in = core->knull;
01097 const wchar *ptr = in->c_str();
01098 return MathUtils::parseInt(ptr, in->length(), radix, false);
01099 }
01100
01101 double Toplevel::parseFloat(Stringp in)
01102 {
01103 double result;
01104
01105 AvmCore* core = this->core();
01106 if (!in) in = core->knull;
01107 if (!MathUtils::convertStringToDouble(in->c_str(), in->length(), &result, false)) {
01108 result = MathUtils::nan();
01109 }
01110
01111 return result;
01112 }
01113
01114 Stringp Toplevel::escape(Stringp in)
01115 {
01116 AvmCore* core = this->core();
01117
01118 if (!in) in = core->knull;
01119
01120 const wchar *str = in->c_str();
01121 StringBuffer buffer(core);
01122
01123 for (int i=0, n=in->length(); i<n; i++) {
01124 wchar ch = str[i];
01125 if (contains(unescaped, ch)) {
01126 buffer << ch;
01127 } else if (ch & 0xff00) {
01128 buffer << "%u";
01129 buffer.writeHexWord(ch);
01130 } else {
01131 buffer << '%';
01132 buffer.writeHexByte((uint8)ch);
01133 }
01134 }
01135
01136 return core->newString(buffer.c_str());
01137 }
01138
01139 Stringp Toplevel::escapeBytes(Stringp input)
01140 {
01141 AvmCore* core = this->core();
01142
01143 UTF8String* inputUTF8 = input->toUTF8String();
01144 const uint8* src = (const uint8*) inputUTF8->c_str();
01145
01146 StringBuffer buffer(core);
01147
01148 for (int i=0, n=inputUTF8->length(); i<n; i++) {
01149 uint8 ch = src[i];
01150 if (contains(unescaped, ch)) {
01151 buffer << (wchar)ch;
01152 } else {
01153 buffer << '%';
01154 buffer.writeHexByte((uint8)ch);
01155 }
01156 }
01157
01158 return core->newString(buffer.c_str());
01159 }
01160
01161
01162 int Toplevel::parseHexChar(wchar c)
01163 {
01164 if ('0' <= c && c <= '9') {
01165 return c-'0';
01166 }
01167 if ('A' <= c && c <= 'F') {
01168 return c-'A'+10;
01169 }
01170 if ('a' <= c && c <= 'f') {
01171 return c-'a'+10;
01172 }
01173 return -1;
01174 }
01175
01176 wchar Toplevel::extractCharacter(const wchar*& src)
01177 {
01178 if (*src == '%') {
01179 const wchar *ptr = src;
01180 ptr++;
01181 if (*ptr == 0) {
01182 return *src++;
01183 }
01184 wchar value = 0;
01185 int len = 2;
01186 if (*ptr == 'u') {
01187 len = 4;
01188 ptr++;
01189 }
01190 for (int i=0; i<len; i++) {
01191 int v = parseHexChar(*ptr++);
01192 if (v < 0) {
01193 return *src++;
01194 }
01195 value = (wchar)((value<<4) | v);
01196 }
01197 src = ptr;
01198 return value;
01199 }
01200 return *src++;
01201 }
01202
01203 Stringp Toplevel::unescape(Stringp in)
01204 {
01205 AvmCore* core = this->core();
01206
01207 if (!in) in = core->knull;
01208
01209 Stringp out = new (core->GetGC()) String(in->length());
01210
01211 const wchar *src = in->c_str();
01212 wchar *outbuf = out->lockBuffer();
01213 wchar *dst = outbuf;
01214 const wchar *end = src + in->length();
01215 while (src < end) {
01216 *dst++ = extractCharacter(src);
01217 }
01218 *dst = 0;
01219 out->unlockBuffer((int)(dst-outbuf));
01220
01221 return out;
01222 }
01223
01224 Stringp Toplevel::encode(Stringp in, bool encodeURIComponentFlag)
01225 {
01226 StringBuffer out(core());
01227
01228 const wchar *src = in->c_str();
01229 int len = in->length();
01230
01231 while (len--) {
01232 wchar ch = *src;
01233
01234 if (contains(uriUnescaped, ch) ||
01235 (!encodeURIComponentFlag &&
01236 contains(uriReservedPlusPound, ch)))
01237 {
01238 out << (char)ch;
01239 src++;
01240 } else {
01241 if (ch >= 0xDC00 && ch <= 0xDFFF) {
01242 return NULL;
01243 }
01244 uint32 V;
01245 if (ch >= 0xD800 && ch < 0xDC00) {
01246 if (src[1] < 0xDC00 || src[1] > 0xDFFF) {
01247 return NULL;
01248 }
01249 V = (ch - 0xD800) * 0x400 + (src[1] - 0xDC00) * 0x10000;
01250 src += 2;
01251 } else {
01252 V = ch;
01253 src++;
01254 }
01255 uint8 Octets[6];
01256 int OctetsLen = UnicodeUtils::Ucs4ToUtf8(V, Octets);
01257 if (!OctetsLen) {
01258 return NULL;
01259 }
01260 for (int i=0; i<OctetsLen; i++) {
01261 out << '%';
01262 out.writeHexByte(Octets[i]);
01263 }
01264 }
01265 }
01266
01267 return core()->newString(out.c_str());
01268 }
01269
01270 Stringp Toplevel::decode(Stringp in, bool decodeURIComponentFlag)
01271 {
01272 const wchar *chars = in->c_str();
01273 int length = in->length();
01274 wchar *out = (wchar*) core()->GetGC()->Alloc(length*2+1);
01275 int outLen = 0;
01276
01277 for (int k = 0; k < length; k++) {
01278 wchar C = chars[k];
01279 if (C == '%') {
01280 int start = k;
01281 if ((k + 2) >= length) {
01282 return NULL;
01283 }
01284 int v1 = parseHexChar(chars[k+1]);
01285 if (v1 == -1) {
01286 return NULL;
01287 }
01288 int v2 = parseHexChar(chars[k+2]);
01289 if (v2 == -1) {
01290 return NULL;
01291 }
01292 k += 2;
01293 uint8 B = (uint8)((v1<<4) | v2);
01294 uint32 V;
01295 if (!(B & 0x80)) {
01296 V = (wchar)B;
01297 } else {
01298
01299
01300 int n = 1;
01301 while (((B<<n) & 0x80) != 0) {
01302 n++;
01303 }
01304
01305
01306
01307 if (n == 1 || n > 4) {
01308 return NULL;
01309 }
01310 uint8 Octets[4];
01311 Octets[0] = B;
01312 if (k + 3*(n-1) >= length) {
01313 return NULL;
01314 }
01315 for (int j=1; j<n; j++) {
01316 k++;
01317 if (chars[k] != '%') {
01318 return NULL;
01319 }
01320 int v1 = parseHexChar(chars[k+1]);
01321 if (v1 == -1) {
01322 return NULL;
01323 }
01324 int v2 = parseHexChar(chars[k+2]);
01325 if (v2 == -1) {
01326 return NULL;
01327 }
01328 B = (uint8)((v1<<4) | v2);
01329
01330
01331
01332 if ((B&0xC0) != 0x80) {
01333 return NULL;
01334 }
01335
01336 k += 2;
01337 Octets[j] = B;
01338 }
01339
01340
01341
01342 if (!UnicodeUtils::Utf8ToUcs4(Octets, n, &V)) {
01343 return NULL;
01344 }
01345 }
01346
01347 if (V < 0x10000) {
01348
01349 if (!decodeURIComponentFlag) {
01350 if (contains(uriReservedPlusPound, V)) {
01351 while (start <= k) {
01352 out[outLen++] = chars[start++];
01353 }
01354 } else {
01355 out[outLen++] = (wchar)V;
01356 }
01357 } else {
01358 out[outLen++] = (wchar)V;
01359 }
01360 } else {
01361
01362 if (V > 0x10FFFF) {
01363 return NULL;
01364 }
01365
01366
01367 uint32 L = (((V - 0x10000) & 0x3FF) + 0xDC00);
01368 uint32 H = ((((V - 0x10000) >> 10) & 0x3FF) + 0xD800);
01369 out[outLen++] = (wchar)H;
01370 out[outLen++] = (wchar)L;
01371 }
01372 } else {
01373 out[outLen++] = C;
01374 }
01375 }
01376
01377 out[outLen] = 0;
01378 return new (gc()) String(out,outLen);
01379 }
01380
01381
01382
01383
01384 const uint32 Toplevel::uriUnescaped[] = {
01385 0x00000000,
01386 0x03ff6782,
01387 0x87fffffe,
01388 0x47fffffe
01389 };
01390
01391
01392
01393
01394
01395
01396 const uint32 Toplevel::uriReservedPlusPound[] = {
01397 0x00000000,
01398 0xac009858,
01399 0x00000001,
01400 0x00000000
01401 };
01402
01408 const uint32 Toplevel::unescaped[] = {
01409 0x00000000,
01410 0x03ffec00,
01411 0x87ffffff,
01412 0x07fffffe
01413 };
01414
01415 bool Toplevel::isXMLName(Atom v)
01416 {
01417 return core()->isXMLName(v);
01418 }
01419
01420 unsigned int Toplevel::readU30(const byte *&p) const
01421 {
01422 unsigned int result = AvmCore::readU30(p);
01423 if (result & 0xc0000000)
01424 throwVerifyError(kCorruptABCError);
01425 return result;
01426 }
01427
01428 void Toplevel::throwVerifyError(int id) const
01429 {
01430 verifyErrorClass()->throwError(id);
01431 }
01432
01433 #ifdef DEBUGGER
01434 void Toplevel::throwVerifyError(int id, Stringp arg1) const
01435 {
01436 verifyErrorClass()->throwError(id, arg1);
01437 }
01438
01439 void Toplevel::throwVerifyError(int id, Stringp arg1, Stringp arg2) const
01440 {
01441 verifyErrorClass()->throwError(id, arg1, arg2);
01442 }
01443 #endif
01444
01445 void Toplevel::throwTypeError(int id) const
01446 {
01447 typeErrorClass()->throwError(id);
01448 }
01449
01450 void Toplevel::throwTypeError(int id, Stringp arg1) const
01451 {
01452 typeErrorClass()->throwError(id, arg1);
01453 }
01454
01455 void Toplevel::throwTypeError(int id, Stringp arg1, Stringp arg2) const
01456 {
01457 typeErrorClass()->throwError(id, arg1, arg2);
01458 }
01459
01460 void Toplevel::throwError(int id) const
01461 {
01462 errorClass()->throwError(id);
01463 }
01464
01465 void Toplevel::throwError(int id, Stringp arg1) const
01466 {
01467 errorClass()->throwError(id, arg1);
01468 }
01469
01470 void Toplevel::throwError(int id, Stringp arg1, Stringp arg2) const
01471 {
01472 errorClass()->throwError(id, arg1, arg2);
01473 }
01474
01475 void Toplevel::throwArgumentError(int id) const
01476 {
01477 argumentErrorClass()->throwError(id);
01478 }
01479
01480 void Toplevel::throwArgumentError(int id, Stringp arg1) const
01481 {
01482 argumentErrorClass()->throwError(id, arg1);
01483 }
01484
01485 void Toplevel::throwArgumentError(int id, const char *s) const
01486 {
01487 argumentErrorClass()->throwError(id, core()->toErrorString(s));
01488 }
01489
01490 void Toplevel::throwArgumentError(int id, Stringp arg1, Stringp arg2) const
01491 {
01492 argumentErrorClass()->throwError(id, arg1, arg2);
01493 }
01494
01495 void Toplevel::throwRangeError(int id) const
01496 {
01497 rangeErrorClass()->throwError(id);
01498 }
01499
01500 void Toplevel::throwRangeError(int id, Stringp arg1) const
01501 {
01502 rangeErrorClass()->throwError(id, arg1);
01503 }
01504
01505 void Toplevel::throwRangeError(int id, Stringp arg1, Stringp arg2) const
01506 {
01507 rangeErrorClass()->throwError(id, arg1, arg2);
01508 }
01509
01510 void Toplevel::throwRangeError(int id, Stringp arg1, Stringp arg2, Stringp arg3) const
01511 {
01512 rangeErrorClass()->throwError(id, arg1, arg2, arg3);
01513 }
01514
01515 void Toplevel::throwReferenceError(int id, const Multiname* multiname, const Traits* traits) const
01516 {
01517 referenceErrorClass()->throwError(id, core()->toErrorString(multiname), core()->toErrorString((Traits*)traits));
01518 }
01519
01520 void Toplevel::throwReferenceError(int id, const Multiname* multiname) const
01521 {
01522 referenceErrorClass()->throwError(id, core()->toErrorString(multiname));
01523 }
01524 }