1 /* Copyright (c) 2012 The Chromium 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.
6 #include "nacl_io_demo.h"
12 #include <sys/mount.h>
15 #include "ppapi/c/pp_errors.h"
16 #include "ppapi/c/pp_module.h"
17 #include "ppapi/c/ppb.h"
18 #include "ppapi/c/ppb_instance.h"
19 #include "ppapi/c/ppb_messaging.h"
20 #include "ppapi/c/ppb_var.h"
21 #include "ppapi/c/ppp.h"
22 #include "ppapi/c/ppp_instance.h"
23 #include "ppapi/c/ppp_messaging.h"
24 #include "nacl_io/nacl_io.h"
29 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
32 #define va_copy(d, s) ((d) = (s))
40 static PP_Instance g_instance = 0;
41 static PPB_GetInterface get_browser_interface = NULL;
42 static PPB_Messaging* ppb_messaging_interface = NULL;
43 static PPB_Var* ppb_var_interface = NULL;
45 static FuncNameMapping g_function_map[] = {
46 {"fopen", HandleFopen},
47 {"fwrite", HandleFwrite},
48 {"fread", HandleFread},
49 {"fseek", HandleFseek},
50 {"fclose", HandleFclose},
52 {"opendir", HandleOpendir},
53 {"readdir", HandleReaddir},
54 {"closedir", HandleClosedir},
55 {"mkdir", HandleMkdir},
56 {"rmdir", HandleRmdir},
57 {"chdir", HandleChdir},
58 {"getcwd", HandleGetcwd},
59 {"gethostbyname", HandleGethostbyname},
60 {"connect", HandleConnect},
63 {"close", HandleClose},
67 /** A handle to the thread the handles messages. */
68 static pthread_t g_handle_message_thread;
71 * Create a new PP_Var from a C string.
72 * @param[in] str The string to convert.
73 * @return A new PP_Var with the contents of |str|.
75 struct PP_Var CStrToVar(const char* str) {
76 if (ppb_var_interface != NULL) {
77 return ppb_var_interface->VarFromUtf8(str, strlen(str));
79 return PP_MakeUndefined();
83 * Printf to a newly allocated C string.
84 * @param[in] format A printf format string.
85 * @param[in] args The printf arguments.
86 * @return The newly constructed string. Caller takes ownership. */
87 char* VprintfToNewString(const char* format, va_list args) {
93 va_copy(args_copy, args);
94 length = vsnprintf(NULL, 0, format, args);
95 buffer = (char*)malloc(length + 1); /* +1 for NULL-terminator. */
96 result = vsnprintf(&buffer[0], length + 1, format, args_copy);
97 if (result != length) {
105 * Printf to a newly allocated C string.
106 * @param[in] format A print format string.
107 * @param[in] ... The printf arguments.
108 * @return The newly constructed string. Caller takes ownership.
110 char* PrintfToNewString(const char* format, ...) {
113 va_start(args, format);
114 result = VprintfToNewString(format, args);
120 * Printf to a new PP_Var.
121 * @param[in] format A print format string.
122 * @param[in] ... The printf arguments.
123 * @return A new PP_Var.
125 struct PP_Var PrintfToVar(const char* format, ...) {
126 if (ppb_var_interface != NULL) {
131 va_start(args, format);
132 string = VprintfToNewString(format, args);
135 var = ppb_var_interface->VarFromUtf8(string, strlen(string));
141 return PP_MakeUndefined();
145 * Convert a PP_Var to a C string, given a buffer.
146 * @param[in] var The PP_Var to convert.
147 * @param[out] buffer The buffer to write to.
148 * @param[in] length The length of |buffer|.
149 * @return The number of characters written.
151 uint32_t VarToCStr(struct PP_Var var, char* buffer, uint32_t length) {
152 if (ppb_var_interface != NULL) {
154 const char* str = ppb_var_interface->VarToUtf8(var, &var_length);
155 /* str is NOT NULL-terminated. Copy using memcpy. */
156 uint32_t min_length = MIN(var_length, length - 1);
157 memcpy(buffer, str, min_length);
158 buffer[min_length] = 0;
167 * Given a message from JavaScript, parse it for functions and parameters.
169 * The format of the message is:
170 * function, param1, param2, param3, etc.
171 * where each element is separated by the \1 character.
174 * "function\1first parameter\1second parameter"
179 * int num_params = ParseMessage(msg, &function, ¶ms, 4);
181 * @param[in, out] message The message to parse. This string is modified
183 * @param[out] out_function The function name.
184 * @param[out] out_params An array of strings, one for each parameter parsed.
185 * @param[in] max_params The maximum number of parameters to parse.
186 * @return The number of parameters parsed.
188 static size_t ParseMessage(char* message,
194 size_t num_params = 0;
196 /* Parse the message: function\1param1\1param2\1param3,... */
197 *out_function = &message[0];
199 separator = strchr(message, 1);
204 *separator = 0; /* NULL-terminate function. */
206 while (separator && num_params < max_params) {
207 param_start = separator + 1;
208 separator = strchr(param_start, 1);
211 out_params[num_params++] = param_start;
215 out_params[num_params++] = param_start;
221 * Given a function name, look up its handler function.
222 * @param[in] function_name The function name to look up.
223 * @return The handler function mapped to |function_name|.
225 static HandleFunc GetFunctionByName(const char* function_name) {
226 FuncNameMapping* map_iter = g_function_map;
227 for (; map_iter->name; ++map_iter) {
228 if (strcmp(map_iter->name, function_name) == 0) {
229 return map_iter->function;
237 * Handle as message from JavaScript on the worker thread.
239 * @param[in] message The message to parse and handle.
241 static void HandleMessage(char* message) {
243 char* params[MAX_PARAMS];
249 num_params = ParseMessage(message, &function_name, ¶ms[0], MAX_PARAMS);
251 function = GetFunctionByName(function_name);
253 /* Function name wasn't found. Error. */
254 ppb_messaging_interface->PostMessage(
256 PrintfToVar("Error: Unknown function \"%s\"", function_name));
260 /* Function name was found, call it. */
261 result = (*function)(num_params, ¶ms[0], &output);
265 if (output != NULL) {
266 var = PrintfToVar("Error: \"%s\" failed: %d: %s.", function_name,
271 "Error: \"%s\" failed: %d.", function_name, result);
274 /* Post the error to JavaScript, so the user can see it. */
275 ppb_messaging_interface->PostMessage(g_instance, var);
279 if (output != NULL) {
280 /* Function returned an output string. Send it to JavaScript. */
281 ppb_messaging_interface->PostMessage(g_instance, CStrToVar(output));
287 * A worker thread that handles messages from JavaScript.
288 * @param[in] user_data Unused.
291 void* HandleMessageThread(void* user_data) {
293 char* message = DequeueMessage();
294 HandleMessage(message);
299 static PP_Bool Instance_DidCreate(PP_Instance instance,
302 const char* argv[]) {
303 g_instance = instance;
304 nacl_io_init_ppapi(instance, get_browser_interface);
306 // By default, nacl_io mounts / to pass through to the original NaCl
307 // filesystem (which doesn't do much). Let's remount it to a memfs
310 mount("", "/", "memfs", 0, "");
312 mount("", /* source */
313 "/persistent", /* target */
314 "html5fs", /* filesystemtype */
316 "type=PERSISTENT,expected_size=1048576"); /* data */
318 mount("", /* source. Use relative URL */
319 "/http", /* target */
320 "httpfs", /* filesystemtype */
324 pthread_create(&g_handle_message_thread, NULL, &HandleMessageThread, NULL);
325 InitializeMessageQueue();
330 static void Instance_DidDestroy(PP_Instance instance) {}
332 static void Instance_DidChangeView(PP_Instance instance,
333 PP_Resource view_resource) {}
335 static void Instance_DidChangeFocus(PP_Instance instance, PP_Bool has_focus) {}
337 static PP_Bool Instance_HandleDocumentLoad(PP_Instance instance,
338 PP_Resource url_loader) {
339 /* NaCl modules do not need to handle the document load function. */
343 static void Messaging_HandleMessage(PP_Instance instance,
344 struct PP_Var message) {
346 VarToCStr(message, &buffer[0], 1024);
347 if (!EnqueueMessage(strdup(buffer))) {
350 "Warning: dropped message \"%s\" because the queue was full.", message);
351 ppb_messaging_interface->PostMessage(g_instance, var);
355 PP_EXPORT int32_t PPP_InitializeModule(PP_Module a_module_id,
356 PPB_GetInterface get_browser) {
357 get_browser_interface = get_browser;
358 ppb_messaging_interface =
359 (PPB_Messaging*)(get_browser(PPB_MESSAGING_INTERFACE));
360 ppb_var_interface = (PPB_Var*)(get_browser(PPB_VAR_INTERFACE));
364 PP_EXPORT const void* PPP_GetInterface(const char* interface_name) {
365 if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) {
366 static PPP_Instance instance_interface = {
368 &Instance_DidDestroy,
369 &Instance_DidChangeView,
370 &Instance_DidChangeFocus,
371 &Instance_HandleDocumentLoad,
373 return &instance_interface;
374 } else if (strcmp(interface_name, PPP_MESSAGING_INTERFACE) == 0) {
375 static PPP_Messaging messaging_interface = {
376 &Messaging_HandleMessage,
378 return &messaging_interface;
383 PP_EXPORT void PPP_ShutdownModule() {}