PS: I bet this is the reason you binary files get mangled:

binaryString = String.fromCharCode.apply(null, array);

I'm not sure what exactly that line does, but there's probably some 
conversion between string encodings happening, and if you throw binary data 
at it, it will try to interpret that as some string encoded, and transform 
that into something else.

If you use FileReader.readAsArrayBuffer(), you can put the loaded data 
directly as binary blob into an Uint8Array:

    reader.onload = function(loadEvent) {
    var content = loadEvent.target.result;
    if (content) {
         var uint8Array = new Uint8Array(content);
         ....


On Friday, 7 September 2018 12:14:06 UTC+2, Floh wrote:
>
> I'm doing exactly that in my YAKC emulator: 
> http://floooh.github.io/virtualkc/ (click on hamburger-menu icon -> load 
> file... -> "Load" button).
>
> The file picker HTML element is here: 
> https://github.com/floooh/yakc/blob/master/web/_includes/load-panel.html#L1
>
> The 'load_files()' JS function is called when the user has selected a file 
> (also when drag'n'dropped a file into the load panel): 
> https://github.com/floooh/yakc/blob/master/web/emsc.js#L141
>
> And here's the C function that takes the file content as a pointer/length 
> pair: https://github.com/floooh/yakc/blob/master/src/yakcapp/Main.cc#L463
>
> Btw, a much nicer alternative to emscripten_runscript() for embedding JS 
> code into the C source is via EM_JS():
>
> See here for instance: 
> https://github.com/floooh/chips-test/blob/bbe01867b9a3e06094c2805174294de99812addb/examples/common/args.h#L94-L105
>
> You can call this 'inline' JS function like a normal C function: 
> https://github.com/floooh/chips-test/blob/bbe01867b9a3e06094c2805174294de99812addb/examples/common/args.h#L114
>
> Hope this helps!
> -Floh
>
> On Thursday, 6 September 2018 20:07:25 UTC+2, Treyten Carey wrote:
>>
>> Hi,
>>
>> This isn't necessarily an Emscripten issue but I thought this was a good 
>> place for this question since I need to call C from JavaScript through 
>> Emscripten.
>>
>> *What I'm trying to do:*
>> The user should be able to select a WebGL button. The button calls an 
>> HTML input file which brings up File Explorer to select a file (such as a 
>> txt file or image). When the user selects a file (including a binary file), 
>> the contents get sent from JavaScript to C, where C then writes the file to 
>> the Emscripten local file system directory and where I should be able to 
>> send the contents of the file over C sockets (this is why I need to be able 
>> to get binary file contents, because I will be doing things with it in C).
>>
>> *What I've tried:*
>> My HTML has an input element:
>> <input id="file-input" type="file" name="name" style="display: none;"/>
>>
>> In my C code, when the user presses the WebGL button, I select the 
>> file-input element to open the file selection:
>> emscripten_run_script(
>>         (char*)((std::string)
>>         "document.getElementById('file-input').click(); " +
>>         "var fileCont; " +
>>         "var reader = new FileReader(); " +
>>         "reader.onloadend = function(evt) { " +
>>         "   if (evt.target.readyState == FileReader.DONE) { " +
>>         "       fileCont = evt.target.result; " +
>>         "   } " +
>>         "   var arrayBuffer = this.result, " +
>>         "     array = new Uint32Array(arrayBuffer), " +
>>         "     binaryString = String.fromCharCode.apply(null, array); " +
>>         "   Module.ccall('EM_gotOpenFileName', null,  ['string', 
>> 'string', 'number'], [document.getElementById('file-input').value, 
>> binaryString, arrayBuffer.byteLength]); " +
>>         "}; " +
>>         
>> "reader.readAsArrayBuffer(document.getElementById('file-input').files[0]); "
>>     ).c_str());
>>
>> Which then calls my C function where I do stuff with the file content:
>> extern "C"
>> {
>>     EMSCRIPTEN_KEEPALIVE void EM_gotOpenFileName(char* fileName, char* 
>> cont, int len)
>>     {
>>         // Store the file in a temporary location so we can read it later 
>> if we need to.
>>         // JavaScript doesn't allow us to grab it's location, so we must 
>> do it this way.
>>         std::string tempFile = fileName;
>>
>>         // Getting the file's name without any directories. i.e 
>> "C:/fakepath/file.png" will turn into "file.png"
>>         std::vector<std::string> tkns = findTokens("/", tempFile);
>>         tempFile = tkns[tkns.size()-1];
>>         tkns = Operations::findTokens("\\", tempFile);
>>         tempFile = tkns[tkns.size()-1];
>>         tempFile = (std::string)".temp/" + tempFile;
>>
>>         writeFile(tempFile, cont, len); // write the file. assume this 
>> works fine using fwrite.
>>
>>         // ...
>>     }
>> }
>>
>> *What's (not) working:*
>> Text files are writing correctly and being transferred with no problems.
>> Binary files, such as images, are not. The data written looks different 
>> than the actual file selected, though they have the same number of bytes.
>> In JavaScript, I've tried using Uint8Array and Uint16Array. Uint32Array 
>> errors "Invalid offset/length when creating typed array", and 
>> Uint64Array doesn't exist.
>>
>> --
>>
>> Is there something I am doing wrong, or some other way I should read a 
>> file (like an image's) contents?
>> I need to be able to load the data (including binary data from an image) 
>> into memory that I can do stuff with in C.
>>
>> Thanks,
>>
>>
>>

-- 
You received this message because you are subscribed to the Google Groups 
"emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to