Ruby
2.0.0p247(2013-06-27revision41674)
|
00001 /****************************************************************************** 00002 Copyright 2012 Google Inc. All Rights Reserved. 00003 Author: yugui@google.com (Yugui Sonoda) 00004 ******************************************************************************/ 00005 00006 #include <stdlib.h> 00007 #include <stdio.h> 00008 #include <string.h> 00009 #include <pthread.h> 00010 #include <sys/stat.h> 00011 #include <fcntl.h> 00012 #include <pthread.h> 00013 #include "ppapi/c/pp_errors.h" 00014 #include "ppapi/c/pp_module.h" 00015 #include "ppapi/c/pp_var.h" 00016 #include "ppapi/c/ppb.h" 00017 #include "ppapi/c/ppb_core.h" 00018 #include "ppapi/c/ppb_file_ref.h" 00019 #include "ppapi/c/ppb_instance.h" 00020 #include "ppapi/c/ppb_messaging.h" 00021 #include "ppapi/c/ppb_url_loader.h" 00022 #include "ppapi/c/ppb_url_request_info.h" 00023 #include "ppapi/c/ppb_url_response_info.h" 00024 #include "ppapi/c/ppb_var.h" 00025 #include "ppapi/c/ppp.h" 00026 #include "ppapi/c/ppp_instance.h" 00027 #include "ppapi/c/ppp_messaging.h" 00028 00029 #include "verconf.h" 00030 #include "ruby/ruby.h" 00031 #include "version.h" 00032 #include "gc.h" 00033 00034 #ifdef HAVE_STRUCT_PPB_CORE 00035 typedef struct PPB_Core PPB_Core; 00036 #endif 00037 #ifdef HAVE_STRUCT_PPB_MESSAGING 00038 typedef struct PPB_Messaging PPB_Messaging; 00039 #endif 00040 #ifdef HAVE_STRUCT_PPB_VAR 00041 typedef struct PPB_Var PPB_Var; 00042 #endif 00043 #ifdef HAVE_STRUCT_PPB_URLLOADER 00044 typedef struct PPB_URLLoader PPB_URLLoader; 00045 #endif 00046 #ifdef HAVE_STRUCT_PPB_URLREQUESTINFO 00047 typedef struct PPB_URLRequestInfo PPB_URLRequestInfo; 00048 #endif 00049 #ifdef HAVE_STRUCT_PPB_URLRESPONSEINFO 00050 typedef struct PPB_URLResponseInfo PPB_URLResponseInfo; 00051 #endif 00052 #ifdef HAVE_STRUCT_PPP_INSTANCE 00053 typedef struct PPP_Instance PPP_Instance; 00054 #endif 00055 00056 static PP_Module module_id = 0; 00057 static PPB_Core* core_interface = NULL; 00058 static PPB_Messaging* messaging_interface = NULL; 00059 static PPB_Var* var_interface = NULL; 00060 static PPB_URLLoader* loader_interface = NULL; 00061 static PPB_URLRequestInfo* request_interface = NULL; 00062 static PPB_URLResponseInfo* response_interface = NULL; 00063 static PPB_FileRef* fileref_interface = NULL; 00064 static struct st_table* instance_data = NULL; 00065 00066 static VALUE instance_table = Qundef; 00067 00068 static PP_Instance current_instance = 0; 00069 00070 /****************************************************************************** 00071 * State of instance 00072 ******************************************************************************/ 00073 00074 static void inst_mark(void *const ptr); 00075 static void inst_free(void *const ptr); 00076 static size_t inst_memsize(void *const ptr); 00077 static const rb_data_type_t pepper_instance_data_type = { 00078 "PepperInstance", 00079 { inst_mark, inst_free, inst_memsize } 00080 }; 00081 00082 struct PepperInstance { 00083 PP_Instance instance; 00084 PP_Resource url_loader; 00085 VALUE self; 00086 void* async_call_args; 00087 union { 00088 int32_t as_int; 00089 const char* as_str; 00090 VALUE as_value; 00091 } async_call_result; 00092 char buf[1000]; 00093 00094 pthread_t th; 00095 pthread_mutex_t mutex; 00096 pthread_cond_t cond; 00097 }; 00098 00099 struct PepperInstance* 00100 pruby_get_instance(PP_Instance instance) 00101 { 00102 VALUE self = rb_hash_aref(instance_table, INT2FIX(instance)); 00103 if (RTEST(self)) { 00104 struct PepperInstance *inst; 00105 TypedData_Get_Struct(self, struct PepperInstance, &pepper_instance_data_type, inst); 00106 return inst; 00107 } 00108 else { 00109 return NULL; 00110 } 00111 } 00112 00113 #define GET_PEPPER_INSTANCE() (pruby_get_instance(current_instance)) 00114 00115 struct PepperInstance* 00116 pruby_register_instance(PP_Instance instance) 00117 { 00118 VALUE obj; 00119 struct PepperInstance *data; 00120 obj = TypedData_Make_Struct(rb_cData, struct PepperInstance, &pepper_instance_data_type, data); 00121 data->self = obj; 00122 data->instance = instance; 00123 data->url_loader = 0; 00124 00125 pthread_mutex_init(&data->mutex, NULL); 00126 pthread_cond_init(&data->cond, NULL); 00127 00128 rb_hash_aset(instance_table, INT2FIX(instance), obj); 00129 return data; 00130 } 00131 00132 int 00133 pruby_unregister_instance(PP_Instance instance) 00134 { 00135 VALUE inst = rb_hash_delete(instance_table, INT2FIX(instance)); 00136 return RTEST(inst); 00137 } 00138 00139 static void 00140 inst_mark(void *const ptr) 00141 { 00142 RUBY_MARK_ENTER("PepperInstance"0); 00143 if (ptr) { 00144 const struct PepperInstance* inst = (struct PepperInstance*)ptr; 00145 RUBY_MARK_UNLESS_NULL(inst->async_call_result.as_value); 00146 } 00147 RUBY_MARK_LEAVE("PepperInstance"0); 00148 } 00149 00150 static void 00151 inst_free(void *const ptr) 00152 { 00153 ruby_xfree(ptr); 00154 } 00155 00156 static size_t 00157 inst_memsize(void *const ptr) 00158 { 00159 if (ptr) { 00160 const struct PepperInstance* inst = (struct PepperInstance*)ptr; 00161 return sizeof(*inst); 00162 } else { 00163 return 0; 00164 } 00165 } 00166 00167 void 00168 pruby_async_return_int(void* data, int32_t result) 00169 { 00170 /* PPAPI main thread */ 00171 struct PepperInstance* const instance = (struct PepperInstance*)data; 00172 instance->async_call_result.as_int = result; 00173 if (pthread_cond_signal(&instance->cond)) { 00174 perror("pepper-ruby:pthread_cond_signal"); 00175 } 00176 } 00177 00178 void 00179 pruby_async_return_str(void* data, const char *result) 00180 { 00181 /* PPAPI main thread */ 00182 struct PepperInstance* const instance = (struct PepperInstance*)data; 00183 instance->async_call_result.as_str = result; 00184 if (pthread_cond_signal(&instance->cond)) { 00185 perror("pepper-ruby:pthread_cond_signal"); 00186 } 00187 } 00188 00189 void 00190 pruby_async_return_value(void* data, VALUE value) 00191 { 00192 /* PPAPI main thread */ 00193 struct PepperInstance* const instance = (struct PepperInstance*)data; 00194 instance->async_call_result.as_value = value; 00195 if (pthread_cond_signal(&instance->cond)) { 00196 perror("pepper-ruby:pthread_cond_signal"); 00197 } 00198 } 00199 /****************************************************************************** 00200 * Conversion between Ruby's VALUE, Pepper's Var and C string 00201 ******************************************************************************/ 00202 00210 static struct PP_Var 00211 pruby_cstr_to_var(const char* str) 00212 { 00213 #ifdef PPB_VAR_INTERFACE_1_0 00214 if (var_interface != NULL) 00215 return var_interface->VarFromUtf8(module_id, str, strlen(str)); 00216 return PP_MakeUndefined(); 00217 #else 00218 return var_interface->VarFromUtf8(str, strlen(str)); 00219 #endif 00220 } 00221 00232 static char* 00233 pruby_var_to_cstr(struct PP_Var var) 00234 { 00235 uint32_t len = 0; 00236 if (var_interface != NULL) { 00237 const char* var_c_str = var_interface->VarToUtf8(var, &len); 00238 if (len > 0) { 00239 char* c_str = (char*)malloc(len + 1); 00240 memcpy(c_str, var_c_str, len); 00241 c_str[len] = '\0'; 00242 return c_str; 00243 } 00244 } 00245 return NULL; 00246 } 00247 00248 static struct PP_Var 00249 pruby_str_to_var(volatile VALUE str) 00250 { 00251 if (!RB_TYPE_P(str, T_STRING)) { 00252 fprintf(stderr, "[BUG] Unexpected object type: %x\n", TYPE(str)); 00253 exit(EXIT_FAILURE); 00254 } 00255 #ifdef PPB_VAR_INTERFACE_1_0 00256 if (var_interface != NULL) { 00257 return var_interface->VarFromUtf8(module_id, RSTRING_PTR(str), RSTRING_LEN(str)); 00258 } 00259 #else 00260 return var_interface->VarFromUtf8(RSTRING_PTR(str), RSTRING_LEN(str)); 00261 #endif 00262 return PP_MakeUndefined(); 00263 } 00264 00265 static struct PP_Var 00266 pruby_obj_to_var(volatile VALUE obj) 00267 { 00268 static const char* const error = 00269 "throw 'Failed to convert the result to a JavaScript object';"; 00270 int state; 00271 obj = rb_protect(&rb_obj_as_string, obj, &state); 00272 if (!state) { 00273 return pruby_str_to_var(obj); 00274 } 00275 else { 00276 return pruby_cstr_to_var(error); 00277 } 00278 } 00279 00280 int 00281 pruby_var_equal_to_cstr_p(struct PP_Var lhs, const char* rhs) 00282 { 00283 uint32_t len = 0; 00284 if (var_interface == NULL) { 00285 return 0; 00286 } 00287 else { 00288 const char* const cstr = var_interface->VarToUtf8(lhs, &len); 00289 return strncmp(cstr, rhs, len) == 0; 00290 } 00291 } 00292 00293 int 00294 pruby_var_prefixed_p(struct PP_Var var, const char* prefix) 00295 { 00296 uint32_t len = 0; 00297 if (var_interface == NULL) { 00298 return 0; 00299 } 00300 else { 00301 const char* const cstr = var_interface->VarToUtf8(var, &len); 00302 const size_t prefix_len = strlen(prefix); 00303 return len >= prefix_len && memcmp(cstr, prefix, len) == 0; 00304 } 00305 } 00306 00307 00308 /****************************************************************************** 00309 * Messaging 00310 ******************************************************************************/ 00311 00312 /* Posts the given C string as a message. 00313 * @param data pointer to a NULL-terminated string */ 00314 void 00315 pruby_post_cstr(void* data) 00316 { 00317 /* PPAPI main thread */ 00318 struct PepperInstance* const instance = (struct PepperInstance*)data; 00319 const char* const msg = (const char*)instance->async_call_args; 00320 messaging_interface->PostMessage(instance->instance, 00321 pruby_cstr_to_var(msg)); 00322 } 00323 00324 /* Posts the given Ruby VALUE as a message. 00325 * @param data a VALUE casted to void* */ 00326 void 00327 pruby_post_value(void* data) 00328 { 00329 /* PPAPI main thread */ 00330 struct PepperInstance* const instance = (struct PepperInstance*)data; 00331 volatile VALUE value = (VALUE)instance->async_call_args; 00332 messaging_interface->PostMessage(instance->instance, pruby_obj_to_var(value)); 00333 } 00334 00335 00336 00337 /****************************************************************************** 00338 * Ruby initialization 00339 ******************************************************************************/ 00340 00341 static void 00342 init_loadpath(void) 00343 { 00344 ruby_incpush("lib/ruby/"RUBY_LIB_VERSION); 00345 ruby_incpush("lib/ruby/"RUBY_LIB_VERSION"/"RUBY_PLATFORM); 00346 ruby_incpush("."); 00347 } 00348 00349 static VALUE 00350 init_libraries_internal(VALUE unused) 00351 { 00352 extern void Init_enc(); 00353 extern void Init_ext(); 00354 00355 init_loadpath(); 00356 Init_enc(); 00357 Init_ext(); 00358 return Qnil; 00359 } 00360 00361 static void* 00362 init_libraries(void* data) 00363 { 00364 int state; 00365 struct PepperInstance* const instance = (struct PepperInstance*)data; 00366 current_instance = instance->instance; 00367 00368 if (pthread_mutex_lock(&instance->mutex)) { 00369 perror("pepper-ruby:pthread_mutex_lock"); 00370 return 0; 00371 } 00372 rb_protect(&init_libraries_internal, Qnil, &state); 00373 pthread_mutex_unlock(&instance->mutex); 00374 00375 if (state) { 00376 volatile VALUE err = rb_errinfo(); 00377 err = rb_obj_as_string(err); 00378 } else { 00379 instance->async_call_args = (void*)"rubyReady"; 00380 core_interface->CallOnMainThread( 00381 0, PP_MakeCompletionCallback(pruby_post_cstr, instance), 0); 00382 } 00383 return NULL; 00384 } 00385 00386 static int 00387 init_libraries_if_necessary(void) 00388 { 00389 static int initialized = 0; 00390 if (!initialized) { 00391 struct PepperInstance* const instance = GET_PEPPER_INSTANCE(); 00392 int err; 00393 initialized = 1; 00394 err = pthread_create(&instance->th, NULL, &init_libraries, instance); 00395 if (err) { 00396 fprintf(stderr, "pepper_ruby:pthread_create: %s\n", strerror(err)); 00397 exit(EXIT_FAILURE); 00398 } 00399 pthread_detach(instance->th); 00400 } 00401 return 0; 00402 } 00403 00404 static int 00405 pruby_init(void) 00406 { 00407 RUBY_INIT_STACK; 00408 ruby_init(); 00409 00410 instance_table = rb_hash_new(); 00411 rb_gc_register_mark_object(instance_table); 00412 00413 return 0; 00414 } 00415 00416 00417 /****************************************************************************** 00418 * Ruby evaluation 00419 ******************************************************************************/ 00420 00421 static void* 00422 pruby_eval(void* data) 00423 { 00424 extern VALUE ruby_eval_string_from_file_protect(const char* src, const char* path, int* state); 00425 struct PepperInstance* const instance = (struct PepperInstance*)data; 00426 volatile VALUE src = (VALUE)instance->async_call_args; 00427 volatile VALUE result = Qnil; 00428 volatile int state; 00429 00430 RUBY_INIT_STACK; 00431 00432 if (pthread_mutex_lock(&instance->mutex)) { 00433 perror("pepper-ruby:pthread_mutex_lock"); 00434 return 0; 00435 } 00436 result = ruby_eval_string_from_file_protect( 00437 RSTRING_PTR(src), "(pepper-ruby)", &state); 00438 pthread_mutex_unlock(&instance->mutex); 00439 00440 if (!state) { 00441 instance->async_call_args = 00442 rb_str_concat(rb_usascii_str_new_cstr("return:"), 00443 rb_obj_as_string(result)); 00444 core_interface->CallOnMainThread( 00445 0, PP_MakeCompletionCallback(pruby_post_value, instance), 0); 00446 return NULL; 00447 } 00448 else { 00449 rb_set_errinfo(Qnil); 00450 instance->async_call_args = 00451 rb_str_concat(rb_usascii_str_new_cstr("error:"), 00452 rb_obj_as_string(result)); 00453 core_interface->CallOnMainThread( 00454 0, PP_MakeCompletionCallback(pruby_post_value, instance), 0); 00455 return NULL; 00456 } 00457 } 00458 00459 00460 /****************************************************************************** 00461 * Pepper Module callbacks 00462 ******************************************************************************/ 00463 00486 static PP_Bool 00487 Instance_DidCreate(PP_Instance instance, 00488 uint32_t argc, const char* argn[], const char* argv[]) 00489 { 00490 struct PepperInstance* data = pruby_register_instance(instance); 00491 current_instance = instance; 00492 return init_libraries_if_necessary() ? PP_FALSE : PP_TRUE; 00493 } 00494 00502 static void Instance_DidDestroy(PP_Instance instance) { 00503 struct PepperInstance* data = pruby_get_instance(instance); 00504 core_interface->ReleaseResource(data->url_loader); 00505 pruby_unregister_instance(instance); 00506 } 00507 00520 #ifdef PPP_INSTANCE_INTERFACE_1_0 00521 static void 00522 Instance_DidChangeView(PP_Instance instance, 00523 const struct PP_Rect* position, 00524 const struct PP_Rect* clip) 00525 { 00526 } 00527 #else 00528 static void 00529 Instance_DidChangeView(PP_Instance instance, PP_Resource view_resource) 00530 { 00531 } 00532 #endif 00533 00551 static void 00552 Instance_DidChangeFocus(PP_Instance instance, PP_Bool has_focus) 00553 { 00554 } 00555 00566 static PP_Bool 00567 Instance_HandleDocumentLoad(PP_Instance instance, PP_Resource url_loader) 00568 { 00569 /* NaCl modules do not need to handle the document load function. */ 00570 return PP_FALSE; 00571 } 00572 00573 00589 void 00590 Messaging_HandleMessage(PP_Instance instance, struct PP_Var var_message) 00591 { 00592 char* const message = pruby_var_to_cstr(var_message); 00593 size_t message_len = strlen(message); 00594 current_instance = instance; 00595 00596 if (strstr(message, "eval:") != NULL) { 00597 volatile VALUE src; 00598 struct PepperInstance* const instance_data = GET_PEPPER_INSTANCE(); 00599 int err; 00600 #define EVAL_PREFIX_LEN 5 00601 src = rb_str_new(message + EVAL_PREFIX_LEN, message_len - EVAL_PREFIX_LEN); 00602 instance_data->async_call_args = (void*)src; 00603 err = pthread_create(&instance_data->th, NULL, &pruby_eval, instance_data); 00604 if (err) { 00605 fprintf(stderr, "pepper_ruby:pthread_create: %s\n", strerror(err)); 00606 exit(EXIT_FAILURE); 00607 } 00608 pthread_detach(instance_data->th); 00609 } 00610 free(message); 00611 } 00612 00620 PP_EXPORT int32_t 00621 PPP_InitializeModule(PP_Module a_module_id, PPB_GetInterface get_browser_interface) 00622 { 00623 module_id = a_module_id; 00624 core_interface = (PPB_Core*)(get_browser_interface(PPB_CORE_INTERFACE)); 00625 if (core_interface == NULL) return PP_ERROR_NOINTERFACE; 00626 00627 var_interface = (PPB_Var*)(get_browser_interface(PPB_VAR_INTERFACE)); 00628 if (var_interface == NULL) return PP_ERROR_NOINTERFACE; 00629 00630 messaging_interface = (PPB_Messaging*)(get_browser_interface(PPB_MESSAGING_INTERFACE)); 00631 if (messaging_interface == NULL) return PP_ERROR_NOINTERFACE; 00632 00633 loader_interface = (PPB_URLLoader*)(get_browser_interface(PPB_URLLOADER_INTERFACE)); 00634 if (loader_interface == NULL) return PP_ERROR_NOINTERFACE; 00635 00636 request_interface = (PPB_URLRequestInfo*)(get_browser_interface(PPB_URLREQUESTINFO_INTERFACE)); 00637 if (request_interface == NULL) return PP_ERROR_NOINTERFACE; 00638 00639 response_interface = (PPB_URLResponseInfo*)(get_browser_interface(PPB_URLRESPONSEINFO_INTERFACE)); 00640 if (response_interface == NULL) return PP_ERROR_NOINTERFACE; 00641 00642 fileref_interface = (PPB_FileRef*)(get_browser_interface(PPB_FILEREF_INTERFACE)); 00643 if (fileref_interface == NULL) return PP_ERROR_NOINTERFACE; 00644 00645 return pruby_init() ? PP_ERROR_FAILED : PP_OK; 00646 } 00647 00654 PP_EXPORT const void* 00655 PPP_GetInterface(const char* interface_name) 00656 { 00657 if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) { 00658 static PPP_Instance instance_interface = { 00659 &Instance_DidCreate, 00660 &Instance_DidDestroy, 00661 &Instance_DidChangeView, 00662 &Instance_DidChangeFocus, 00663 &Instance_HandleDocumentLoad 00664 }; 00665 return &instance_interface; 00666 } else if (strcmp(interface_name, PPP_MESSAGING_INTERFACE) == 0) { 00667 static PPP_Messaging messaging_interface = { 00668 &Messaging_HandleMessage 00669 }; 00670 return &messaging_interface; 00671 } 00672 return NULL; 00673 } 00674 00678 PP_EXPORT void 00679 PPP_ShutdownModule() 00680 { 00681 ruby_cleanup(0); 00682 } 00683 00684 /****************************************************************************** 00685 * Overwrites rb_file_load_ok 00686 ******************************************************************************/ 00687 00688 static void 00689 load_ok_internal(void* data, int32_t unused) 00690 { 00691 /* PPAPI main thread */ 00692 struct PepperInstance* const instance = (struct PepperInstance*)data; 00693 const char *const path = (const char*)instance->async_call_args; 00694 PP_Resource req; 00695 int result; 00696 00697 instance->url_loader = loader_interface->Create(instance->instance); 00698 req = request_interface->Create(instance->instance); 00699 request_interface->SetProperty( 00700 req, PP_URLREQUESTPROPERTY_METHOD, pruby_cstr_to_var("HEAD")); 00701 request_interface->SetProperty( 00702 req, PP_URLREQUESTPROPERTY_URL, pruby_cstr_to_var(path)); 00703 00704 result = loader_interface->Open( 00705 instance->url_loader, req, 00706 PP_MakeCompletionCallback(pruby_async_return_int, instance)); 00707 if (result != PP_OK_COMPLETIONPENDING) { 00708 pruby_async_return_int(instance, result); 00709 } 00710 } 00711 00712 static void 00713 pruby_file_fetch_check_response(void* data, int32_t unused) 00714 { 00715 /* PPAPI main thread */ 00716 PP_Resource res; 00717 struct PepperInstance* const instance = (struct PepperInstance*)data; 00718 00719 res = loader_interface->GetResponseInfo(instance->url_loader); 00720 if (res) { 00721 struct PP_Var status = 00722 response_interface->GetProperty(res, PP_URLRESPONSEPROPERTY_STATUSCODE); 00723 if (status.type == PP_VARTYPE_INT32) { 00724 pruby_async_return_int(instance, status.value.as_int / 100 == 2 ? PP_OK : PP_ERROR_FAILED); 00725 return; 00726 } 00727 else { 00728 messaging_interface->PostMessage( 00729 instance->instance, pruby_cstr_to_var("Unexpected type: ResponseInfoInterface::GetProperty")); 00730 } 00731 } 00732 else { 00733 messaging_interface->PostMessage( 00734 instance->instance, pruby_cstr_to_var("Failed to open URL: URLLoaderInterface::GetResponseInfo")); 00735 } 00736 pruby_async_return_int(instance, PP_ERROR_FAILED); 00737 } 00738 00739 00740 int 00741 rb_file_load_ok(const char *path) 00742 { 00743 struct PepperInstance* const instance = GET_PEPPER_INSTANCE(); 00744 if (path[0] == '.' && path[1] == '/') path += 2; 00745 00746 instance->async_call_args = (void*)path; 00747 core_interface->CallOnMainThread( 00748 0, PP_MakeCompletionCallback(load_ok_internal, instance), 0); 00749 if (pthread_cond_wait(&instance->cond, &instance->mutex)) { 00750 perror("pepper-ruby:pthread_cond_wait"); 00751 return 0; 00752 } 00753 if (instance->async_call_result.as_int != PP_OK) { 00754 fprintf(stderr, "Failed to open URL: %d: %s\n", 00755 instance->async_call_result.as_int, path); 00756 return 0; 00757 } 00758 00759 core_interface->CallOnMainThread( 00760 0, PP_MakeCompletionCallback(pruby_file_fetch_check_response, instance), 0); 00761 if (pthread_cond_wait(&instance->cond, &instance->mutex)) { 00762 perror("pepper-ruby:pthread_cond_wait"); 00763 return 0; 00764 } 00765 return instance->async_call_result.as_int == PP_OK; 00766 } 00767 00768 /****************************************************************************** 00769 * Overwrites rb_load_file 00770 ******************************************************************************/ 00771 00772 static void 00773 load_file_internal(void* data, int32_t unused) 00774 { 00775 /* PPAPI main thread */ 00776 struct PepperInstance* const instance = (struct PepperInstance*)data; 00777 const char *const path = (const char*)instance->async_call_args; 00778 PP_Resource req; 00779 int result; 00780 00781 instance->url_loader = loader_interface->Create(instance->instance); 00782 req = request_interface->Create(instance->instance); 00783 request_interface->SetProperty( 00784 req, PP_URLREQUESTPROPERTY_METHOD, pruby_cstr_to_var("GET")); 00785 request_interface->SetProperty( 00786 req, PP_URLREQUESTPROPERTY_URL, pruby_cstr_to_var(path)); 00787 00788 result = loader_interface->Open( 00789 instance->url_loader, req, 00790 PP_MakeCompletionCallback(pruby_async_return_int, instance)); 00791 if (result != PP_OK_COMPLETIONPENDING) { 00792 pruby_async_return_int(instance, result); 00793 } 00794 } 00795 00796 static void 00797 load_file_read_contents_callback(void *data, int result) 00798 { 00799 struct PepperInstance* const instance = (struct PepperInstance*)data; 00800 if (result > 0) { 00801 rb_str_buf_cat(instance->async_call_result.as_value, 00802 instance->buf, result); 00803 loader_interface->ReadResponseBody( 00804 instance->url_loader, instance->buf, 1000, PP_MakeCompletionCallback(load_file_read_contents_callback, instance)); 00805 } 00806 else if (result == 0) { 00807 pruby_async_return_value(data, instance->async_call_result.as_value); 00808 } 00809 else { 00810 pruby_async_return_value(data, INT2FIX(result)); 00811 } 00812 } 00813 00814 static void 00815 load_file_read_contents(void *data, int result) 00816 { 00817 struct PepperInstance* const instance = (struct PepperInstance*)data; 00818 instance->async_call_result.as_value = rb_str_new(0, 0); 00819 loader_interface->ReadResponseBody( 00820 instance->url_loader, instance->buf, 1000, PP_MakeCompletionCallback(load_file_read_contents_callback, instance)); 00821 } 00822 00823 void* 00824 rb_load_file(const char *path) 00825 { 00826 const char *real_path; 00827 struct PepperInstance* instance; 00828 if (path[0] != '.' || path[1] != '/') path += 2; 00829 00830 instance = GET_PEPPER_INSTANCE(); 00831 00832 instance->async_call_args = (void*)path; 00833 core_interface->CallOnMainThread( 00834 0, PP_MakeCompletionCallback(load_file_internal, instance), 0); 00835 if (pthread_cond_wait(&instance->cond, &instance->mutex)) { 00836 perror("pepper-ruby:pthread_cond_wait"); 00837 return 0; 00838 } 00839 if (instance->async_call_result.as_int != PP_OK) { 00840 fprintf(stderr, "Failed to open URL: %d: %s\n", 00841 instance->async_call_result.as_int, path); 00842 return 0; 00843 } 00844 00845 core_interface->CallOnMainThread( 00846 0, PP_MakeCompletionCallback(pruby_file_fetch_check_response, instance), 0); 00847 if (pthread_cond_wait(&instance->cond, &instance->mutex)) { 00848 perror("pepper-ruby:pthread_cond_wait"); 00849 return 0; 00850 } 00851 if (instance->async_call_result.as_int != PP_OK) return 0; 00852 00853 core_interface->CallOnMainThread( 00854 0, PP_MakeCompletionCallback(load_file_read_contents, instance), 0); 00855 if (pthread_cond_wait(&instance->cond, &instance->mutex)) { 00856 perror("pepper-ruby:pthread_cond_wait"); 00857 return 0; 00858 } 00859 if (FIXNUM_P(instance->async_call_result.as_value)) { 00860 return 0; 00861 } 00862 else if (RB_TYPE_P(instance->async_call_result.as_value, T_STRING)) { 00863 VALUE str = instance->async_call_result.as_value; 00864 extern void* rb_compile_cstr(const char *f, const char *s, int len, int line); 00865 return rb_compile_cstr(path, RSTRING_PTR(str), RSTRING_LEN(str), 0); 00866 } 00867 else { 00868 return 0; 00869 } 00870 } 00871