- add sources.
[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   {"stat", HandleStat},
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},
61   {"send", HandleSend},
62   {"recv", HandleRecv},
63   {"close", HandleClose},
64   {NULL, NULL},
65 };
66
67 /** A handle to the thread the handles messages. */
68 static pthread_t g_handle_message_thread;
69
70 /**
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|.
74  */
75 struct PP_Var CStrToVar(const char* str) {
76   if (ppb_var_interface != NULL) {
77     return ppb_var_interface->VarFromUtf8(str, strlen(str));
78   }
79   return PP_MakeUndefined();
80 }
81
82 /**
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) {
88   va_list args_copy;
89   int length;
90   char* buffer;
91   int result;
92
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) {
98     assert(0);
99     return NULL;
100   }
101   return buffer;
102 }
103
104 /**
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.
109  */
110 char* PrintfToNewString(const char* format, ...) {
111   va_list args;
112   char* result;
113   va_start(args, format);
114   result = VprintfToNewString(format, args);
115   va_end(args);
116   return result;
117 }
118
119 /**
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.
124  */
125 struct PP_Var PrintfToVar(const char* format, ...) {
126   if (ppb_var_interface != NULL) {
127     char* string;
128     va_list args;
129     struct PP_Var var;
130
131     va_start(args, format);
132     string = VprintfToNewString(format, args);
133     va_end(args);
134
135     var = ppb_var_interface->VarFromUtf8(string, strlen(string));
136     free(string);
137
138     return var;
139   }
140
141   return PP_MakeUndefined();
142 }
143
144 /**
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.
150  */
151 uint32_t VarToCStr(struct PP_Var var, char* buffer, uint32_t length) {
152   if (ppb_var_interface != NULL) {
153     uint32_t var_length;
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;
159
160     return min_length;
161   }
162
163   return 0;
164 }
165
166 /**
167  * Given a message from JavaScript, parse it for functions and parameters.
168  *
169  * The format of the message is:
170  *   function, param1, param2, param3, etc.
171  * where each element is separated by the \1 character.
172  *
173  * e.g.
174  *   "function\1first parameter\1second parameter"
175  *
176  * How to use:
177  *   char* function;
178  *   char* params[4];
179  *   int num_params = ParseMessage(msg, &function, &params, 4);
180  *
181  * @param[in, out] message The message to parse. This string is modified
182  *     in-place.
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.
187  */
188 static size_t ParseMessage(char* message,
189                            char** out_function,
190                            char** out_params,
191                            size_t max_params) {
192   char* separator;
193   char* param_start;
194   size_t num_params = 0;
195
196   /* Parse the message: function\1param1\1param2\1param3,... */
197   *out_function = &message[0];
198
199   separator = strchr(message, 1);
200   if (!separator) {
201     return num_params;
202   }
203
204   *separator = 0; /* NULL-terminate function. */
205
206   while (separator && num_params < max_params) {
207     param_start = separator + 1;
208     separator = strchr(param_start, 1);
209     if (separator) {
210       *separator = 0;
211       out_params[num_params++] = param_start;
212     }
213   }
214
215   out_params[num_params++] = param_start;
216
217   return num_params;
218 }
219
220 /**
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|.
224  */
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;
230     }
231   }
232
233   return NULL;
234 }
235
236 /**
237  * Handle as message from JavaScript on the worker thread.
238  *
239  * @param[in] message The message to parse and handle.
240  */
241 static void HandleMessage(char* message) {
242   char* function_name;
243   char* params[MAX_PARAMS];
244   size_t num_params;
245   char* output = NULL;
246   int result;
247   HandleFunc function;
248
249   num_params = ParseMessage(message, &function_name, &params[0], MAX_PARAMS);
250
251   function = GetFunctionByName(function_name);
252   if (!function) {
253     /* Function name wasn't found. Error. */
254     ppb_messaging_interface->PostMessage(
255         g_instance,
256         PrintfToVar("Error: Unknown function \"%s\"", function_name));
257     return;
258   }
259
260   /* Function name was found, call it. */
261   result = (*function)(num_params, &params[0], &output);
262   if (result != 0) {
263     /* Error. */
264     struct PP_Var var;
265     if (output != NULL) {
266       var = PrintfToVar("Error: \"%s\" failed: %d: %s.", function_name,
267                         result, output);
268       free(output);
269     } else {
270       var = PrintfToVar(
271           "Error: \"%s\" failed: %d.", function_name, result);
272     }
273
274     /* Post the error to JavaScript, so the user can see it. */
275     ppb_messaging_interface->PostMessage(g_instance, var);
276     return;
277   }
278
279   if (output != NULL) {
280     /* Function returned an output string. Send it to JavaScript. */
281     ppb_messaging_interface->PostMessage(g_instance, CStrToVar(output));
282     free(output);
283   }
284 }
285
286 /**
287  * A worker thread that handles messages from JavaScript.
288  * @param[in] user_data Unused.
289  * @return unused.
290  */
291 void* HandleMessageThread(void* user_data) {
292   while (1) {
293     char* message = DequeueMessage();
294     HandleMessage(message);
295     free(message);
296   }
297 }
298
299 static PP_Bool Instance_DidCreate(PP_Instance instance,
300                                   uint32_t argc,
301                                   const char* argn[],
302                                   const char* argv[]) {
303   g_instance = instance;
304   nacl_io_init_ppapi(instance, get_browser_interface);
305
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
308   // filesystem.
309   umount("/");
310   mount("", "/", "memfs", 0, "");
311
312   mount("",                                       /* source */
313         "/persistent",                            /* target */
314         "html5fs",                                /* filesystemtype */
315         0,                                        /* mountflags */
316         "type=PERSISTENT,expected_size=1048576"); /* data */
317
318   mount("",       /* source. Use relative URL */
319         "/http",  /* target */
320         "httpfs", /* filesystemtype */
321         0,        /* mountflags */
322         "");      /* data */
323
324   pthread_create(&g_handle_message_thread, NULL, &HandleMessageThread, NULL);
325   InitializeMessageQueue();
326
327   return PP_TRUE;
328 }
329
330 static void Instance_DidDestroy(PP_Instance instance) {}
331
332 static void Instance_DidChangeView(PP_Instance instance,
333                                    PP_Resource view_resource) {}
334
335 static void Instance_DidChangeFocus(PP_Instance instance, PP_Bool has_focus) {}
336
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. */
340   return PP_FALSE;
341 }
342
343 static void Messaging_HandleMessage(PP_Instance instance,
344                                     struct PP_Var message) {
345   char buffer[1024];
346   VarToCStr(message, &buffer[0], 1024);
347   if (!EnqueueMessage(strdup(buffer))) {
348     struct PP_Var var;
349     var = PrintfToVar(
350         "Warning: dropped message \"%s\" because the queue was full.", message);
351     ppb_messaging_interface->PostMessage(g_instance, var);
352   }
353 }
354
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));
361   return PP_OK;
362 }
363
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 = {
367       &Instance_DidCreate,
368       &Instance_DidDestroy,
369       &Instance_DidChangeView,
370       &Instance_DidChangeFocus,
371       &Instance_HandleDocumentLoad,
372     };
373     return &instance_interface;
374   } else if (strcmp(interface_name, PPP_MESSAGING_INTERFACE) == 0) {
375     static PPP_Messaging messaging_interface = {
376       &Messaging_HandleMessage,
377     };
378     return &messaging_interface;
379   }
380   return NULL;
381 }
382
383 PP_EXPORT void PPP_ShutdownModule() {}