1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "xfa/src/foxitlib.h"
8 #include "fxv8.h"
9 #include "context.h"
10 #include "class.h"
11 #include "value.h"
12 #include "scope_inline.h"
13 #include "util_inline.h"
FXJSE_Context_Create(FXJSE_HRUNTIME hRuntime,const FXJSE_CLASS * lpGlobalClass,void * lpGlobalObject)14 FXJSE_HCONTEXT FXJSE_Context_Create(FXJSE_HRUNTIME hRuntime,
15                                     const FXJSE_CLASS* lpGlobalClass,
16                                     void* lpGlobalObject) {
17   CFXJSE_Context* pContext = CFXJSE_Context::Create(
18       reinterpret_cast<v8::Isolate*>(hRuntime), lpGlobalClass, lpGlobalObject);
19   return reinterpret_cast<FXJSE_HCONTEXT>(pContext);
20 }
FXJSE_Context_Release(FXJSE_HCONTEXT hContext)21 void FXJSE_Context_Release(FXJSE_HCONTEXT hContext) {
22   CFXJSE_Context* pContext = reinterpret_cast<CFXJSE_Context*>(hContext);
23   if (pContext) {
24     delete pContext;
25   }
26 }
FXJSE_Context_GetGlobalObject(FXJSE_HCONTEXT hContext)27 FXJSE_HVALUE FXJSE_Context_GetGlobalObject(FXJSE_HCONTEXT hContext) {
28   CFXJSE_Context* pContext = reinterpret_cast<CFXJSE_Context*>(hContext);
29   if (!pContext) {
30     return NULL;
31   }
32   CFXJSE_Value* lpValue = CFXJSE_Value::Create(pContext->GetRuntime());
33   ASSERT(lpValue);
34   pContext->GetGlobalObject(lpValue);
35   return reinterpret_cast<FXJSE_HVALUE>(lpValue);
36 }
FXJSE_Context_GetRuntime(FXJSE_HCONTEXT hContext)37 FXJSE_HRUNTIME FXJSE_Context_GetRuntime(FXJSE_HCONTEXT hContext) {
38   CFXJSE_Context* pContext = reinterpret_cast<CFXJSE_Context*>(hContext);
39   return pContext ? reinterpret_cast<FXJSE_HRUNTIME>(pContext->GetRuntime())
40                   : NULL;
41 }
42 static const FX_CHAR* szCompatibleModeScripts[] = {
43     "(function (global, list) { 'use strict'; var objname; for (objname in list) { var globalobj = global[objname];\n\
44 			if (globalobj) { list[objname].forEach( function (name) { if (!globalobj[name]) { Object.defineProperty(globalobj, name, {writable: true, enumerable: false, value: \n\
45 			(function (obj) {\n\
46 	if (arguments.length === 0) {\n\
47 		throw new TypeError('missing argument 0 when calling function ' + objname + '.' + name);\n\
48 	}\n\
49 	return globalobj.prototype[name].apply(obj, Array.prototype.slice.call(arguments, 1));\n\
50 })});}});}}}(this, {String: ['substr', 'toUpperCase']}));",
51 };
FXJSE_Context_EnableCompatibleMode(FXJSE_HCONTEXT hContext,FX_DWORD dwCompatibleFlags)52 void FXJSE_Context_EnableCompatibleMode(FXJSE_HCONTEXT hContext,
53                                         FX_DWORD dwCompatibleFlags) {
54   for (uint32_t i = 0; i < (uint32_t)FXJSE_COMPATIBLEMODEFLAGCOUNT; i++) {
55     if (dwCompatibleFlags & (1 << i)) {
56       FXJSE_ExecuteScript(hContext, szCompatibleModeScripts[i], NULL, NULL);
57     }
58   }
59 }
FXJSE_ExecuteScript(FXJSE_HCONTEXT hContext,const FX_CHAR * szScript,FXJSE_HVALUE hRetValue,FXJSE_HVALUE hNewThisObject)60 FX_BOOL FXJSE_ExecuteScript(FXJSE_HCONTEXT hContext,
61                             const FX_CHAR* szScript,
62                             FXJSE_HVALUE hRetValue,
63                             FXJSE_HVALUE hNewThisObject) {
64   CFXJSE_Context* pContext = reinterpret_cast<CFXJSE_Context*>(hContext);
65   ASSERT(pContext);
66   return pContext->ExecuteScript(
67       szScript, reinterpret_cast<CFXJSE_Value*>(hRetValue),
68       reinterpret_cast<CFXJSE_Value*>(hNewThisObject));
69 }
FXJSE_CreateReturnValue(v8::Isolate * pIsolate,v8::TryCatch & trycatch)70 v8::Local<v8::Object> FXJSE_CreateReturnValue(v8::Isolate* pIsolate,
71                                               v8::TryCatch& trycatch) {
72   v8::Local<v8::Object> hReturnValue = v8::Object::New(pIsolate);
73   if (trycatch.HasCaught()) {
74     v8::Local<v8::Value> hException = trycatch.Exception();
75     v8::Local<v8::Message> hMessage = trycatch.Message();
76     if (hException->IsObject()) {
77       v8::Local<v8::Value> hValue;
78       hValue = hException.As<v8::Object>()->Get(
79           v8::String::NewFromUtf8(pIsolate, "name"));
80       if (hValue->IsString() || hValue->IsStringObject()) {
81         hReturnValue->Set(0, hValue);
82       } else {
83         hReturnValue->Set(0, v8::String::NewFromUtf8(pIsolate, "Error"));
84       }
85       hValue = hException.As<v8::Object>()->Get(
86           v8::String::NewFromUtf8(pIsolate, "message"));
87       if (hValue->IsString() || hValue->IsStringObject()) {
88         hReturnValue->Set(1, hValue);
89       } else {
90         hReturnValue->Set(1, hMessage->Get());
91       }
92     } else {
93       hReturnValue->Set(0, v8::String::NewFromUtf8(pIsolate, "Error"));
94       hReturnValue->Set(1, hMessage->Get());
95     }
96     hReturnValue->Set(2, hException);
97     hReturnValue->Set(3, v8::Integer::New(pIsolate, hMessage->GetLineNumber()));
98     hReturnValue->Set(4, hMessage->GetSourceLine());
99     hReturnValue->Set(5,
100                       v8::Integer::New(pIsolate, hMessage->GetStartColumn()));
101     hReturnValue->Set(6, v8::Integer::New(pIsolate, hMessage->GetEndColumn()));
102   }
103   return hReturnValue;
104 }
FXJSE_ReturnValue_GetMessage(FXJSE_HVALUE hRetValue,CFX_ByteString & utf8Name,CFX_ByteString & utf8Message)105 FX_BOOL FXJSE_ReturnValue_GetMessage(FXJSE_HVALUE hRetValue,
106                                      CFX_ByteString& utf8Name,
107                                      CFX_ByteString& utf8Message) {
108   CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hRetValue);
109   if (!lpValue) {
110     return FALSE;
111   }
112   v8::Isolate* pIsolate = lpValue->GetIsolate();
113   CFXJSE_ScopeUtil_IsolateHandleRootContext scope(pIsolate);
114   v8::Local<v8::Value> hValue =
115       v8::Local<v8::Value>::New(pIsolate, lpValue->DirectGetValue());
116   if (!hValue->IsObject()) {
117     return FALSE;
118   }
119   v8::String::Utf8Value hStringVal0(
120       hValue.As<v8::Object>()->Get(0)->ToString());
121   utf8Name = *hStringVal0;
122   v8::String::Utf8Value hStringVal1(
123       hValue.As<v8::Object>()->Get(1)->ToString());
124   utf8Message = *hStringVal1;
125   return TRUE;
126 }
FXJSE_ReturnValue_GetLineInfo(FXJSE_HVALUE hRetValue,int32_t & nLine,int32_t & nCol)127 FX_BOOL FXJSE_ReturnValue_GetLineInfo(FXJSE_HVALUE hRetValue,
128                                       int32_t& nLine,
129                                       int32_t& nCol) {
130   CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hRetValue);
131   if (!lpValue) {
132     return FALSE;
133   }
134   v8::Isolate* pIsolate = lpValue->GetIsolate();
135   CFXJSE_ScopeUtil_IsolateHandleRootContext scope(pIsolate);
136   v8::Local<v8::Value> hValue =
137       v8::Local<v8::Value>::New(pIsolate, lpValue->DirectGetValue());
138   if (!hValue->IsObject()) {
139     return FALSE;
140   }
141   nLine = hValue.As<v8::Object>()->Get(3)->ToInt32()->Value();
142   nCol = hValue.As<v8::Object>()->Get(5)->ToInt32()->Value();
143   return TRUE;
144 }
Create(v8::Isolate * pIsolate,const FXJSE_CLASS * lpGlobalClass,void * lpGlobalObject)145 CFXJSE_Context* CFXJSE_Context::Create(v8::Isolate* pIsolate,
146                                        const FXJSE_CLASS* lpGlobalClass,
147                                        void* lpGlobalObject) {
148   CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
149   CFXJSE_Context* pContext = new CFXJSE_Context(pIsolate);
150   CFXJSE_Class* lpGlobalClassObj = NULL;
151   v8::Local<v8::ObjectTemplate> hObjectTemplate;
152   if (lpGlobalClass) {
153     lpGlobalClassObj = CFXJSE_Class::Create(pContext, lpGlobalClass, TRUE);
154     ASSERT(lpGlobalClassObj);
155     v8::Local<v8::FunctionTemplate> hFunctionTemplate =
156         v8::Local<v8::FunctionTemplate>::New(pIsolate,
157                                              lpGlobalClassObj->m_hTemplate);
158     hObjectTemplate = hFunctionTemplate->InstanceTemplate();
159   } else {
160     hObjectTemplate = v8::ObjectTemplate::New();
161     hObjectTemplate->SetInternalFieldCount(1);
162   }
163   v8::Local<v8::Context> hNewContext =
164       v8::Context::New(pIsolate, NULL, hObjectTemplate);
165   v8::Local<v8::Context> hRootContext = v8::Local<v8::Context>::New(
166       pIsolate, CFXJSE_RuntimeData::Get(pIsolate)->m_hRootContext);
167   hNewContext->SetSecurityToken(hRootContext->GetSecurityToken());
168   v8::Local<v8::Object> hGlobalObject =
169       FXJSE_GetGlobalObjectFromContext(hNewContext);
170   FXJSE_UpdateObjectBinding(hGlobalObject, lpGlobalObject);
171   pContext->m_hContext.Reset(pIsolate, hNewContext);
172   return pContext;
173 }
~CFXJSE_Context()174 CFXJSE_Context::~CFXJSE_Context() {
175   for (int32_t i = 0, count = m_rgClasses.GetSize(); i < count; i++) {
176     CFXJSE_Class* pClass = m_rgClasses[i];
177     if (pClass) {
178       delete pClass;
179     }
180   }
181   m_rgClasses.RemoveAll();
182 }
GetGlobalObject(CFXJSE_Value * pValue)183 void CFXJSE_Context::GetGlobalObject(CFXJSE_Value* pValue) {
184   ASSERT(pValue);
185   CFXJSE_ScopeUtil_IsolateHandleContext scope(this);
186   v8::Local<v8::Context> hContext =
187       v8::Local<v8::Context>::New(m_pIsolate, m_hContext);
188   v8::Local<v8::Object> hGlobalObject = hContext->Global();
189   pValue->ForceSetValue(hGlobalObject);
190 }
ExecuteScript(const FX_CHAR * szScript,CFXJSE_Value * lpRetValue,CFXJSE_Value * lpNewThisObject)191 FX_BOOL CFXJSE_Context::ExecuteScript(const FX_CHAR* szScript,
192                                       CFXJSE_Value* lpRetValue,
193                                       CFXJSE_Value* lpNewThisObject) {
194   CFXJSE_ScopeUtil_IsolateHandleContext scope(this);
195   v8::TryCatch trycatch;
196   v8::Local<v8::String> hScriptString =
197       v8::String::NewFromUtf8(m_pIsolate, szScript);
198   if (lpNewThisObject == NULL) {
199     v8::Local<v8::Script> hScript = v8::Script::Compile(hScriptString);
200     if (!trycatch.HasCaught()) {
201       v8::Local<v8::Value> hValue = hScript->Run();
202       if (!trycatch.HasCaught()) {
203         if (lpRetValue) {
204           lpRetValue->m_hValue.Reset(m_pIsolate, hValue);
205         }
206         return TRUE;
207       }
208     }
209     if (lpRetValue) {
210       lpRetValue->m_hValue.Reset(m_pIsolate,
211                                  FXJSE_CreateReturnValue(m_pIsolate, trycatch));
212     }
213     return FALSE;
214   } else {
215     v8::Local<v8::Value> hNewThis =
216         v8::Local<v8::Value>::New(m_pIsolate, lpNewThisObject->m_hValue);
217     ASSERT(!hNewThis.IsEmpty());
218     v8::Local<v8::Script> hWrapper =
219         v8::Script::Compile(v8::String::NewFromUtf8(
220             m_pIsolate, "(function () { return eval(arguments[0]); })"));
221     v8::Local<v8::Value> hWrapperValue = hWrapper->Run();
222     ASSERT(hWrapperValue->IsFunction());
223     v8::Local<v8::Function> hWrapperFn = hWrapperValue.As<v8::Function>();
224     if (!trycatch.HasCaught()) {
225       v8::Local<v8::Value> rgArgs[] = {hScriptString};
226       v8::Local<v8::Value> hValue =
227           hWrapperFn->Call(hNewThis.As<v8::Object>(), 1, rgArgs);
228       if (!trycatch.HasCaught()) {
229         if (lpRetValue) {
230           lpRetValue->m_hValue.Reset(m_pIsolate, hValue);
231         }
232         return TRUE;
233       }
234     }
235     if (lpRetValue) {
236       lpRetValue->m_hValue.Reset(m_pIsolate,
237                                  FXJSE_CreateReturnValue(m_pIsolate, trycatch));
238     }
239     return FALSE;
240   }
241 }
242