Example #1
0
    ArrayObject * ProgramClass::_getEnviron()
    {
        Toplevel *toplevel = this->toplevel();
        AvmCore *core = this->core();

        ArrayObject *array = toplevel->arrayClass()->newArray();

        #if AVMSYSTEM_WIN32
            wchar **cur = VMPI_GetEnviron16();
            int i = 0;
            while( cur[i] )
            {
                Stringp value = core->newStringUTF16(cur[i]);
                StUTF8String valueUTF8(value);

                array->setUintProperty( i, core->newStringUTF8( valueUTF8.c_str() )->atom() );
                i++;
            }
        #else
            char **cur = VMPI_GetEnviron();
            int i = 0;
            while( cur[i] )
            {
                array->setUintProperty( i, core->newStringUTF8( cur[i] )->atom() );
                i++;
            }
        #endif
        
        return array;
    }
	ArrayObject* HTTPFormClass::convertForm(std::vector<FormEntry>& vec)
	{
		AvmCore *core = this->core();
		ArrayObject *out = this->toplevel()->arrayClass->newArray();

		for (std::vector<FormEntry>::iterator it=vec.begin(); it!=vec.end(); it++)
		{
	    	ArrayObject* arr;
	    	Stringp key = core->internStringUTF8((*it).name.data(), (*it).name.length());
	    	Stringp value = core->internStringUTF8((*it).value.data(), (*it).value.length());
	    	//we have it, append
	    	if (out->hasStringProperty(key))
	    	{
	    		arr = (ArrayObject*) core->atomToScriptObject(out->getStringProperty(key));
		    	arr->setUintProperty(arr->get_length(), value->atom());
	    	}
	    	//create array
	    	else
	    	{
		    	arr = this->toplevel()->arrayClass->newArray();
		    	arr->setUintProperty(0, value->atom());
		    	out->setStringProperty(key, arr->atom());
	    	}
		}
		return out;
	}
Example #3
0
	static Atom twoInts(ScriptObject *obj, unsigned int high, unsigned int low) {
		Atom highatom = obj->core()->uintToAtom(high);
		Atom lowatom = obj->core()->uintToAtom(low);
		ArrayObject *ret = obj->toplevel()->arrayClass()->newArray(2);
		ret->setUintProperty(0, highatom);
		ret->setUintProperty(1, lowatom);
		return ret->atom();
	}
Example #4
0
    /*static*/ ChostentObject* CNetdbClass::gethostbyname(ScriptObject* self, Stringp name)
    {
        AvmCore *core = self->core();
        Toplevel* toplevel = self->toplevel();

        if( !name )
        {
            toplevel->throwArgumentError(kNullArgumentError, "name");
        }

        struct hostent *he;
        StUTF8String nameUTF8(name);

        he = VMPI_gethostbyname( nameUTF8.c_str() );

        if( he )
        {
            ShellToplevel* shelltop = (ShellToplevel*)self->toplevel();
            ChostentClass *hc = shelltop->getShellClasses()->get_hostentClass();
            ChostentObject *ho = hc->constructObject();

            ho->set_h_name( core->newStringUTF8( he->h_name ) );
            
            ArrayObject *aliases = toplevel->arrayClass()->newArray();
            int count = 0;
            int i;
            for( i=0; he->h_aliases[i] != NULL; ++i )
            {
                aliases->setUintProperty( count++, core->newStringUTF8( he->h_aliases[i] )->atom() );
            }
            ho->set_h_aliases( aliases );

            ho->set_h_addrtype( he->h_addrtype );
            ho->set_h_length( he->h_length );

            ArrayObject *addrlist = toplevel->arrayClass()->newArray();
            count = 0;
            for( i=0; he->h_addr_list[i] != NULL; ++i )
            {
                struct in_addr in;
                memcpy(&in.s_addr, he->h_addr_list[i], sizeof (in.s_addr));

                CIn_AddrClass *ac = shelltop->getShellClasses()->get_in_addrClass();
                CIn_AddrObject *ao = ac->constructObject();

                ao->set_s_addr( in.s_addr );
                addrlist->setUintProperty( count++, ao->toAtom() );                

                //addrlist->setUintProperty( count++, core->newStringUTF8( inet_ntoa(in) )->atom() );
            }
            ho->set_h_addr_list( addrlist );

            return ho;
        }

        return NULL;
    }
