Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / examples / demo / nacl_io / nacl_io_demo.c
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.
4  */
5
6 #include "nacl_io_demo.h"
7
8 #include <assert.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/mount.h>
13 #include <pthread.h>
14
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"
25
26 #include "handlers.h"
27 #include "queue.h"
28
29 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
30
31 #if defined(WIN32)
32 #define va_copy(d, s) ((d) = (s))
33 #endif
34
35 typedef struct {
36   const char* name;
37   HandleFunc function;
38 } FuncNameMapping;
39
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;
44
45 static FuncNameMapping g_function_map[] = {
46   { "fopen", HandleFopen },
47   { "fwrite", HandleFwrite },
48   { "fread", HandleFread },
49   { "fseek", HandleFseek },
50   { "fclose", HandleFclose },
51   { "fflush", HandleFflush },
52   { "stat", HandleStat },
53   { "opendir", HandleOpendir },
54   { "readdir", HandleReaddir },
55   { "closedir", HandleClosedir },
56   { "mkdir", HandleMkdir },
57   { "rmdir", HandleRmdir },
58   { "chdir", HandleChdir },
59   { "getcwd", HandleGetcwd },
60   { "getaddrinfo", HandleGetaddrinfo },
61   { "gethostbyname", HandleGethostbyname },
62   { "connect", HandleConnect },
63   { "send", HandleSend },
64   { "recv", HandleRecv },
65   { "close", HandleClose },
66   { NULL, NULL },
67 };
68
69 /** A handle to the thread the handles messages. */
70 static pthread_t g_handle_message_thread;
71
72 /**
73  * Create a new PP_Var from a C string.
74  * @param[in] str The string to convert.
75  * @return A new PP_Var with the contents of |str|.
76  */
77 struct PP_Var CStrToVar(const char* str) {
78   if (ppb_var_interface != NULL) {
79     return ppb_var_interface->VarFromUtf8(str, strlen(str));
80   }
81   return PP_MakeUndefined();
82 }
83
84 /**
85  * Printf to a newly allocated C string.
86  * @param[in] format A printf format string.
87  * @param[in] args The printf arguments.
88  * @return The newly constructed string. Caller takes ownership. */
89 char* VprintfToNewString(const char* format, va_list args) {
90   va_list args_copy;
91   int length;
92   char* buffer;
93   int result;
94
95   va_copy(args_copy, args);
96   length = vsnprintf(NULL, 0, format, args);
97   buffer = (char*)malloc(length + 1); /* +1 for NULL-terminator. */
98   result = vsnprintf(&buffer[0], length + 1, format, args_copy);
99   if (result != length) {
100     assert(0);
101     return NULL;
102   }
103   return buffer;
104 }
105
106 /**
107  * Printf to a newly allocated C string.
108  * @param[in] format A print format string.
109  * @param[in] ... The printf arguments.
110  * @return The newly constructed string. Caller takes ownership.
111  */
112 char* PrintfToNewString(const char* format, ...) {
113   va_list args;
114   char* result;
115   va_start(args, format);
116   result = VprintfToNewString(format, args);
117   va_end(args);
118   return result;
119 }
120
121 /**
122  * Printf to a new PP_Var.
123  * @param[in] format A print format string.
124  * @param[in] ... The printf arguments.
125  * @return A new PP_Var.
126  */
127 struct PP_Var PrintfToVar(const char* format, ...) {
128   if (ppb_var_interface != NULL) {
129     char* string;
130     va_list args;
131     struct PP_Var var;
132
133     va_start(args, format);
134     string = VprintfToNewString(format, args);
135     va_end(args);
136
137     var = ppb_var_interface->VarFromUtf8(string, strlen(string));
138     free(string);
139
140     return var;
141   }
142
143   return PP_MakeUndefined();
144 }
145
146 /**
147  * Convert a PP_Var to a C string, given a buffer.
148  * @param[in] var The PP_Var to convert.
149  * @param[out] buffer The buffer to write to.
150  * @param[in] length The length of |buffer|.
151  * @return The number of characters written.
152  */
153 uint32_t VarToCStr(struct PP_Var var, char* buffer, uint32_t length) {
154   if (ppb_var_interface != NULL) {
155     uint32_t var_length;
156     const char* str = ppb_var_interface->VarToUtf8(var, &var_length);
157     /* str is NOT NULL-terminated. Copy using memcpy. */
158     uint32_t min_length = MIN(var_length, length - 1);
159     memcpy(buffer, str, min_length);
160     buffer[min_length] = 0;
161
162     return min_length;
163   }
164
165   return 0;
166 }
167
168 /**
169  * Given a message from JavaScript, parse it for functions and parameters.
170  *
171  * The format of the message is:
172  *   function, param1, param2, param3, etc.
173  * where each element is separated by the \1 character.
174  *
175  * e.g.
176  *   "function\1first parameter\1second parameter"
177  *
178  * How to use:
179  *   char* function;
180  *   char* params[4];
181  *   int num_params = ParseMessage(msg, &function, &params, 4);
182  *
183  * @param[in, out] message The message to parse. This string is modified
184  *     in-place.
185  * @param[out] out_function The function name.
186  * @param[out] out_params An array of strings, one for each parameter parsed.
187  * @param[in] max_params The maximum number of parameters to parse.
188  * @return The number of parameters parsed.
189  */
190 static size_t ParseMessage(char* message,
191                            char** out_function,
192                            char** out_params,
193                            size_t max_params) {
194   char* separator;
195   char* param_start;
196   size_t num_params = 0;
197
198   /* Parse the message: function\1param1\1param2\1param3,... */
199   *out_function = &message[0];
200
201   separator = strchr(message, 1);
202   if (!separator) {
203     return num_params;
204   }
205
206   *separator = 0; /* NULL-terminate function. */
207
208   while (separator && num_params < max_params) {
209     param_start = separator + 1;
210     separator = strchr(param_start, 1);
211     if (separator) {
212       *separator = 0;
213       out_params[num_params++] = param_start;
214     }
215   }
216
217   out_params[num_params++] = param_start;
218
219   return num_params;
220 }
221
222 /**
223  * Given a function name, look up its handler function.
224  * @param[in] function_name The function name to look up.
225  * @return The handler function mapped to |function_name|.
226  */
227 static HandleFunc GetFunctionByName(const char* function_name) {
228   FuncNameMapping* map_iter = g_function_map;
229   for (; map_iter->name; ++map_iter) {
230     if (strcmp(map_iter->name, function_name) == 0) {
231       return map_iter->function;
232     }
233   }
234
235   return NULL;
236 }
237
238 /**
239  * Handle as message from JavaScript on the worker thread.
240  *
241  * @param[in] message The message to parse and handle.
242  */
243 static void HandleMessage(char* message) {
244   char* function_name;
245   char* params[MAX_PARAMS];
246   size_t num_params;
247   char* output = NULL;
248   int result;
249   HandleFunc function;
250
251   num_params = ParseMessage(message, &function_name, &params[0], MAX_PARAMS);
252
253   function = GetFunctionByName(function_name);
254   if (!function) {
255     /* Function name wasn't found. Error. */
256     ppb_messaging_interface->PostMessage(
257         g_instance,
258         PrintfToVar("Error: Unknown function \"%s\"", function_name));
259     return;
260   }
261
262   /* Function name was found, call it. */
263   result = (*function)(num_params, &params[0], &output);
264   if (result != 0) {
265     /* Error. */
266     struct PP_Var var;
267     if (output != NULL) {
268       var = PrintfToVar("Error: \"%s\" failed: %d: %s.", function_name,
269                         result, output);
270       free(output);
271     } else {
272       var = PrintfToVar(
273           "Error: \"%s\" failed: %d.", function_name, result);
274     }
275
276     /* Post the error to JavaScript, so the user can see it. */
277     ppb_messaging_interface->PostMessage(g_instance, var);
278     return;
279   }
280
281   if (output != NULL) {
282     /* Function returned an output string. Send it to JavaScript. */
283     ppb_messaging_interface->PostMessage(g_instance, CStrToVar(output));
284     free(output);
285   }
286 }
287
288 /**
289  * A worker thread that handles messages from JavaScript.
290  * @param[in] user_data Unused.
291  * @return unused.
292  */
293 void* HandleMessageThread(void* user_data) {
294   while (1) {
295     char* message = DequeueMessage();
296     HandleMessage(message);
297     free(message);
298   }
299 }
300
301 static PP_Bool Instance_DidCreate(PP_Instance instance,
302                                   uint32_t argc,
303                                   const char* argn[],
304                                   const char* argv[]) {
305   g_instance = instance;
306   nacl_io_init_ppapi(instance, get_browser_interface);
307
308   // By default, nacl_io mounts / to pass through to the original NaCl
309   // filesystem (which doesn't do much). Let's remount it to a memfs
310   // filesystem.
311   umount("/");
312   mount("", "/", "memfs", 0, "");
313
314   mount("",                                       /* source */
315         "/persistent",                            /* target */
316         "html5fs",                                /* filesystemtype */
317         0,                                        /* mountflags */
318         "type=PERSISTENT,expected_size=1048576"); /* data */
319
320   mount("",       /* source. Use relative URL */
321         "/http",  /* target */
322         "httpfs", /* filesystemtype */
323         0,        /* mountflags */
324         "");      /* data */
325
326   pthread_create(&g_handle_message_thread, NULL, &HandleMessageThread, NULL);
327   InitializeMessageQueue();
328
329   return PP_TRUE;
330 }
331
332 static void Instance_DidDestroy(PP_Instance instance) {}
333
334 static void Instance_DidChangeView(PP_Instance instance,
335                                    PP_Resource view_resource) {}
336
337 static void Instance_DidChangeFocus(PP_Instance instance, PP_Bool has_focus) {}
338
339 static PP_Bool Instance_HandleDocumentLoad(PP_Instance instance,
340                                            PP_Resource url_loader) {
341   /* NaCl modules do not need to handle the document load function. */
342   return PP_FALSE;
343 }
344
345 static void Messaging_HandleMessage(PP_Instance instance,
346                                     struct PP_Var message) {
347   char buffer[1024];
348   VarToCStr(message, &buffer[0], 1024);
349   if (!EnqueueMessage(strdup(buffer))) {
350     struct PP_Var var;
351     var = PrintfToVar(
352         "Warning: dropped message \"%s\" because the queue was full.", message);
353     ppb_messaging_interface->PostMessage(g_instance, var);
354   }
355 }
356
357 PP_EXPORT int32_t PPP_InitializeModule(PP_Module a_module_id,
358                                        PPB_GetInterface get_browser) {
359   get_browser_interface = get_browser;
360   ppb_messaging_interface =
361       (PPB_Messaging*)(get_browser(PPB_MESSAGING_INTERFACE));
362   ppb_var_interface = (PPB_Var*)(get_browser(PPB_VAR_INTERFACE));
363   return PP_OK;
364 }
365
366 PP_EXPORT const void* PPP_GetInterface(const char* interface_name) {
367   if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) {
368     static PPP_Instance instance_interface = {
369       &Instance_DidCreate,
370       &Instance_DidDestroy,
371       &Instance_DidChangeView,
372       &Instance_DidChangeFocus,
373       &Instance_HandleDocumentLoad,
374     };
375     return &instance_interface;
376   } else if (strcmp(interface_name, PPP_MESSAGING_INTERFACE) == 0) {
377     static PPP_Messaging messaging_interface = {
378       &Messaging_HandleMessage,
379     };
380     return &messaging_interface;
381   }
382   return NULL;
383 }
384
385 PP_EXPORT void PPP_ShutdownModule() {}