-
Notifications
You must be signed in to change notification settings - Fork 4
/
emscripten_browser_file.h
97 lines (76 loc) · 4.53 KB
/
emscripten_browser_file.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#ifndef EMSCRIPTEN_UPLOAD_FILE_H_INCLUDED
#define EMSCRIPTEN_UPLOAD_FILE_H_INCLUDED
#include <string>
#include <emscripten.h>
#define _EM_JS_INLINE(ret, c_name, js_name, params, code) \
extern "C" { \
ret c_name params EM_IMPORT(js_name); \
EMSCRIPTEN_KEEPALIVE \
__attribute__((section("em_js"), aligned(1))) inline char __em_js__##js_name[] = \
#params "<::>" code; \
}
#define EM_JS_INLINE(ret, name, params, ...) _EM_JS_INLINE(ret, name, name, params, #__VA_ARGS__)
namespace emscripten_browser_file {
/////////////////////////////////// Interface //////////////////////////////////
using upload_handler = void(*)(std::string const&, std::string const&, std::string_view buffer, void*);
inline void upload(std::string const &accept_types, upload_handler callback, void *callback_data = nullptr);
inline void download(std::string const &filename, std::string const &mime_type, std::string_view buffer);
///////////////////////////////// Implementation ///////////////////////////////
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmissing-variable-declarations"
EM_JS_INLINE(void, upload, (char const *accept_types, upload_handler callback, void *callback_data), {
/// Prompt the browser to open the file selector dialogue, and pass the file to the given handler
/// Accept-types are in the format ".png,.jpeg,.jpg" as per https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept
/// Upload handler callback signature is:
/// void my_handler(std::string const &filename, std::string const &mime_type, std::string_view buffer, void *callback_data = nullptr);
globalThis["open_file"] = function(e) {
const file_reader = new FileReader();
file_reader.onload = (event) => {
const uint8Arr = new Uint8Array(event.target.result);
const data_ptr = Module["_malloc"](uint8Arr.length);
const data_on_heap = new Uint8Array(Module["HEAPU8"].buffer, data_ptr, uint8Arr.length);
data_on_heap.set(uint8Arr);
Module["ccall"]('upload_file_return', 'number', ['string', 'string', 'number', 'number', 'number', 'number'], [event.target.filename, event.target.mime_type, data_on_heap.byteOffset, uint8Arr.length, callback, callback_data]);
Module["_free"](data_ptr);
};
file_reader.filename = e.target.files[0].name;
file_reader.mime_type = e.target.files[0].type;
file_reader.readAsArrayBuffer(e.target.files[0]);
};
var file_selector = document.createElement('input');
file_selector.setAttribute('type', 'file');
file_selector.setAttribute('onchange', 'globalThis["open_file"](event)');
file_selector.setAttribute('accept', UTF8ToString(accept_types));
file_selector.click();
});
#pragma GCC diagnostic pop
inline void upload(std::string const &accept_types, upload_handler callback, void *callback_data) {
/// C++ wrapper for javascript upload call
upload(accept_types.c_str(), callback, callback_data);
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmissing-variable-declarations"
EM_JS_INLINE(void, download, (char const *filename, char const *mime_type, void const *buffer, size_t buffer_size), {
/// Offer a buffer in memory as a file to download, specifying download filename and mime type
var a = document.createElement('a');
a.download = UTF8ToString(filename);
a.href = URL.createObjectURL(new Blob([new Uint8Array(Module["HEAPU8"].buffer, buffer, buffer_size)], {type: UTF8ToString(mime_type)}));
a.click();
});
#pragma GCC diagnostic pop
inline void download(std::string const &filename, std::string const &mime_type, std::string_view buffer) {
/// C++ wrapper for javascript download call, accepting a string_view
download(filename.c_str(), mime_type.c_str(), buffer.data(), buffer.size());
}
namespace {
extern "C" {
EMSCRIPTEN_KEEPALIVE inline int upload_file_return(char const *filename, char const *mime_type, char *buffer, size_t buffer_size, upload_handler callback, void *callback_data);
EMSCRIPTEN_KEEPALIVE inline int upload_file_return(char const *filename, char const *mime_type, char *buffer, size_t buffer_size, upload_handler callback, void *callback_data) {
/// Load a file - this function is called from javascript when the file upload is activated
callback(filename, mime_type, {buffer, buffer_size}, callback_data);
return 1;
}
}
}
}
#endif // EMSCRIPTEN_UPLOAD_FILE_H_INCLUDED