Example #5
0
    ArrayObject* StringClass::_split(Stringp in, Atom delimAtom, uint32 limit)
    {
        AvmCore* core = this->core();

        if (limit == 0)
            return toplevel()->arrayClass->newArray();

        if (in->length() == 0)
        {
            ArrayObject* out = toplevel()->arrayClass->newArray();
            out->setUintProperty(0,in->atom());
            return out;
        }

        // handle RegExp case
        if (AvmCore::istype(delimAtom, core->traits.regexp_itraits))
        {
            RegExpObject *reObj = (RegExpObject*) AvmCore::atomToScriptObject(delimAtom);
            return reObj->split(in, limit);
        }

        ArrayObject *out = toplevel()->arrayClass->newArray();
        Stringp delim = core->string(delimAtom);

        int ilen = in->length();
        int dlen = delim->length();
        int count = 0;

        if (dlen <= 0)
        {
            // delim is empty string, split on each char
            for (int i = 0; i < ilen && (unsigned)i < limit; i++)
            {
                Stringp sub = in->substr(i, 1);
                out->setUintProperty(count++, sub->atom());
            }
            return out;
        }

        int32_t start = 0;

        while (start <= in->length())
        {
            if ((limit != 0xFFFFFFFFUL) && (count >= (int) limit))
                break;
            int32_t bgn = in->indexOf(delim, start);
            if (bgn < 0)
                // not found, use the string remainder
                bgn = in->length();
            Stringp sub = in->substring(start, bgn);
            out->setUintProperty(count++, sub->atom());
            start = bgn + delim->length();
        }
        return out;
    }
Example #6
0
    /*static*/ CprotoentObject* CNetdbClass::getprotoent(ScriptObject* self)
    {
        struct protoent *pp;

        pp = VMPI_getprotoent();

        if( pp )
        {
            ShellToplevel* shelltop = (ShellToplevel*)self->toplevel();
            CprotoentClass *pc = shelltop->getShellClasses()->get_protoentClass();
            CprotoentObject *po = pc->constructObject();

            po->set_p_name( self->core()->newStringUTF8( pp->p_name ) );
            po->set_p_proto( pp->p_proto );

            Toplevel* toplevel = self->toplevel();
            ArrayObject *aliases = toplevel->arrayClass()->newArray();
            int count = 0;
            int i;
            for( i=0; pp->p_aliases[i] != NULL; ++i )
            {
                aliases->setUintProperty( count++, self->core()->newStringUTF8( pp->p_aliases[i] )->atom());
            }
            po->set_p_aliases( aliases );

            return po;
        }

        return NULL;
    }
Example #7
0
    bool SamplerScript::set_stack(ScriptObject* self, ClassFactoryClass* cf, const Sample& sample, SampleObject* sam)
    {
        if (sample.stack.depth > 0)
        {
            Toplevel* toplevel = self->toplevel();
            AvmCore* core = toplevel->core();
            Sampler* s = core->get_sampler();

            StackFrameClass* sfcc = (StackFrameClass*)cf->get_StackFrameClass();
            ArrayObject* stack = toplevel->arrayClass()->newArray(sample.stack.depth);
            StackTrace::Element* e = (StackTrace::Element*)sample.stack.trace;
            for(uint32_t i=0; i < sample.stack.depth; i++, e++)
            {
                StackFrameObject* sf = sfcc->constructObject();

                // at every allocation the sample buffer could overflow and the samples could be deleted
                // the StackTrace::Element pointer is a raw pointer into that buffer so we need to check
                // that its still around before dereferencing e
                uint32_t num;
                if (s->getSamples(num) == NULL)
                    return false;

                sf->setconst_name(e->name()); // NOT e->info()->name() because e->name() can be a fake name
                sf->setconst_file(e->filename());
                sf->setconst_line(e->linenum());
                sf->setconst_scriptID(static_cast<double>(e->functionId()));

                stack->setUintProperty(i, sf->atom());
            }
            sam->setconst_stack(stack);
        }
        return true;
    }
