Mozilla/mozilla/js/tamarin/core/StringClass.cpp
gerv%gerv.net 0a3a70857a Bug 236613: fix formatting of MPL/LGPL/GPL tri-license.
git-svn-id: svn://10.0.0.236/trunk@220064 18797224-902f-48f8-a5cc-f745e15eee43
2007-02-13 18:05:02 +00:00

392 lines
11 KiB
C++

/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is [Open Source Virtual Machine.].
*
* The Initial Developer of the Original Code is
* Adobe System Incorporated.
* Portions created by the Initial Developer are Copyright (C) 2004-2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Adobe AS3 Team
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "avmplus.h"
namespace avmplus
{
#ifdef __MWERKS__
typedef void (String::*StringHandler)();
NativeTableEntry::Handler stringMethod(StringHandler stringHandler)
{
union
{
StringHandler foo;
NativeTableEntry::Handler bar;
};
foo = stringHandler;
return bar;
}
#define STRING_METHOD(handler) stringMethod((StringHandler)handler)
#else
#define STRING_METHOD(x) x
#endif
BEGIN_NATIVE_MAP(StringClass)
// instance methods
NATIVE_METHOD2_FLAGS(String_length_get, STRING_METHOD(&String::length), 0)
NATIVE_METHOD2_FLAGS(String_AS3_localeCompare, STRING_METHOD(&String::localeCompare), AbstractFunction::NEED_REST)
NATIVE_METHOD2_FLAGS(String_private__indexOf, STRING_METHOD(&String::indexOf), 0)
NATIVE_METHOD2_FLAGS(String_AS3_indexOf, STRING_METHOD(&String::indexOfDouble), 0)
NATIVE_METHOD2_FLAGS(String_private__lastIndexOf, STRING_METHOD(&String::lastIndexOf), 0)
NATIVE_METHOD2_FLAGS(String_AS3_lastIndexOf, STRING_METHOD(&String::lastIndexOfDouble), 0)
NATIVE_METHOD2_FLAGS(String_private__charAt, STRING_METHOD(&String::charAt), 0)
NATIVE_METHOD2_FLAGS(String_AS3_charAt, STRING_METHOD(&String::charAtDouble), 0)
NATIVE_METHOD2_FLAGS(String_private__charCodeAt, STRING_METHOD(&String::charCodeAt), 0)
NATIVE_METHOD2_FLAGS(String_AS3_charCodeAt, STRING_METHOD(&String::charCodeAtDouble), 0)
NATIVE_METHOD2_FLAGS(String_private__substring, STRING_METHOD(&String::substring), 0)
NATIVE_METHOD2_FLAGS(String_AS3_substring, STRING_METHOD(&String::substringDouble), 0)
NATIVE_METHOD2_FLAGS(String_private__slice, STRING_METHOD(&String::slice), 0)
NATIVE_METHOD2_FLAGS(String_AS3_slice, STRING_METHOD(&String::sliceDouble), 0)
NATIVE_METHOD2_FLAGS(String_private__substr, STRING_METHOD(&String::substr), 0)
NATIVE_METHOD2_FLAGS(String_AS3_substr, STRING_METHOD(&String::substrDouble), 0)
NATIVE_METHOD2_FLAGS(String_AS3_toLowerCase, STRING_METHOD(&String::toLowerCase), 0)
NATIVE_METHOD2_FLAGS(String_AS3_toUpperCase, STRING_METHOD(&String::toUpperCase), 0)
// static method (language feature - by design)
NATIVE_METHODV(String_AS3_fromCharCode, StringClass::fromCharCode)
// static methods (require AvmCore *)
NATIVE_METHOD2(String_private__match, &StringClass::match)
NATIVE_METHOD2(String_private__replace, &StringClass::replace)
NATIVE_METHOD2(String_private__search, &StringClass::search)
NATIVE_METHOD2(String_private__split, &StringClass::split)
END_NATIVE_MAP()
StringClass::StringClass(VTable* cvtable)
: ClassClosure(cvtable)
{
toplevel()->stringClass = this;
createVanillaPrototype();
// Some sanity tests for string/wchar* comparison routines
#if 0 && defined(_DEBUG)
Stringp a = core()->newString ("a", 1);
Stringp b = core()->newString ("b", 1);
Stringp c = core()->newString ("c", 1);
AvmAssert( (*a == *a));
AvmAssert(!(*a != *a));
AvmAssert( (*a >= *a));
AvmAssert( (*a <= *a));
AvmAssert(!(*a > *a));
AvmAssert(!(*a < *a));
AvmAssert(!(*a == *b));
AvmAssert( (*a != *b));
AvmAssert(!(*a >= *b));
AvmAssert( (*a <= *b));
AvmAssert(!(*a > *b));
AvmAssert( (*a < *b));
AvmAssert(!(*c == *b));
AvmAssert( (*c != *b));
AvmAssert( (*c >= *b));
AvmAssert(!(*c <= *b));
AvmAssert( (*c > *b));
AvmAssert(!(*c < *b));
wchar d[2];
d[0] = 'a';
d[1] = 0;
AvmAssert( (d == *a));
AvmAssert(!(d != *a));
AvmAssert( (d >= *a));
AvmAssert( (d <= *a));
AvmAssert(!(d > *a));
AvmAssert(!(d < *a));
AvmAssert( (*a == d));
AvmAssert(!(*a != d));
AvmAssert( (*a >= d));
AvmAssert( (*a <= d));
AvmAssert(!(*a > d));
AvmAssert(!(*a < d));
AvmAssert(!(d == *b));
AvmAssert( (d != *b));
AvmAssert(!(d >= *b));
AvmAssert( (d <= *b));
AvmAssert(!(d > *b));
AvmAssert( (d < *b));
wchar e[2];
e[0] = 'b';
e[1] = 0;
AvmAssert(!(*c == e));
AvmAssert( (*c != e));
AvmAssert( (*c >= e));
AvmAssert(!(*c <= e));
AvmAssert( (*c > e));
AvmAssert(!(*c < e));
#endif
}
// this = argv[0] (ignored)
// arg1 = argv[1]
// argN = argv[argc]
Atom StringClass::construct(int argc, Atom* argv)
{
if (argc == 0) {
return core()->kEmptyString->atom();
} else {
return core()->string(argv[1])->atom();
}
// TODO ArgumentError if argc > 1
}
// this = argv[0] (ignored)
// arg1 = argv[1]
// argN = argv[argc]
Atom StringClass::call(int argc, Atom* argv)
{
return construct(argc, argv);
}
Stringp StringClass::fromCharCode(Atom *argv, int argc)
{
AvmCore* core = this->core();
Stringp out = new (core->GetGC()) String(argc);
wchar *ptr = out->lockBuffer();
for (int i=0; i<argc; i++) {
*ptr++ = wchar(core->integer(argv[i]));
}
*ptr = 0;
out->unlockBuffer();
return out;
}
ArrayObject *StringClass::match(Stringp in, Atom regexpAtom)
{
AvmCore* core = this->core();
if (!core->istype(regexpAtom, core->traits.regexp_itraits))
{
// ECMA-262 15.5.4.10
// If the argument is not a RegExp, invoke RegExp(exp)
regexpAtom = core->newRegExp(toplevel()->regexpClass(),
core->string(regexpAtom),
core->kEmptyString)->atom();
}
RegExpObject *reObj = (RegExpObject*) AvmCore::atomToScriptObject(regexpAtom);
return reObj->match(in);
}
Stringp StringClass::replace(Stringp subject, Atom pattern, Atom replacementAtom)
{
AvmCore* core = this->core();
ScriptObject *replaceFunction = NULL;
Stringp replacement = NULL;
if (core->istype(replacementAtom, core->traits.function_itraits)) {
replaceFunction = AvmCore::atomToScriptObject(replacementAtom);
} else {
replacement = core->string(replacementAtom);
}
if (core->istype(pattern, core->traits.regexp_itraits)) {
// RegExp mode
RegExpObject *reObj = (RegExpObject*) core->atomToScriptObject(pattern);
if (replaceFunction) {
return core->string(reObj->replace(subject, replaceFunction));
} else {
return core->string(reObj->replace(subject, replacement));
}
} else {
// String replace mode
Stringp searchString = core->string(pattern);
int index = subject->indexOf(searchString);
if (index == -1) {
// Search string not found; return input unchanged.
return subject;
}
if (replaceFunction) {
// Invoke the replacement function to figure out the
// replacement string
Atom argv[4] = { undefinedAtom,
searchString->atom(),
core->uintToAtom(index),
subject->atom() };
replacement = core->string(toplevel()->op_call(replaceFunction->atom(),
3, argv));
}
int newlen = subject->length() - searchString->length() + replacement->length();
Stringp out = new (core->GetGC()) String(newlen);
wchar *buffer = out->lockBuffer();
memcpy(buffer, subject->c_str(), index*sizeof(wchar));
memcpy(buffer+index, replacement->c_str(), replacement->length()*sizeof(wchar));
memcpy(buffer+index+replacement->length(),
subject->c_str()+index+searchString->length(),
(subject->length()-searchString->length()-index+1)*sizeof(wchar));
buffer[newlen] = 0;
out->unlockBuffer();
return out;
}
}
int StringClass::search(Stringp in, Atom regexpAtom)
{
AvmCore* core = this->core();
if (!core->istype(regexpAtom, core->traits.regexp_itraits)) {
// ECMA-262 15.5.4.10
// If the argument is not a RegExp, invoke RegExp(exp)
regexpAtom = core->newRegExp(toplevel()->regexpClass(),
core->string(regexpAtom),
core->kEmptyString)->atom();
}
RegExpObject *reObj = (RegExpObject*) AvmCore::atomToScriptObject(regexpAtom);
return reObj->search(in);
}
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 (core->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;
int start = 0;
int w = 0;
if (dlen <= 0)
{
// delim is empty string, split on each char
for (int i = 0; i < ilen && (unsigned)i < limit; i++)
{
Stringp sub = new (core->GetGC()) String(in, i, 1);
out->setUintProperty(count++, sub->atom());
}
return out;
}
const wchar *delimch = delim->c_str();
wchar dlast = delimch[dlen-1];
while (delimch[w] != dlast)
w++;
//loop1:
unsigned numSeg = 0;
const wchar *inchar = in->c_str();
for (int i = w; i < ilen; i++)
{
bool continue_loop1 = false;
wchar c = inchar[i];
if (c == dlast)
{
int k = i-1, j;
for (j=dlen-2; j >= 0; j--, k--) {
if (inchar[k] != delimch[j]) {
continue_loop1 = true;
break;
}
}
if (!continue_loop1) {
numSeg++;
// if we have found more segments than
// the limit we can stop looking
if( numSeg > limit )
break;
int sublen=k+1-start;
Stringp sub = new (core->GetGC()) String(in, start, sublen);
out->setUintProperty(count++, sub->atom());
start = i+1;
i += w;
}
}
}
// if numSeg is less than limit when we're done, add the rest of
// the string to the last element of the array
if( numSeg < limit )
{
Stringp sub = new (core->GetGC()) String(in, start, ilen);
out->setUintProperty(count, sub->atom());
}
return out;
}
}