Atom VectorBaseObject::filter(ScriptObject *callback, Atom thisObject) { AvmCore* core = this->core(); VectorBaseObject *r = newVector(); if (!callback) return r->atom(); ScriptObject *d = this; uint32 len = m_length; for (uint32 i = 0, k = 0; i < len; i++) { // If thisObject is null, the call function will substitute the global object // args are modified in place by callee Atom element = d->getUintProperty(i); Atom args[4] = { thisObject, element, core->uintToAtom(i), // index this->atom() }; Atom result = callback->call(3, args); if (result == trueAtom) r->setUintProperty(k++, element); } return r->atom(); }
Atom VectorBaseObject::filter(ScriptObject *callback, Atom thisObject) { AvmCore* core = this->core(); VectorBaseObject *r = newVector(); if (!callback) return r->atom(); ScriptObject *d = this; uint32 len = m_length; // If thisObject is null, the call function will substitute the global object Atom args[4] = { thisObject, nullObjectAtom, nullObjectAtom, this->atom() }; for (uint32 i = 0, k = 0; i < len; i++) { args[1] = d->getUintProperty (i); // element args[2] = core->uintToAtom (i); // index Atom result = callback->call(3, args); if (result == trueAtom) { r->setUintProperty (k++, args[1]); } } return r->atom(); }
/** * Array.prototype.reverse() * TRANSFERABLE: Needs to support generic objects as well as Array objects */ /*static*/ Atom ArrayClass::generic_reverse(Toplevel* toplevel, Atom thisAtom) { ArrayObject *a = isArray(toplevel, thisAtom); if (a && (a->isSimpleDense())) { a->m_denseArr.reverse(); return thisAtom; } // generic object version if (!AvmCore::isObject(thisAtom)) return thisAtom; ScriptObject *d = AvmCore::atomToScriptObject(thisAtom); uint32 j = getLengthHelper(toplevel, d); uint32 i = 0; if (j) j--; while (i < j) { Atom frontAtom = d->getUintProperty(i); Atom backAtom = d->getUintProperty(j); d->setUintProperty(i++, backAtom); d->setUintProperty(j--, frontAtom); } return thisAtom; }
/** * Array.prototype.pop() * TRANSFERABLE: Needs to support generic objects as well as Array objects */ /*static*/ Atom ArrayClass::generic_pop(Toplevel* toplevel, Atom thisAtom) { ArrayObject *a = isArray(toplevel, thisAtom); if (a) return a->pop(); if (!AvmCore::isObject(thisAtom)) return undefinedAtom; // Different than Rhino (because of delete) but matches 262.pdf ScriptObject *d = AvmCore::atomToScriptObject(thisAtom); uint32 len = getLengthHelper(toplevel, d); if (!len) { setLengthHelper(toplevel, d, 0); return undefinedAtom; } else { Atom outAtom = d->getUintProperty (len-1); d->delUintProperty (len - 1); setLengthHelper(toplevel, d, len - 1); return outAtom; } }
/** * Array.prototype.shift() * TRANSFERABLE: Needs to support generic objects as well as Array objects */ /*static*/ Atom ArrayClass::generic_shift(Toplevel* toplevel, Atom thisAtom) { ArrayObject *a = isArray(toplevel, thisAtom); if (a && a->isSimpleDense()) { if (!a->m_length) return undefinedAtom; a->m_length--; return (a->m_denseArr.shift()); } if (!AvmCore::isObject(thisAtom)) return undefinedAtom; Atom outAtom; ScriptObject *d = AvmCore::atomToScriptObject(thisAtom); uint32 len = getLengthHelper(toplevel, d); if (len == 0) { // set len to 0 (ecmascript spec) setLengthHelper(toplevel, d, 0); outAtom = undefinedAtom; } else { // Get the 0th element to return outAtom = d->getUintProperty(0); // Move all of the elements down for (uint32 i=0; i<len-1; i++) { d->setUintProperty(i, d->getUintProperty(i+1)); } d->delUintProperty (len - 1); setLengthHelper(toplevel, d, len - 1); } return outAtom; }
/** * Array.prototype.slice() * TRANSFERABLE: Needs to support generic objects as well as Array objects */ /*static*/ ArrayObject* ArrayClass::generic_slice(Toplevel* toplevel, Atom thisAtom, double A, double B) { if (!AvmCore::isObject(thisAtom)) return 0; ScriptObject *d = AvmCore::atomToScriptObject(thisAtom); uint32 len = getLengthHelper(toplevel, d); // if a param is passed then the first one is A // if no params are passed then A = 0 uint32 a = NativeObjectHelpers::ClampIndex(A, len); uint32 b = NativeObjectHelpers::ClampIndex(B, len); if (b < a) b = a; ArrayObject *out = toplevel->arrayClass->newArray(b-a); uint32 outIndex=0; for (uint32 i=a; i<b; i++) { out->setUintProperty (outIndex++, d->getUintProperty (i)); } return out; }
/** 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ] ] ] ) When the concat method is called with zero or more arguments item1, item2, etc., it returns an array containing the array elements of the object followed by the array elements of each argument in order. The following steps are taken: 1. Let A be a new array created as if by the expression new Array(). 2. Let n be 0. 3. Let E be this object. 4. If E is not an Array object, go to step 16. 5. Let k be 0. 6. Call the [[Get]] method of E with argument "length". 7. If k equals Result(6) go to step 19. 8. Call ToString(k). 9. If E has a property named by Result(8), go to step 10, but if E has no property named by Result(8), go to step 13. 10. Call ToString(n). 11. Call the [[Get]] method of E with argument Result(8). 12. Call the [[Put]] method of A with arguments Result(10) and Result(11). 13. Increase n by 1. 14. Increase k by 1. 15. Go to step 7. 16. Call ToString(n). 17. Call the [[Put]] method of A with arguments Result(16) and E. 18. Increase n by 1. 19. Get the next argument in the argument list; if there are no more arguments, go to step 22. 20. Let E be Result(19). 21. Go to step 4. 22. Call the [[Put]] method of A with arguments "length" and n. 23. Return A. The length property of the concat method is 1. NOTE The concat function is intentionally generic; it does not require that its this value be an Array object. Therefore it can be transferred to other kinds of objects for use as a method. Whether the concat function can be applied successfully to a host object is implementation-dependent. */ /*static*/ ArrayObject* ArrayClass::generic_concat(Toplevel* toplevel, Atom thisAtom, ArrayObject* args) { AvmCore* core = toplevel->core(); ScriptObject *d = AvmCore::isObject(thisAtom) ? AvmCore::atomToScriptObject(thisAtom) : 0; uint32 len = 0; if (d) { len = getLengthHelper(toplevel, d); } ArrayObject *a = isArray(toplevel, thisAtom); uint32 i; uint32 argc = args->getLength(); int newLength = len; for (i = 0; i< argc; i++) { Atom atom = args->getUintProperty(i); if (AvmCore::istype(atom, ARRAY_TYPE)) { ArrayObject *b = (ArrayObject*) AvmCore::atomToScriptObject(atom); newLength += b->getLength(); } else { newLength++; } } ArrayObject *out = toplevel->arrayClass->newArray(newLength); int denseLength = 0; // Only copy over elements for Arrays, not objects according to spec // 4. If E is not an Array object, go to step 16. if (a && newLength) { denseLength = a->getDenseLength(); // copy over our dense part out->m_denseArr.push (&a->m_denseArr); out->m_length += denseLength; // copy over any non-dense values (or all values if this isn't an array object) for (i = denseLength; i < len; i++) { out->setUintProperty(i, d->getUintProperty(i)); } } for (i = 0; i< (uint32)argc; i++) { Atom atom = args->getUintProperty(i); if (AvmCore::istype(atom, ARRAY_TYPE)) { ArrayObject *b = (ArrayObject*) AvmCore::atomToScriptObject(atom); // copy over dense parts out->m_denseArr.push (&b->m_denseArr); out->m_length += b->getDenseLength(); // copy over any non-dense values uint32 len = b->getLength(); for (uint32 j=b->getDenseLength(); j<len; j++) { out->m_denseArr.push (b->getUintProperty(j)); out->m_length++; } } else { out->m_denseArr.push (atom); out->m_length++; } } return out; }