Example #8
0
    /*static*/ ChostentObject* CNetdbClass::gethostent(ScriptObject* self)
    {
        struct hostent *hh;

        hh = VMPI_gethostent();

        if( hh )
        {
            ShellToplevel* shelltop = (ShellToplevel*)self->toplevel();
            ChostentClass *hc = shelltop->getShellClasses()->get_hostentClass();
            ChostentObject *ho = hc->constructObject();

            ho->set_h_name( self->core()->newStringUTF8( hh->h_name ) );
            
            Toplevel* toplevel = self->toplevel();
            ArrayObject *aliases = toplevel->arrayClass()->newArray();
            int count = 0;
            int i;
            for( i=0; hh->h_aliases[i] != NULL; ++i )
            {
                aliases->setUintProperty( count++, self->core()->newStringUTF8( hh->h_aliases[i] )->atom());
            }
            ho->set_h_aliases( aliases );

            ho->set_h_addrtype( hh->h_addrtype );
            ho->set_h_length( hh->h_length );

            ArrayObject *addrlist = toplevel->arrayClass()->newArray();
            count = 0;
            for( i=0; hh->h_addr_list[i] != NULL; ++i )
            {
                struct in_addr in;
                memcpy(&in.s_addr, hh->h_addr_list[i], sizeof (in.s_addr));
                addrlist->setUintProperty( count++, self->core()->newStringUTF8( inet_ntoa(in) )->atom());
            }
            ho->set_h_addr_list( addrlist );

            return ho;
        }

        return NULL;
    }
	ArrayObject* HTTPFormClass::listFileKeys()
	{
		AvmCore *core = this->core();
		ArrayObject *out = this->toplevel()->arrayClass->newArray();

		for (std::vector<FormFile>::iterator it=sapi->files.begin(); it!=sapi->files.end(); it++)
		{
	    	out->setUintProperty(out->get_length(), core->newStringUTF8((*it).name.data(), (*it).name.length())->atom());
		}
		return out;
	}
