📄 scripter.cpp
字号:
/****************License************************************************
*
* Copyright 2000-2003. ScanSoft, Inc.
*
* Use of this software is subject to notices and obligations set forth
* in the SpeechWorks Public License - Software Version 1.2 which is
* included with this software.
*
* ScanSoft is a registered trademark of ScanSoft, Inc., and OpenSpeech,
* SpeechWorks and the SpeechWorks logo are registered trademarks or
* trademarks of SpeechWorks International, Inc. in the United States
* and other countries.
*
***********************************************************************/
/***********************************************************************
*
* This is largely a wrapper around the VXIjsi interface. The limited
* responsibilities of this layer include:
*
* (1) storing the VXIjsiContext and current scope name;
* (2) generating error.semantic exceptions for ECMAScript failures;
* (3) converting vxistring's to const wchar_t *;
* (4) converting VXIValue types.
*
***********************************************************************/
#include <vxibuildopts.h>
#if P_VXI
#include "Scripter.hpp"
#include "CommonExceptions.hpp"
#include "VXML.h"
#include "vxi/VXIjsi.h"
#include <sstream>
#ifdef _MSC_VER
#pragma warning(disable:4061)
#pragma warning(disable:4505)
#endif
// This is a simple conversion tool from VXIString -> vxistring.
static vxistring toString(const VXIString * s)
{
if (s == NULL) return L"";
const VXIchar * temp = VXIStringCStr(s);
if (temp == NULL) return L"";
return temp;
}
/*****************************************************************************
* Constructor/Destructor - here is where the VXIjsiContext is managed.
*****************************************************************************/
Scripter::Scripter(VXIjsiInterface *jsiapi) : jsi_api(jsiapi)
{
if (jsi_api == NULL)
maybe_throw_js_error(VXIjsi_RESULT_INVALID_ARGUMENT);
maybe_throw_js_error(jsi_api->CreateContext(jsi_api, &jsi_context));
}
Scripter::~Scripter()
{
jsi_api->DestroyContext(jsi_api, &jsi_context);
}
/*****************************************************************************
* Raise javascript exeception on error
****************************************************************************/
void Scripter::maybe_throw_js_error(int err) const
{
switch (err) {
case VXIjsi_RESULT_SUCCESS:
return;
case VXIjsi_RESULT_FAILURE: // Normal failure
case VXIjsi_RESULT_NON_FATAL_ERROR: // Non-fatal non-specific error
case VXIjsi_RESULT_SYNTAX_ERROR: // JavaScript syntax error
case VXIjsi_RESULT_SCRIPT_EXCEPTION: // JavaScript exception thrown
case VXIjsi_RESULT_SECURITY_VIOLATION:// JavaScript security violation
throw VXIException::InterpreterEvent(EV_ERROR_ECMASCRIPT);
default:
throw VXIException::JavaScriptError();
}
}
/*****************************************************************************
* Wrappers around basic JSI interface. VXI only call JavaScript through here.
*****************************************************************************/
void Scripter::MakeVar(const vxistring & name, const vxistring & expr)
{
if (expr.empty()) {
EvalScript(L"var " + name);
return;
}
VXIjsiResult err = jsi_api->CreateVarExpr(jsi_api, jsi_context,
name.c_str(), expr.c_str());
// This handles variables such as x.y which are invalid arguments.
if (err == VXIjsi_RESULT_INVALID_ARGUMENT && !name.empty())
err = VXIjsi_RESULT_FAILURE;
maybe_throw_js_error(err);
}
void Scripter::MakeVar(const vxistring & name, const VXIValue * value)
{
VXIjsiResult err = jsi_api->CreateVarValue(jsi_api, jsi_context,
name.c_str(), value);
// This handles variables such as x.y which are invalid arguments.
if (err == VXIjsi_RESULT_INVALID_ARGUMENT && !name.empty())
err = VXIjsi_RESULT_FAILURE;
maybe_throw_js_error(err);
}
void Scripter::SetVar(const vxistring & name, const vxistring & expr)
{
VXIjsiResult err = jsi_api->SetVarExpr(jsi_api, jsi_context,
name.c_str(), expr.c_str());
maybe_throw_js_error(err);
}
void Scripter::SetVarReadOnly(const vxistring & name)
{
VXIjsiResult err = jsi_api->SetReadOnly(jsi_api, jsi_context,
name.c_str());
maybe_throw_js_error(err);
}
void Scripter::ClearVar(const vxistring & name)
{
VXIjsiResult err = jsi_api->SetVarExpr(jsi_api, jsi_context,
name.c_str(), L"undefined");
maybe_throw_js_error(err);
}
void Scripter::SetValue(const vxistring & var, const VXIValue * value)
{
VXIjsiResult err = jsi_api->SetVarValue(jsi_api, jsi_context,
var.c_str(), value);
maybe_throw_js_error(err);
}
VXIValue * Scripter::GetValue(const vxistring & name) const
{
VXIValue* val = NULL;
VXIjsiResult err = jsi_api->GetVar(jsi_api, jsi_context, name.c_str(), &val);
switch (err) {
case VXIjsi_RESULT_FAILURE: // ECMAScript type Null
case VXIjsi_RESULT_NON_FATAL_ERROR: // ECMAScript type Undefined
case VXIjsi_RESULT_SUCCESS:
break;
default:
maybe_throw_js_error(err);
}
return val;
}
void Scripter::SetString(const vxistring & name, const vxistring & val)
{
vxistring line = val;
// Normalize whitespace to ' '
for (unsigned int i = 0; i < line.length(); ++i) {
VXIchar c = line[i];
if (c == '\n' || c == '\r' || c == '\t') line[i] = ' ';
}
// Escape the ' characters.
const VXIchar APOSTROPHE = '\'';
const VXIchar * const SLASH = L"\\";
vxistring::size_type pos = line.find(APOSTROPHE);
if (pos != vxistring::npos) {
unsigned int size = line.length();
do {
line.insert(pos, SLASH); // Convert ' -> \'
if (++pos == size) break; // Stop if last character was replaced.
++size; // Update the size.
pos = line.find(APOSTROPHE, pos + 1);
} while (pos != vxistring::npos);
}
// Pass the expression to ECMAScript.
line = name + L" = '" + line + L"';";
VXIjsiResult err = jsi_api->Eval(jsi_api, jsi_context, line.c_str(), NULL);
maybe_throw_js_error(err);
}
void Scripter::PushScope(const vxistring & name, bool alias)
{
VXIjsiScopeAttr scopeAttr
= alias ? VXIjsi_ALIAS_SCOPE : VXIjsi_NATIVE_SCOPE;
VXIjsiResult err = jsi_api->PushScope(jsi_api, jsi_context, name.c_str(),
scopeAttr);
if (err == VXIjsi_RESULT_SUCCESS)
scopeStack.push_back(name);
maybe_throw_js_error(err);
}
void Scripter::PopScope()
{
VXIjsiResult err = jsi_api->PopScope(jsi_api, jsi_context);
if (err == VXIjsi_RESULT_SUCCESS)
scopeStack.pop_back();
maybe_throw_js_error(err);
}
bool Scripter::CurrentScope(const vxistring & name) const
{
return name == scopeStack.back();
}
#ifdef _MSC_VER
#pragma warning(disable:4702)
#endif
bool Scripter::IsVarDefined(const vxistring & name)
{
switch (jsi_api->CheckVar(jsi_api, jsi_context, name.c_str())) {
case VXIjsi_RESULT_SUCCESS:
return true;
case VXIjsi_RESULT_NON_FATAL_ERROR:
case VXIjsi_RESULT_FAILURE:
return false;
default:
throw VXIException::JavaScriptError();
}
// We should never get here.
return false;
}
bool Scripter::IsVarDeclared(const vxistring & name)
{
switch (jsi_api->CheckVar(jsi_api, jsi_context, name.c_str())) {
case VXIjsi_RESULT_FAILURE:
case VXIjsi_RESULT_SUCCESS:
return true;
case VXIjsi_RESULT_NON_FATAL_ERROR:
return false;
default:
throw VXIException::JavaScriptError();
}
// We should never get here.
return false;
}
bool Scripter::TestCondition(const vxistring & script)
{
return (EvalScriptToInt(script) != 0);
}
VXIint Scripter::EvalScriptToInt(const vxistring & expr)
{
VXIValue* val = NULL;
VXIjsiResult err = jsi_api->Eval(jsi_api, jsi_context, expr.c_str(), &val);
VXIint result;
if (err == VXIjsi_RESULT_SUCCESS) {
switch (VXIValueGetType(val)) {
case VALUE_STRING: {
const VXIchar* s =
VXIStringCStr(reinterpret_cast<const VXIString*>(val));
result = ((s != NULL && *s != L'\0') ? 1 : 0);
} break;
case VALUE_BOOLEAN:
result = VXIint(VXIBooleanValue(reinterpret_cast<const VXIBoolean*>(val)));
break;
case VALUE_INTEGER:
result = VXIIntegerValue(reinterpret_cast<const VXIInteger*>(val));
break;
case VALUE_FLOAT: {
// Convert float down to VXIint.
// For GCC 3.2.2, convert float to int not correctly produce result
// therefore we must cast to unsigned long first
#if defined(__GNUC__) && ((__GNUC__ >= 3) && (__GLIBCPP__ >= 20030205))
result = VXIint(VXIulong(VXIFloatValue(reinterpret_cast<const VXIFloat*>(val))));
#else
result = VXIint(VXIFloatValue(reinterpret_cast<const VXIFloat*>(val)));
#endif
} break;
case VALUE_MAP: {
// if the map is not empty, return 1
result = 0;
const VXIMap* temp = reinterpret_cast<const VXIMap*>(val);
if( temp && (VXIMapNumProperties(temp) > 0) ) result = 1;
} break;
default:
err = VXIjsi_RESULT_FAILURE;
break;
}
}
VXIValueDestroy(&val);
maybe_throw_js_error(err);
return result;
}
void Scripter::EvalScriptToString(const vxistring & expr, vxistring & result)
{
VXIValue * val = NULL;
VXIjsiResult err = jsi_api->Eval(jsi_api, jsi_context, expr.c_str(), &val);
std::basic_ostringstream<wchar_t> os;
if (err == VXIjsi_RESULT_SUCCESS) {
switch (VXIValueGetType(val)) {
case VALUE_BOOLEAN:
if(VXIBooleanValue(reinterpret_cast<const VXIBoolean*>(val)) == TRUE)
os << L"true";
else
os << L"false";
break;
case VALUE_INTEGER:
os << VXIIntegerValue(reinterpret_cast<const VXIInteger*>(val));
break;
case VALUE_FLOAT:
os << VXIFloatValue(reinterpret_cast<const VXIFloat*>(val));
break;
case VALUE_STRING:
std::fixed(os);
os << VXIStringCStr(reinterpret_cast<const VXIString *>(val));
break;
default:
err = VXIjsi_RESULT_FAILURE;
break;
}
}
VXIValueDestroy(&val);
result = os.str();
maybe_throw_js_error(err);
}
void Scripter::EvalScript(const vxistring & expr)
{
VXIjsiResult err = jsi_api->Eval(jsi_api, jsi_context, expr.c_str(), NULL);
maybe_throw_js_error(err);
}
VXIValue * Scripter::EvalScriptToValue(const vxistring & expr)
{
VXIValue* val = NULL;
VXIjsiResult err = jsi_api->Eval(jsi_api, jsi_context, expr.c_str(), &val);
if (err == VXIjsi_RESULT_FAILURE) return NULL; // from ECMAScript 'null'
maybe_throw_js_error(err);
return val;
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -