Empty Buffer when read char pointer data using node-ffi - node-ffi

The DLL file was developed in Delphi. The Function was described as bellow:
Function name: GetMsg
Function description: It is used to get error
info.
Function prototype: procedure GetMsg(ret: Integer; var Msg:
PChar); stdcall;
Parameter description: ret: It indicates error code. Msg: It is used
to output the corresponding error info.
Firstly, you need to allocate
memory. The memory is greater than or equal to 255.
According to the description, I know Msg parameter is a pointer, then I use node-ffi to invoke the GetMsg procedure as bellow:
var ffi = require('ffi');
var ref = require('ref');
var TheLib = ffi.Library('TheLib.dll', {
GetMsg: ['void', ['int', ref.types.CString]]
});
const outNameBuffer = Buffer.alloc(255);
TheLib.GetMsg(-25, outNameBuffer);
console.log(outNameBuffer, ref.readCString(outNameBuffer));
I always get this response:
Note that, I i use ctypes in Python, I could get a Chinese message corresponding to the value -25.
Any suggestion on this?

I had about the same problem, try my solution:
var ffi = require('ffi');
var ref = require('ref');
var ArrayType = require('ref-array');
var charPtrArray = ArrayType('char *', 64);
var charPtrArrayPtr = ref.refType(charPtrArray);
var TheLib = ffi.Library('TheLib.dll', {
GetMsg: ['void', ['int', charPtrArrayPtr]
});
console.log(charPtrArrayPtr);

Related

Problem assigning 'doJavaScript' return value to a variable (array)

I'm experimenting with JXA and trying to 'port' a small script, which parses track names from the web page. This script is currently working as Keyboard Maestro macro and is executed in current Safari window:
var trackBlock = document.getElementsByClassName("track tracklist_track_title");
var trackList = [];
for (var a of trackBlock) {
trackList.push(a.innerText);
}
trackList.join("\n");
The problem is that my porting attempt works well in JXA if doJavaScript returns a single string (variable trackName1 contains track title):
var sfr = Application("Safari");
var trackName1 = sfr.doJavaScript('document.getElementsByClassName("track tracklist_track_title")[1].innerText', { in: sfr.windows[0].currentTab });
trackName1 // contains track name
But if I change the code, so that doJavaScript returns an array (as it was in the initial code), the variable is null. Can you, please, explain me: what am I doing wrong?
var sfr = Application("Safari");
var trackBlock = sfr.doJavaScript('document.getElementsByClassName("track tracklist_track_title")', { in: sfr.windows[0].currentTab });
trackBlock[0].innerText; // null
Thank you!
I think the problem is this statement:
trackList.join("\n");
When you put that code in a JXA script, you need to escape the \n:
trackList.join("\\n");
Here's my script that works:
'use strict';
(function myMain() { // function will auto-run when script is executed
var app = Application.currentApplication();
app.includeStandardAdditions = true;
/*
HOW TO USE:
1. Open Safari to this URL:
https://forum.keyboardmaestro.com/
2. Run this script
*/
var jsStr = `
(function myMain2() {
//debugger;
//return 'Just testing';
var elemCol = document.querySelectorAll('div.category-text-title');
var elemArr = Array.from(elemCol);
var titleArr = elemArr.map(e => {return e.innerText});
return titleArr.join('\\n');
})();
`
var safariApp = Application("Safari");
var oTab = safariApp.windows[0].currentTab();
var pageURL = oTab.url();
var pageTitle = oTab.name();
var jsScriptResults = safariApp.doJavaScript(jsStr, {in: oTab})
console.log(jsScriptResults);
return jsScriptResults;
})();
//-->RETURNS:
/* Questions & Suggestions
Macro Library
Plug In Actions
Tips & Tutorials
Wiki
Announcements
Status Menu Icons
Forum Admin
*/
Here is a more clear example of the issue. Here is the code:
var sfr = Application("Safari");
var scr2run = 'document.getElementsByClassName("tracklist_track_title")';
var scr2run1 = 'document.getElementsByClassName("tracklist_track_title")[0]';
var scr2run2 = 'document.getElementsByClassName("tracklist_track_title")[0].innerText';
var trackName = sfr.doJavaScript(scr2run, { in: sfr.windows[0].currentTab });
var trackName1 = sfr.doJavaScript(scr2run1, { in: sfr.windows[0].currentTab });
var trackName2 = sfr.doJavaScript(scr2run2, { in: sfr.windows[0].currentTab });
Here is the output:
app = Application("Safari")
app.doJavaScript("document.getElementsByClassName(\"tracklist_track_title\")", {in:app.windows.at(0).currentTab})
--> null
app.doJavaScript("document.getElementsByClassName(\"tracklist_track_title\")[0]", {in:app.windows.at(0).currentTab})
--> null
app.doJavaScript("document.getElementsByClassName(\"tracklist_track_title\")[0].innerText", {in:app.windows.at(0).currentTab})
--> "From What Is Said To When It's Read"
Why the two first doJavaScript calls return null, but the third one returns expected value?
In answer to your second question:
Why the two first doJavaScript calls return null, but the third one
returns expected value?
var scr2run = 'document.getElementsByClassName("tracklist_track_title")';
var scr2run1 = 'document.getElementsByClassName("tracklist_track_title")[0]';
var scr2run2 = 'document.getElementsByClassName("tracklist_track_title")[0].innerText';
The third JavaScript returns a text value, whereas the first two do not. They return an element collection and an element.

How to check the data in websocket?

Am now using websocket in HTML5 to build my web app.
Because my previous work was based on TCP and I used CRC16 algorithm to wrap the content that will transfer to server side;
Construct message with CRC16 code below:
public static byte[] ConstructMessageWithCRC(string message)
{
//Message with a |
var messageToConstruct = message + "|";
//calculate CRC value
var crcCode = CRC16.CalculateCrc16(messageToConstruct);
var crcCodeShort = ushort.Parse(crcCode);
//CRC high value
var crcHigh = byte.Parse((crcCodeShort / 256).ToString());
//CRC low value
var crcLow = byte.Parse((crcCodeShort % 256).ToString());
var messageBytes = Encoding.Default.GetBytes(messageToConstruct);
var messageLength = messageBytes.Length;
var messageBytesWithCRC = new byte[messageLength + 2];
Array.Copy(messageBytes, 0, messageBytesWithCRC, 0, messageLength);
//append crc value to the message
messageBytesWithCRC[messageLength] = crcHigh;
messageBytesWithCRC[messageLength + 1] = crcLow;
return messageBytesWithCRC;
}
After server side received the data, it will calculate the content via CRC16 algorithm also to ensure that the data is correct.
Check CRC code below:
public static bool CheckMessageCRC(byte[] message, out string messageReceived)
{
//message length that received
var messageLength = message.Length;
//message received without crc value
var messageReceivedStrBytes = new byte[messageLength - 2];
Array.Copy(message, 0, messageReceivedStrBytes, 0, messageLength - 2);
//crc value received
var messageReceivedCrcBytes = new byte[2];
Array.Copy(message, messageLength - 2, messageReceivedCrcBytes, 0, 2);
//get the received message with correct decoding
var messageCalculatedString = Encoding.Default.GetString(messageReceivedStrBytes);
messageReceived = messageCalculatedString;
//get the received crc value
var currentCRC = byte.Parse(messageReceivedCrcBytes[0].ToString()) * 256 + byte.Parse(messageReceivedCrcBytes[1].ToString());
//crc value recalculate
var result = ushort.Parse(CRC16.CalculateCrc16(messageCalculatedString));
//comparison
if (currentCRC == result)
return true;
return false;
}
From above code, you can see what I did.
But in some articles that using websocket: Working with Websockets, it will use below code to handle the message directly:
//When the server is sending data to this socket, this method is called
ws.onmessage = function (evt) {
//Received data is a string; We parse it to a JSON object using jQuery
//http://api.jquery.com/jQuery.parseJSON/
var jsonObject = $.parseJSON(evt.data);
//Do something with the JSON object
};
//Creates an object that will be sent to the server
var myObject = {
Property: "Value",
AnotherProperty: "AnotherValue"
};
//We need to stringify it through JSON before sending it to the server
ws.send(JSON.stringify(myJsonObject));
It will directly send the data out without any check mechanism with the data. So if the data is intercepted by others and we won't know the data has been changed. Also, because of poor network, the data will arrival out of order, then below code won't work correctly, maybe we wanted data as ABC, but we got BCA:
var jsonObject = $.parseJSON(evt.data);
So for evt.data, just wonder how should we check the data transfer complete, data order correct, data content correct and so on.
I have googled a lot and didn't see any info regarding this, just want use this question to declare the right way to transfer data via websocket, thx.
EDIT:
My friend send me this: https://www.rfc-editor.org/rfc/rfc6455, in section 5.2
I think the protocol seems do this work already. Need more of your discusses on it. thx

Error: PKCS#5:unpad: Invalid padding value. expected [154], found [253] using as3crypto

I downloaded as3crypto and have been trying to integrate it into my project.
I'm trying to do a simple test to match the decrypt results I'm getting in the demo - http://crypto.hurlant.com/demo/ but I'm getting the above error.
I'm working on the Secret Key tab. I'm using AES, CBC, PKCS5 and prepending the IV.
Both the Key and Cipher text is set to HEX.
I first did an Encrypt and then copy the key and the cipher text to my function to test the decrypt to see if it match. I copied the code direct from the SecretTab.mxml and modified it a little to take the hard coded values.
I wrote a small program in C# to decrypt it using the same values and it works fine.
I verified the key and cipher text many times and it is correct.
public static function decrypt2():void
{
// 2: get a key
var k:String = Hex.fromString("e5693983c5c21e0f6191eb025d12803d6d17c5359994bf435b964cd0c107fc2c");
var kdata:ByteArray = Hex.toArray(k);
//trace(String.fromCharCode(kdata[0]));
// 3: get an output
var txt:String = Hex.fromString("691682969f1946a1465ccfe19d429ace4188ee254425caa7fa84db5b1fba44a77f1dedfba7a1ffe516cb0646638e28f8ae6422b3cd63d380b21f8b8dcfbe067a");
var data:ByteArray = Hex.toArray(txt);
// 1: get an algorithm..
var name:String = "simple-aes-cbc";
var pad:IPad = new PKCS5; //:new NullPad;
//var pad:IPad = new NullPad();
var mode:ICipher = Crypto.getCipher(name, kdata, pad);
pad.setBlockSize(mode.getBlockSize());
// if an IV is there, set it.
if (mode is IVMode) {
trace("mode is IVMode");
var ivmode:IVMode = mode as IVMode;
//ivmode.IV = Hex.toArray(iv.text);
}
mode.decrypt(data);
trace(Hex.fromArray(data));
}
You need to explicitly set both byte arrays, the data and the IV, before decrypting. I don't think as3crypto will break it out for you, even if the simple flag is used on the name.
I don't know what your example states, however the error indicates that the byte array is not correct. Example with the IV explicitly set.
var cipher:ICipher = Crypto.getCipher("aes256-cbc", keydata);;
var dataBA:ByteArray = Hex.toArray(Hex.fromString(data));
var data:ByteArray = Hex.toArray(Hex.fromString("some data"));
(cipher as IVMode).IV = Hex.toArray(Hex.fromString("some IV"));
cipher.decrypt(data);
I found my typos. I had to change the following lines
var k:String = Hex.fromString("e5693983c5c21e0f6191eb025d12803d6d17c5359994bf435b964cd0c107fc2c");
to
var k:String = "e5693983c5c21e0f6191eb025d12803d6d17c5359994bf435b964cd0c107fc2c";
v
and
var txt:String = Hex.fromString("691682969f1946a1465ccfe19d429ace4188ee254425caa7fa84db5b1fba44a77f1dedfba7a1ffe516cb0646638e28f8ae6422b3cd63d380b21f8b8dcfbe067a");
to
var txt:String = "691682969f1946a1465ccfe19d429ace4188ee254425caa7fa84db5b1fba44a77f1dedfba7a1ffe516cb0646638e28f8ae6422b3cd63d380b21f8b8dcfbe067a";
and
trace(Hex.fromArray(data));
to
trace(Hex.toString(Hex.fromArray(data)));

How to use streams to JSON stringify large nested objects in Node.js?

I have a large javascript object that I want to convert to JSON and write to a file. I thought I could do this using streams like so
var fs = require('fs');
var JSONStream = require('JSONStream');
var st = JSONStream.stringifyObject()
.pipe(fs.createWriteStream('./output_file.js'))
st.write(large_object);
When I try this I get an error:
stream.js:94
throw er; // Unhandled stream error in pipe.
^
TypeError: Invalid non-string/buffer chunk
at validChunk (_stream_writable.js:153:14)
at WriteStream.Writable.write (_stream_writable.js:182:12)
So apparently I cant just write an object to this stringifyObject. I'm not sure what the next step is. I need to convert the object to a buffer? Run the object through some conversion stream and pipe it to strinigfyObject
JSONStream doesn't work that way but since your large object is already loaded into memory there is no point to that.
var fs = require('fs-extra')
var file = '/tmp/this/path/does/not/exist/file.txt'
fs.outputJson(file, {name: 'JP'}, function (err) {
console.log(err) // => null
});
That will write the JSON.
If you want to use JSONStream you could do something like this:
var fs = require('fs');
var jsonStream = require('JSONStream');
var fl = fs.createWriteStream('dat.json');
var out = jsonStream.stringifyObject();
out.pipe(fl);
obj = { test:10, ok: true };
for (key in obj) out.write([key, obj[key]]);
out.end();
Well the question is quite old but still valid for nowadays, I faced same issue but solved it using this JsonStreamStringify package.
const { JsonStreamStringify } = require("json-stream-stringify");
Now,
x = new JsonStreamStringify(cursor).pipe(res);
x.on("data", (doc) => {
res.write(doc);
});
Here you can read your file using fs and then write the above code. 'cursor' will be pointing to your file.
In this way, you can stream your file in valid JSON Format.
For Docs:
https://www.npmjs.com/package/json-stream-stringify

Creating a zip file from a JSON object using adm-zip

I'm trying to create a .zip file from a JSON object in Node.js. I'm using adm-zip to do that however I'm unable to make it work with this code:
var admZip = require('adm-zip');
var zip = new admZip();
zip.addFile(Date.now() + '.json', new Buffer(JSON.stringify(jsonObject));
var willSendthis = zip.toBuffer();
fs.writeFileSync('./example.zip', willSendthis);
This code creates example.zip but I'm not able to extract it, I tried with a .zipextractor but also with this code:
var admZip = require('adm-zip');
var zip = new admZip("./example.zip");
var zipEntries = zip.getEntries(); // an array of ZipEntry records
zipEntries.forEach(function(zipEntry) {
console.log(zipEntry.data.toString('utf8'));
});
It returns Cannot read property 'toString' of undefined at the line with console.log.
I could use zip.writeZip() for this example but I'm sending the .zipfile to Amazon S3 thus I need to use the method .toBuffer() to do something like this after using adm-zip:
var params = {Key: 'example.zip', Body: zip.toBuffer()};
s3bucket.upload(params, function(err, data) {...});
I don't see what is wrong, am I using the package correctly?
Try use zipEntry.getData().toString('utf8') instead zipEntry.data.toString('utf8'):
var admZip = require('adm-zip');
var zip = new admZip("./example.zip");
var zipEntries = zip.getEntries(); // an array of ZipEntry records
zipEntries.forEach(function(zipEntry) {
console.log(zipEntry.getData().toString('utf8'));
});