I'm trying to read a file in order to perform certain actions on the binary data before sending it to a server.
At a certain point I'm trying to convert the data returned by FileReader.readAsArrayBuffer() to an Uint16Array(). However upon doing so the code allocating the array fails with: 'Error: invalid arguments'. I need the data to be a hex string representing the entire binary.
This is the code I'm using:
function HexToHexString(ByteBuffer)
{
//Similar constructs like: 'var Array = new Uint16Array(ByteBuffer);' also fail
var View = new DataView(ByteBuffer);
var Array = new Uint16Array((ByteBuffer.byteLength / 2)); // <- this line fails
for(var i = 0; i < Array.length; i++)
{
Array[i] = View.getUint16(i*2);
}
return String.fromCharCode.apply(null, Array);
}
function OnReadFileCompletion(FileReadEvent)
{
if(FileReadEvent.target.readyState == FileReader.DONE)
{
// Debug code, will be replaced:
document.getElementById('byte_content').textContent = HexToHexString(FileReadEvent.target.result);
//FileReadEvent.target.result;
}
}
function ReadFile(File, ResultFunction)
{
var Reader = new FileReader();
Reader.onloadend = ResultFunction;
Reader.readAsArrayBuffer(File.slice(0, File.size - 1));
}
File Is a file object, ResultFunction is OnReadFileCompletion(), ByteBuffer is an '[object ArrayBuffer]'.
When I output the size of the ArrayBuffer it matches the size of the file (82kb). I'm on firefox 32 with no plugins installed.
I'm not a javascript programmer, does anyone know what I'm doing wrong?
Edit1:
It appears to have something to-do with the size of the file I'm trying to read, using a 1kb text file appears to work while a 82kb binary file does not.
Edit2
I spoke too soon, perhaps it has something to do with file types. An image file of 200kb works, while an executable of 82 does not.
It appears that javascript does not allow executable files to be accesed this way, does anybody know of any way where I could possibly access the data in hex form?
try using .length instead of byteLength
I've hacked together code that works for me, I don't know why this works or what I did wrong the other time. But it works.
function ApplyPadding(Number, PaddingLength)
{
var s = Number + "";
while (s.length < PaddingLength)
s = "0" + s;
return s;
}
function HexToHexString(ByteBuffers)
{
var AnArray = new Uint8Array(ByteBuffers);
var Result = "";
for(var i = 0; i < AnArray.length; i++)
{
if(i%2==0)
Result += ApplyPadding(AnArray[i].toString(16), 2);
}
return Result;
}
function HexStringToHex(aString)
{
var Buffer = new ArrayBuffer(aString.length*2); // 2 bytes for each char
var BufferView = new Uint16Array(Buffer);
for (var i = 0;i < aString.length; i++)
{
BufferView[i] = aString.charCodeAt(i);
}
return Buffer;
}
function OnReadFileCompletion(FileReadEvent)
{
if(FileReadEvent.target.readyState == FileReader.DONE)
{
//document.getElementById('byte_content').textContent =FileReadEvent.target.result;
var DataOfFile = HexStringToHex(FileReadEvent.target.result);
var FinalData = HexToHexString(DataOfFile);
document.getElementById('byte_content').textContent = FinalData;
//FileReadEvent.target.result;
}
}
function ReadFile(File, ResultFunction)
{
var Reader = new FileReader();
Reader.onloadend = ResultFunction;
Reader.readAsBinaryString(File.slice(0, File.size - 1));
}
Related
I'm working in an Javascript application that receives a base64 array. This array encodes a 16 bits per pixel raw image.
Thus, I would like to do some calculations in it. For this, I need to unpack this Base64 string in a Uint16Array, so I can iterate over pixels and perform the required calculations.
What are my options for doing that?
After some hours looking for a solution, I found a way for doing this:
function getData()
{
fetch("test_data/img_base64.txt")
.then(res => res.text())
.then((out) => {
rawString = window.atob(out);
uint8Array = new Uint8Array(rawString.length);
for(var i = 0; i < rawString.length; i++)
{
uint8Array[i] = rawString.charCodeAt(i);
}
uint16Array = new Uint16Array(uint8Array.buffer);
console.log(uint16Array);
})
.catch(err => { throw err });
}
First I fetch my base64 string from a file. Then using window.atob it is converted to a JavaScript string. After this, I need to fill a Uint8Array with every byte loaded from the string. Finally, I had to convert this Uint8Array, into the final Uint16Array.
That was tough to achieve exactly what I was looking. But I have found it.
You can use this function that converts a base64 string into a binary Uint16 Array
var BASE64_MARKER = ';base64,';
function convertDataURIToBinary(dataURI) {
var base64Index = dataURI.indexOf(BASE64_MARKER) + BASE64_MARKER.length;
var base64 = dataURI.substring(base64Index);
var raw = window.atob(base64);
var rawLength = raw.length;
var array = new Uint16Array(new ArrayBuffer(rawLength));
for(i = 0; i < rawLength; i++) {
array[i] = raw.charCodeAt(i);
}
return array;
}
If you're targeting Firefox and feeling adventurous you can shorten the function down to this:
var BASE64_MARKER = ';base64,';
function convertDataURIToBinaryFF(dataURI) {
var base64Index = dataURI.indexOf(BASE64_MARKER) + BASE64_MARKER.length;
var raw = window.atob(dataURI.substring(base64Index));
return Uint8Array.from(Array.prototype.map.call(raw, function(x) {
return x.charCodeAt(0);
}));
};
The examples I've seen show essentially this:
fetch('simple.wasm').then(response =>
response.arrayBuffer()
).then(bytes =>
WebAssembly.instantiate(bytes, {})
).then(result =>
result.instance.exports...
)
But I would like to do it without making that extra HTTP request. Wondering if the only way is this (or some variation of it, which would be helpful to know):
var binary = '...mywasmbinary...'
var buffer = new ArrayBuffer(binary.length)
var view = new DataView(buffer)
for (var i = 0, n = binary.length; i < n; i++) {
var x = binary[i]
view.setInt8(i * 8, x)
}
Wondering if I have to worry about endianess or anything like that.
Or perhaps doing something with URL and blobs might be better, I'm not sure.
Yes, you are correct, in order to inline wasm modules and avoid the HTTP request, you'll have to perform some sort of encoding. I'd recommend using Base64 encoded strings as they are the most compact form.
You can encode as follows:
const readFileSync = require('fs').readFileSync;
const wasmCode = readFileSync(id);
const encoded = Buffer.from(wasmCode, 'binary').toString('base64');
You can then load the module as follows:
var encoded = "... contents of encoded from above ...";
function asciiToBinary(str) {
if (typeof atob === 'function') {
// this works in the browser
return atob(str)
} else {
// this works in node
return new Buffer(str, 'base64').toString('binary');
}
}
function decode(encoded) {
var binaryString = asciiToBinary(encoded);
var bytes = new Uint8Array(binaryString.length);
for (var i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return bytes.buffer;
}
var module = WebAssembly.instantiate(decode(encoded), {});
I try to make a javascript code for ImageJ, wich have to goal to allow me to select a directory, and return me all jpg and jpeg file in the directory and sub-directory.
I have do this code, it's work well for direct children, he call well getJpeg on subdirectories (I have verify it with some IJ.log), but the jpeg Array is not concat with result of recursives call
Have you an idea?
importClass(Packages.ij.IJ);
importClass(Packages.ij.plugin.frame.RoiManager);
importClass(Packages.ij.gui.GenericDialog);
importClass(Packages.ij.io.OpenDialog);
importClass(Packages.java.io.File);
var dirstr = IJ.getDirectory("Choose the stacks folder");
var jpeg = getJpeg(dirstr);
for (var i = 0; i < jpeg.length; i++) {
IJ.log(jpeg[i]);
}
function getJpeg(dirst) {
var dir = new java.io.File(dirst);
var names = dir.listFiles();
var jpeg = new Array();
for (var i = 0 ; i < names.length; i++) {
if(names[i].isDirectory()){
jpeg.concat(getJpeg(names[i].getPath()));
continue;
}
var namest = names[i].getName();
if (namest.match(/.*\.jpg|jpeg/)) {
var path = names[i].getPath();
jpeg.push(path);
}
}
return jpeg;
}
Thank you :)
The problem come from a missread from concat documentation ( w3schools.com/jsreF/jsref_concat_array.asp ). Have to put
jpeg = jpeg.concat(getJpeg(names[i].getPath()));
i am writing a chrome app, and i want to send some strings over UDP to some server. i'm new to javascript and i'm kinda stuck. this is a snippet of the code:
var wholeString = "what is the meaning of life";
chrome.sockets.udp.create({}, function (socketInfo) {
// The socket is created, now we can send some data
var socketId = socketInfo['socketId'];
var arrayBuffer = stringToArrayBuffer("hello");
chrome.sockets.udp.bind(socketId, "127.0.0.1", 0, function (result) {
chrome.sockets.udp.send(socketId, stringToArrayBuffer(wholeString), "127.0.0.1", 3050, function (sendInfo) {
console.log("sent " + sendInfo.bytesSent);
if (sendInfo.resultCode < 0) {
console.log("Error listening: " + chrome.runtime.lastError.message);
}
});
});
});
the problem lies when i try to send(), and the argument stringToArrayBuffer(wholeString) is problematic. the stringToArrayBuffer() is here:
function stringToArrayBuffer(string) {
var arrayBuffer = new ArrayBuffer(string.length * 2);
var buffer = new Uint8Array(arrayBuffer);
for (var i = 0, stringLength = string.length; i < stringLength; i++) {
buffer = string.charCodeAt(i);
}
return buffer;
}
The error message i get is:
Error in response to sockets.udp.bind: Error: Invocation of form sockets.udp.send(integer, integer, string, integer, function) doesn't match definition sockets.udp.send(integer socketId, binary data, string address, integer port, function callback)
at Object.callback (chrome-extension://pmkjeflkfhfekliappbhemngaejmnbec/helper.js:45:24)
at Object.callback (chrome-extension://pmkjeflkfhfekliappbhemngaejmnbec/helper.js:42:23)
i thought the function will change my string to a byte array? whats wrong??
There's a tiny mistake in your stringToArrayBuffer function.
function stringToArrayBuffer(string) {
var arrayBuffer = new ArrayBuffer(string.length * 2);
var buffer = new Uint8Array(arrayBuffer);
for (var i = 0, stringLength = string.length; i < stringLength; i++) {
buffer[i] = string.charCodeAt(i);
// Was: buffer = string.charCodeAt(i);
}
return buffer;
}
So you were overwriting the binary array with just one integer value.
I am not sure it's the only problem though. Why are you using Uint8 instead of Uint16? See this guide linked from Chrome docs.
I'm having trouble passing a WCHAR_T to ReadProcessMemory
This is how to succesfully pass a pointers address to ReadProcessMemory, I can do it with structures:
remote_tbb = ralloc_alloc(struct_TBButton.size);
var rez = SendMessage(hToolbar, TB_GETBUTTON, i, ctypes.voidptr_t(remote_tbb));
if (!rez) { throw new Error('Failed on SendMessage of TB_GETBUTTON') }
var local_tbb = new struct_TBButton();
var retRead = ralloc_read(remote_tbb, local_tbb.address());
var freed = ralloc_free(remote_tbb);
But now I need to do with WCHAR_T, so this is what I have:
var chars = SendMessage(hToolbar, TB_GETBUTTONTEXTW, local_tbb.idCommand, ctypes.voidptr_t(0));
console.log('chars=', chars, chars.toString(), uneval(chars));
if (chars && parseInt(chars.toString()) > 0) {
var remote_buf = ralloc_alloc(parseInt(chars.toString()));
var charsRe = SendMessage(hToolbar, TB_GETBUTTONTEXTW, local_tbb.idCommand, ctypes.voidptr_t(remote_buf));
console.log('charsRe=', charsRe);
var local_buf = ctypes.jschar; //WCHAR_T
var retRead = ralloc_read(remote_buf, local_buf.address()); ///PROBLEM LINE
console.log('retRead=', retRead);
var freed = ralloc_free(remote_buf);
console.log('freed=', freed);
console.log('Button Text = ', local_buf, local_buf.toString());
} else {
console.log('Button Text = NONE');
}
So my problem is on line:
var retRead = ralloc_read(remote_buf, local_buf.address());`
and it is specifically on the local_buf.address()
Errors in my experimenting that get thrown are:
expected type pointer, got ctypes.jschar
local_buf.address is not a function
So how to pass WCHAR_T as reference?
Edit:
Here is my ralloc_read implemetnation:
function ralloc_read(remote_address, local_buffer) {
var found_addr;
for (var i = 0; i < buffers.length; i++) {
if (buffers[i][0] == remote_address) {
found_addr = buffers[i]
break;
}
}
if (!found_addr) {
return null;
}
/*using the found remote address(found_addr[0]),
*i read size bytes (found_addr[1]) into my local_buffer*/
//console.info('found_addr[0]', found_addr[0].toString());
var rez = ReadProcessMemory(proc, found_addr[0], local_buffer, found_addr[1], 0);
return rez;
}
If ralloc_read calls ReadProcessMemory, then you'll need to allocate a jschar array that will receive the result.
var local_buf = ctypes.jschar.array()(chars);
ralloc_read(remote_buf, local_buf.address());
var str = local_buf.readString();
Edit However, the allocation call is wrong:
ralloc_alloc(parseInt(chars.toString()));
This will allocate chars bytes, e.g. chars = 11, 11 bytes.
A wchar_t/jschar however is not 1 byte but 2 bytes.
ctypes.jschar.size
// 2
So you'll actually need to allocate a remote memory buffer that is larger:
ralloc_alloc(parseInt(chars.toString()) * ctypes.jschar.size);
// That would be ralloc_alloc(count * sizeof(wchar_t*)) in C/C++
The local_buf stuff is correct, though as js-ctypes arrays will automatically calculate the required storage if it knows the size of the array element type, so a ctypes.jschar.array()(11) buffer will actually have 11 elements of size 2 bytes, i.e. 11 items * 2 bytes/item == 22 bytes.