Example #10
0
    ArrayObject * ProgramClass::_getArgv()
    {
        Toplevel *toplevel = this->toplevel();
        AvmCore *core = this->core();

        ArrayObject *array = toplevel->arrayClass()->newArray();
        for( int i=0; i<user_argc; i++ )
        {
            array->setUintProperty(i, core->newStringUTF8(user_argv[i])->atom());
        }
        
        return array;
    }
	ArrayObject* RegExpObject::match(Stringp subject)
	{
		UsesUTF8String utf8Subject(subject);
		if (!get_global())
		{
			return _exec(subject, utf8Subject);
		}
		else
		{
			ArrayObject *a = toplevel()->arrayClass->newArray();

			int oldLastIndex = m_lastIndex;
			m_lastIndex = 0;

			int n = 0;

			ArrayObject* matchArray;
			while (true)
			{
				int last = m_lastIndex;
				int matchIndex = 0, matchLen = 0;
				int startIndex = Utf16ToUtf8Index(subject, utf8Subject,	m_lastIndex);

				matchArray = _exec(subject,
								  utf8Subject,
								  startIndex,
								  matchIndex,
								  matchLen);
				m_lastIndex = Utf8ToUtf16Index(subject,
											   utf8Subject,
											   matchIndex+matchLen);
				
				if ((matchArray == NULL) || (last == m_lastIndex))
					break;
				a->setUintProperty(n++, matchArray->getUintProperty(0));
			}
			
			if (m_lastIndex == oldLastIndex)
			{
				m_lastIndex++;
			}
			
			return a;
		}
	}
    /**
     * 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;
	}
Example #13
0
    ChostentObject* CNetdbClass::gethostbyaddr4(CIn_AddrObject* addr, int type)
    {
        Toplevel* toplevel = this->toplevel();
        AvmCore* core = toplevel->core();

        if( !addr )
        {
            toplevel->throwArgumentError(kNullArgumentError, "addr");
        }

        struct hostent *he;
        struct in_addr ipv4addr;
        ipv4addr.s_addr = addr->get_s_addr(); //uint

        if( addr->call_isValid() == false )
        {
            return NULL;
        }

        he = VMPI_gethostbyaddr( (char *)&ipv4addr, sizeof ipv4addr, type );

        if( he )
        {
            ShellToplevel* shelltop = (ShellToplevel*)this->toplevel();
            ChostentClass *hc = shelltop->getShellClasses()->get_hostentClass();
            ChostentObject *ho = hc->constructObject();

            ho->set_h_name( core->newStringUTF8( he->h_name ) );
            
            ArrayObject *aliases = toplevel->arrayClass()->newArray();
            int count = 0;
            int i;
            for( i=0; he->h_aliases[i] != NULL; ++i )
            {
                aliases->setUintProperty( count++, core->newStringUTF8( he->h_aliases[i] )->atom() );
            }
            ho->set_h_aliases( aliases );

            ho->set_h_addrtype( he->h_addrtype );
            ho->set_h_length( he->h_length );

            ArrayObject *addrlist = toplevel->arrayClass()->newArray();
            count = 0;
            for( i=0; he->h_addr_list[i] != NULL; ++i )
            {
                struct in_addr in;
                memcpy(&in.s_addr, he->h_addr_list[i], sizeof (in.s_addr));

                CIn_AddrClass *ac = shelltop->getShellClasses()->get_in_addrClass();
                CIn_AddrObject *ao = ac->constructObject();

                ao->set_s_addr( in.s_addr );
                addrlist->setUintProperty( count++, ao->toAtom() );
            }
            ho->set_h_addr_list( addrlist );

            return ho;
        }

        return NULL;
    }
Example #14
0
    /*static*/ ArrayObject* CNetdbClass::getaddrinfo(ScriptObject* self, Stringp nodename, Stringp servname, CaddrinfoObject* hints, CEAIrrorObject* eaierr)
    {
        AvmCore *core = self->core();
        Toplevel* toplevel = self->toplevel();
        ShellToplevel* shelltop = (ShellToplevel*)self->toplevel();

        if( !hints )
        {
            CaddrinfoClass *ai_c = shelltop->getShellClasses()->get_addrinfoClass();
            CaddrinfoObject *hints = ai_c->constructObject();

            //default properties
            hints->set_ai_family( AF_UNSPEC );
            hints->set_ai_socktype( SOCK_STREAM );
        }

        StUTF8String nodenameUTF8(nodename);
        StUTF8String servnameUTF8(servname);

        //(void)hints;

        struct addrinfo h;
        VMPI_memset(&h, 0, sizeof h);
        
        h.ai_flags    = hints->get_ai_flags();
        h.ai_family   = hints->get_ai_family();
        h.ai_socktype = hints->get_ai_socktype();
        h.ai_protocol = hints->get_ai_protocol();
        //ignore other propertiess
        
        struct addrinfo *res, *p;

        int result = VMPI_getaddrinfo( nodenameUTF8.c_str(), servnameUTF8.c_str(), &h, &res );

        if( result != 0 )
        {
            //printf( "getaddrinfo: %s\n", gai_strerror(result));
            if( eaierr )
            {
                eaierr->call_apply( result );
            }

            return NULL;
        }

        ArrayObject *infolist = toplevel->arrayClass()->newArray();
        int count = 0;
        for( p = res; p != NULL; p = p->ai_next )
        {
            CaddrinfoClass *infoc = shelltop->getShellClasses()->get_addrinfoClass();
            CaddrinfoObject *info = infoc->constructObject();

            info->set_ai_flags( p->ai_flags );
            info->set_ai_family( p->ai_family );
            info->set_ai_socktype( p->ai_socktype );
            info->set_ai_protocol( p->ai_protocol );
            info->set_ai_addrlen( (int) p->ai_addrlen );
            info->set_ai_canonname( core->newStringUTF8( p->ai_canonname ) );

            if( p->ai_family == AF_INET )
            {
                struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
                CSockaddr_inClass *addr4c = shelltop->getShellClasses()->get_sockaddr_inClass();
                CSockaddr_inObject *addr4o = addr4c->constructObject();

                addr4o->set_sin_family( ipv4->sin_family );
                addr4o->set_sin_port( ipv4->sin_port );

                CIn_AddrClass *ac = shelltop->getShellClasses()->get_in_addrClass();
                CIn_AddrObject *ao = ac->constructObject();

                ao->set_s_addr( ipv4->sin_addr.s_addr );
                addr4o->set_sin_addr( ao );

                info->set_ai_addr( addr4o->toAtom() );
            }
            else if( p->ai_family == AF_INET6 )
            {
                struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
                CSockaddr_in6Class *addr6c = shelltop->getShellClasses()->get_sockaddr_in6Class();
                CSockaddr_in6Object *addr6o = addr6c->constructObject();

                addr6o->set_sin6_family( ipv6->sin6_family );
                addr6o->set_sin6_port( ipv6->sin6_port );
                addr6o->set_sin6_flowinfo( ipv6->sin6_flowinfo );
                addr6o->set_sin6_scope_id( ipv6->sin6_scope_id );

                CIn6_AddrClass *ac6 = shelltop->getShellClasses()->get_in6_addrClass();
                CIn6_AddrObject *ao6 = ac6->constructObject();

                ao6->fromStruct( ipv6->sin6_addr );
                addr6o->set_sin6_addr( ao6 );

                info->set_ai_addr( addr6o->toAtom() );
            }

            infolist->setUintProperty( count++, info->toAtom() );
        }

        VMPI_freeaddrinfo( res );

        return infolist;
    }
	/**
	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;
	}
    ArrayObject* RegExpObject::_exec(Stringp subject, 
									UTF8String *utf8Subject,
									int startIndex,
									int& matchIndex,
									int& matchLen)
	{
		AvmAssert(subject != NULL);
		AvmAssert(utf8Subject != NULL);
		
		int ovector[OVECTOR_SIZE];
		int results;
		int subjectLength = utf8Subject->length();

		if( startIndex < 0 ||
			startIndex > subjectLength ||
			(results = pcre_exec((pcre*)m_pcreInst,
								NULL,
								utf8Subject->c_str(),
								subjectLength,
								startIndex,
								PCRE_NO_UTF8_CHECK,
								ovector,
								OVECTOR_SIZE)) < 0)
		{
			matchIndex = 0;
			matchLen = 0;
			return NULL;
		}

		AvmCore *core = this->core();
		ArrayObject *a = toplevel()->arrayClass->newArray(results);

		a->setAtomProperty(toplevel()->regexpClass()->kindex,
			   core->intToAtom(Utf8ToUtf16Index(subject, utf8Subject, ovector[0])));
		a->setAtomProperty(toplevel()->regexpClass()->kinput,
			   subject->atom());
		a->setLength(results);

		// set array slots
		for (int i=0; i<results; i++) {
			if (ovector[i*2] > -1) {
				int length = ovector[i*2 + 1] - ovector[i*2];
				Atom match = stringFromUTF8(utf8Subject->c_str()+ovector[i*2], length);
				a->setUintProperty(i, match);
			} else {
				a->setUintProperty(i, undefinedAtom);
			}
		}

		// handle named groups
		if (m_hasNamedGroups)
		{
			int entrySize;
			pcre_fullinfo((pcre*)m_pcreInst, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrySize);
	 
			int nameCount;
			pcre_fullinfo((pcre*)m_pcreInst, NULL, PCRE_INFO_NAMECOUNT, &nameCount);
	 
			// this space is freed when (pcre*)m_pcreInst is freed 
			char *nameTable;
			pcre_fullinfo((pcre*)m_pcreInst, NULL, PCRE_INFO_NAMETABLE, &nameTable);
	 
			/* nameTable is a series of fixed length entries (entrySize) 
			   the first two bytes are the index into the ovector and the result
			   is a null terminated string (the subgroup name) */
			for (int i = 0; i < nameCount; i++)
			{
				int nameIndex, length;
				nameIndex = (nameTable[0] << 8) + nameTable[1];
				length = ovector[nameIndex * 2 + 1] - ovector[ nameIndex * 2 ];

				Atom name = stringFromUTF8((char*)(nameTable+2), (uint32)strlen(nameTable+2));
				name = core->internString(name)->atom();

				Atom value = stringFromUTF8(utf8Subject->c_str()+ovector[nameIndex*2], length);

				a->setAtomProperty(name, value);

				nameTable += entrySize;
			}
		}
		
		matchIndex = ovector[0];
		matchLen = ovector[1]-ovector[0];

		return a;
	}
	ArrayObject* RegExpObject::split(Stringp subject, uint32 limit)
	{
		AvmCore *core = this->core();
		ArrayObject *out = toplevel()->arrayClass->newArray();
		UsesUTF8String utf8Subject(subject);

		int startIndex=0;
		int matchIndex;
		int matchLen;
		ArrayObject* matchArray;
		unsigned n=0;
		bool isEmptyRE = m_source->length() == 0;
		while ((matchArray = _exec(subject,
								  utf8Subject,
								  startIndex,
								  matchIndex,
								  matchLen)) != NULL)
		{
			// [cn 11/22/04] when match is made, but is length 0 we've matched the empty
			//  position between characters.  Although we've "matched", its zero length so just break out.
			if (matchLen == 0 ) {
				matchLen = 0;
				matchIndex = startIndex+numBytesInUtf8Character((uint8*)(utf8Subject->c_str())+startIndex); // +1char  will advance startIndex, extract just one char
				if( !isEmptyRE )
				{
					// don't break if we're processing an empty regex - then we want to split the string into each character
					// so we want the loop to continue
					break;
				}
			}

			//[ed 8/10/04] don't go past end of string. not sure why pcre doesn't return null
			//for a match starting past the end.
			//[cn 12/3/04] because a regular expression which matches an empty position (space between characters)
			//  will match the empty position just past the last character.  This test is correct, though 
			//  it needs to come before we do any setProperties to avoid a bogus xtra result.
			if (matchIndex+matchLen > utf8Subject->length()) {
				startIndex = matchIndex+matchLen;
				break;
			} else {
				out->setUintProperty(n++,
									 (core->newString(utf8Subject->c_str()+startIndex,
													  matchIndex-startIndex))->atom());
				if (n >= limit)
					break;
				for (uint32 j=1; j<matchArray->getLength(); j++) {
					out->setUintProperty(n++, matchArray->getUintProperty(j));
					if (n >= limit)
						break;
				}
				// Advance past this match
				startIndex = matchIndex+matchLen;				
			}
		}

		// If we found no match, or we did find a match and are still under limit, and there is a remainder left, add it 
		if ((unsigned)n < limit && startIndex <= utf8Subject->length()) {
			out->setUintProperty(n++,
								 (core->newString(utf8Subject->c_str()+startIndex,
												  utf8Subject->length()-startIndex))->atom());
		}

		return out;
	}