mirror of https://github.com/Cisco-Talos/clamav
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
943 lines
23 KiB
943 lines
23 KiB
/*
|
|
* The builtin String object.
|
|
* Copyright (c) 1998-1999 New Generation Software (NGS) Oy
|
|
*
|
|
* Author: Markku Rossi <mtr@ngs.fi>
|
|
*/
|
|
|
|
/*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the Free
|
|
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
|
* MA 02111-1307, USA
|
|
*/
|
|
|
|
/*
|
|
* $Source: /tmp/cvsroot-15-2-2007/clamav-devel/libclamav/js/b_string.c,v $
|
|
* $Id: b_string.c,v 1.2 2006/10/28 11:27:44 njh Exp $
|
|
*/
|
|
|
|
/* TODO: global method: String (obj) => string */
|
|
#if HAVE_CONFIG_H
|
|
#include "clamav-config.h"
|
|
#endif
|
|
|
|
#ifdef CL_EXPERIMENTAL
|
|
|
|
#include "jsint.h"
|
|
|
|
/*
|
|
* Types and definitions.
|
|
*/
|
|
|
|
#define UNPACK_NEED(n) \
|
|
do { \
|
|
if (bufpos + (n) > buflen) \
|
|
{ \
|
|
sprintf (vm->error, \
|
|
"String.%s(): too short string for the format", \
|
|
js_vm_symname (vm, method)); \
|
|
js_vm_error (vm); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define UNPACK_EXPAND() \
|
|
do { \
|
|
js_vm_expand_array (vm, result_return, result_len + 1); \
|
|
rnode = &result_return->u.varray->data[result_len]; \
|
|
result_len++; \
|
|
} while (0)
|
|
|
|
/* Class context. */
|
|
struct string_ctx_st
|
|
{
|
|
JSSymbol s_length;
|
|
|
|
JSSymbol s_append;
|
|
JSSymbol s_charAt;
|
|
JSSymbol s_charCodeAt;
|
|
JSSymbol s_concat;
|
|
JSSymbol s_crc32;
|
|
JSSymbol s_fromCharCode;
|
|
JSSymbol s_indexOf;
|
|
JSSymbol s_lastIndexOf;
|
|
JSSymbol s_match;
|
|
JSSymbol s_pack;
|
|
JSSymbol s_replace;
|
|
JSSymbol s_search;
|
|
JSSymbol s_slice;
|
|
JSSymbol s_split;
|
|
JSSymbol s_substr;
|
|
JSSymbol s_substring;
|
|
JSSymbol s_toLowerCase;
|
|
JSSymbol s_toUpperCase;
|
|
JSSymbol s_unpack;
|
|
|
|
/* Data we need to implement the RegExp related stuffs. */
|
|
JSBuiltinInfo *regexp_info;
|
|
};
|
|
|
|
typedef struct string_ctx_st StringCtx;
|
|
|
|
|
|
/*
|
|
* Static functions.
|
|
*/
|
|
|
|
/* Global method proc. */
|
|
static void
|
|
global_method (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info,
|
|
void *instance_context, JSNode *result_return,
|
|
JSNode *args)
|
|
{
|
|
if (args->u.vinteger == 0)
|
|
js_vm_make_static_string (vm, result_return, "", 0);
|
|
else if (args->u.vinteger == 1)
|
|
js_vm_to_string (vm, &args[1], result_return);
|
|
else
|
|
{
|
|
sprintf (vm->error, "String(): illegal amount of arguments");
|
|
js_vm_error (vm);
|
|
}
|
|
}
|
|
|
|
/* Method proc. */
|
|
static int
|
|
method (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info,
|
|
void *instance_context, JSSymbol method, JSNode *result_return,
|
|
JSNode *args)
|
|
{
|
|
StringCtx *ctx = builtin_info->obj_context;
|
|
JSNode *n = instance_context;
|
|
unsigned int ui;
|
|
int i;
|
|
|
|
/*
|
|
* Static methods.
|
|
*/
|
|
|
|
if (method == ctx->s_fromCharCode)
|
|
{
|
|
js_vm_make_string (vm, result_return, NULL, args->u.vinteger);
|
|
|
|
for (i = 0; i < args->u.vinteger; i++)
|
|
{
|
|
if (args[1 + i].type != JS_INTEGER)
|
|
goto argument_type_error;
|
|
|
|
result_return->u.vstring->data[i]
|
|
= (unsigned char) args[1 + i].u.vinteger;
|
|
}
|
|
}
|
|
/* ********************************************************************** */
|
|
else if (method == ctx->s_pack)
|
|
{
|
|
unsigned int op;
|
|
unsigned int arg = 2;
|
|
JSUInt32 ui;
|
|
double dval;
|
|
unsigned char *buffer = NULL;
|
|
unsigned int bufpos = 0;
|
|
|
|
if (args->u.vinteger < 1)
|
|
goto argument_error;
|
|
if (args[1].type != JS_STRING)
|
|
goto argument_type_error;
|
|
|
|
for (op = 0; op < args[1].u.vstring->len; op++)
|
|
{
|
|
if (arg >= args->u.vinteger + 1)
|
|
{
|
|
sprintf (vm->error, "String.%s(): too few arguments for format",
|
|
js_vm_symname (vm, method));
|
|
js_vm_error (vm);
|
|
}
|
|
|
|
switch (args[1].u.vstring->data[op])
|
|
{
|
|
case 'C':
|
|
if (args[arg].type != JS_INTEGER)
|
|
goto argument_type_error;
|
|
|
|
buffer = js_vm_realloc (vm, buffer, bufpos + 1);
|
|
buffer[bufpos++] = (unsigned char) args[arg++].u.vinteger;
|
|
break;
|
|
|
|
case 'n':
|
|
if (args[arg].type != JS_INTEGER)
|
|
goto argument_type_error;
|
|
|
|
ui = args[arg++].u.vinteger;
|
|
|
|
buffer = js_vm_realloc (vm, buffer, bufpos + 2);
|
|
buffer[bufpos++] = (unsigned char) ((ui & 0x0000ff00) >> 8);
|
|
buffer[bufpos++] = (unsigned char) (ui & 0x000000ff);
|
|
break;
|
|
|
|
case 'N':
|
|
if (args[arg].type != JS_INTEGER)
|
|
goto argument_type_error;
|
|
|
|
ui = args[arg++].u.vinteger;
|
|
|
|
buffer = js_vm_realloc (vm, buffer, bufpos + 4);
|
|
buffer[bufpos++] = (unsigned char) ((ui & 0xff000000) >> 24);
|
|
buffer[bufpos++] = (unsigned char) ((ui & 0x00ff0000) >> 16);
|
|
buffer[bufpos++] = (unsigned char) ((ui & 0x0000ff00) >> 8);
|
|
buffer[bufpos++] = (unsigned char) ((ui & 0x000000ff));
|
|
break;
|
|
|
|
case 'd':
|
|
if (args[arg].type != JS_INTEGER && args[arg].type != JS_FLOAT)
|
|
goto argument_type_error;
|
|
|
|
if (args[arg].type == JS_INTEGER)
|
|
dval = (double) args[arg].u.vinteger;
|
|
else
|
|
dval = args[arg].u.vfloat;
|
|
arg++;
|
|
|
|
buffer = js_vm_realloc (vm, buffer, bufpos + sizeof (double));
|
|
memcpy (buffer + bufpos, &dval, sizeof (double));
|
|
bufpos += sizeof (double);
|
|
break;
|
|
|
|
default:
|
|
/* Silently ignore it. */
|
|
break;
|
|
}
|
|
}
|
|
|
|
js_vm_make_static_string (vm, result_return, buffer, bufpos);
|
|
result_return->u.vstring->staticp = 0;
|
|
}
|
|
/* ********************************************************************** */
|
|
else if (method == vm->syms.s_toString)
|
|
{
|
|
if (n)
|
|
JS_COPY (result_return, n);
|
|
else
|
|
js_vm_make_static_string (vm, result_return, "String", 6);
|
|
}
|
|
/* ********************************************************************** */
|
|
else if (method == vm->syms.s_valueOf)
|
|
{
|
|
if (n)
|
|
JS_COPY (result_return, n);
|
|
else
|
|
{
|
|
n = &vm->globals[js_vm_intern (vm, "String")];
|
|
JS_COPY (result_return, n);
|
|
}
|
|
}
|
|
/* ********************************************************************** */
|
|
else if (n)
|
|
{
|
|
/*
|
|
* Instance methods.
|
|
*/
|
|
|
|
if (method == ctx->s_append)
|
|
{
|
|
if (args->u.vinteger != 1)
|
|
goto argument_error;
|
|
|
|
if (n->u.vstring->staticp)
|
|
{
|
|
sprintf (vm->error,
|
|
"String.%s(): can't append to a static string",
|
|
js_vm_symname (vm, method));
|
|
js_vm_error (vm);
|
|
}
|
|
|
|
if (args[1].type == JS_STRING)
|
|
{
|
|
/* Append a string. */
|
|
n->u.vstring->data = js_vm_realloc (vm, n->u.vstring->data,
|
|
n->u.vstring->len
|
|
+ args[1].u.vstring->len);
|
|
memcpy (n->u.vstring->data + n->u.vstring->len,
|
|
args[1].u.vstring->data,
|
|
args[1].u.vstring->len);
|
|
n->u.vstring->len += args[1].u.vstring->len;
|
|
}
|
|
else if (args[1].type == JS_INTEGER)
|
|
{
|
|
/* Append a character. */
|
|
n->u.vstring->data = js_vm_realloc (vm, n->u.vstring->data,
|
|
n->u.vstring->len + 1);
|
|
n->u.vstring->data[n->u.vstring->len++]
|
|
= (unsigned char) args[1].u.vinteger;
|
|
}
|
|
else
|
|
goto argument_type_error;
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_charAt)
|
|
{
|
|
if (args->u.vinteger != 1)
|
|
goto argument_error;
|
|
if (args[1].type != JS_INTEGER)
|
|
goto argument_type_error;
|
|
|
|
js_vm_make_string (vm, result_return, NULL, 1);
|
|
|
|
ui = args[1].u.vinteger;
|
|
|
|
if (ui >= n->u.vstring->len)
|
|
result_return->u.vstring->len = 0;
|
|
else
|
|
result_return->u.vstring->data[0] = n->u.vstring->data[ui];
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_charCodeAt)
|
|
{
|
|
if (args->u.vinteger == 0)
|
|
ui = 0;
|
|
else if (args->u.vinteger == 1)
|
|
{
|
|
if (args[1].type != JS_INTEGER)
|
|
goto argument_type_error;
|
|
ui = args[1].u.vinteger;
|
|
}
|
|
else
|
|
goto argument_error;
|
|
|
|
if (ui >= n->u.vstring->len)
|
|
{
|
|
sprintf (vm->error, "String.%s(): index out of range",
|
|
js_vm_symname (vm, method));
|
|
js_vm_error (vm);
|
|
}
|
|
|
|
result_return->type = JS_INTEGER;
|
|
result_return->u.vinteger = n->u.vstring->data[ui];
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_concat)
|
|
{
|
|
int nlen, pos;
|
|
|
|
/* Count the new length. */
|
|
|
|
nlen = n->u.vstring->len;
|
|
|
|
for (i = 0; i < args->u.vinteger; i++)
|
|
{
|
|
if (args[i + 1].type != JS_STRING)
|
|
goto argument_type_error;
|
|
nlen += args[i + 1].u.vstring->len;
|
|
}
|
|
|
|
js_vm_make_string (vm, result_return, NULL, nlen);
|
|
|
|
memcpy (result_return->u.vstring->data, n->u.vstring->data,
|
|
n->u.vstring->len);
|
|
|
|
/* Append the argumens. */
|
|
|
|
pos = n->u.vstring->len;
|
|
|
|
for (i = 0; i < args->u.vinteger; i++)
|
|
{
|
|
memcpy (result_return->u.vstring->data + pos,
|
|
args[i + 1].u.vstring->data, args[i + 1].u.vstring->len);
|
|
pos += args[i + 1].u.vstring->len;
|
|
}
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_crc32)
|
|
{
|
|
if (args->u.vinteger != 0)
|
|
goto argument_error;
|
|
|
|
result_return->type = JS_INTEGER;
|
|
result_return->u.vinteger = js_crc32 (n->u.vstring->data,
|
|
n->u.vstring->len);
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_indexOf)
|
|
{
|
|
int start_index = 0;
|
|
|
|
if (args->u.vinteger < 1 || args->u.vinteger > 2)
|
|
goto argument_error;
|
|
if (args[1].type != JS_STRING)
|
|
goto argument_type_error;
|
|
|
|
if (args->u.vinteger == 2)
|
|
{
|
|
if (args[2].type != JS_INTEGER)
|
|
goto argument_type_error;
|
|
|
|
start_index = args[2].u.vinteger;
|
|
}
|
|
|
|
result_return->type = JS_INTEGER;
|
|
result_return->u.vinteger = -1;
|
|
|
|
if (start_index >= 0
|
|
&& start_index + args[1].u.vstring->len <= n->u.vstring->len)
|
|
{
|
|
/* Use the Brute Force Luke! */
|
|
for (; start_index + args[1].u.vstring->len <= n->u.vstring->len;
|
|
start_index++)
|
|
if (memcmp (n->u.vstring->data + start_index,
|
|
args[1].u.vstring->data,
|
|
args[1].u.vstring->len) == 0)
|
|
{
|
|
result_return->u.vinteger = start_index;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_lastIndexOf)
|
|
{
|
|
int start_index;
|
|
|
|
if (args->u.vinteger < 1 || args->u.vinteger > 2)
|
|
goto argument_error;
|
|
if (args[1].type != JS_STRING)
|
|
goto argument_type_error;
|
|
|
|
if (args->u.vinteger == 2)
|
|
{
|
|
if (args[2].type != JS_INTEGER)
|
|
goto argument_type_error;
|
|
|
|
start_index = args[2].u.vinteger;
|
|
}
|
|
else
|
|
start_index = n->u.vstring->len - args[1].u.vstring->len;
|
|
|
|
result_return->type = JS_INTEGER;
|
|
result_return->u.vinteger = -1;
|
|
|
|
if (start_index >= 0
|
|
&& start_index + args[1].u.vstring->len <= n->u.vstring->len)
|
|
{
|
|
for (; start_index >= 0; start_index--)
|
|
if (memcmp (n->u.vstring->data + start_index,
|
|
args[1].u.vstring->data,
|
|
args[1].u.vstring->len) == 0)
|
|
{
|
|
result_return->u.vinteger = start_index;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_match)
|
|
{
|
|
if (args->u.vinteger != 1)
|
|
goto argument_error;
|
|
|
|
if (args[1].type != JS_BUILTIN
|
|
|| args[1].u.vbuiltin->info != ctx->regexp_info)
|
|
goto argument_type_error;
|
|
|
|
js_builtin_RegExp_match (vm, n->u.vstring->data, n->u.vstring->len,
|
|
&args[1], result_return);
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_replace)
|
|
{
|
|
if (args->u.vinteger != 2)
|
|
goto argument_error;
|
|
|
|
if (args[1].type != JS_BUILTIN
|
|
|| args[1].u.vbuiltin->info != ctx->regexp_info
|
|
|| args[2].type != JS_STRING)
|
|
goto argument_type_error;
|
|
|
|
js_builtin_RegExp_replace (vm, n->u.vstring->data, n->u.vstring->len,
|
|
&args[1], args[2].u.vstring->data,
|
|
args[2].u.vstring->len, result_return);
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_search)
|
|
{
|
|
if (args->u.vinteger != 1)
|
|
goto argument_error;
|
|
|
|
if (args[1].type != JS_BUILTIN
|
|
|| args[1].u.vbuiltin->info != ctx->regexp_info)
|
|
goto argument_type_error;
|
|
|
|
js_builtin_RegExp_search (vm, n->u.vstring->data, n->u.vstring->len,
|
|
&args[1], result_return);
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_slice)
|
|
{
|
|
int start, end;
|
|
|
|
if (args->u.vinteger != 1 && args->u.vinteger != 2)
|
|
goto argument_error;
|
|
|
|
if (args[1].type != JS_INTEGER)
|
|
goto argument_type_error;
|
|
|
|
start = args[1].u.vinteger;
|
|
if (start < 0)
|
|
start += n->u.vstring->len;
|
|
if (start < 0)
|
|
start = 0;
|
|
if (start > n->u.vstring->len)
|
|
start = n->u.vstring->len;
|
|
|
|
if (args->u.vinteger == 2)
|
|
{
|
|
if (args[2].type != JS_INTEGER)
|
|
goto argument_type_error;
|
|
|
|
end = args[2].u.vinteger;
|
|
if (end < 0)
|
|
end += n->u.vstring->len;
|
|
if (end < 0)
|
|
end = 0;
|
|
if (end > n->u.vstring->len)
|
|
end = n->u.vstring->len;
|
|
}
|
|
else
|
|
end = n->u.vstring->len;
|
|
|
|
if (start > end)
|
|
end = start;
|
|
|
|
js_vm_make_string (vm, result_return, n->u.vstring->data + start,
|
|
end - start);
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_split)
|
|
{
|
|
if (args->u.vinteger == 0)
|
|
{
|
|
js_vm_make_array (vm, result_return, 1);
|
|
js_vm_make_string (vm, &result_return->u.varray->data[0],
|
|
n->u.vstring->data, n->u.vstring->len);
|
|
}
|
|
else
|
|
{
|
|
unsigned int limit;
|
|
|
|
if (args->u.vinteger == 1)
|
|
limit = -1;
|
|
else if (args->u.vinteger == 2)
|
|
{
|
|
if (args[2].type != JS_INTEGER)
|
|
goto argument_type_error;
|
|
|
|
limit = args[2].u.vinteger;
|
|
}
|
|
else
|
|
goto argument_error;
|
|
|
|
if (args[1].type == JS_STRING)
|
|
{
|
|
unsigned int start = 0, pos;
|
|
unsigned int alen = 0;
|
|
|
|
js_vm_make_array (vm, result_return, alen);
|
|
|
|
for (pos = 0;
|
|
(alen < limit
|
|
&& pos + args[1].u.vstring->len <= n->u.vstring->len);
|
|
)
|
|
{
|
|
if (memcmp (n->u.vstring->data + pos,
|
|
args[1].u.vstring->data,
|
|
args[1].u.vstring->len) == 0)
|
|
{
|
|
/* Found the separator. */
|
|
js_vm_expand_array (vm, result_return, alen + 1);
|
|
js_vm_make_string (vm,
|
|
&(result_return
|
|
->u.varray->data[alen]),
|
|
n->u.vstring->data + start,
|
|
pos - start);
|
|
alen++;
|
|
|
|
if (args[1].u.vstring->len == 0)
|
|
{
|
|
start = pos;
|
|
pos++;
|
|
}
|
|
else
|
|
{
|
|
pos += args[1].u.vstring->len;
|
|
start = pos;
|
|
}
|
|
}
|
|
else
|
|
pos++;
|
|
}
|
|
|
|
if (alen < limit)
|
|
{
|
|
/* And finally, insert all leftovers. */
|
|
js_vm_expand_array (vm, result_return, alen + 1);
|
|
js_vm_make_string (vm,
|
|
&result_return->u.varray->data[alen],
|
|
n->u.vstring->data + start,
|
|
n->u.vstring->len - start);
|
|
}
|
|
}
|
|
else if (args[1].type == JS_BUILTIN
|
|
&& args[1].u.vbuiltin->info == ctx->regexp_info)
|
|
{
|
|
js_builtin_RegExp_split (vm, n->u.vstring->data,
|
|
n->u.vstring->len, &args[1],
|
|
limit, result_return);
|
|
}
|
|
else
|
|
goto argument_type_error;
|
|
}
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_substr)
|
|
{
|
|
int start, length;
|
|
|
|
if (args->u.vinteger != 1 && args->u.vinteger != 2)
|
|
goto argument_error;
|
|
|
|
if (args[1].type != JS_INTEGER)
|
|
goto argument_type_error;
|
|
|
|
start = args[1].u.vinteger;
|
|
|
|
if (args->u.vinteger == 2)
|
|
{
|
|
if (args[2].type != JS_INTEGER)
|
|
goto argument_type_error;
|
|
|
|
length = args[2].u.vinteger;
|
|
if (length < 0)
|
|
length = 0;
|
|
}
|
|
else
|
|
length = n->u.vstring->len;
|
|
|
|
if (start < 0)
|
|
start += n->u.vstring->len;
|
|
if (start < 0)
|
|
start = 0;
|
|
if (start > n->u.vstring->len)
|
|
start = n->u.vstring->len;
|
|
|
|
if (start + length > n->u.vstring->len)
|
|
length = n->u.vstring->len - start;
|
|
|
|
js_vm_make_string (vm, result_return, n->u.vstring->data + start,
|
|
length);
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_substring)
|
|
{
|
|
int start, end;
|
|
|
|
if (args->u.vinteger != 1 && args->u.vinteger != 2)
|
|
goto argument_error;
|
|
|
|
if (args[1].type != JS_INTEGER)
|
|
goto argument_type_error;
|
|
|
|
start = args[1].u.vinteger;
|
|
|
|
if (args->u.vinteger == 2)
|
|
{
|
|
if (args[2].type != JS_INTEGER)
|
|
goto argument_type_error;
|
|
|
|
end = args[2].u.vinteger;
|
|
}
|
|
else
|
|
end = n->u.vstring->len;
|
|
|
|
if (start < 0)
|
|
start = 0;
|
|
|
|
if (end > n->u.vstring->len)
|
|
end = n->u.vstring->len;
|
|
|
|
if (start > end)
|
|
{
|
|
sprintf (vm->error,
|
|
"String.%s(): start index is bigger than end",
|
|
js_vm_symname (vm, method));
|
|
js_vm_error (vm);
|
|
}
|
|
|
|
js_vm_make_string (vm, result_return, n->u.vstring->data + start,
|
|
end - start);
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_toLowerCase)
|
|
{
|
|
if (args->u.vinteger != 0)
|
|
goto argument_type_error;
|
|
|
|
js_vm_make_string (vm, result_return, n->u.vstring->data,
|
|
n->u.vstring->len);
|
|
|
|
for (i = 0; i < result_return->u.vstring->len; i++)
|
|
result_return->u.vstring->data[i]
|
|
= js_latin1_tolower[result_return->u.vstring->data[i]];
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_toUpperCase)
|
|
{
|
|
if (args->u.vinteger != 0)
|
|
goto argument_type_error;
|
|
|
|
js_vm_make_string (vm, result_return, n->u.vstring->data,
|
|
n->u.vstring->len);
|
|
|
|
for (i = 0; i < result_return->u.vstring->len; i++)
|
|
result_return->u.vstring->data[i]
|
|
= js_latin1_toupper[result_return->u.vstring->data[i]];
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_unpack)
|
|
{
|
|
unsigned int op;
|
|
unsigned char *buffer;
|
|
unsigned int buflen;
|
|
unsigned int bufpos = 0;
|
|
JSUInt32 ui;
|
|
unsigned int result_len = 0;
|
|
JSNode *rnode;
|
|
|
|
if (args->u.vinteger != 1)
|
|
goto argument_error;
|
|
if (args[1].type != JS_STRING)
|
|
goto argument_type_error;
|
|
|
|
buffer = n->u.vstring->data;
|
|
buflen = n->u.vstring->len;
|
|
|
|
js_vm_make_array (vm, result_return, 0);
|
|
|
|
for (op = 0; op < args[1].u.vstring->len; op++)
|
|
{
|
|
switch (args[1].u.vstring->data[op])
|
|
{
|
|
case 'C':
|
|
UNPACK_NEED (1);
|
|
UNPACK_EXPAND ();
|
|
rnode->type = JS_INTEGER;
|
|
rnode->u.vinteger = buffer[bufpos++];
|
|
break;
|
|
|
|
case 'n':
|
|
UNPACK_NEED (2);
|
|
UNPACK_EXPAND ();
|
|
|
|
ui = buffer[bufpos++];
|
|
ui <<= 8;
|
|
ui |= buffer[bufpos++];
|
|
|
|
rnode->type = JS_INTEGER;
|
|
rnode->u.vinteger = ui;
|
|
break;
|
|
|
|
case 'N':
|
|
UNPACK_NEED (4);
|
|
UNPACK_EXPAND ();
|
|
|
|
ui = buffer[bufpos++];
|
|
ui <<= 8;
|
|
ui |= buffer[bufpos++];
|
|
ui <<= 8;
|
|
ui |= buffer[bufpos++];
|
|
ui <<= 8;
|
|
ui |= buffer[bufpos++];
|
|
|
|
rnode->type = JS_INTEGER;
|
|
rnode->u.vinteger = ui;
|
|
break;
|
|
|
|
case 'd':
|
|
UNPACK_NEED (8);
|
|
UNPACK_EXPAND ();
|
|
|
|
rnode->type = JS_FLOAT;
|
|
memcpy (&rnode->u.vfloat, buffer + bufpos, 8);
|
|
bufpos += 8;
|
|
break;
|
|
|
|
default:
|
|
/* Silently ignore it. */
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/* ***************************************************************** */
|
|
else
|
|
return JS_PROPERTY_UNKNOWN;
|
|
}
|
|
else
|
|
return JS_PROPERTY_UNKNOWN;
|
|
|
|
return JS_PROPERTY_FOUND;
|
|
|
|
|
|
/*
|
|
* Error handling.
|
|
*/
|
|
|
|
argument_error:
|
|
sprintf (vm->error, "String.%s(): illegal amount of arguments",
|
|
js_vm_symname (vm, method));
|
|
js_vm_error (vm);
|
|
|
|
argument_type_error:
|
|
sprintf (vm->error, "String %s(): illegal argument",
|
|
js_vm_symname (vm, method));
|
|
js_vm_error (vm);
|
|
|
|
/* NOTREACHED */
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* Property proc. */
|
|
static int
|
|
property (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info,
|
|
void *instance_context, JSSymbol property, int set, JSNode *node)
|
|
{
|
|
StringCtx *ctx = builtin_info->obj_context;
|
|
JSNode *n = instance_context;
|
|
|
|
if (n && property == ctx->s_length)
|
|
{
|
|
if (set)
|
|
goto immutable;
|
|
|
|
node->type = JS_INTEGER;
|
|
node->u.vinteger = n->u.vstring->len;
|
|
}
|
|
else
|
|
{
|
|
if (!set)
|
|
node->type = JS_UNDEFINED;
|
|
|
|
return JS_PROPERTY_UNKNOWN;
|
|
}
|
|
|
|
return JS_PROPERTY_FOUND;
|
|
|
|
|
|
/*
|
|
* Error handling.
|
|
*/
|
|
|
|
immutable:
|
|
sprintf (vm->error, "String.%s: immutable property",
|
|
js_vm_symname (vm, property));
|
|
js_vm_error (vm);
|
|
|
|
/* NOTREACHED. */
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* New proc. */
|
|
static void
|
|
new_proc (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info, JSNode *args,
|
|
JSNode *result_return)
|
|
{
|
|
JSNode source_n;
|
|
JSNode *source;
|
|
|
|
if (args->u.vinteger == 0)
|
|
js_vm_make_string (vm, result_return, NULL, 0);
|
|
else if (args->u.vinteger == 1)
|
|
{
|
|
if (args[1].type == JS_STRING)
|
|
source = &args[1];
|
|
else
|
|
{
|
|
js_vm_to_string (vm, &args[1], &source_n);
|
|
source = &source_n;
|
|
}
|
|
|
|
js_vm_make_string (vm, result_return, source->u.vstring->data,
|
|
source->u.vstring->len);
|
|
}
|
|
else
|
|
{
|
|
sprintf (vm->error, "new String(): illegal amount of arguments");
|
|
js_vm_error (vm);
|
|
}
|
|
|
|
/* Set the [[Prototype]] and [[Class]] properties. */
|
|
/* XXX 15.8.2 */
|
|
}
|
|
|
|
/*
|
|
* Global functions.
|
|
*/
|
|
|
|
void
|
|
js_builtin_String (JSVirtualMachine *vm)
|
|
{
|
|
StringCtx *ctx;
|
|
JSNode *n;
|
|
JSBuiltinInfo *info;
|
|
|
|
ctx = js_calloc (vm, 1, sizeof (*ctx));
|
|
|
|
ctx->s_length = js_vm_intern (vm, "length");
|
|
|
|
ctx->s_append = js_vm_intern (vm, "append");
|
|
ctx->s_charAt = js_vm_intern (vm, "charAt");
|
|
ctx->s_charCodeAt = js_vm_intern (vm, "charCodeAt");
|
|
ctx->s_concat = js_vm_intern (vm, "concat");
|
|
ctx->s_crc32 = js_vm_intern (vm, "crc32");
|
|
ctx->s_fromCharCode = js_vm_intern (vm, "fromCharCode");
|
|
ctx->s_indexOf = js_vm_intern (vm, "indexOf");
|
|
ctx->s_lastIndexOf = js_vm_intern (vm, "lastIndexOf");
|
|
ctx->s_match = js_vm_intern (vm, "match");
|
|
ctx->s_pack = js_vm_intern (vm, "pack");
|
|
ctx->s_replace = js_vm_intern (vm, "replace");
|
|
ctx->s_search = js_vm_intern (vm, "search");
|
|
ctx->s_slice = js_vm_intern (vm, "slice");
|
|
ctx->s_split = js_vm_intern (vm, "split");
|
|
ctx->s_substr = js_vm_intern (vm, "substr");
|
|
ctx->s_substring = js_vm_intern (vm, "substring");
|
|
ctx->s_toLowerCase = js_vm_intern (vm, "toLowerCase");
|
|
ctx->s_toUpperCase = js_vm_intern (vm, "toUpperCase");
|
|
ctx->s_unpack = js_vm_intern (vm, "unpack");
|
|
|
|
info = js_vm_builtin_info_create (vm);
|
|
vm->prim[JS_STRING] = info;
|
|
|
|
info->global_method_proc = global_method;
|
|
info->method_proc = method;
|
|
info->property_proc = property;
|
|
info->new_proc = new_proc;
|
|
info->obj_context = ctx;
|
|
info->obj_context_delete = js_free;
|
|
|
|
/* Define it. */
|
|
n = &vm->globals[js_vm_intern (vm, "String")];
|
|
js_vm_builtin_create (vm, n, info, NULL);
|
|
|
|
/* Fetch the JSBuiltinInfo of the RegExp object. */
|
|
n = &vm->globals[js_vm_intern (vm, "RegExp")];
|
|
ctx->regexp_info = n->u.vbuiltin->info;
|
|
}
|
|
#endif /*CL_EXPERIMENTAL*/
|
|
|